我的目的是想抓获所有通过 IE 收发的数据包,对此进行分析,可以考虑采用的技术有:
1、Hook API ,就是现在用的;
2、SPI , 这个没试过;
3、Mime Filter, 这个了解了相关技术,但有两个问题解决不了;
4、NDIS ,这个基本不考虑了,有些小题大作了;


我所知道的实现 API Hook 有两种方式,IAT 和 Jmp。

最开始我用的是 jmp 方式实现的,就是修改函数入口的前5个字节,程序完成了发现了两个问题:
1、只能对IE6.0抓包,IE7.0和8.0一启动抓包就打不开网页;
2、在使用IE6.0上网时,发邮件不能发送附件,而且凡是需要上传的地方都上传不了;

后来改用了IAT的方式实现,但根本抓不了包了。如果挂接了WSASend和WSARecv函数,IE一启动就退出;如果不挂接这两个函数,IE可以正常使用,但抓不到包。

请高手帮忙,高分相赠。

 


如果Hook API的方式不行的话,那就只能考虑用SPI技术实现了。
更多 0 分享到:


 

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 回复次数:11
cnzdgs
关注
cnzdgs
cnzdgs
本版等级:T11
Blank Blank Blank
更多勋章
#1 得分:0 回复于: 2008-11-02 21:10:28
代码有问题,没什么好说的。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#2 得分:0 回复于: 2008-11-02 21:56:08
我把代码贴出来,帮忙看看。

这是我自己写的用来替换的 send 函数,是Dephi的

function MySend(s: TSocket; var Buf; len, flags: Integer): integer; stdcall;
var
cp: COPYDATASTRUCT;
begin
APIHk_MySend.Lock;
try
APIHk_MySend.HookOFF_jmp;
Result := send(s, Buf, len, flags); // 调用原 send 函数
APIHk_MySend.HookON_jmp;

cp.dwData := Integer(AppID);
cp.cbData := len;
cp.lpData := @buf;

h := FindWindow(nil, pShareMem.RecvWndTitle); //查找接收数据的窗口句柄
if h > 0 then
begin
SendMessage(h, WM_COPYDATA, 0, Integer(@cp)); //用 wm_copydata 消息发送数据
end;

finally
APIHk_MySend.UnLock;
end;
end;


APIHk_MySend 是我写的 Hook 类,它的关键代码如下:

h := LoadLibraryA(PAnsichar(DllName)); //加载dll
FpOrigProc := GetProcAddress(h, PAnsiChar(ProcName)); //获取被挂接的函数的地址

if FpOrigProc = nil then //获取不到原始地址,加载该DLL失败或DLL中不存在该函数,退出
Exit;

//将被挂接函数的前五个字节保存到 FT5Orig
CopyMemory(@FT5Orig, FpOrigProc, 5); //保存被挂接函数的 前5个字节

//jmp指令,跳转到自定义函数
FT5New.JmpCommand := $E9; //jmp指令
FT5New.ptr := DWord(FpHookProc) - DWord(FpOrigProc) - 5;

HookON_jmp; //将 FT5New 写入到原函数的前5个字节

FlushInstructionCache(GetCurrentProcess, @FpOrigProc, 5);
end;
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#3 得分:0 回复于: 2008-11-02 22:25:48
360safe 在开启 恶意网站拦截 之后, send函数的前5个字节也被更改了,如下:
E96C545E9E

应该也是用了jmp指令,跳转到了自定义的函数。

 

我down 了 WSockExpert 软件,在监控ie时, send函数的前 6 个字节被改了,如下:
FF2588091602

这我就不知道用的是什么指令了,对汇编不熟。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#4 得分:0 回复于: 2008-11-02 22:32:29
WSockExpert 应该只对 wsock32.dll 中的函数做了hook,没有对 ws2_32.dll 中的函数进行 hook。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
cnzdgs
关注
cnzdgs
cnzdgs
本版等级:T11
Blank Blank Blank
更多勋章
#5 得分:50 回复于: 2008-11-02 23:27:02
对Delphi不熟,看起来好象没什么错。如果不调用FindWindow和SendMessage会出错吗?
FF2588091602是jmp [02160988](跳转到一个函数指针变量中储存的地址)。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#6 得分:0 回复于: 2008-11-03 00:10:08
试过了,不调用FindWindow和SendMessage 还是出现一样的情况,不能发带附件的邮件。

360safe也是用的改写前5个字节。

我估计是自定义的那几个 send 、recv 函数有问题,还可能与 每个函数里的对象同步代码有关,对象同步的目的是为了防止重入。

