首页
论坛
专栏
课程

[原创]另类挂钩-RING3数据包监视

2009-2-1 15:20 176043

[原创]另类挂钩-RING3数据包监视

2009-2-1 15:20
176043
另类挂钩 RING3数据包监视

前几天朋友让帮忙写一个RING3程序来监视TCP包并做数据包分析

本来想HOOK ws2_32!WSASend/Send/WSARecv/Recv,后来发现网上的方法都非常挫,尽是不稳定的HEADER INLINE和修改内存~用SPI之类的,又很麻烦

于是自己写了一种方式实现,非常简单,隐蔽,而且在RING3下应该算是最底层的数据包拦截点了~

目前实现了对HTTP包的过滤和显示~将这个CPP编译成DLL用任意方式注入目标进程,打开DBGVIEW就可以看到目标进程所有的发送和接受的HTTP包了~

下面是代码

#include "stdafx.h"
#include "windows.h"
#include "winnt.h"

PVOID pNtDeviceIoControl  = NULL ;
//

#define AFD_RECV 0x12017

#define AFD_SEND 0x1201f

typedef struct AFD_WSABUF{
        UINT  len ;
        PCHAR  buf ;
}AFD_WSABUF , *PAFD_WSABUF;

typedef struct AFD_INFO {
        PAFD_WSABUF  BufferArray ;
        ULONG  BufferCount ;
        ULONG  AfdFlags ;
        ULONG  TdiFlags ;
} AFD_INFO,  *PAFD_INFO;
typedef LONG NTSTATUS;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

const CHAR GetXX[] = "GET ";
const CHAR PostXX[] = "POST ";
const CHAR HttpXX[] = "HTTP";
//////////////////////////////////////////////////////////////////////////
//
// LookupSendPacket
// 检查Send包
// 目前实现了过滤HTTP请求(GET AND POST)
//
//////////////////////////////////////////////////////////////////////////

BOOL LookupSendPacket(PVOID Buffer , ULONG Len)
{
        if (Len < 5)
        {
                return FALSE ;
        }

        //外层已有异常捕获

        if (memcmp(Buffer , GetXX , 4) == 0
                ||
                memcmp(Buffer , PostXX , 5) == 0 )
        {
                return TRUE ;
        }
        return FALSE ;
}       
//////////////////////////////////////////////////////////////////////////
//
// LookupRecvPacket
//
// 检查Recv包
// 在这里可以实现Recv包查字典功能
// 目前实现了过滤HTTP返回数据包的功能
//
//
///////////////////////////////////////////////////////////////////////////
BOOL LookupRecvPacket(PVOID Buffer , ULONG Len)
{
        if (Len < 4)
        {
                return FALSE ;
        }

        if (memcmp(Buffer , HttpXX , 4) == 0 )
        {
                return TRUE ;
        }

        return FALSE ;
}
//hook函数

//////////////////////////////////////////////////////////////////////////
//
// NtDeviceIoControlFile的HOOK函数
// ws2_32.dll的send , recv最终会调用到mswsock.dll内的数据发送函数
// mswsock.dll会调用NtDeviceIoControlFile向TDI Client驱动发送Send Recv指令
// 我们在这里做拦截,可以过滤所有的TCP 收发包(UDP之类亦可,不过要更改指令)
//
//////////////////////////////////////////////////////////////////////////

