天天看点

C# NetCut / Only

本类库实际上是一种很失败的东西,至少在我看来是足够失败 当时也不知道是头发热

还是人未醒,居然会去拦截WinInet,看来几年前学习的WebProxy与HTTP是白学了,

我想应该是 Retrieve-HttpOnly-Session-Cookie-in-WebBrowser 这篇帖子中的一些话

误导了我把,本类库的源代码实际上只是提供给大家学习API-HOOK的一个小小应用

不过API-HOOK分了好几种,我最喜欢的还是IAT,EAT,INLINE三种,不过论到实

用性INLINE是最好的,RING3级 稳定性与安全性还是很OK的、

Hooking the methods exposed by WININET.DLL gives the ability to interact with each request sending to server, including the 

AJAX 

request! 

The probable call sequence is shown as below: 

Hide    Copy Code

1=> InternetOpen
2=> InternetConnect
3=> HttpOpenRequest
// .............
X=> InternetCloseHandle        

By hooking these methods, it is possible for us to detect each request sent to the web server, and inject our codes before / after each request.

Why not WINSOCK? It is easier to hook methods exposed by WININET.DLL than hooking 

WINSOCK 

methods, since the former wraps the HTTP protocol.

There are two different ways in hooking, inline hook and routine hook. Inline hook is universal for almost all of the cases, however, routine hook is more robust. The sample implements it by modifying the IAT(Import Address Table), one of the routine hooks.

If you need more details about IAT hook, here is an article for reference. 

好吧,不在给自己找理由,本类库已经修正了一些命名 主要是把源代码移植到使用  API-Hook / RING3

上,我注解一些命名上的变动,实际上你改回去也是一样的。

Inline-Hook ->Ex-> NetHook、

NetCut ->NetworkCut、

NetTab -> NetworkTable、

NetworkProtocol ->NetServer、

NetTabCollection ->NetworkTableCollection、

NetCutRequestComplete -> NetworkCutRequestComplete

C# NetCut / Only

不过我们到也可以可以看看,如果通过“封包 / 截包”技术可以轻松得到什么?

C# NetCut / Only

该处拦截的是ws2_32.dll导出的函数,有些人会问为什么不去拦截wsock32.dl呢?

你可以这样去看待,实际上这两个DLL并没有太大的区别,一个微软用于CString

一个用于string,本质上它是 CString-> string 所以是 wsock32.dll ->ws2_32.dll

Http请求首先会去解析对方主机的地址表,然后选择一个候选地址通过socket连

接对方的主机的80端口,一个完整的Http请求首先是客户端发送协议头,中包含

请求的协议头,对方接收到后进行一个处理并进行相应我们只需要去接受来自服

务器返回的数据包即可,微软在Internet Explorer 9中支持开发人员可以网络抓包

大概则是这样去实现的, 我是不太相信微软开发人员可能会使用 SOCK SPI 的、

在NetCut中你也可以实现获取类似的功能,只是相对性的会复杂一些,那么我举

一个列子我们需要获取请求返回给客户端的Cookie,如何去做呢?

// example:
private const int HTTP_QUERY_SET_COOKIE = 43;

private void _NetCut_RequestComplete(object sender, NetCut.NetTab e)
{
StringBuilder strBufferBuider = new StringBuilder(4096);
string strSetCookieValue = e.QueryInfo(e.RequestHandle, HTTP_QUERY_SET_COOKIE, strBufferBuider);
if(strSetCookieValue != null && strSetCookieValue.Length > 0)
Console.WriteLine(strSetCookieValue);
}
           

上面则是通过NetTab去获取请求返回给客户端的 Cookie,如果有则返回否则会返回 null

不过在NetTab对象中可以通过ResponseCookie属性获取Cookie,你可以不必使用上述

代码进行获取服务器返回给客户端的Cookie

C# NetCut / Only

好的,如果我们需要客户端发送请求附加的Cookie需要调用到WININET.DLL中导出的