不知道有没有一种方式,可以既能防止重入,又不要加入同步代码。关于这一点,我有试过一种方法,将wsock32.dll改个名字叫socket1.0.dll,
在我的自定义 send 函数中先调用 socket1.0.dll中的send函数,然后再处理数据,这样做的好处是可以将同步代码去掉,在发邮件的时候也可以发送带附件
的邮件了,但我将程序拿到其他电脑上测试的时候,发现会导致ie异常死掉或者ie打开网页的速度非常慢。也就是说这种方法兼容性太差。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
cnzdgs
关注
cnzdgs
cnzdgs
本版等级:T11
Blank Blank Blank
更多勋章
#7 得分:0 回复于: 2008-11-03 00:26:22
可能是你的Lock和UnLock代码有问题,也可能是你为来回修改API入口代码的问题。因为当API的入口不是JMP的时候,不会执行到你的程序,此时Hook不到;如果在你修改的中途,有其它线程调用此函数,就会产生异常。Hook API通常是把API入口处的指令搬移若干条出来,在搬移出的指令后面用JMP指令跳转回去,继续执行后面的指令,程序调用搬移出来的指令来实现调用原函数,运行过程中就不再修改API入口处的指令了。你可以搜索一下Detours详细了解一下。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#8 得分:0 回复于: 2008-11-03 01:50:00
cnzdgs 多谢你了。


我认真的检查了程序,找到了问题所在。


在mysend函数中,我将

APIHk_MySend.HookOFF_jmp;
Result := send(s, Buf, len, flags); // 调用原 send 函数
APIHk_MySend.HookON_jmp;

这段代码移到了函数的末尾,解决了邮件不能发送附件的问题。

但我将程序在IE7中测试时发现,ie7根本打不开网页,我想可能是因为我定义的mysend、myrecv函数中的变量太多了,破坏了堆栈,因此,我将那些不是很必要的变量统统注释掉,只保留了 cp: COPYDATASTRUCT; 变量,结果果真可以在 IE7 中运行了。

虽然问题解决了,但解决方案并不完美,因为我用的是 jmp 式的挂接,在每个函数中加了同步代码防止重入,如果多个线程同时调用send和recv的话,被我的代码
限制成了单线程,速度必定受到影响。

听您的建议,在网上找到了Detours的资料,正在学习。Detours才是更完美的hook实现方式。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
godlessme
关注
godlessme
godlessme
本版等级:T1
#9 得分:0 回复于: 2008-11-04 23:45:42
我用jmp方式实现的抓包,功能基本OK,但在实际应用的时候还是有些小bug:

我打开40个左右的IE窗口时会出现 内存访问异常, 或者在百度打开10个左右的视频同时播放时,有时也会出现 内存访问异常;

Hook的函数有 wsocket.dll的send, ws2_32.dll 函数的 send 和recv。 这样可以抓到IE的所有数据包了。

这三个函数的替换函数的源码如下:

//// ws2_32.dll send
function MySend(s: TSocket; var Buf; len, flags: Integer): integer; stdcall;
begin
APIHk_MySend.Lock;
try
APIHk_MySend.HookOFF_jmp;
Result := WinSock2.send(s, Buf, len, flags);
APIHk_MySend.HookON_jmp;

if (len >= 32) and (len <= 8192) then
begin
try
EnterCriticalSection(csSend);
try
GetMem(pSend, Len + 1);
FillMemory(pSend, Len + 1, 0);
CopyMemory(pSend, @buf, len);

lsSend.Add(pSend);
finally
LeaveCriticalSection(csSend);
end;
except
end;
end;
finally
APIHk_MySend.UnLock;
end;
end;


//// wsock32.dll recv
function Mywsock32Recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
begin
APIHk_Mywsock32Recv.Lock;
try
APIHk_Mywsock32Recv.HookOFF_jmp;
Result := WinSock.recv(s, buf, len, flags);
APIHk_Mywsock32Recv.HookON_jmp;

try
if (len >= 32) and (len <= 8192) then
begin
EnterCriticalSection(cswsock32Recv);
try
GetMem(pwsock32Recv, Len + 1);
FillMemory(pwsock32Recv, Len + 1, 0);
CopyMemory(pwsock32Recv, @buf, len);

lswsock32Recv.Add(pwsock32Recv);
finally
LeaveCriticalSection(cswsock32Recv);
end;
end;
except
end;
finally
APIHk_Mywsock32Recv.UnLock;
end;
end;


//// ws2_32.dll recv
function Myws2_32Recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
begin
APIHk_Myws2_32Recv.Lock;
try
APIHk_Myws2_32Recv.HookOFF_jmp;
Result := WinSock2.recv(s, buf, len, flags);
APIHk_Myws2_32Recv.HookON_jmp;

if (len >= 32) and (len <= 8192) then //数据包的长度 >= 32 时的数据才有分析的价值
begin
try
EnterCriticalSection(csws2_32Recv);
try
GetMem(pws2_32Recv, Len + 1);
FillMemory(pws2_32Recv, Len + 1, 0);
CopyMemory(pws2_32Recv, @buf, len);

lsws2_32Recv.Add(pws2_32Recv);
finally
LeaveCriticalSection(csws2_32Recv);
end;
except
end;
end;
finally
APIHk_Myws2_32Recv.UnLock;
end;
end;


请帮我看下有没有问题。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
lwh_gsww
关注
lwh_gsww
lwh_gsww
本版等级:T1
#10 得分:0 回复于: 2009-02-17 23:12:52
正在相关的资料,太谢谢了。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
tlgoo
关注
tlgoo
tlgoo
本版等级:T1
#11 得分:0 回复于: 2010-07-20 10:30:54
sdfasdddddddddddddddddddddddddddddddddddddddddddddddd
垃圾