截取指定程序的网络封包fordelphi hook api

有时候我们需要对其它应用程序发送和接收的网络数据进行拦截,比如要对IE发送的HTTP头进行分析,得到请求的地址等.这次我们可以用一些例如WPE, Sniffer之类的工具来达到目的.但是工具功能有限,要想实现更强大的功能,还是我们自己动手来DIY吧.

拦截网络数据封包的方法有三种,一是将网卡设为混杂模式,这次就可以监视到局域网上所有的数据包,二是HOOK目标进程的发送和接收的API函 数,第三种方法是自己实现一个代理的DLL.在这里我们使用HOOK API的方法,这样易于实现,而且也不会得到大量的无用数据(如第一种方法就会监视到所有的网络数据).

下面是一个尽量简化了的API HOOK的模版,原理是利用消息钩子将DLL中的代码注入到目标进程中,再用GetProcAddress得到API函数入口地址,将函数入口址改为自己 定义的函数入口,这样就得到了API函数的相应参数,处理完后,再改回真实API函数入口地址,并调用它.

HOOK.DLL的代码:
library Hook;

uses
SysUtils,
windows,
Messages,
APIHook in ’APIHook.pas’;

type
PData = ^TData;
TData = record
Hook: THandle;
Hooked: Boolean;
end;

var
DLLData: PData;