NTSTATUS __stdcall NewNtDeviceIoControlFile(
                                           HANDLE FileHandle,
                                           HANDLE Event OPTIONAL,
                                           PVOID ApcRoutine OPTIONAL,
                                           PVOID ApcContext OPTIONAL,
                                           PVOID IoStatusBlock,
                                           ULONG IoControlCode,
                                           PVOID InputBuffer OPTIONAL,
                                           ULONG InputBufferLength,
                                           PVOID OutputBuffer OPTIONAL,
                                           ULONG OutputBufferLength
    )
{
       
        //先调用原始函数

        LONG stat ;
        __asm
        {
                push        OutputBufferLength
                push        OutputBuffer
                push        InputBufferLength
                push        InputBuffer
                push        IoControlCode
                push        IoStatusBlock
                push        ApcContext
                push        ApcRoutine
                push        Event
                push        FileHandle
                call        pNtDeviceIoControl
                mov                stat ,eax
        }

        //如果原始函数失败了(例如RECV无数据)

        if (!NT_SUCCESS(stat))
        {
                return stat ;
        }

        //检查是否为TCP收发指令

        if (IoControlCode != AFD_SEND && IoControlCode != AFD_RECV)
        {
                return stat ;
        }

        //访问AFD INFO结构,获得SEND或RECV的BUFFER信息
        //这里可能是有问题的BUFFER,因此我们要加TRY EXCEPT
        //

        __try
        {
                //从InputBuffer得到Buffer和Len

                PAFD_INFO AfdInfo = (PAFD_INFO)InputBuffer ;
                PVOID Buffer = AfdInfo->BufferArray->buf ;
                ULONG Len = AfdInfo->BufferArray->len;

                if (IoControlCode == AFD_SEND)
                {
                        if (LookupSendPacket(Buffer , Len))
                        {
                                //输出包内容
                                //这里输出调试信息,可以用DbgView查看,如果有UI可以做成SendMessage形式~
                                OutputDebugString("SendPacket!\n");               
                                OutputDebugString((char*)Buffer);
                        }
                }
                else
                {
                        if (LookupRecvPacket(Buffer , Len))
                        {
                                OutputDebugString("RecvPacket!\n");
                                OutputDebugString((char*)Buffer);
                        }
                }
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
                return stat ;
        }

        return stat ;
         

       
}

//////////////////////////////////////////////////////////////////////////
//
//  Hook mswsock.dll导出表的Ntdll!NtDeviceIoControlFile
//  并过滤其对TDI Cilent的请求来过滤封包
//  稳定,隐蔽,RING3下最底层的包过滤~
//
//////////////////////////////////////////////////////////////////////////
void SuperHookDeviceIoControl()
{
        //得到ws2_32.dll的模块基址
        HMODULE hMod = LoadLibrary("mswsock.dll");
        if (hMod == 0 )
        {
                return ;
        }

        //得到DOS头

        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod ;

        //如果DOS头无效
        if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
        {
                return ;
        }

        //得到NT头

        PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG)hMod + pDosHeader->e_lfanew);

        //如果NT头无效
        if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
        {
                return ;
        }

        //检查输入表数据目录是否存在
        if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0 ||
                pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 )
        {
                return ;
        }
        //得到输入表描述指针

        PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)hMod + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

        PIMAGE_THUNK_DATA ThunkData ;

        //检查每个输入项
        while(ImportDescriptor->FirstThunk)
        {
                //检查输入表项是否为ntdll.dll

                char* dllname = (char*)((ULONG)hMod + ImportDescriptor->Name);
               
                //如果不是,则跳到下一个处理

                if (stricmp(dllname , "ntdll.dll") !=0)
                {
                        ImportDescriptor ++ ;
                        continue;
                }
               
                ThunkData = (PIMAGE_THUNK_DATA)((ULONG)hMod + ImportDescriptor->OriginalFirstThunk);

                int no = 1;
                while(ThunkData->u1.Function)
                {
                        //检查函数是否为NtDeviceIoControlFile

                        char* functionname = (char*)((ULONG)hMod + ThunkData->u1.AddressOfData + 2);
                        if (stricmp(functionname , "NtDeviceIoControlFile") == 0 )
                        {
                                //
                                //如果是,那么记录原始函数地址
                                //HOOK我们的函数地址
                                //
                                ULONG myaddr = (ULONG)NewNtDeviceIoControlFile;
                                ULONG btw ;
                                PDWORD lpAddr = (DWORD *)((ULONG)hMod + (DWORD)ImportDescriptor->FirstThunk) +(no-1);
                                pNtDeviceIoControl = (PVOID)(*(ULONG*)lpAddr) ;
                                WriteProcessMemory(GetCurrentProcess() , lpAddr , &myaddr , sizeof(ULONG), &btw );
                                return ;

                        }

                        no++;
                        ThunkData ++;
                }
                ImportDescriptor ++;
        }
        return ;
}

