代码是转贴的,注释是我胡乱加上去的。没别的意思,只是网上对用madCodeHook控件的使用讨论的太少,希望有更多大虾能把他们在这方面的
使用经验贴出来共享,谢谢!
{
Delphi Winsock Hooking Example by Aphex
This example shows you how to hook winsock functions
of a target process and control incomming and outgoing
data. It is based on send and recv but it will work the
same way applied to sendto and recvfrom.
这个例子显示你如何钩Winsock的功能和过程控制目标incomming进出数据. 它是基于工作派遣和recv但同样适用于sendto和recvfrom.
The output file is a CPL (Control Panel Extension) which
is simply a special DLL that is loaded when it is double
clicked. This saves us from having to write a seperate
loader for the hook library.
输出档案是刑诉法(控制面板扩展)这是一种特殊的DLL,当它是装双拨动. 这样节省我们从当年写的另装载机钩图书馆.
The example shows how to hook the needed functions and
perform some simple manipulation of the data, using two
different methods of accessing the data. The second, which
uses pointers, is more flexible but also more complex.
}
function ConvertDataToAscii(Buffer: pointer; Length: Word): string;{数据转换成ASCII码}
var
Iterator: integer;{iterator=泛型}
AsciiBuffer: string;{buffer=缓冲区}
begin
AsciiBuffer := '';
for Iterator := 0 to Length - 1 do{length=长度} //在ASCII码缓冲区搜索符合条件的代码}
{如果你知道你的查询会返回非常大量的对象,但是你不希望全部使用它们,你可以用iterate()方法获得更好的性能
Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,
从而避免向客户端暴露集合的内部结构。}
begin
//CHAR=字符:容纳单字符的一种基本数据类型,POINTER= {工作指针}.
if char(pointer(integer(Buffer) + Iterator)^) in [#32..#127] then
AsciiBuffer := AsciiBuffer + ' ' + char(pointer(integer(Buffer) + Iterator)^) + ' '
else
AsciiBuffer := AsciiBuffer + ' . ';
end;
Result := AsciiBuffer;
end;
function ConvertDataToHex(Buffer: pointer; Length: Word): string;;{数据转换成Hex码}
var
Iterator: integer;
HexBuffer: string;
begin
HexBuffer := '';
for Iterator := 0 to Length - 1 do
begin
HexBuffer := HexBuffer + IntToHex(Ord(char(pointer(integer(Buffer) + Iterator)^)), 2) + ' ';
end;
Result := HexBuffer;
end;
function recvHookProc(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
AsciiBuffer: string;
HexBuffer: string;
DataBuffer: pchar;
begin
//call the real winsock function
呼吁真正的WinSock功能
Result := recvNextHook(s, Buf, len, flags);{result=结果}
//allocate memory for our copy of the data
分配数据存储的副本
GetMem(DataBuffer, Result);{动态分配内存的函数}
try
{实现异常保护的TRY...FINALLY语句。在实际应用过程中,可能因为某些原因使得对数据库表的更新不能进行下去。如当程序试图执行Post方法将修改后的记录写回磁盘时,而又因为某种原因磁盘没有准备好,这时便出现了异常。当出现异常时,应用程序会暂停下来并且会弹出一对话框显示有关的错误信息,在用户单击错误信息对话框之后,程序将继续执行到某一个地方去,而这个地方常常不是用户所能预料到的。
在执行Post方法之前,窗体中所有的部件与TTable部件都已失去联系。因此,这种异常将导致窗体中显示的数据和数据库无关。
Try...Finally语句为我们解决上述异常问题提供了一个解决方法。在Delphi中仍然采用了这一语句用来处理异常问题。实际上,Try...Finally 语句是把两组语句组合在一起。语句的Try部分包含了可能产生异常的程序代码,Finally部分包含了即使发生了异常也必须执行的一条或多条语句。}
//get our copy of the data
我们得到的数据副本
CopyMemory(DataBuffer, @Buf, Result);{将一块内存的数据从一个位置复制到另一个位置的函数}
{函数原型
VOID CopyMemory(
PVOID Destination,
CONST VOID *Source,
DWORD Length
);
参数
Destination
要复制内存块的目的地址。
Source
要复制内存块的源地址。
Length
指定要复制内存块的大小,单位为字节
返回值
该函数为VOID型,没有返回值。}
//using the data as a byte array
采用数据作为字节数组的复制过程
DataBuffer[0] := chr(10); //changing first byte首字节改变
DataBuffer[1] := chr(20); //changing second byte转变第二字节
DataBuffer[2] := chr(30); //changing thrid byte改变第三字节
//using the data as a pointer to other data sizes
运用数据资料,作为对其他大小的指示物
word(pointer(DataBuffer)^) := 10; //changing first 2 bytes改变首两字节
dword(pointer(integer(DataBuffer) + 2)^) := 20; //changing next 4 bytes改变其后4字节
word(pointer(integer(DataBuffer) + 6)^) := 30; //changing next 2 bytes改变其后2字节
//overwrite the original data with our new data
改写新数据与原数据
CopyMemory(@Buf, DataBuffer, Result);{将一块内存的数据从一个位置复制到另一个位置的函数}
finally{最后}
FreeMem(DataBuffer);{动态释放内存的函数,释放内存中的数据缓冲区}
end;
//convert data to readable ascii suitable for logging
资料转换为可读性代码适合读取
AsciiBuffer := ConvertDataToAscii(@Buf, Result);
//convert data to readable hex suitable for logging
资料转换为可读性代码适合读取
HexBuffer := ConvertDataToHex(@Buf, Result);
end;
function sendHookProc(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
var
AsciiBuffer: string;
HexBuffer: string;
DataBuffer: pchar;
begin
Result := 0;
//save the socket so we can send data too
储存socket,方便我们传送数据
DataSocket := s;
{基于TCP/IP协议并对其进行高度封装,能在测试测量过程中实现服务器与多用户的实时数据交换与共享,而用户不必关心程序底层的细节。}
//allocate memory for our copy of the data
分配数据存储的副本
GetMem(DataBuffer, Result);{动态分配内存的函数,获取内存数据缓冲区中的结果}
try{实现异常保护的TRY...FINALLY语句}
//get our copy of the data
我们得到的数据副本
CopyMemory(DataBuffer, @Buf, Result);{将一块内存的数据从一个位置复制到另一个位置的函数}
//using the data as a byte array
采用数据作为字节数组
DataBuffer[0] := chr(10); //changing first byte首字节改变
DataBuffer[1] := chr(20); //changing second byte转变第二字节
DataBuffer[2] := chr(30); //changing thrid byte改变第三字节
//using the data as a pointer to other data sizes
运用数据资料,作为对其他大小的指示物
word(pointer(DataBuffer)^) := 10; //changing first 2 bytes改变首两字节
dword(pointer(integer(DataBuffer) + 2)^) := 20; //changing next 4 bytes改变其后4字节
word(pointer(integer(DataBuffer) + 6)^) := 30; //changing next 2 bytes改变其后2字节
//overwrite the original data with our new data
改写新数据与原数据
CopyMemory(@Buf, DataBuffer, Result);{将一块内存的数据从一个位置复制到另一个位置的函数}
finally{最后}
FreeMem(DataBuffer);{动态释放内存的函数,释放内存中的数据缓冲区}
end;
//convert data to readable ascii suitable for logging
资料转换为可读性代码适合读取
AsciiBuffer := ConvertDataToAscii(@Buf, Result);
//convert data to readable hex suitable for logging
资料转换为可读性代码适合读取
HexBuffer := ConvertDataToHex(@Buf, Result);
//call the real winsock function
呼吁真正的WinSock功能
Result := sendNextHook(s, Buf, len, flags);
end;
procedure EntryPoint(Reason: dword); stdcall;{Entry=进入,Reason=原因}
var
lpFileName: array [0..MAX_PATH - 1] of char;{lpFileName=IP地址}
StartInfo: TStartupInfo;{用来指定要启动的处理序,启动资讯}
ProcInfo: TProcessInformation;{从/proc目录里读取相关数据,将数据妥善整理过后输出到标准输出设备。进程资料}
begin
if Reason = DLL_PROCESS_ATTACH then
{当处理DLL_PROCESS_ATTACH时,DLL应该执行DLL中的函数要求的任何与进程相关的初始化。当DLL被初次映射到进程的地址空间中时,系统将调用该DLL的DllMain函数,给它传递参数fdwReason的值DLL_PROCESS_ATTACH。
当DllMain处理一个DLL_PROCESS_ATTACH通知时,DllMain的返回值能够指明DLL的初始化是否已经取得成功。如果对HeapCreate的调用取得了成功,DllMain应该返回TRUE。如果堆栈不能创建,它应该返回FALSE。如果fdwReason使用的是其他的值,即DLL_PROCESS_DETACH、DLL_THREAD_ATTACH和DLL_THREAD_DETACH,那么系统将忽略DllMain返回的值。}
begin
//check if we are injected inside the target
如果我们注入内检查对象
if lstrcmpi(pchar(Copy(ParamStr(0), Length(ParamStr(0)) - Length(szTargetExe) + 1, Length(szTargetExe))), pchar(szTargetExe)) = 0 then
{比较两个字元字串,不分大小写}
begin
//if we are then we hook the needed functions
如果我们需要的功能便钩
DataSocket := 0;
HookCode(@send, @sendHookProc, @sendNextHook);{这样就Hook了API了}
HookCode(@recv, @recvHookProc, @recvNextHook);
end
else
begin
//if not then load the target and inject ourself
如果不是那么负荷目标注入误判
GetModuleFileName(hInstance, @lpFileName, MAX_PATH);{取得应用所在路径}
ZeroMemory(@StartInfo, SizeOf(TStartupInfo));{将一块内存置零}
ZeroMemory(@ProcInfo, SizeOf(TProcessInformation));
StartInfo.dwFlags := STARTF_USESHOWWINDOW;{用来指定要启动的处理序}
StartInfo.wShowWindow := SW_SHOW;
CreateProcess(PChar(ExtractFilePath(lpFileName) + szTargetExe), nil, nil, nil, False, 0, nil, nil, StartInfo, ProcInfo);
Sleep(3000);
InjectLibrary(ProcInfo.hProcess, lpFileName);
{要在主调程序中调用InjectLibrary, 才能在被监控程序中成功的设置Hook}
end;
end;
end;
begin
DLLProc := @EntryPoint;
EntryPoint(DLL_PROCESS_ATTACH);
end.