功能简介
HookAPI 是一个截获Windows 32位API函数的开发包,它可以在Windows调用某个API函数的时候,先调用自己编写的函数,从而实现特殊的功能。
HookAPI同样也适用于截获用户自己编写的DLL文件中的输出函数。
1.5系统特点:
1)自己编写的替代函数的参数形式和原API函数完全一样,方便了Delphi和VB用户的使用。
2)实时截获所有新建立的进程,即进程建立后马上安装钩子,而不是采用定时扫描进程的方法
3)由于不采用定时扫描进程的方法,所以系统资源消耗少,基本上看不到消耗CPU资源。
4)新建立的InstDLL动态库,减少了用户调用HookAPI的代码。
运行和开发平台为Windows NT/2000/9x/XP
包含的文件列表:
【EXE目录】:调用InstHook.dll来安装HookAPI的执行程序
【InstHook目录】:安装HookAPI的DLL程序
【dll目录】:NT/2000/XP/XP下截获32位API函数的DLL程序
【HOOKAPI9x.dll】:Win9x下截获32位API函数的DLL程序
【EXE目录】:HookAPI.exe的源码
【HOOKSOCKET目录】:截获Socket函数的mydll例子
【HOOKREG目录】:截获注册表函数的mydll例子
【HOOKFILE目录】:截获文件存取的mydll例子
【HOOKFILE9x目录】:win9x下的截获文件存取的mydll_9x例子
【HookFile_Delphi目录】:截获文件存取的Delphi下的mydll的例子
【HookSocket_Delphi目录】:截取Socket函数的Delphi下的mydll的例子
使用:用户编写要截获的API函数相对应的自己的实现函数,编译成mydll.dll,同时在自己的程序中调用InstHook.dll中的安装/卸载函数就可以实现自己的截获过程。
开发指南
用户需要做的就是编写一个替换老API函数的mydll.dll,并在自己的程序中调用InstHook.dll中的安装/卸载函数就行了。
Mydll文件的编写:
1) 建立生成DLL的工程文件mydll
2) 如果工程名称不是mydll,则如果是win9x,则在工程文件的设置中修改生成的目标输出文件为mydll_9x.dll,其他操作系统(NT/2K/XP)输出文件为mydll.dll
3) 编写含有自己的调用过程的mydll.cpp程序和DLL输出函数说明文件mydll.def
4) 编译生成mydll.dll/mydll_9x.dll
mydll.cpp文件的编写
从三个例子程序可以看出,mydll.cpp文件其实非常简单,它包含如下内容
1) 包含mydll.h文件,此文件中只有一个MYAPIINFO结构说明:
typedef struct
{
char *module_name;
char *function_name;
char *myfunc_name;
}MYAPIINFO;
module_name是要截获的DLL或其他模块文件的名称,如kernel32.dll
function_name是要截获的API或用户DLL文件中函数的名称和参数,类似C中的说明格式,如connect函数为:connect(SOCKET, struct sockaddr *, INT)
myfunc_name为自己编写的替代函数的名称,如自己编写了myconnect函数,则myfunc为”myconnect”
2) 为生成win9x下的dll文件(mydll_9x.dll)加入下列编译选项
#ifdef WIN95
#pragma code_seg("_INIT")
#pragma comment(linker,"/SECTION:.bss,RWS /SECTION:.data,RWS /SECTION:.rdata,RWS /SECTION:.text,RWS /SECTION:_INIT,RWS ")
#pragma comment(linker,"/BASE:0xBFF70000")
#endif
如果是生成的win9x下的dll文件(mydll_9x.dll),那么编译选项里要先定义WIN95
3) 包含一个MYAPIINFO myapi_info[]结构数组定义并赋值,最后必须包含一个NULL项。此结构数组就是要截获的函数信息,如:
MYAPIINFO myapi_info[] =
{
{"WSOCK32.DLL", "socket(INT, INT, INT)", “mysocket”},
{"WSOCK32.DLL", "connect(SOCKET, struct sockaddr *, INT)", “myconnect”},
{"WSOCK32.DLL", "recv(INT, char *, INT, INT)", “myrecv”},
{"WSOCK32.DLL", "send(INT, char *, INT, INT)", “mysend”},
{"ADVAPI32.DLL", "RegOpenKeyA(HKEY, LPCSTR, PHKEY)", “myRegOpenKeyA”},
{NULL,NULL,NULL} //最后必须包含此项
};
4) 必须包含函数GetMyAPIInfo,如下:
MYAPIINFO *GetMyAPIInfo()
{
return &myapi_info[0];
}
5) 编写替换函数,替换函数格式为:
DWORD _cdecl MyFuncName(type1 param1, type2, param2, …)
其中函数必须为WINAPI调用方式(Delphi下为stdcall),函数的参数声明必须和原api函数中的参数相对应,如:
int WINAPI myconnect(SOCKET s, struct sockaddr *name, int namelen)
{
struct sockaddr_in *paddr =(struct sockaddr_in *)name;
char *ip =inet_ntoa(paddr->sin_addr);
int port =ntohs(paddr->sin_port);
int ret =connect(s, name, namelen);
int err=WSAGetLastError();
WriteLog("connect: ip=%s, port=%d, ret=%d\n", ip, port, ret);
// check filter
WSASetLastError(err);
return ret;
}
在此例子中,有保存和恢复错误码的代码,因为在编写自己的处理过程时,错误码可能会被修改,而原调用程序很可能根据错误码来判断进一步的动作;即使在myconnect中不调用原函数connect,那么在myconnect返回时,也要使用WSASetLastError或SetLastError来正确设置错误码。其他替换函数也应该这样做。
另外,在win9x下,最好在mydll中调用一下任意一个原先的api函数,以便mydll能调用原先的dll模块,否则就要在hookapi.exe中调用mydll前使用LoadLibrary调用一下原先的dll文件;否则将Hook不成功。
mydll.def文件的编写
mydll.def中包含GetMyAPIInfo和自己编写的替换函数的输出说明,如下:
EXPORTS
GetMyAPIInfo @1
MyFunc1 @2
MyFunc2 @3
InstallHook.dll文件的使用
InstHook.dll中的内容很简单,只有四个函数(参见InstHook.h):
1) int WINAPI InitHookAPI();
此函数初始化HookAPI
2) int WINAPI HookAllProcesses();
此函数实现截获和替换mydll中定义的API
3) int WINAPI UnhookAllProcesses();
此函数恢复原先系统的mydll中定义的API
4) int WINAPI NTHookProcess(DWORD process_id);
此函数在NT下截获和替换某个特定的进程中的mydll中定义的API,进程必须已经存在
5) int WINAPI NTUnhookProcess(DWORD process_id);
此函数在NT下恢复某个特定的进程中的mydll中定义的API,进程必须已经存在
6) int WINAPI NTHookProcess2(char *mod_name);
此函数在NT下Hook某个文件或模块名为mod_name的进程,进程必须已经存在
7) int WINAPI NTUnhookProcess2(char *mod_name);
此函数在NT下Unhook此函数在NT下截获和替换某个文件或模块名为mod_name的进程,进程必须已经存在
例子说明
API中实现了三个例子,每个例子都是截获函数调用,并写日志到c:\hookapi.log,并未进行其他的操作
截获Socket函数的例子
本例子中演示了截获Windows 32位Socket API函数,截获的DLL文件为WSOCK32.dll,截获的函数有socket,connect,recv,send。
mysocket函数:只是写日志。用户可以不调用socket()函数而直接返回一个socket值,从而在所有的socket函数调用中实现虚假的网络调用,欺骗应用程序。
myconnect函数:写日志。用户可以在此如下修改myconnect函数:不调用connect()而直接返回成功,欺骗应用程序;connect另外一个主机地址;connect另外一个端口。
myrecv函数:写日志。用户可以在此如下修改myrecv函数:不调用recv()函数而直接填充自己的buf,欺骗应用程序;调用recv,记录分析接收的数据包;调用recv,解密数据包;调用recv,使用send和另一端再次通讯;等等。
mysend函数:写日志。用户可以在此如下修改mysend函数:不调用send()函数而直接返回成功,欺骗应用程序;记录分析要发送的数据包;加密数据包(使用另一个buffer),然后调用send将加密包发送出去;等等。
但截获标准Socket API并不能获取所有系统对网络存取的内容,如驱动程序对网络的存取,如果要截获所有网络存取情况,可以看ipfilter等相关的源码,在编程沙龙上有很多。
截获注册表函数的例子
通过截获注册表函数和注册表的值,可以记录分析程序使用和创建了哪些注册表项,用于去除日期限制等应用。但截获标准注册表API并不能获取所有系统对文件存取的内容,如驱动程序对注册表的存取,如果要截获所有注册表存取情况,可以看regmon的源码,在编程沙龙上有。
截获文件存取的例子
通过截获文件存取,用户可以分析某个程序的文件存取情况等,但截获标准文件API并不能获取所有系统对文件存取的内容,如驱动程序对文件的存取,如果要截获所有文件存取情况,可以看filemon的源码,在编程沙龙上有。
根据上述例子,用户可以编写自己感兴趣的mydll,截获系统API或某些应用程序附带的dll中的函数的使用情况,来实现自己的特殊功能,如通过截获CreateProcessW来限制用户只能执行特定的应用程序或打开特定的文件。
编译和运行
将例子编译成mydll.dll/mydll_9x.dll,将mydll.dll、mydll_9x.dll、injlib.dll、HookAPINT.dll、HookAPI9x.dll、InstHook.dll放到和调用InstHook.dll的应用程序(如HookAPI.exe)相同的目录下。然后运行调用InstHook.dll<SPAN style="FONT-FAMILY: 宋体;
#include "stdafx.h"
#include <stdio.h>
#include "mydll.h"
#ifdef WIN95
#pragma code_seg("_INIT")
#pragma comment(linker,"/SECTION:.bss,RWS /SECTION:.data,RWS /SECTION:.rdata,RWS /SECTION:.text,RWS /SECTION:_INIT,RWS ")
#pragma comment(linker,"/BASE:0xBFF70000")
#endif
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
void WriteLog(char *fmt,...)
{
va_list args;
char modname[200];
char temp[5000];
HANDLE hFile;
DWORD dw;
GetModuleFileName(NULL, modname, sizeof(modname));
if((hFile =CreateFile("c:\\hookapi.log", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) <0)
{
return;
}
_llseek((HFILE)hFile, 0, SEEK_END);
wsprintf(temp, "mydll.dll:%s:", modname);
WriteFile(hFile, temp, strlen(temp), &dw, NULL);
va_start(args,fmt);
vsprintf(temp, fmt, args);
va_end(args);
WriteFile(hFile, temp, strlen(temp), &dw, NULL);
wsprintf(temp, "\r\n");
WriteFile(hFile, temp, strlen(temp), &dw, NULL);
_lclose((HFILE)hFile);
}
HANDLE WINAPI myCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
char temp[200];
GetModuleFileName(NULL, temp, sizeof(temp));
WriteLog("%s, myCreateFileA:filename=%s", temp, lpFileName);
//MessageBox(NULL, temp, "mydll", MB_OK);
if(strstr(lpFileName, "aaa") !=NULL) return NULL;
return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
HANDLE WINAPI myCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
//MessageBox(NULL, "myCreateFileW", "ok", MB_OK);
char temp[200];
GetModuleFileName(NULL, temp, sizeof(temp));
char fname[128];
WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, fname, 128,NULL,NULL);
WriteLog("%s, myCreateFileW:filename=%s", temp, fname);
//MessageBox(NULL, temp, "mydll", MB_OK);
if(strstr(fname, "aaa.txt") !=NULL)
{
WriteLog("CreateFileW aaa found!");
return CreateFileA("c:\\temp\\bbb.txt", dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
//SetLastError(ERROR_FILE_NOT_FOUND);
//return NULL;
}
return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
BOOL WINAPI myReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
WriteLog("ReadFile:handle=%x", hFile);
return ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
BOOL WINAPI myReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
WriteLog("ReadFileEx");
return ReadFileEx(hFile, lpBuffer, nNumberOfBytesToRead,
lpOverlapped, lpCompletionRoutine);
}
BOOL WINAPI myDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
// struct _iobuf f;
WriteLog("DeviceIoControl=%x", hDevice);
WriteLog("dwIoControlCode=%x,lpInBuffer=%x,lpOutBuffer=%x,lpBytesReturned=%x ",lpInBuffer,dwIoControlCode,lpOutBuffer,lpBytesReturned);
// fprintf(f, "DeviceIoControl(%x, %x, ...)\n", hDevice, dwIoControlCode);
return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned,NULL);
}
MYAPIINFO myapi_info[] =
{
{"KERNEL32.DLL", "CreateFileA", 7, "myCreateFileA"},
{"KERNEL32.DLL", "CreateFileW", 7, "myCreateFileW"},
{"KERNEL32.DLL", "ReadFile", 5, "myReadFile"},
{"KERNEL32.DLL", "ReadFileEx", 5, "myReadFileEx"},
{"KERNEL32.DLL", "DeviceIoControl", 8, "myDeviceIoControl"},
{NULL,NULL,NULL}
};
MYAPIINFO *GetMyAPIInfo()
{
return &myapi_info[0];
}
网友: laomms | 时间:2007-05-18 10:31:04 | |||
|