//////////////////////////////////////////////////////////////////////////
//
// CheckProcess 检查是否是需要挂钩的进程
//
//
//////////////////////////////////////////////////////////////////////////

BOOL CheckProcess()
{
        //在此加入你的进程过滤
        return TRUE ;
}

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                                         )
{
        //当加载DLL时,进行API HOOK

        if (ul_reason_for_call == DLL_PROCESS_ATTACH)
        {       
                //检查是否是要过滤的进程
                if (CheckProcess() == FALSE)
                {       
                        //如果不是,返回FALSE,将自身从进程中卸除
                        return FALSE ;
                }

                //HOOK API
                SuperHookDeviceIoControl();
        }
    return TRUE;
}

[公告]看雪20周年会 | 感恩有你,一路同行

最新回复 (177)
heXer 3 2009-2-1 15:33
2
0
还有注释啊.
XSJS 2009-2-1 15:50
3
0
我是来顶qihoocom和heXer两个大牛的
NaX 2009-2-1 15:56
4
0
强力占个座位
qdk 2009-2-1 16:01
5
0
占座
123456
大菜一号 21 2009-2-1 16:29
6
0
仔细学习学习
fool 2009-2-1 16:30
7
0
收藏了慢慢看
weolar 10 2009-2-1 16:31
8
0
试了一下,果然很好使。不过网络相关的还不是太熟悉,还要慢慢研究研究
achillis 15 2009-2-1 16:34
9
0
MJ就是不一般…连抓包都这么与众不同
zhuwg 11 2009-2-1 17:32
10
0
占座学习中。。
shoooo 16 2009-2-1 17:34
11
0
向王小姐学习
木桩 8 2009-2-1 18:11
12
0
这个还真没见过,立即改个Delphi的去瞧瞧。

