首页
社区
课程
招聘
[原创]另类挂钩-RING3数据包监视
发表于: 2009-2-1 15:20 182598

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

2009-2-1 15:20
182598

另类挂钩 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;
}


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 8
支持
分享
最新回复 (178)
雪    币: 254
活跃值: (126)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
还有注释啊.
2009-2-1 15:33
0
雪    币: 152
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我是来顶qihoocom和heXer两个大牛的
2009-2-1 15:50
0
雪    币: 218
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
NaX
4
强力占个座位
2009-2-1 15:56
0
雪    币: 231
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qdk
5
占座
123456
2009-2-1 16:01
0
雪    币: 424
活跃值: (10)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
6
仔细学习学习
2009-2-1 16:29
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
收藏了慢慢看
2009-2-1 16:30
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
8
试了一下,果然很好使。不过网络相关的还不是太熟悉,还要慢慢研究研究
2009-2-1 16:31
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
9
MJ就是不一般…连抓包都这么与众不同
2009-2-1 16:34
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
10
占座学习中。。
2009-2-1 17:32
0
雪    币: 398
活跃值: (343)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
11
向王小姐学习
2009-2-1 17:34
0
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
12
这个还真没见过,立即改个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和返回数据都抓下来了。
上传的附件:
2009-2-1 18:11
0
雪    币: 215
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
够另类啊,学习,非http的send/recv/WSA……的IoControlCode是多少呢?
2009-2-1 18:12
0
雪    币: 262
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
14
学习。。。。。。。。。。。。。。。
2009-2-1 18:30
0
雪    币: 357
活跃值: (3438)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
15
支持一下
2009-2-1 18:56
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
16
仔细看看代码就知道了,这个可以拦任何TCP的封包,过滤HTTP是在过滤包内容时做的
2009-2-1 19:22
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
17
MJ的第二篇精华了~
2009-2-1 21:31
0
雪    币: 231
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
坐底上膜拜
2009-2-1 21:59
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
改完共享一下原代码吧   谢谢
2009-2-1 22:12
0
雪    币: 119
活跃值: (313)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
支持! 嘿嘿 SPI挫啊挫!
2009-2-1 23:19
0
雪    币: 126
活跃值: (61)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
顶,不过貌似MJ打错字了

//  Hook mswsock.dll导出表的Ntdll!NtDeviceIoControlFile 。 中的“导出”应该是“输入”吧
2009-2-2 01:04
0
雪    币: 66
活跃值: (960)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22


MJ 放血,快快吸血~~~
2009-2-2 03:16
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
23
确实写错了,应为 导入/输入表 谢谢指正
2009-2-2 11:21
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
24
好老啊,第一次提到这些ioctrlcode是在xfocus的水区~~~、
AFD_Sendto
AFD_RecvFrom
AFD_Connect
AFD_Bind
几个小编号也都有记录~~
2009-2-2 21:10
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
25
以下定义 出自 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
2009-2-2 21:18
0
游客
登录 | 注册 方可回帖
返回
//