1

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.

5
  • 1
    The only thing I could image is that NI VISA doesn't use the connect method from ws2_32.dll and instead uses something else. You should be able to check with the process monitor Commented Oct 28 at 14:59
  • @MindSwipe I can see in the process monitor that ws2_32.dll is loaded. But I don't know how to see which connect method is called. I tried as well for testing replacing all NI VISA stuff with a simple var client = new TcpClient(); client.Connect("10.0.0.2", 80) which loads as well the ws2_32.dll. But as well here my ConnectHook method is never called. Commented Oct 29 at 7:45
  • Looking into the winsock2 API it might be as simple as hooking the WSAConnect function instead. If that doesn't work you'll probably have to look into hooking into syscalls and seeing which is used. Commented Oct 29 at 8:00
  • @MindSwipe TcpClient is using WSAConnect and I can hook it. But NI VISA GlobalResourceManager.Open(rn) is not using WSAConnect and not connect. Commented Oct 29 at 8:47
  • Setting a breakpoint to ws2_32!WSASend I can see that this is been called by NI VISA. Commented Oct 29 at 9:05

1 Answer 1

0

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;

    // ...
 
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.