果然好用,膜拜一下!明天试试修改数据包内容
翻译的Delphi版源码见附件,这是我GET百度的数据。
00007368 23.14766884 [4048] [HOOK] NDIC_Hook dll loaded.
00007369 23.14779282 [4048] [HOOK] Lock "NtDeviceIoControlFile" for HOOK.
00007370 23.14781952 [4048] [HOOK] Base=719C0000, Thunk=0000127C, ID=F
00007371 23.14791679 [4048] [HOOK] Orign[0x719C12B8]=0x7C92D8E3, new Addr=0x04DEA3C4
00008751 28.35400581 [4048] [HTTP Send] Length = 822
00008752 28.35421753 [4048] GET / HTTP/1.1
00008753 28.35421753 [4048] Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
00008754 28.35421753 [4048] Accept-Language: zh-cn
00008755 28.35421753 [4048] User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; CIBA; TheWorld)
00008756 28.35421753 [4048] UA-CPU: x86
00008757 28.35421753 [4048] Accept-Encoding: gzip, deflate
00008758 28.35421753 [4048] Host: www.baidu.com
00008759 28.35421753 [4048] Connection: Keep-Alive
00008760 28.35421753 [4048] Cookie: BAIDUID=F07CEBAE4F4B5A6DE8A3D73BDA7CBB34:FG=1;...
00008761 28.35421753 [4048]
00008783 28.39130974 [4048] [HTTP Recv] Length = 1024
00008784 28.39136696 [4048] HTTP/1.1 200 OK
00008785 28.39136696 [4048] Date: Sun, 01 Feb 2009 14:43:22 GMT
00008786 28.39136696 [4048] Server: BWS/1.0
00008787 28.39136696 [4048] Content-Length: 2029
00008788 28.39136696 [4048] Content-Type: text/html
00008789 28.39136696 [4048] Cache-Control: private
00008790 28.39136696 [4048] Expires: Sun, 01 Feb 2009 14:43:22 GMT
00008791 28.39136696 [4048] Content-Encoding: gzip
00008792 28.39136696 [4048]
00008793 28.39136696 [4048] ?
00008814 28.42530823 [4048] [HTTP Send] Length = 796
00008815 28.42535210 [4048] GET /js/bdsug.js?v=1.0.1.0 HTTP/1.1
00008816 28.42535210 [4048] Accept: */*
00008817 28.42535210 [4048] Referer: http://www.baidu.com/
00008818 28.42535210 [4048] Accept-Language: zh-cn
00008819 28.42535210 [4048] User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; CIBA; TheWorld)
00008820 28.42535210 [4048] UA-CPU: x86
00008821 28.42535210 [4048] Accept-Encoding: gzip, deflate
00008822 28.42535210 [4048] If-Modified-Since: Mon, 19 Jan 2009 13:18:00 GMT
00008823 28.42535210 [4048] If-None-Match: "1599-49747d88"
00008824 28.42535210 [4048] Host: www.baidu.com
00008825 28.42535210 [4048] Connection: Keep-Alive
00008826 28.42535210 [4048] Cookie: BAIDUID=F07CEBAE4F4B5A6DE8A3D73BDA7CBB34:FG=1;...
00008827 28.42535210 [4048]
00008840 28.45828247 [4048] [HTTP Recv] Length = 1024
00008844 28.45885849 [4048] HTTP/1.1 304 Not Modified
00008845 28.45885849 [4048] Date: Sun, 01 Feb 2009 14:43:22 GMT
00008846 28.45885849 [4048] Server: Apache/1.3.27
00008847 28.45885849 [4048] ETag: "1599-49747d88"
00008848 28.45885849 [4048]

两个GET和返回数据都抓下来了。
上传的附件:
veninson 2009-2-1 18:12
13
0
够另类啊,学习,非http的send/recv/WSA……的IoControlCode是多少呢?
magicboy 2009-2-1 18:30
14
0
学习。。。。。。。。。。。。。。。
KooJiSung 2009-2-1 18:56
15
0
支持一下
qihoocom 9 2009-2-1 19:22
16
0
仔细看看代码就知道了,这个可以拦任何TCP的封包,过滤HTTP是在过滤包内容时做的
achillis 15 2009-2-1 21:31
17
0
MJ的第二篇精华了~
escript 2009-2-1 21:59
18
0
坐底上膜拜
wping 2009-2-1 22:12
19
0
改完共享一下原代码吧   谢谢
渗透 2009-2-1 23:19
20
0
支持! 嘿嘿 SPI挫啊挫!
xyzreg 1 2009-2-2 01:04
21
0
顶,不过貌似MJ打错字了

//  Hook mswsock.dll导出表的Ntdll!NtDeviceIoControlFile 。 中的“导出”应该是“输入”吧
dnybz 2009-2-2 03:16
22
0


MJ 放血,快快吸血~~~
qihoocom 9 2009-2-2 11:21
23
0
确实写错了,应为 导入/输入表 谢谢指正
cvcvxk 10 2009-2-2 21:10
24
0
好老啊,第一次提到这些ioctrlcode是在xfocus的水区~~~、
AFD_Sendto
AFD_RecvFrom
AFD_Connect
AFD_Bind
几个小编号也都有记录~~
cvcvxk 10 2009-2-2 21:18
25
0
以下定义 出自 byshell 1.00 private版代码

#define AFD_BIND 0x12003

#define AFD_CONNECT 0x12007

#define AFD_SET_CONTEXT 0x12047

#define AFD_RECV 0x12017

#define AFD_SEND 0x1201f

#define AFD_SELECT 0x12024

#define AFD_SENDTO 0x12023
cvcvxk 10 2009-2-2 21:26
26
0
AFD_GET_SOCK_NAME (0x0001202F)

AFD_GET_TDI_HANDLES (0x00012037)

AFD_SET_INFO (0x0001203B)
ppanger 4 2009-2-2 21:29
27
0
感谢分享 ^_^
cvcvxk 10 2009-2-2 21:30
28
0
0x1200B
AFD_START_LISTEN

0x1207B
AFD_GET_INFO

0x1201B
AFD_RECVFROM

好像就这么多了吧~
qihoocom 9 2009-2-2 21:45
29
0
这些code在nt4代码中一查即知~
另外很多纯R0的也有了

老V漏了很多UDP的 呵呵
dragonyee 2009-2-2 22:30
30
0
值得学习!谢谢分享~~
cvcvxk 10 2009-2-2 22:50
31
0
NT4代码早扔了,现在一般情况下连机器都不开了~~
qihoocom 9 2009-2-2 22:58
32
0
最近都改在东北二人转小棚里走穴了?
clide2000 7 2009-2-2 23:07
33
0
[QUOTE=木桩;571841]这个还真没见过,立即改个Delphi的去瞧瞧。

果然好用,膜拜一下!明天试试修改数据包内容
翻译的Delphi版源码见附件,这是我GET百度的数据。[/QUOTE]

支持楼主。更要支持兄弟,只会delphi
SexFenG 2009-2-3 00:59
34
0
我也~占个座位
xicao 2009-2-3 08:29
35
0
很好很强大,立即下载下来试下
我要获取同一个socket的send/recv的完整数据,
在NtDeviceIoControlFile中用哪个参数标识数据包是同一个socket?
木桩 8 2009-2-3 09:07
36
0
我找到的几个,不过没有更进一步的资料了。
/*
  AFD_BIND (0x00012003)
  AFD_GET_SOCK_NAME (0x0001202F)
  AFD_SET_INFO (0x0001203B)
  AFD_GET_INFO (0x0001207B)
  AFD_CONNECT (0x00012007)
  AFD_RECVFROM (0x0001201B)
  AFD_SENDTO (0x00012023)
  AFD_SELECT (0x00012024)
  AFD_GET_TDI_HANDLES (0x00012037)
  AFD_SET_CONTEXT (0x00012047)
  AFD_SEND (0x0001201F)
  AFD_RECV (0x00012017)
*/

