API挂接

作者在 2009-02-15 21:50:41 发布以下内容
下面这段代码是一个动态链接库的源码,它用于挂接MessageBoxW的调用
#include <windows.h>
#include 
<ImageHlp.h>                //for ImageDirectoryEntryToData
#include <TlHelp32.h>                 //for Module32First,MODULEENTRY32 and CreateToolhelp32Snapshot
#pragma comment(lib,"ImageHlp")       //for ImageDirectoryEntryToData
 
#pragma data_seg("Shared")
HHOOK hhk 
= NULL;                        //shared by all process,must be initilized
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,rws") //tell the linker to put hhk into the Shared section
 
//钩子函数.它只简单地把消息传递到下一个钩子过程
LRESULT CALLBACK GetMsgProc( int nCode, WPARAM wParam, LPARAM lParam ){
       
return CallNextHookEx(hhk,nCode,wParam,lParam);
}
//替换了的MessageBoxW.注意函数原型要和原来的一致,包括WIAPI
//它显示一个消息框指明MessageBoxW已被截获
int WINAPI MyMessageBoxW( HWND hwnd,LPCWSTR lpszContent,LPCWSTR lpszCaption,UINT uType ){
       MessageBoxW(hwnd,L
"Call to MessageBoxW is interceptedZZZZZZZZZZ!",L"Hook",MB_OK);
       
return MessageBoxW( hwnd,lpszContent,lpszCaption,uType);
}
//修改输入表
VOID ModifyIAT(HMODULE hmodCaller,LPCSTR szDllName,PROC pfnOrg,PROC pfnNew){
       PIMAGE_THUNK_DATA pITD;
       ULONG ulSize;
       
//对每一个用到的dll,在输入表中都用一个IMAGE_IMPORT_DESCRIPTOR类型的
       
//结构体保存该dll的信息
       PIMAGE_IMPORT_DESCRIPTOR pIID;
       
//用ImageDirectoryEntryToData可以取得输入表中的第一项
       
//参数IMAGE_DIRECTORY_ENTRY_IMPORT指明要取得输入表,而不是其他表
       pIID =(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
       
//如果pIID为NULL,表示该模块没有输入表,返回
       if!pIID )
              
return;
       
//IMAGE_IMPORT_DESCRIPTOR有一个Name的成员,该成员是dll名字的RVA
       
//hmodCaller实质是模块映射到进程空间中的基地址,通过将它转换为PBYTE类型,
       
//再加上Name这个RVA就可以得到这项IMAGE_IMPORT_DESCRIPTOR记录的dll的名字
       
//将这个名字与我们要挂接的dll的名字比较
       
//如果两个名字不同,则pIID++取下一项IMAGE_IMPORT_DESCRIPTOR
       for(; pIID->Name; pIID++){
              
if!lstrcmpiA( szDllName,(LPSTR)((PBYTE)hmodCaller + pIID->Name) ) )
                     
break;
       }
       
//如果遍历完所有dll都没有找到我们要挂接的dll,则返回
       if!pIID->Name )
              
return;
       
//可以从一个dll中输入多个函数.对每一个输入的函数,用一个IMAGE_THUNK_DATA
       
//结构体保存它的信息.在IMAGE_IMPORT_DESCRIPTOR中,有一个FirstThunk成员记录着
       
//第一个IMAGE_THUNK_DATA(这个IMAGE_THUNK_DATA保存着第一个输入函数的信息)的RVA
       
//我们用与取得dll名字一样的方法(基址+RVA)取得这个IMAGE_THUNK_DATA
       pITD = (PIMAGE_THUNK_DATA)( (PBYTE)hmodCaller + pIID->FirstThunk );
       
//IMAGE_THUNK_DATA有一个ul成员,它是一个共同体.通过这个共同体的Function成员,我们
       
//可以得到输入函数在进程空间中的真实地址
       
//将这个真实地址和我们要挂接的函数的地址比较,如果相同,则修改
       
//否则pITD++取下一个输入函数的信息
       for(; pITD->u1.Function ; pITD++){
              PROC
* ppfn = (PROC*)&pITD->u1.Function;
              
if*ppfn == pfnOrg ){
                     WriteProcessMemory(GetCurrentProcess(),ppfn,
&pfnNew,sizeof(pfnNew),NULL);
                     
return;
              }
       }
}
//安装钩子
_declspec(dllexport) VOID SetHook(){
       
if!hhk ){
              HINSTANCE hInst 
= LoadLibrary( TEXT("HOOKAPILIB.DLL") );
              
if!hInst )
                     
return;
              hhk 
= SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,0);
              FreeLibrary( hInst );
       }
}
//缷载钩子
_declspec(dllexport) VOID UnHook(){
       
if( hhk ){               
/*           ModifyIAT(
                     hCurrentProcess,
                     "USER32.DLL",
                     (PROC)MyMessageBoxW,
                     GetProcAddress( GetModuleHandle("USER32.DLL"),"MessageBoxW" )                 
                     );
*/
              UnhookWindowsHookEx( hhk );
       }
}
//dll的入口函数.每当这个dll被映射到一个进程的地址空间中,我们就挂接MessageBoxW
//在dll从进程的地址空间中缷载时,我们将原来的MessageboxW的地址写回进程中
//要取得这个进程的基地址,要用到MODULEENTRY32和CreateToolhelp32Snapshot
//MODULEENTRY32的hModule成员就是进程的基地址
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved ){
 
       HMODULE hCurrentProcess;
       MODULEENTRY32 me32;    
       HANDLE hSnapshot 
= CreateToolhelp32Snapshot( TH32CS_SNAPMODULE,GetCurrentProcessId() );
       me32.dwSize 
= sizeof( MODULEENTRY32 );
       Module32First(hSnapshot,
&me32);
       hCurrentProcess 
= me32.hModule;
 
       
switch( dwReason ){
       
case DLL_PROCESS_ATTACH:
              ModifyIAT(
                     hCurrentProcess,
                     
"USER32.DLL",
                     GetProcAddress( GetModuleHandle(
"USER32.DLL"),"MessageBoxW" ),
                     (PROC)MyMessageBoxW                   
                     );
              
break;
       
case DLL_PROCESS_DETACH:
              ModifyIAT(
                     hCurrentProcess,
                     
"USER32.DLL",
                     (PROC)MyMessageBoxW,
                     GetProcAddress( GetModuleHandle(
"USER32.DLL"),"MessageBoxW" )                 
                     );
              
break;
       }
       
return TRUE;
}
下面的代码调用上面的dll导出的SetHook和UnHook,将该dll注入到其他进程
#include <windows.h>
 
#define DLLNAME "HOOKAPILIB.DLL"
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, 
int iCmdShow)
{
     
static TCHAR szAppName[] = TEXT ("HOOKAPI") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
 
     wndclass.style         
= CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   
= WndProc ;
     wndclass.cbClsExtra    
= 0 ;
     wndclass.cbWndExtra    
= 0 ;
     wndclass.hInstance     
= hInstance ;
     wndclass.hIcon         
= LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       
= LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground 
= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName 
= NULL ;
     wndclass.lpszClassName 
= szAppName ;
 
     
if (!RegisterClass (&wndclass)){
               MessageBox(NULL,TEXT(
"DDFD"),TEXT("DDDFAS"),MB_OK);
          
return 0 ;
        }
     
    hwnd 
= CreateWindow (szAppName,                  // window class name
                          TEXT ("HOOKAPI"), // window caption
                          WS_OVERLAPPEDWINDOW,        // window style
                          462,              // initial x position
                          353,              // initial y position
                          100,                                        // initial x size
                          62,              // initial y size
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters
    
     
if( hwnd ){
               ShowWindow (hwnd, iCmdShow) ;
               UpdateWindow (hwnd) ;
        }
     
     
while (GetMessage (&msg, NULL, 00))
     {
          TranslateMessage (
&msg) ;
          DispatchMessage (
&msg) ;
     }
     
return msg.wParam ;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     
switch (message)
     {
     
case WM_CREATE:
               {
                      PROC SetHook;
                      HINSTANCE hInst 
= LoadLibrary(DLLNAME);
                      
if!hInst ){
                             DestroyWindow(hwnd);
                             MessageBox(hwnd,TEXT(
"Can not load dll!"),TEXT("HOOKAPI"),MB_ICONHAND);
                             PostQuitMessage(
0);
                             
return 0;
                      }
                      SetHook 
= GetProcAddress(hInst,"SetHook");
                      
if!SetHook ){
                             DestroyWindow(hwnd);
                             MessageBox(hwnd,TEXT(
"Can not find function!"),TEXT("HOOKAPI"),MB_ICONHAND);
                             PostQuitMessage(
0);
                             
return 0;
                      }
                      
//安装钩子,这样我们的dll就被映射到每一个gui程序的进程空间中
                      SetHook();
                      FreeLibrary(hInst);
                      
return 0 ;
               }
     
case WM_DESTROY:
               {
                      PROC UnHook;
                      HINSTANCE hInst 
= LoadLibrary(DLLNAME);
                      
if!hInst ){
                             MessageBox(hwnd,TEXT(
"Can not load dll!"),TEXT("HOOKAPI"),MB_ICONHAND);
                             PostQuitMessage(
0);
                             
return 0;
                      }
                      UnHook 
= GetProcAddress(hInst,"UnHook");
                      
if!UnHook ){
                             MessageBox(hwnd,TEXT(
"Can not find function!"),TEXT("HOOKAPI"),MB_ICONHAND);
                             PostQuitMessage(
0);
                             
return 0;
                      }
                      
//退出之前我们要缷载钩子
                      UnHook();
                      PostQuitMessage (
0) ;
                      
return 0 ;
               }
     }
     
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
运行上面这段程序之后,当你修改一个文本文件之后,在关闭记事本的时候,记事本对MessageBoxW的调用就被截获了.
下面我们把我们的截获做得彻底些
下面新的dll的代码,里面加入了对LoadLibraryA和GetProcAddress的截获
 