两个函数 InternetGetCookie / InternetGetCookieEx 便可以了、

C# Declare:

[DllImport("wininet.dll", SetLastError=true)]
public static extern bool InternetGetCookie(
  string url, string cookieName, StringBuilder cookieData, ref int size);
           
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool InternetGetCookieEx(string pchURL, string pchCookieName, StringBuilder pchCookieData, ref System.UInt32 pcchCookieData, int dwFlags, IntPtr lpReserved);
           

如果你需要查阅NetCut中的源代码,那么你首先需要下载: CAT / Inline-Hook.dll

如果你需要阅读一些相关的资料可以查阅C#方面的内容: Inline-Hook / CSDN Blog.

当你下载完毕后解压 会看其中有包含4.0、2.0的两个文件夹根据你的项目

中使用的.NET框架版本打开对应版本的文件夹

C# NetCut / Only

注意一般项目默认是AnyCPU,在64位系统中默认为x64,在32系统中默认为x86

所以你在选择DLL的时候一定要注意这样的问题,在代码中会使用到不安全代码

Unsafe,也可以说是本地代码 所以你必须要在项目属性中勾选“允许不安全代码”

C# NetCut / Only

在上面我是使用的x86程序所以,我需要X86的DLL且因我的项目.NET版本为4.0

C# NetCut / Only

现在我们需要添加项目引用,点击“添加引用(R)”

C# NetCut / Only

在弹出的“引用管理中”点击“浏览(B)”按钮,然后我们把需要引用的DLL路径复制进去

点击“选择要引用的文件...”窗口中“添加”按钮,OK、

C# NetCut / Only

需要注意的地方基本上没有了现在就是贴代码、首先是NetHook部分

namespace System.Runtime.InteropServices
{
    public class NetHook : InlineHook
    {
        public void Install(string strLibraryName, string strMethodName, IntPtr newMethodAddress)
        {
            IntPtr oldMethodAddress = base.GetProcAddress(strLibraryName, strMethodName);
            base.Install(oldMethodAddress, newMethodAddress);
        }
    }
}
           

在上面为了支持源NetCut类的源代码,所以我必须在此处为InlineHook扩展一个Install方法

NetCut使用的办法,你可以参阅 NetCut / CSDN Blog. 包含示例代码 两个类是相等的、

下面是NetCut类的源代码,有一些不足之处已经被我小小修复了一下、本类工作最多的部分

是在NetworkTableCollection,其他类实在是没做什么、不过需要你去了解需求使用的 API、

using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;

#pragma warning disable 649

namespace System.Net
{
    [Flags]
    public enum NetworkProtocol : uint
    {
        Ftp = 1,
        Gopher,
        Http
    }

    unsafe class Win32Native
    {
        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr InternetConnect(
                IntPtr hInternet,
                string lpszServerName,
                short nServerPort,
                string lpszUsername,
                string lpszPassword,
                int dwService,
                int dwFlags,
                IntPtr dwContext
            );

        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr HttpOpenRequest(
                IntPtr hConnect,
                string lpszVerb,
                string lpszObjectName,
                string lpszVersion,
                string lpszReferer,
                char** lplpszAcceptTypes,
                int dwFlags,
                IntPtr dwContext
            );

        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool HttpAddRequestHeaders(
                IntPtr hRequest,
                string pwszHeaders,
                int dwHeadersLength,
                uint dwModifiers
            );

        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool HttpSendRequest(
                IntPtr hRequest,
                string lpszHeaders,
                uint dwHeadersLength,
                IntPtr lpOptional,
                uint dwOptionalLength
            );

        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool HttpQueryInfo(
                IntPtr hInternet,
                int dwInfoLevel,
                StringBuilder lpBuffer,
                ref uint lpdwBufferLength,
                IntPtr lpdwIndex
            );