要是有人知道更详细的,比如 AFD_BIND 时InputBuffer和OutputBuffer里内容,也请共享一下。
还有,如何取该数据包的IP、端口等信息(这个Buffer里实际取出的是TCP/UDP的负载,而没有以太网头部、TCP头)?网上看到一种方法是用 IOCTL_TCP_QUERY_INFORMATION_EX 查询,还没验证过,不敢瞎说
人很老实 2 2009-2-3 09:40
37
0
好贴,学习了。
ljlLionel 2009-2-3 09:55
38
0
学习了,坐马扎
cvcvxk 10 2009-2-3 14:24
39
0
一切结构定义很简单,找找就有了~
cvcvxk 10 2009-2-3 14:26
40
0
Handle和进程~~
vfer 2009-2-3 17:25
41
0
被标题诱惑了  以为是类似HIJACK的  原来还是HOOK
qihoocom 9 2009-2-3 18:09
42
0
hijack也没什么技术含量
shellwolf 10 2009-2-3 18:31
43
0
学习,顶一下。
chengf 2009-2-3 20:25
44
0
路过,学习ing...
niuniult 2009-2-4 10:32
45
0
好东西啊
Isaiah 10 2009-2-4 11:27
46
0
学习了。。。
yzwyq 2009-2-9 23:41
47
0
好东西,长见识
xicao 2009-2-11 23:33
48
0
我在LookupSendPacket(Buffer , Len)里修改数据包,貌似对方接收到的没有改变
安摧 2 2009-2-12 09:26
49
0
IAT hook + Filter,不错不错,,,够底层的
solohac 1 2009-2-12 09:46
50
0
代码写得太漂亮的
游客
登录 | 注册 方可回帖
返回