Based on my question C# IVI VISA (e.g.: NI VISA) TCP Keep Alive I tried to use EasyHook to patch how NI VISA is opening a SOCKET connection. Finally I would like to modify the keep alive settings in the ConnectHook method (not in there yet).
I've the following code:
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
delegate int ConnectDelegate(IntPtr socket, IntPtr sockaddr, int namelen);
[DllImport("ws2_32.dll", SetLastError = true, EntryPoint = "connect")]
static extern int Connect(IntPtr socket, IntPtr sockaddr, int namelen);
static int ConnectHook(IntPtr socket, IntPtr sockaddr, int namelen)
{
Console.WriteLine("SOCKET Connect");
int s = Connect(socket, sockaddr, namelen);
return s;
}
and
static void Main(string[] args)
{
string rn = "TCPIP::10.0.0.2::hislip0::INSTR";
//string rn = "TCPIP::10.0.0.2::inst0::INSTR"; // VXI-11
// Make sure ws2_32.dll is loaded
var vi = GlobalResourceManager.Open(rn) as IMessageBasedSession;
vi.Dispose();
LocalHook hook = LocalHook.Create(LocalHook.GetProcAddress("ws2_32.dll", "connect"),
new ConnectDelegate(ConnectHook),
null);
hook.ThreadACL.SetInclusiveACL(new int[] { 0 });
// Connect
vi = GlobalResourceManager.Open(rn) as IMessageBasedSession;
// IDN query
vi.RawIO.Write("*IDN?");
Console.WriteLine(vi.RawIO.ReadString());
// Sleep to monitor keep alive traffic using Wireshark
Thread.Sleep(10 * 1000);
// IDN query
vi.RawIO.Write("*IDN?");
Console.WriteLine(vi.RawIO.ReadString());
// Disconnect
vi.Dispose();
hook.Dispose();
}
The above source code is all in the same assembly (Console application). But my ConnectHook method is newer called when GlobalResourceManager.Open(rn) is running.
I'm able to run and hook the MessageBeep example from https://easyhook.github.io/tutorials/createlocalhook.html.
1 Answer 1
NI VISA GlobalResourceManager.Open(rn) calls WSASocketW and not connect to establish a TCP connection.
So I was able to hook the WSASocketW method with the following code:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate IntPtr WSASocketWDelegate(int af, int type, int protocol, IntPtr lpProtocolInfo, uint g, uint dwFlags);
[DllImport("Ws2_32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "WSASocketW")]
static extern IntPtr WSASocketW(int af, int type, int protocol, IntPtr lpProtocolInfo, uint g, uint dwFlags);
static IntPtr WSASocketWHook(int af, int type, int protocol, IntPtr lpProtocolInfo, uint g, uint dwFlags)
{
Console.WriteLine("SOCKET WSASocketW");
IntPtr s = WSASocketW(af, type, protocol, lpProtocolInfo, g, dwFlags);
return s;
}
and now my WSASocketWHook method gets called in the second GlobalResourceManager.Open(rn) call after the hook is activated.
The first call, which is used to make sure that the Ws2_32.dll is loaded, could be replaced with call to WSAStartup with the following code:
[DllImport("ws2_32.dll", SetLastError = true)]
static extern int WSAStartup(ushort wVersionRequested, out WSAData wsaData);
[StructLayout(LayoutKind.Sequential)]
struct WSAData
{
public short wVersion;
public short wHighVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string szDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string szSystemStatus;
public short iMaxSockets;
public short iMaxUdpDg;
public IntPtr lpVendorInfo;
}
static void EnsureWs2_32Loaded()
{
WSAData wsaData;
int result = WSAStartup(0x202, out wsaData); // Version 2.2
if (result != 0)
throw new Exception("WSAStartup failed.");
}
and finally in the main method:
static void Main(string[] args)
{
//string rn = "TCPIP::10.0.0.2::hislip0::INSTR";
string rn = "TCPIP::10.0.0.2::inst0::INSTR"; // VXI-11
EnsureWs2_32Loaded();
LocalHook hook = LocalHook.Create(LocalHook.GetProcAddress("ws2_32.dll", "WSASocketW"),
new WSASocketWDelegate(WSASocketWHook),
null);
hook.ThreadACL.SetInclusiveACL(new int[] { 0 });
// Connect
var vi = GlobalResourceManager.Open(rn) as IMessageBasedSession;
// ...
}
Comments
Explore related questions
See similar questions with these tags.
var client = new TcpClient(); client.Connect("10.0.0.2", 80)which loads as well the ws2_32.dll. But as well here myConnectHookmethod is never called.WSAConnectfunction instead. If that doesn't work you'll probably have to look into hooking into syscalls and seeing which is used.TcpClientis usingWSAConnectand I can hook it. But NI VISAGlobalResourceManager.Open(rn)is not usingWSAConnectand notconnect.ws2_32!WSASendI can see that this is been called by NI VISA.