API挂接

 

在阅读这篇文章之前,你可能要先阅读 http://www.codeproject.com/system/inject2exe.asp#PortableExecutablefileformat2
下面这段代码是一个动态链接库的源码,它用于挂接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,  0 0 ))
     {
          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(
" KERNEL32.DLL " ,
                     GetProcAddress(GetModuleHandle(
" KERNEL32.DLL " ), " GetProcAddress " ),
                     (PROC)MyGetProcAddress);
              
break ;
       
case  DLL_PROCESS_DETACH:
              ModifyIATs(
                     
" USER32.DLL " ,
                     (PROC)MyMessageBoxW,
                     GetProcAddress(GetModuleHandle(
" USER32.DLL " ),
                     
" MessageBoxW " ));
              ModifyIATs(
                     
" KERNEL32.DLL " ,
                     (PROC)MyLoadLibraryA,
                     GetProcAddress(GetModuleHandle(
" KERNEL32.DLL " ), " LoadLibraryA " ));
              ModifyIATs(
                     
" KERNEL32.DLL " ,
                     (PROC)MyGetProcAddress,
                     GetProcAddress(GetModuleHandle(
" KERNEL32.DLL " ), " GetProcAddress " ));
              
break ;
       }
       
return  TRUE;
}
由于一个程序可能在运行的时候动态加载其他dll,而这些dll也可能调用MessageBoxW,所以我们要截获LoadLibrary的调用(这里只截获LoadLibraryA,而没有管LoadLibraryW)
而一个程序也可能通过GetProcAddress来获得MessageBoxW的真正地址,所以我们也要截获GetProcAddress的调用
下面是一个测试程序和一个测试用的dll.它通过三种方法调用MessageBoxW.第一种是直接调用.对这种调用,我们的第一个dll就可以截获.第二种是调用另外的dll中的函数,而这个另外的dll的函数调用了MessageBoxW.第三种是通过GetProcAddress来调用MessageBoxW
#include  < windows.h >
 
/* 注释1
_declspec(dllimport) int IndirectMessageBox( HWND hwnd );
#pragma comment(lib,"HOOKAPITESTLIB")
*/
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 
int  WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, 
int  iCmdShow)
{
     
static  TCHAR szAppName[]  =  TEXT ( " HOOKAPITESTER " ) ;
     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 ( " HOOKAPITESTER " ),   //  window caption
                          WS_OVERLAPPEDWINDOW,         //  window style
                          CW_USEDEFAULT,               //  initial x position
                          CW_USEDEFAULT,               //  initial y position
                          CW_USEDEFAULT,                   //  initial x size
                          CW_USEDEFAULT,               //  initial y size
                          NULL,                        //  parent window handle
                          NULL,                        //  window menu handle
                          hInstance,                   //  program instance handle
                          NULL) ;                      //  creation parameters
     
               ShowWindow (hwnd, iCmdShow) ;
               UpdateWindow (hwnd) ;
     
     
while  (GetMessage ( & msg, NULL,  0 0 ))
     {
          TranslateMessage (
& msg) ;
          DispatchMessage (
& msg) ;
     }
     
return  msg.wParam ;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     
switch  (message)
     {
        
case  WM_LBUTTONDOWN :
               {
                      
// IndirectMessageBox(hwnd); // 注释1
/*
注释2
                      HMODULE hmodNewlyLoaded;
                      //注意PROC定义的函数调用方式是WINAPI 的,
                      //所以,IndirectMessageBox也必须是WINAPI的,否则出现错误                 
                      PROC IndirectMessageBox; 
                      hmodNewlyLoaded = LoadLibrary( TEXT("HOOKAPITESTLIB.DLL") );
                      IndirectMessageBox = GetProcAddress(hmodNewlyLoaded,"IndirectMessageBox");
                      IndirectMessageBox( hwnd );
                      FreeLibrary( hmodNewlyLoaded );
*/
//                    MessageBoxW(hwnd,L"HookAPITester",L"HookAPITester",MB_OK); // 注释0
                      PROC MessageBoxWPROC  =  GetProcAddress(
                             GetModuleHandle(
" USER32.DLL " ), " MessageBoxW " );
                      MessageBoxWPROC(hwnd,L
" HookAPITester " ,L " HookAPITester " ,MB_OK);
                      
break ;
               }
     
case  WM_DESTROY:
               PostQuitMessage (
0 ) ;
               
return   0  ;
     }
     
return  DefWindowProc (hwnd, message, wParam, lParam) ;
}
 
 下面是一个测试dll,它有一个调用 了MessageBoxW的导出函数
#include  < windows.h >
int  WINAPI IndirectMessageBox( HWND hwnd ){
       
return  MessageBoxW(hwnd,
              L
" IndirectMessageBox " ,
              L
" HookAPITestLib " ,
              MB_OK);
}
下面是这个dll的.def文件 
LIBRARY
       EXPORTS
              IndirectMessageBox

==============================

欢迎交流.如果你发现本文有错,或者有什么意见以改进,可以给我发邮件xkf.com.net@163.com

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值