        [DllImport("WinInet.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool InternetCloseHandle(IntPtr hInternet);

        public static readonly IntPtr NULL = IntPtr.Zero;
        public const int HTTP_QUERY_RAW_HEADERS = 21;
        public const int HTTP_QUERY_RAW_HEADERS_CRLF = 22;
        public const int HTTP_QUERY_STATUS_CODE = 19;
        public const int HTTP_QUERY_SET_COOKIE = 43;
    }

    public delegate void NetworkCutRequestComplete(object sender, NetworkTable e);

    public partial class NetworkCut
    {
        private class NetworkCutBase
        {
            public NetHook InternetConnectA;
            public NetHook InternetConnectW;
            public NetHook HttpOpenRequestA;
            public NetHook HttpOpenRequestW;
            public NetHook HttpAddRequestHeadersA;
            public NetHook HttpAddRequestHeadersW;
            public NetHook HttpSendRequestA;
            public NetHook HttpSendRequestW;

            public NetworkCutBase()
            {
                var fields = typeof(NetworkCutBase).GetFields();
                foreach (var field in fields)
                    field.SetValue(this, new NetHook());
            }
        }

        private unsafe class Win32Pointer
        {
            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
            public delegate IntPtr InternetConnectA(
                     IntPtr hInternet,
                     string lpszServerName,
                     short nServerPort,
                     string lpszUsername,
                     string lpszPassword,
                     int dwService,
                     int dwFlags,
                     IntPtr dwContext
                 );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
            public delegate IntPtr InternetConnectW(
                     IntPtr hInternet,
                     string lpszServerName,
                     short nServerPort,
                     string lpszUsername,
                     string lpszPassword,
                     int dwService,
                     int dwFlags,
                     IntPtr dwContext
                 );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
            public delegate IntPtr HttpOpenRequestA(
                    IntPtr hConnect,
                    string lpszVerb,
                    string lpszObjectName,
                    string lpszVersion,
                    string lpszReferer,
                    char** lplpszAcceptTypes,
                    int dwFlags,
                    IntPtr dwContext
                );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
            public delegate IntPtr HttpOpenRequestW(
                    IntPtr hConnect,
                    string lpszVerb,
                    string lpszObjectName,
                    string lpszVersion,
                    string lpszReferer,
                    char** lplpszAcceptTypes,
                    int dwFlags,
                    IntPtr dwContext
                );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
            public delegate bool HttpAddRequestHeadersA(
                    IntPtr hRequest,
                    string pwszHeaders,
                    int dwHeadersLength,
                    uint dwModifiers
                );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
            public delegate bool HttpAddRequestHeadersW(
                    IntPtr hRequest,
                    string pwszHeaders,
                    int dwHeadersLength,
                    uint dwModifiers
                );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
            public delegate bool HttpSendRequestA(
                   IntPtr hRequest,
                   string lpszHeaders,
                   uint dwHeadersLength,
                   IntPtr lpOptional,
                   uint dwOptionalLength
               );

            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
            public delegate bool HttpSendRequestW(
                   IntPtr hRequest,
                   string lpszHeaders,
                   uint dwHeadersLength,
                   IntPtr lpOptional,
                   uint dwOptionalLength
               );
        }
    }

    public partial class NetworkCut
    {
        private NetworkCutBase mNetCutBase;
        public event NetworkCutRequestComplete RequestComplete;

        public NetworkCut()
        {
            this.mNetCutBase = new NetworkCutBase();
            this.Items = new NetworkTableCollection(this);
        }

        public void Install()
        {
            this.ExecuteCommand(-1);
        }

        public void Uninstall()
        {
            this.ExecuteCommand(0);
        }

        public void Suspend()
        {
            this.ExecuteCommand(2);
        }

        public void Resume()
        {
            this.ExecuteCommand(1);
        }

        private void ExecuteCommand(int command)
        {
            var asm = typeof(NetworkCutBase).Assembly;
            var fields = typeof(NetworkCutBase).GetFields();
            foreach (var field in fields)
            {
                NetHook h = (field.GetValue(mNetCutBase) as NetHook);
                switch (command)
                {
                    case -1:
                        Type td = asm.GetType("System.Net.NetworkCut+Win32Pointer+" + field.Name);
                        Delegate d = Delegate.CreateDelegate(td, this, field.Name);
                        h.Install("WinInet.dll", field.Name, Marshal.GetFunctionPointerForDelegate(d));
                        break;
                    case 0:
                        h.Uninstall();
                        break;
                    case 1:
                        h.Resume();
                        break;
                    case 2:
                        h.Suspend();
                        break;
                }
            }
        }

        public NetworkTableCollection Items
        {
            get;
            private set;
        }

        internal void OnRequestComplete(NetworkTable tab)
        {
            if (this.RequestComplete != null)
                this.RequestComplete(this, tab);
        }
    }

    public unsafe partial class NetworkCut
    {
        private IntPtr InternetConnectA(IntPtr hInternet, string lpszServerName, short nServerPort,
                string lpszUsername, string lpszPassword, int dwService, int dwFlags, IntPtr dwContext)
        {
            try
            {
                mNetCutBase.InternetConnectA.Suspend();
                IntPtr hConnect = Win32Native.InternetConnect(hInternet, lpszServerName, nServerPort,
                    lpszUsername, lpszPassword, dwService, dwFlags, dwContext);
                this.Items.Add(hInternet, hConnect, lpszServerName, lpszUsername, lpszPassword, dwService, nServerPort);
                return hConnect;
            }
            finally
            {
                mNetCutBase.InternetConnectA.Resume();
            }
        }

        private IntPtr InternetConnectW(IntPtr hInternet, string lpszServerName, short nServerPort,
                string lpszUsername, string lpszPassword, int dwService, int dwFlags, IntPtr dwContext)
        {
            try
            {
                mNetCutBase.InternetConnectW.Suspend();
                IntPtr hConnect = Win32Native.InternetConnect(hInternet, lpszServerName, nServerPort,
                    lpszUsername, lpszPassword, dwService, dwFlags, dwContext);
                this.Items.Add(hInternet, hConnect, lpszServerName, lpszUsername, lpszPassword, dwService, nServerPort);
                return hConnect;
            }
            finally
            {
                mNetCutBase.InternetConnectW.Resume();
            }
        }

        private IntPtr HttpOpenRequestA(IntPtr hConnect, string lpszVerb, string lpszObjectName, string lpszVersion,
                string lpszReferer, char** lplpszAcceptTypes, int dwFlags, IntPtr dwContext)
        {
            try
            {
                mNetCutBase.HttpOpenRequestA.Suspend();
                IntPtr hRequest = Win32Native.HttpOpenRequest(hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferer, lplpszAcceptTypes, dwFlags, dwContext);
                this.Items.Add(hConnect, hRequest, lpszVerb, lpszObjectName, lplpszAcceptTypes, lpszVersion);
                return hRequest;
            }
            finally
            {
                mNetCutBase.HttpOpenRequestA.Resume();
            }
        }

        private IntPtr HttpOpenRequestW(IntPtr hConnect, string lpszVerb, string lpszObjectName, string lpszVersion,
                string lpszReferer, char** lplpszAcceptTypes, int dwFlags, IntPtr dwContext)
        {
            try
            {
                mNetCutBase.HttpOpenRequestW.Suspend();
                IntPtr hRequest = Win32Native.HttpOpenRequest(hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferer, lplpszAcceptTypes, dwFlags, dwContext);
                this.Items.Add(hConnect, hRequest, lpszVerb, lpszObjectName, lplpszAcceptTypes, lpszVersion);
                return hRequest;
            }
            finally
            {
                mNetCutBase.HttpOpenRequestW.Resume();
            }
        }

        private bool HttpAddRequestHeadersA(IntPtr hRequest, string pwszHeaders, int dwHeadersLength, uint dwModifiers)
        {
            try
            {
                this.Items.Add(hRequest, pwszHeaders);
                mNetCutBase.HttpAddRequestHeadersA.Suspend();
                return Win32Native.HttpAddRequestHeaders(hRequest, pwszHeaders, dwHeadersLength, dwModifiers);
            }
            finally
            {
                mNetCutBase.HttpAddRequestHeadersA.Resume();
            }
        }

        private bool HttpAddRequestHeadersW(IntPtr hRequest, string pwszHeaders, int dwHeadersLength, uint dwModifiers)
        {
            try
            {
                this.Items.Add(hRequest, pwszHeaders);
                mNetCutBase.HttpAddRequestHeadersW.Suspend();
                return Win32Native.HttpAddRequestHeaders(hRequest, pwszHeaders, dwHeadersLength, dwModifiers);
            }
            finally
            {
                mNetCutBase.HttpAddRequestHeadersW.Resume();
            }
        }

        private bool HttpSendRequestA(IntPtr hRequest, string lpszHeaders, uint dwHeadersLength, IntPtr lpOptional, uint dwOptionalLength)
        {
            try
            {
                mNetCutBase.HttpSendRequestA.Suspend();
                return this.Items.Add(hRequest, lpOptional, dwOptionalLength,
                        Win32Native.HttpSendRequest(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength)
                    );
            }
            finally
            {
                mNetCutBase.HttpSendRequestA.Resume();
            }
        }

        private bool HttpSendRequestW(IntPtr hRequest, string lpszHeaders, uint dwHeadersLength, IntPtr lpOptional, uint dwOptionalLength)
        {
            try
            {
                mNetCutBase.HttpSendRequestW.Suspend();
                return this.Items.Add(hRequest, lpOptional, dwOptionalLength,
                        Win32Native.HttpSendRequest(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength)
                    );
            }
            finally
            {
                mNetCutBase.HttpSendRequestW.Resume();
            }
        }
    }

    public sealed class NetworkTableCollection : List<NetworkTable>
    {
        private NetworkCut mNetCut;
        private StringBuilder mBuffer = new StringBuilder(4096);

        internal NetworkTableCollection(NetworkCut netCut)
        {
            this.mNetCut = netCut;
        }

        internal bool Add(IntPtr RequestHandle, IntPtr Data, uint Length, bool SendRequest)
        {
            if (RequestHandle != Win32Native.NULL)
                for (int i = 0, nNoOfStatusCode; i < base.Count; i++)
                {
                    var item = base[i];
                    if (item.RequestHandle == RequestHandle)
                    {
                        if (SendRequest)
                        {
                            item.SendRequest = SendRequest;
                            item.ResponseStatus = NetworkTable.HttpQueryInfo(RequestHandle, Win32Native.HTTP_QUERY_RAW_HEADERS, mBuffer);
                            item.ResponseCookie = NetworkTable.HttpQueryInfo(RequestHandle, Win32Native.HTTP_QUERY_SET_COOKIE, mBuffer);
                            int.TryParse(NetworkTable.HttpQueryInfo(RequestHandle, Win32Native.HTTP_QUERY_STATUS_CODE, mBuffer), out nNoOfStatusCode);
                            this.Add(item.ResponseHeaders, NetworkTable.HttpQueryInfo(RequestHandle, Win32Native.HTTP_QUERY_RAW_HEADERS_CRLF, mBuffer));
                            item.StatusCode = (HttpStatusCode)nNoOfStatusCode;
                        }
                        if (Data != Win32Native.NULL && Length > 0)
                        {
                            item.RequestData = new byte[Length];
                            Marshal.Copy(Data, item.RequestData, 0, (int)Length);
                        }
                        this.mNetCut.OnRequestComplete(item);
                        break;
                    }
                }
            return SendRequest;
        }

        internal void Add(IntPtr RequestHandle, string Headers)
        {
            if (RequestHandle != Win32Native.NULL && Headers != null && Headers.Length > 0)
                try
                {
                    foreach (var item in this)
                        if (item.RequestHandle == RequestHandle)
                            this.Add(item.RequestHeaders, Headers);
                }
                catch
                {
                    return;
                }
        }

        internal void Add(WebHeaderCollection Item, string Headers)
        {
            if (Headers != null && Headers.Length > 0)
            {
                var splits = Headers.Split('\r', '\n');
                foreach (var split in splits)
                {
                    int index = -1;
                    if (split.Length > 0 && (index = split.IndexOf(':')) > -1)
                    {
                        var key = split.Substring(0, index++);
                        var value = split.Substring(++index);
                        Item.Add(key, value);
                    }
                }
            }
        }

        internal void Add(IntPtr SessionHandle, IntPtr ConnectHandle, string Host, string Username, string Password, int Service, short Port)
        {
            var item = new NetworkTable();
            item.RequestPort = Port;
            item.RequestHost = Host;
            item.Username = Username;
            item.Password = Password;
            item.ConnectHandle = ConnectHandle;
            item.SessionHandle = SessionHandle;
            item.ConnectProtocol = (NetworkProtocol)Service;
            base.Add(item);
        }

        internal unsafe void Add(IntPtr ConnectHandle, IntPtr RequestHandle, string Method, string Url, char** Accept, string Version)
        {
            if (ConnectHandle != Win32Native.NULL)
                try
                {
                    foreach (var item in this)
                        if (item.ConnectHandle == ConnectHandle)
                        {
                            item.RequestUrl = Url;
                            item.RequestMethod = Method;
                            item.ProtocolVersion = Version ?? "HTTP/1.1";
                            item.RequestHandle = RequestHandle;
                            var accept = string.Empty;
                            while (*Accept != null)
                                accept += new string(*Accept++);
                            item.Accept = accept;
                            return;
                        }
                }
                catch
                {
                    return;
                }
        }
    }

    public partial class NetworkTable
    {
        public NetworkTable()
        {
            this.RequestHeaders = new WebHeaderCollection();
            this.ResponseHeaders = new WebHeaderCollection();
        }

        public IntPtr ConnectHandle
        {
            get;
            set;
        }

        public IntPtr RequestHandle
        {
            get;
            set;
        }

        public IntPtr SessionHandle
        {
            get;
            set;
        }

        public string RequestMethod // verb
        {
            get;
            set;
        }

        public string Username
        {
            get;
            set;
        }

        public string Password
        {
            get;
            set;
        }

        public short RequestPort
        {
            get;
            set;
        }

        public string RequestHost
        {
            get;
            set;
        }

        public string RequestUrl
        {
            get;
            set;
        }

        public NetworkProtocol ConnectProtocol
        {
            get;
            set;
        }

        public string Accept
        {
            get;
            set;
        }

        public string ProtocolVersion
        {
            get;
            set;
        }

        public WebHeaderCollection RequestHeaders
        {
            get;
            set;
        }

        public byte[] RequestData
        {
            get;
            set;
        }

        public WebHeaderCollection ResponseHeaders
        {
            get;
            set;
        }

        public string ResponseCookie
        {
            get;
            set;
        }

        public string ResponseStatus
        {
            get;
            set;
        }

        public HttpStatusCode StatusCode
        {
            get;
            set;
        }

        public bool SendRequest
        {
            get;
            set;
        }

        public bool CloseHandle()
        {
            return Win32Native.InternetCloseHandle(this.RequestHandle) |
             Win32Native.InternetCloseHandle(this.ConnectHandle) |
             Win32Native.InternetCloseHandle(this.SessionHandle);
        }

        public string QueryInfo(IntPtr Handle, int Query, StringBuilder Buffer)
        {
            return HttpQueryInfo(Handle, Query, Buffer);
        }

        public static string HttpQueryInfo(IntPtr Handle, int Query, StringBuilder Buffer)
        {
            uint size = (uint)Buffer.Capacity;
            if (Win32Native.HttpQueryInfo(Handle, Query, Buffer, ref size, IntPtr.Zero))
                return Convert.ToString(Buffer);
            return null;
        }
    }
}
           

继续阅读