#include <windows.h>
#include 
<ImageHlp.h>
#include 
<TlHelp32.h>
#pragma comment(lib,"ImageHlp")
 
#pragma data_seg("Shared")
HHOOK hhk 
= NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,rws")
 
HMODULE hmodThisDll;
 
LRESULT CALLBACK GetMsgProc( 
int nCode,WPARAM wParam,LPARAM lParam){
       
return CallNextHookEx(hhk,nCode,wParam,lParam);
}
 
int WINAPI MyMessageBoxW(HWND hwnd,LPCWSTR lpszContent,LPCWSTR lpszCaption,UINT uType){
       MessageBoxW(hwnd,L
"Call to MessageBoxW is intercepted!",L"HOOKAPILIB2",MB_OK);
       
return MessageBoxW(hwnd,lpszContent,lpszCaption,uType);
}
 
VOID ModifyIAT(HMODULE hmodCaller,LPCSTR szDllName,PROC pfnOrg,PROC pfnNew){
       PIMAGE_THUNK_DATA pITD;
       ULONG ulSize;
       PIMAGE_IMPORT_DESCRIPTOR pIID;
       pIID 
= (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hmodCaller,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ulSize);
       
if!pIID )
              
return;
       
for( ; pIID->Name; pIID++ ){
              
if!lstrcmpiA(szDllName,(LPSTR)((PBYTE)hmodCaller+pIID->Name)) )
                     
break;
       }
       
if!pIID->Name )
              
return;
       pITD 
= (PIMAGE_THUNK_DATA)((PBYTE)hmodCaller+pIID->FirstThunk);
       
for( ; pITD->u1.Function ; pITD++ ){
              PROC
* ppfn = (PROC*)&pITD->u1.Function;
              
if(*ppfn == pfnOrg){
                     WriteProcessMemory(GetCurrentProcess()
/*hmodCaller*/,ppfn,&pfnNew,sizeof(pfnNew),NULL);
                     
return;
              }
       }
}
//在这里枚举进程的所有模块,并修改各个模块对MessageBoxW的调用
//这个枚举过程用到了Module32First和Module32Next
VOID ModifyIATs(LPCSTR szDllName,PROC pfnOrg,PROC pfnNew){
       BOOL fOk 
= FALSE;
       MODULEENTRY32 me32;
       HANDLE hSnapshot;
       hSnapshot 
= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());
       me32.dwSize 
= sizeof( me32 );
       
for( fOk = Module32First( hSnapshot,&me32 ); fOk ; fOk = Module32Next(hSnapshot,&me32)){
              
if( me32.hModule != hmodThisDll ){
                     ModifyIAT(me32.hModule,szDllName,pfnOrg,pfnNew);
              }
       }
       CloseHandle( hSnapshot );
}
//LoadLriary的替代函数
HMODULE WINAPI MyLoadLibraryA( LPCSTR lpLibFileName ){
       
       HMODULE hmod 
= LoadLibrary( lpLibFileName );
       ModifyIAT( hmod,
"USER32.DLL",
              GetProcAddress(GetModuleHandle(
"USER32.DLL"),"MessageBoxW"),MyMessageBoxW
              );
       
return hmod;
}
//GetProcAddress的替代函数
FARPROC WINAPI MyGetProcAddress( HMODULE hModule,LPCSTR lpProcName ){
       
if( hModule == GetModuleHandle("USER32.DLL"&&
              
!lstrcmpiA(lpProcName,"MessageBoxW") )
              
return (PROC)MyMessageBoxW;
       
else
              
return GetProcAddress( hModule,lpProcName );
}
 
//_declspec(dllexport) VOID SetHook( DWORD dwThreadId ){
_declspec(dllexport) VOID SetHook( ){
       
if!hhk ){
              HINSTANCE hInst 
= LoadLibrary("HOOKAPILIB2.DLL");
              
if!hInst )
                     
return;
              hhk 
= SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,0);
              FreeLibrary( hInst );
       }
}
 
_declspec(dllexport) VOID UnHook(){
       
if( hhk )
              UnhookWindowsHookEx( hhk );
}
//在DLL_PROCESS_ATTACH通知时,修改MessageBoxW,LoadLibraryA,GetProcAddress的地址
//在DLL_PROCESS_DETACH通知时,将地址改回原来的地址
BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID lpvReserved){
       hmodThisDll 
= hInstance;
       
switch( dwReason ){
       
case DLL_PROCESS_ATTACH:
              ModifyIATs(
                     
"USER32.DLL",
                     GetProcAddress(GetModuleHandle(
"USER32.DLL"),
                     
"MessageBoxW"),
                     (PROC)MyMessageBoxW);
              ModifyIATs(
                     
"KERNEL32.DLL",
                     GetProcAddress(GetModuleHandle(
"KERNEL32.DLL"),"LoadLibraryA"),
                     (PROC)MyLoadLibraryA);
              ModifyIATs(
vc | 阅读 5002 次
文章评论,共0条
游客请输入验证码