{------------------------------------}
{过程名:HookProc
{过程功能:HOOK过程
{过程参数:nCode, wParam, lParam消息的相
{ 关参数
{------------------------------------}
procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
begin
if not DLLData^.Hooked then
begin
HookAPI;
DLLData^.Hooked := True;
end;
//调用下一个Hook
CallNextHookEx(DLLData^.Hook, nCode, wParam, lParam);
end;


{------------------------------------}
{函数名:InstallHook
{函数功能:在指定窗口上安装HOOK
{函数参数:sWindow:要安装HOOK的窗口
{返回值:成功返回TRUE,失败返回FALSE
{------------------------------------}
function InstallHook(SWindow: LongWORD):Boolean;stdcall;
var
ThreadID: LongWORD;
begin
Result := False;
DLLData^.Hook := 0;
ThreadID := GetWindowThreadProcessId(sWindow, nil);
//给指定窗口挂上钩子
DLLData^.Hook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, ThreadID);
if DLLData^.Hook > 0 then
Result := True //是否成功HOOK
else
exit;
end;

{------------------------------------}
{过程名:UnHook
{过程功能:卸载HOOK
{过程参数:无
{------------------------------------}
procedure UnHook;stdcall;
begin
UnHookAPI;
//卸载Hook
UnhookWindowsHookEx(DLLData^.Hook);
end;

{------------------------------------}
{过程名:DLL入口函数
{过程功能:进行DLL初始化,释放等
{过程参数:DLL状态
{------------------------------------}
procedure MyDLLHandler(Reason: Integer);
var
FHandle: LongWORD;
begin
case Reason of
DLL_PROCESS_ATTACH:
begin //建立文件映射,以实现DLL中的全局变量
FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, $ffff, ’MYDLLDATA’);
if FHandle = 0 then
if GetLastError = ERROR_ALREADY_EXISTS then
begin
FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, ’MYDLLDATA’);
if FHandle = 0 then Exit;
end else Exit;
DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if DLLData = nil then
CloseHandle(FHandle);
end;
DLL_PROCESS_DETACH:
begin
if Assigned(DLLData) then
begin
UnmapViewOfFile(DLLData);
DLLData := nil;
end;
end;
end;
end;

{$R *.res}
exports
InstallHook, UnHook, HookProc;

begin
DLLProc := @MyDLLHandler;
MyDLLhandler(DLL_PROCESS_ATTACH);
DLLData^.Hooked := False;
end.

----------------------------------------------------------------------------------------
APIHook.Pas的代码:

unit APIHook;

interface

uses
SysUtils,
Windows, WinSock;

type
//要HOOK的API函数定义
TSockProc = function (s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;

PJmpCode = ^TJmpCode;
TJmpCode = packed record
JmpCode: BYTE;
Address: TSockProc;
MovEAX: Array [0..2] of BYTE;
end;

//--------------------函数声明---------------------------
procedure HookAPI;
procedure UnHookAPI;

var
OldSend, OldRecv: TSockProc; //原来的API地址
JmpCode: TJmpCode;
OldProc: array [0..1] of TJmpCode;
AddSend, AddRecv: pointer; //API地址
TmpJmp: TJmpCode;
ProcessHandle: THandle;
implementation

{---------------------------------------}
{函数功能:Send函数的HOOK
{函数参数:同Send
{函数返回值:integer
{---------------------------------------}
function MySend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
dwSize: cardinal;
begin
//这儿进行发送的数据处理
MessageBeep(1000); //简单的响一声
//调用直正的Send函数
WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
Result := OldSend(S, Buf, len, flags);
JmpCode.Address := @MySend;
WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize);
end;

{---------------------------------------}
{函数功能:Recv函数的HOOK
{函数参数:同Recv
{函数返回值:integer
{---------------------------------------}
function MyRecv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
dwSize: cardinal;
begin
//这儿进行接收的数据处理
MessageBeep(1000); //简单的响一声
//调用直正的Recv函数
WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
Result := OldRecv(S, Buf, len, flags);
JmpCode.Address := @MyRecv;
WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize);
end;

{------------------------------------}
{过程功能:HookAPI
{过程参数:无
{------------------------------------}
procedure HookAPI;
var
DLLModule: THandle;
dwSize: cardinal;
begin
ProcessHandle := GetCurrentProcess;
DLLModule := LoadLibrary(’ws2_32.dll’);
AddSend := GetProcAddress(DLLModule, ’send’); //取得API地址
AddRecv := GetProcAddress(DLLModule, ’recv’);
JmpCode.JmpCode := $B8;
JmpCode.MovEAX[0] := $FF;
JmpCode.MovEAX[1] := $E0;
JmpCode.MovEAX[2] := 0;
ReadProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
JmpCode.Address := @MySend;
WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize); //修改Send入口
ReadProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
JmpCode.Address := @MyRecv;
WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize); //修改Recv入口
OldSend := AddSend;
OldRecv := AddRecv;
end;

{------------------------------------}
{过程功能:取消HOOKAPI
{过程参数:无
{------------------------------------}
procedure UnHookAPI;
var
dwSize: Cardinal;
begin
WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);
WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);
end;

end.

---------------------------------------------------------------------------------------------
编译这个DLL后,再新建一个程序调用这个DLL的InstallHook并传入目标进程的主窗口句柄就可:
unit fmMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
InstallHook: function (SWindow: THandle):Boolean;stdcall;
UnHook: procedure;stdcall;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
ModuleHandle: THandle;
TmpWndHandle: THandle;
begin
TmpWndHandle := 0;
TmpWndHandle := FindWindow(nil, ’目标窗口的标题’);
if not isWindow(TmpWndHandle) then
begin
MessageBox(self.Handle, ’没有找到窗口’, ’!!!’, MB_OK);
exit;
end;
ModuleHandle := LoadLibrary(’Hook.dll’);
@InstallHook := GetProcAddress(ModuleHandle, ’InstallHook’);
@UnHook := GetProcAddress(ModuleHandle, ’UnHook’);
if InstallHook(FindWindow(nil, ’Untitled’)) then
ShowMessage(’Hook OK’);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
UnHook
end;

end.
HOOK征途实现拦截系统公告 语音视频下载地址 http://115.com/file/cly4tyga .版本 2 .子程序 _窗口1_创建完毕 .局部变量 tmp, 整数型 窗口1.标题 = 取执行文件名 () Process = GetCurrentProcessId () ' 004A31D7 E8 F4D30700 CALL zhengtu.005205D0 游戏公告显示的call地址 原始数据 = 读整型内存 (Process, 4862424) ' 读取E8 后面的call地址机器码 E8占一个字节 所以读取我们加上1(就是004A31D7+1) 也就是 005205D0 这个机器码 hook函数地址 = 到整数 (&hook;) ' 取出hook这个子程序的地址 tmp = hook函数地址 + 4 ' hook程序地址 + 4 ' '''''''''''''''''''''''''''''''''解释下为什么加4 ' '''''这个是hook程序原型 ' 008715D7 >/$ 56 PUSH ESI hook程序地址 ' 008715D8 |. 57 PUSH EDI ' 008715D9 |. 53 PUSH EBX ' 008715DA |. E8 09FBFFFF CALL ye_cat.008710E8 +4 来到 E8(008715D7+4),把E8不算进去 这里读取到这个call的机器码之后 下面换算出这个call地址(008710E8) ' 008715DF |. 5B POP EBX ' 008715E0 |. 5F POP EDI ' 008715E1 |. 5E POP ESI ' 008715E2 \. C3 RETN ' '''''''''''''''''''''''''''''''''''''''''''''''''call 008710e8 内部代码 也就是hook这个子程序的核心 ' 008710E8 /$ 55 PUSH EBP 'hook这个call的开始,系统自动分配了堆栈 ' 008710E9 |. 8BEC MOV EBP,ESP ' 008710EB |. 81EC 08000000 SUB ESP,8 ' 008710F1 |. C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0 ' 008710F8 |. 53 PUSH EBX '这个是我们用内联写的(我们要让游戏里面公告的call直接call我们这个地址(call 008710F8)) 游戏里面原来call内部代码就是这样子的(游戏call内部代码我也贴出来了 在底下) ' 008710F9 |. 8B9C24 080000>MOV EBX,DWORD PTR SS:[ESP+8] '存放公告内容的地址 ' 00871100 |. 55 PUSH EBP ' 00871101 |. 56 PUSH ESI ' 00871102 |. 57 PUSH EDI ' 00871103 |. 899D FCFFFFFF MOV DWORD PTR SS:[EBP-4],EBX ‘传给我们申请的局部变量([ebp-4]表示第一个局部变量) Str ' 00871109 |. 68 808A8D00 PUSH ye_cat.008D8A80 ; ASCII "\r\n" ' 0087110E |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ' 00871111 |. B9 02000000 MOV ECX,2 ' 00871116 |. E8 71FFFFFF CALL ye_cat.0087108C ' 0087111B |. 83C4 08 ADD ESP,8 ' 0087111E |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX ' 00871121 |. 68 04000080 PUSH 80000004 ' 00871126 |. 6A 00 PUSH 0 ' 00871128 |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] ' 0087112B |. 85C0 TEST EAX,EAX ' 0087112D |. 75 05 JNZ SHORT ye_cat.00871134 ' 0087112F |. B8 838A8D00 MOV EAX,ye_cat.008D8A83 ' 00871134 |> 50 PUSH EAX ' 00871135 |. 68 05000100 PUSH 10005 ' 0087113A |. 68 09000116 PUSH 16010009 ' 0087113F |. 68 06000152 PUSH 52010006 ' 00871144 |. 68 02000000 PUSH 2 ' 00871149 |. BB D0198700 MOV EBX,ye_cat.008719D0 ' 0087114E |. E8 DF040000 CALL ye_cat.00871632 ' 00871153 |. 83C4 1C ADD ESP,1C ' 00871156 |. 8B5D F8 MOV EBX,DWORD PTR SS:[EBP-8] ' 00871159 |. 85DB TEST EBX,EBX ' 0087115B |. 74 09 JE SHORT ye_cat.00871166 ' 0087115D |. 53 PUSH EBX ' 0087115E |. E8 D5040000 CALL ye_cat.00871638 ' 00871163 |. 83C4 04 ADD ESP,4 ' 00871166 |> 5F POP EDI ' 00871167 |. 5E POP ESI ' 00871168 |. 5D POP EBP ' 00871169 |. 5B POP EBX ' 0087116A \. C2 1400 RETN 14 //////////////////////////////////////////////////////////////// call目的地地址 = 读整型内存 (Process, tmp) call目的地地址 = call目的地地址 + tmp + 5 + 15 ' 取得hook程序里面 push ebx 的内存地址 为了不出错所以和游戏里面一样 不能从hook这个子程序头部开始调用 所以我加上相应的偏移(18)得到 push ebx的地址 ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' '''''''''游戏原来call的原型 ' 005205D0 /$ 53 PUSH EBX ' 005205D1 |. 8B5C24 08 MOV EBX,DWORD PTR SS:[ESP+8] ' 005205D5 |. 55 PUSH EBP ' 005205D6 |. 56 PUSH ESI ' 005205D7 |. 8B7424 14 MOV ESI,DWORD PTR SS:[ESP+14] ' 005205DB |. 83FE 03 CMP ESI,3 ' 005205DE |. 57 PUSH EDI ' 005205DF |. 8B7C24 1C MOV EDI,DWORD PTR SS:[ESP+1C] ' 005205E3 |. 8BE9 MOV EBP,ECX ' 005205E5 |. 74 05 JE SHORT zhengtu.005205EC ' 005205E7 |. 83FE 04 CMP ESI,4 ' 005205EA |. 75 11 JNZ SHORT zhengtu.005205FD ' 005205EC |> 8B0D 98B3CA00 MOV ECX,DWORD PTR DS:[CAB398] ' 005205F2 |. 85C9 TEST ECX,ECX ' 005205F4 |. 74 07 JE SHORT zhengtu.005205FD ' 005205F6 |. 57 PUSH EDI ' 005205F7 |. 53 PUSH EBX ' 005205F8 |. E8 43092000 CALL zhengtu.00720F40 ' 005205FD |> 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24] ' 00520601 |. 8B4C24 20 MOV ECX,DWORD PTR SS:[ESP+20] ' 00520605 |. 50 PUSH EAX ' 00520606 |. 51 PUSH ECX ' 00520607 |. 57 PUSH EDI ' 00520608 |. 56 PUSH ESI ' 00520609 |. 53 PUSH EBX ' 0052060A |. 8BCD MOV ECX,EBP ' 0052060C |. E8 CFF6FFFF CALL zhengtu.0051FCE0 ' 00520611 |. 5F POP EDI ' 00520612 |. 5E POP ESI ' 00520613 |. 5D POP EBP ' 00520614 |. 5B POP EBX ' 00520615 \. C2 1400 RETN 14 /这个call 5个参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值