C# Easyhook Winsock WS2_32.dll,connect hook Socks5
Asked Answered
M

0

6

I'm trying to hook the winsock connect function and route the TCP connection through socks5 proxy /w auth.

This works if the socket is a blocking socket, but while using firefox ( nonblocking sockets ) I get a lot of 10035, 10022 winsock Errors.

How can i determine if it's a nonblocking / blocking socket?

I would really appreciate any hints or ideas to achieve the functionality to hook the wsock connect function and route tcp traffic through a socks5 server.

I can put the demo application on github if anybody wants to test it. ( Works with any version of firefox )

Edit1: https://github.com/duketwo/WinsockConnectHookSocks5/

( You have to edit the proxy information in WSockConnectHook/HookManager.cs and the path of firefox in Injector/MainForm.cs )

Edit2: It's easyhook which is causing the trouble, anything after the original function call doesn't work properly.

Edit3: Seems like i got it working with many flaws, in fact it is required differentiate between nonblocking sockets and blocking sockets. Any ideas how to achieve this?

Edit4: Windows doesn't offer any method to retrieve the blocking-attribute of a socket, so I might have to hook the ioctlsocket function to keep track of the blocking status of the sockets.

Thanks

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using EasyHook;
using System.IO;
using System.Windows.Forms;

namespace WSockConnectHook
{
    public class WinSockConnectController : IDisposable, IHook
    {
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet =     CharSet.Ansi, SetLastError = true)]
        private delegate int WinsockConnectDelegate(IntPtr s, IntPtr     addr, int addrsize);

    [DllImport("WS2_32.dll", SetLastError = true)]
    public static extern int connect(IntPtr s, IntPtr addr, int addrsize);

    [StructLayout(LayoutKind.Sequential, Size = 16)]
    public struct sockaddr_in
    {
        public const int Size = 16;

        public short sin_family;
        public ushort sin_port;
        public struct in_addr
        {
            public uint S_addr;
            public struct _S_un_b
            {
                public byte s_b1, s_b2, s_b3, s_b4;
            }
            public _S_un_b S_un_b;
            public struct _S_un_w
            {
                public ushort s_w1, s_w2;
            }
            public _S_un_w S_un_w;
        }
        public in_addr sin_addr;
    }

    [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int WSAGetLastError();

    [DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern void WSASetLastError(int set);

    [DllImport("Ws2_32.dll", CharSet = CharSet.Ansi)]
    public static extern uint inet_addr(string cp);

    [DllImport("Ws2_32.dll")]
    public static extern ushort htons(ushort hostshort);

    [DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr socket(short af, short socket_type, int protocol);

    [DllImport("Ws2_32.dll")]
    public static extern int send(IntPtr s, IntPtr buf, int len, int flags);

    [DllImport("Ws2_32.dll")]
    public static extern int recv(IntPtr s, IntPtr buf, int len, int flags);

    [DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int closesocket(IntPtr s);

    [DllImport("Ws2_32.dll")]
    public static extern ushort ntohs(ushort netshort);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern void SetLastError(int errorCode);

    private string _name;
    private LocalHook _hook;
    public bool Error { get; set; }
    public string Name { get; set; }

    private string proxyIp, proxyPort, proxyUser, proxyPass;

    public WinSockConnectController(IntPtr address, string proxyIp, string proxyPort, string proxyUser, string proxyPass)
    {
        this.Name = typeof(WinSockConnectController).Name;

        this.proxyIp = proxyIp;
        this.proxyPort = proxyPort;
        this.proxyUser = proxyUser;
        this.proxyPass = proxyPass;

        try
        {

            _name = string.Format("WinsockHook_{0:X}", address.ToInt32());
            _hook = LocalHook.Create(address, new WinsockConnectDelegate(WinsockConnectDetour), this);
            _hook.ThreadACL.SetExclusiveACL(new Int32[] { 1 });

        }
        catch (Exception)
        {

            this.Error = true;

        }

    }

    private object wSockLock = new object();
    private int WinsockConnectDetour(IntPtr s, IntPtr addr, int addrsize)
    {

        lock (wSockLock)
        {

            // retrieve remote ip
            sockaddr_in structure = (sockaddr_in)Marshal.PtrToStructure(addr, typeof(sockaddr_in));
            string remoteIp = new System.Net.IPAddress(structure.sin_addr.S_addr).ToString();
            ushort remotePort = ntohs(structure.sin_port);
            HookManager.Log("Ip: " + remoteIp + " Port: " + remotePort.ToString() + " Addrsize: " + addrsize);

            if (!proxyIp.Equals(""))
                //if (!proxyIp.Equals(""))
            {

                // connect to socks5 server
                SetAddr(s, addr, proxyIp, proxyPort);
                var result = Connect(s, addr, addrsize);
                if (result == -1)
                    return -1;

                // send socks 5 request
                IntPtr socksProtocolRequest = SetUpSocks5Request();
                result = send(s, socksProtocolRequest, 4, 0);
                if (result == -1)
                    return -1;

                // retrieve server repsonse
                var response = Recieve(s, 2);
                if (response == IntPtr.Zero)
                    return -1;

                byte[] recvBytes = new byte[2] { Marshal.ReadByte(response), Marshal.ReadByte(response, 1) };
                if (recvBytes[1] == 255)
                {
                    HookManager.Log("No authentication method was accepted by the proxy server");
                    return -1;
                }
                if (recvBytes[0] != 5)
                {
                    HookManager.Log("No SOCKS5 proxy");
                    return -1;
                }

                // if auth request response, send authenicate request
                if (recvBytes[1] == 2)
                {
                    int length = 0;
                    var authenticateRequest = SetUpAuthenticateRequest(proxyUser, proxyPass, out length);
                    result = Send(s, authenticateRequest, length);

                    response = Recieve(s, 2);
                    if (response == IntPtr.Zero)
                        return -1;

                    recvBytes = new byte[2] { Marshal.ReadByte(response), Marshal.ReadByte(response, 1) };
                    if (recvBytes[1] != 0)
                    {
                        HookManager.Log("Proxy: incorrect username/password");
                        return -1;
                    }
                }

                // request bind with server
                var bindRequest = SetUpBindWithRemoteHost(remoteIp, remotePort);
                result = Send(s, bindRequest, 10);
                if (result == -1)
                    return -1;

                // response
                response = Recieve(s, 10);
                if (response == IntPtr.Zero)
                    return -1;
                if (!VerifyBindResponse(response))
                    return -1;

                // success
                WSASetLastError(0);
                SetLastError(0);

                // clean memory
                foreach (var ptr in allocatedMemory)
                    Marshal.FreeHGlobal(ptr);

                allocatedMemory.Clear();
                return 0;
            }
            else
            {
                var result = connect(s, addr, addrsize);
                return result;
            }
        }
    }

    private int Connect(IntPtr socket, IntPtr addr, int addrsize)
    {
        var result = connect(socket, addr, addrsize);
        while (result == -1)
        {
            var errorcode = WSAGetLastError();
            HookManager.Log("Error: " + errorcode);
            if (errorcode == 10056)
                break;

            if (errorcode == 10037)
                break;

            if (errorcode != 10035 && errorcode != 10037)
                return -1;

            //flag = 1;
            result = connect(socket, addr, addrsize);
        }
        return result;
    }

    private int Send(IntPtr socket, IntPtr buf, int len)
    {
        var result = send(socket, buf, len, 0);
        while (result == -1)
        {
            var errorcode = WSAGetLastError();
            HookManager.Log("Error: " + errorcode);
            if (errorcode == 10056)
                break;

            if (errorcode == 10037)
                break;

            if (errorcode != 10035 && errorcode != 10037)
                return -1;

            result = send(socket, buf, 4, 0);
        }
        return result;
    }

    private List<IntPtr> allocatedMemory = new List<IntPtr>();
    private IntPtr Recieve(IntPtr socket, int len)
    {
        var buffer = Marshal.AllocHGlobal(len);
        allocatedMemory.Add(buffer);

        var result = recv(socket, buffer, len, 0);
        if (result == -1)
        {
            HookManager.Log("Error2: " + WSAGetLastError());
            return IntPtr.Zero;
        }

        return buffer;
    }

    private IntPtr RecieveAuth(IntPtr socket, int len)
    {
        var buffer = Marshal.AllocHGlobal(len);
        allocatedMemory.Add(buffer);

        var result = recv(socket, buffer, len, 0);
        if (result == -1)
        {
            HookManager.Log("Error3: " + WSAGetLastError());
            return IntPtr.Zero; ;
        }

        if (result == 0)
            return buffer;

        if (result != 2)
        {
            HookManager.Log("Proxy: Bad response from server");
            return IntPtr.Zero;
        }
        return buffer;
    }

    private IntPtr RecieveBind(IntPtr socket, int len)
    {
        var buffer = Marshal.AllocHGlobal(len);
        allocatedMemory.Add(buffer);

        var result = recv(socket, buffer, len, 0);
        if (result == -1)
        {
            HookManager.Log("Error3: " + WSAGetLastError());
            return IntPtr.Zero; ;
        }

        if (result == 0)
            return buffer;

        if (result != 10)
        {
            HookManager.Log("Proxy: Bad response from server");
            return IntPtr.Zero;
        }
        return buffer;
    }

    private void SetAddr(IntPtr socket, IntPtr addr, string ip, string port)
    {
        sockaddr_in structure = (sockaddr_in)Marshal.PtrToStructure(addr, typeof(sockaddr_in));
        string originalip = new System.Net.IPAddress(structure.sin_addr.S_addr).ToString();
        ushort originalport = ntohs(structure.sin_port);

        structure.sin_addr.S_addr = inet_addr(ip);
        structure.sin_port = htons(Convert.ToUInt16(port));
        Marshal.StructureToPtr(structure, addr, true);
        structure = (sockaddr_in)Marshal.PtrToStructure(addr, typeof(sockaddr_in));
    }

    private IntPtr SetUpSocks5Request()
    {
        var initialRequest = Marshal.AllocHGlobal(4);

        Marshal.WriteByte(initialRequest, Convert.ToByte(5));
        Marshal.WriteByte(initialRequest + 1, Convert.ToByte(2));
        Marshal.WriteByte(initialRequest + 2, Convert.ToByte(0));
        Marshal.WriteByte(initialRequest + 3, Convert.ToByte(2));

        return initialRequest;
    }

    private IntPtr SetUpAuthenticateRequest(string username, string password, out int index)
    {
        index = 0;
        var size = 3 + Encoding.Default.GetBytes(username).Length + Encoding.Default.GetBytes(password).Length;
        var authenticateBuffer = Marshal.AllocHGlobal(size);

        Marshal.WriteByte(authenticateBuffer + index++, Convert.ToByte(1));
        Marshal.WriteByte(authenticateBuffer + index++, Convert.ToByte(username.Length));
        byte[] rawBytes;
        if (username.Length > 0)
        {
            rawBytes = Encoding.Default.GetBytes(username);
            for (int i = 0; i < rawBytes.Length; i++)
            {
                Marshal.WriteByte(authenticateBuffer + index++, rawBytes[i]);
            }
        }
        Marshal.WriteByte(authenticateBuffer + index++, Convert.ToByte(password.Length));
        if (password.Length > 0)
        {
            rawBytes = Encoding.Default.GetBytes(password);
            for (int i = 0; i < rawBytes.Length; i++)
            {
                Marshal.WriteByte(authenticateBuffer + index++, rawBytes[i]);
            }
        }

        return authenticateBuffer;
    }

    private IntPtr SetUpBindWithRemoteHost(string eveIP, ushort evePort)
    {
        var bindWithEveBuffer = Marshal.AllocHGlobal(10);
        var iplist = eveIP.Split('.').ToList();
        byte[] portbyte = BitConverter.GetBytes(evePort).Reverse().ToArray();
        byte[] newbyte = new byte[2];
        int indexy = 0;
        foreach (var byty in portbyte)
        {
            newbyte[indexy] = byty;
            indexy++;
        }

        // bind with remote server
        Marshal.WriteByte(bindWithEveBuffer, Convert.ToByte(5));
        Marshal.WriteByte(bindWithEveBuffer + 1, Convert.ToByte(1));
        Marshal.WriteByte(bindWithEveBuffer + 2, Convert.ToByte(0));
        Marshal.WriteByte(bindWithEveBuffer + 3, Convert.ToByte(1));
        Marshal.WriteByte(bindWithEveBuffer + 4, Convert.ToByte(iplist[0]));
        Marshal.WriteByte(bindWithEveBuffer + 5, Convert.ToByte(iplist[1]));
        Marshal.WriteByte(bindWithEveBuffer + 6, Convert.ToByte(iplist[2]));
        Marshal.WriteByte(bindWithEveBuffer + 7, Convert.ToByte(iplist[3]));
        Marshal.WriteByte(bindWithEveBuffer + 8, newbyte[0]);
        Marshal.WriteByte(bindWithEveBuffer + 9, newbyte[1]);

        return bindWithEveBuffer;
    }

    private bool VerifyBindResponse(IntPtr buffer)
    {
        var recvBytes = new byte[10] { Marshal.ReadByte(buffer), Marshal.ReadByte(buffer, 1), Marshal.ReadByte(buffer, 2), Marshal.ReadByte(buffer, 3), Marshal.ReadByte(buffer, 4), Marshal.ReadByte(buffer, 5), Marshal.ReadByte(buffer, 6), Marshal.ReadByte(buffer, 7), Marshal.ReadByte(buffer, 8), Marshal.ReadByte(buffer, 9) };

        if (recvBytes[1] != 0)
        {
            if (recvBytes[1] == 1)
                HookManager.Log("General failure");
            if (recvBytes[1] == 2)
                HookManager.Log("connection not allowed by ruleset");
            if (recvBytes[1] == 3)
                HookManager.Log("network unreachable");
            if (recvBytes[1] == 4)
                HookManager.Log("host unreachable");
            if (recvBytes[1] == 5)
                HookManager.Log("connection refused by destination host");
            if (recvBytes[1] == 6)
                HookManager.Log("TTL expired");
            if (recvBytes[1] == 7)
                HookManager.Log("command not supported / protocol error");
            if (recvBytes[1] == 8)
                HookManager.Log("address type not supported");

            HookManager.Log("Proxy: Connection error binding eve server");
            return false;
        }
        return true;
    }


    public void Dispose()
    {
        if (_hook == null)
            return;

        _hook.Dispose();
        _hook = null;
    }
}

}

Molina answered 27/8, 2015 at 20:47 Comment(2)
Why are you using dll calls instead of using the Socket class?Boice
Im trying to detour a native win api function ( Ws2_32.dll, connect ) by dll injection to route ANY tcp traffic of a program through a socks5 proxy server. You can't use any net classes while dealing with native api functions. Similiar tools are for example proxifier, sockscap, freecapMolina

© 2022 - 2024 — McMap. All rights reserved.