先读下HookAPI 使用文档:

功能简介

HookAPI 是一个截获Windows 32API函数的开发包,它可以在Windows调用某个API函数的时候,先调用自己编写的函数,从而实现特殊的功能。

HookAPI同样也适用于截获用户自己编写的DLL文件中的输出函数。

 

1.5系统特点:

1自己编写的替代函数的参数形式和原API函数完全一样,方便了DelphiVB用户的使用。

2实时截获所有新建立的进程,即进程建立后马上安装钩子,而不是采用定时扫描进程的方法

3由于不采用定时扫描进程的方法,所以系统资源消耗少,基本上看不到消耗CPU资源。

4新建立的InstDLL动态库,减少了用户调用HookAPI的代码。

 

运行和开发平台Windows NT/2000/9x/XP

包含的文件列表

EXE目录】:调用InstHook.dll来安装HookAPI的执行程序

InstHook目录】:安装HookAPIDLL程序

dll目录】:NT/2000/XP/XP下截获32API函数的DLL程序

HOOKAPI9x.dll】:Win9x下截获32API函数的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返回时,也要使用WSASetLastErrorSetLastError来正确设置错误码。其他替换函数也应该这样做。

另外,在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);

此函数在NTHook某个文件或模块名为mod_name的进程,进程必须已经存在

7) int WINAPI NTUnhookProcess2(char *mod_name);

此函数在NTUnhook此函数在NT下截获和替换某个文件或模块名为mod_name的进程,进程必须已经存在

 

 

 

 

 


 

例子说明

API中实现了三个例子,每个例子都是截获函数调用,并写日志到c:\hookapi.log,并未进行其他的操作

截获Socket函数的例子

本例子中演示了截获Windows 32Socket API函数,截获的DLL文件为WSOCK32.dll,截获的函数有socketconnectrecvsend

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.dllmydll_9x.dllinjlib.dllHookAPINT.dllHookAPI9x.dllInstHook.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
调用程序:
#include <windows.h>
#include "resource.h"

#define MsgBox(msg) MessageBox(NULL, msg, "HookAPI - www.programsalon.com", MB_OK)

BOOL CALLBACK MainDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);

typedef int (WINAPI *FuncHookOneProcess2)(HWND hwndNotify, char *exe_name);
typedef int (WINAPI *FuncUnhookOneProcess2)(char *exe_name);
typedef int (WINAPI *FuncHookAllProcess)();
typedef int (WINAPI *FuncUnhookAllProcess)();

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WriteProfileString("HookAPI", "exe_name", "HookAPI.exe");

    int isNT =false;
    OSVERSIONINFO VersionInfo;
    VersionInfo.dwOSVersionInfoSize =sizeof(OSVERSIONINFO);

    if(!GetVersionEx(&VersionInfo))
        return false;

    if(VersionInfo.dwPlatformId ==VER_PLATFORM_WIN32_NT)
        isNT =true;

    HINSTANCE hLib;
    if(isNT)
        hLib =LoadLibrary("HookAPINT.dll");
    else
        hLib =LoadLibrary("HookAPI9x.dll");
    if(hLib ==NULL)
    {
        MessageBox(NULL, "LoadLibrary HookAPIxx.dll failed", "HookAPI.exe", MB_OK);
        return false;
    }

    FuncHookOneProcess2 HookOneProcess2 =(FuncHookOneProcess2)GetProcAddress(hLib, "HookOneProcess2");
    FuncUnhookOneProcess2 UnhookOneProcess2 =(FuncUnhookOneProcess2)GetProcAddress(hLib, "UnhookOneProcess2");
    FuncHookAllProcess HookAllProcess =(FuncHookAllProcess)GetProcAddress(hLib, "HookAllProcess");
    FuncUnhookAllProcess UnhookAllProcess =(FuncUnhookAllProcess)GetProcAddress(hLib, "UnhookAllProcess");

    if(HookAllProcess ==NULL)
    {
        MsgBox("HookAllProcess ==NULL");
        FreeLibrary(hLib);
        return 0;
    }
    
    if(UnhookAllProcess ==NULL)
    {
        MsgBox("UnhookAllProcess ==NULL");
        FreeLibrary(hLib);
        return 0;
    }
    if(HookAllProcess() <0)
    {
        MsgBox("HookAllProcesses error!");
        UnhookAllProcess();
        FreeLibrary(hLib);
        return 0;
    }
    // 测试只Hook一个正在运行的程序,下面的函数已经在1.6版本中取消,但还是很有用,所以以后版本中还是会提供
/*
    if(HookOneProcess2(NULL, "ship.exe") <0)
    {
        MsgBox("HookOneProcess failed!");
        return  0;
    }
*/
    /// HookAllProcesses2是针对无法截获按Ctrl-Alt_Del键时运行的任务管理器等程序的情况使用的。
    /*if(HookAllProcesses2(1000) <0)
    {
        MsgBox("HookAllProcesses error!");

        return 0;
    }*/
    /*char temp[200], temp2[20], temp3[256];

    char *p =(char *)0x7FCEDCF1;//(char *)funcSHFileOperationA;

    wsprintf(temp, "func:%x", p);
    wsprintf(temp2, "%x,%x,%x,%x", *p&0xFF, *(p+1)&0xFF, *(p+2), *(p+3), *(p+4));
    wsprintf(temp3, "[%s], %s", temp, temp2);
    MessageBox(NULL, temp3, "ok", MB_OK);*/

    DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc);

    UnhookAllProcess();
    FreeLibrary(hLib);

    return 0;
}

BOOL CALLBACK MainDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDOK:
            EndDialog(hDlg, IDOK);
            break;
        case ID_HIDE:
            ShowWindow(hDlg, SW_HIDE);
            break;
        }
    default:
        break;
    }

    return FALSE;
}
posted on 2010-05-26 09:05  wl666lw  阅读(13304)  评论(0编辑  收藏  举报