久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

《windows核心編程系列》二十二談?wù)勑薷膶?dǎo)入段攔截API。

 求真我 2014-04-20
 一個模塊的導(dǎo)入段包含一組DLL,。為了讓模塊能夠運行,,這些DLL是必須的。導(dǎo)入段還包含一個符號表,。它列出了該模塊從各DLL中導(dǎo)入的符號,。當(dāng)模塊調(diào)用這些導(dǎo)入符號的時候,系統(tǒng)實際上會調(diào)用轉(zhuǎn)換函數(shù),,獲得導(dǎo)入函數(shù)在導(dǎo)入表的地址,,然后再跳到相應(yīng)的位置。如果我們能將導(dǎo)入段中相應(yīng)導(dǎo)入函數(shù)的地址替換成自定義的函數(shù)的地址,,即可實現(xiàn)對該函數(shù)的攔截,。在自定義的函數(shù)中,我們既可以調(diào)用攔截的函數(shù),,也可以執(zhí)行其他工作,。

      要實現(xiàn)修改導(dǎo)入段來攔截API必須對PE文件格式有很好的了解。網(wǎng)上關(guān)于它的資料鋪天蓋地,,自己搜吧,。此處不打算介紹。

      為了修改要攔截的函數(shù)在導(dǎo)入段的地址,,首先要獲得PE文件導(dǎo)入段的地址,。這可以調(diào)用ImageDirectoryEntryToData.函數(shù)。

  1. PVOID WINAPI ImageDirectoryEntryToData(   
  2.   
  3. __in   PVOID Base,   
  4.   
  5. __in   BOOLEAN MappedAsImage,   
  6.   
  7. __in   USHORT DirectoryEntry,   
  8.   
  9. __out  PULONG Size );  


     Base為要獲得導(dǎo)入段所在模塊的基地址,。它一般是GetModuleHandle的返回值,。

     MappedAsImage,它為true時,,系統(tǒng)將該模塊以映像文件的形式映射,,否則以數(shù)據(jù)文件的形式映射。

     DirectoryEntry,,要獲得的段的索引,。此函數(shù)不僅僅能夠獲得導(dǎo)入段的地址,根據(jù)此索引的不同,,該函數(shù)返回對應(yīng)段的地址,。此處我們使用 IMAGE_DIRECTORY_ENTRY_IMPORT表示我們要獲得導(dǎo)入段的地址。

     Size返回表項的大小。注意其類型,。

     看代碼:

  1. ULONG size;  
  2.   
  3. HMODULE hModule=GetModuleHandle(NULL);  
  4.   
  5. PIMAGE_IMPORT_DESCRIPTOR pImport=  
  6.   
  7. ImageDirectoryEntryToData(hModule,true,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);  
  8.   
  9. while(pImport->FirstThunk)  
  10.   
  11. {  
  12.   
  13. int i=0;  
  14.   
  15. char *ModuleName=(char*)((BYTE*)hModule+pImport->Name);  
  16.   
  17. PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)  
  18.   
  19.                                                 ((BYTE*)hModule+pImport->FirstThunk);  
  20.   
  21. while(pThunk->u1.Function)  
  22.   
  23. {  
  24.   
  25.                   char*Func=(char*)((BYTE*)hModule+pThunk->u1.AddressOfData+2);  
  26.   
  27. If(Func=="MessageBoxA")   
  28.   
  29.                    {  
  30.   
  31. MessageBox("找到函數(shù)");  
  32.   
  33.                    }  
  34.   
  35.           }  
  36.   
  37.     }  


       IMAGE_IMPORT_DESCRIPTOR 結(jié)構(gòu)是導(dǎo)入段的基本結(jié)構(gòu),,導(dǎo)入段是由此類型組成的數(shù)組構(gòu)成,每個DLL對應(yīng)數(shù)組中的一項,。數(shù)組的最后一項為NULL,。每一項中有兩個關(guān)鍵成員,指出IMAGEA_THUNK_DATA類型的數(shù)組的偏移量,,這兩個數(shù)組分別列出了從此DLL導(dǎo)入的函數(shù)名稱,,以及它它們在本進(jìn)程地址空間的RVA

以下是其定義:

  1. typedef struct _IMAGE_IMPORT_DESCRIPTOR {  
  2.    union {  
  3.           DWORD Characteristics;  
  4.           DWORD OriginalFirstThunk;// 指向一個 IMAGE_THUNK_DATA 結(jié)構(gòu)數(shù)組的RVA  
  5.          }  
  6.    DWORD TimeDateStamp;// 文件生成的時間  
  7.     DWORD ForwarderChain;// 這個數(shù)據(jù)一般為0,,可以不關(guān)心  
  8.     DWORD Name;   // RVA,,指向DLL名字的指針,ASCII字符串  
  9.     DWORD FirstThunk; //指向一個 IMAGE_THUNK_DATA 結(jié)構(gòu)數(shù)組的RVA,這個數(shù)據(jù)與IAT所指向的地址一致  
  10. }IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR  


      OriginalFirstThunk FirstThunk是此結(jié)構(gòu)中的關(guān)鍵成員,。它們指出這兩個IMAGE_THUNK_DATA類型的數(shù)組,。

      Name 是指向DLL名稱的指針。

      pImport指向模塊的導(dǎo)入段,,可以使用它來訪問IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)的每一個成員,。

      注意:以上所有偏移量都是相對于模塊基地址的,因此在實際使用中一定要加上模塊的地址,。

      OriginalFirstThunk指向NAT,,NAT列出了從該DLL導(dǎo)入的所有導(dǎo)入函數(shù)的名稱。

      FirstThunk 指向IAT,,IAT列出了與NAT相對應(yīng)的導(dǎo)入函數(shù)的地址,。

      看此結(jié)構(gòu)定義:

  1. typedef struct _IMAGE_THUNK_DATA32 {       
  2.   
  3.      union {           
  4.   
  5.                PBYTE  ForwarderString;     
  6.   
  7.                PDWORD Function;           
  8.   
  9.                DWORD Ordinal;     
  10.   
  11.                PIMAGE_IMPORT_BY_NAME  AddressOfData;       
  12.   
  13.           } u1;  
  14.   
  15. } IMAGE_THUNK_DATA32;   


      上述代碼中,外層循環(huán)while(pImport->FirstThunk)用于遍歷所有DLL,,內(nèi)層循環(huán)用于遍歷查找每個DLL中的導(dǎo)入函數(shù)名稱,。我們以查找MessageBoxA函數(shù)為例來做介紹。此處我們通過對NAT進(jìn)行掃描,,將其與我們給出的字符串類型的函數(shù)名MessageBoxA進(jìn)行比較,。注意要使用大小寫不敏感的函數(shù):

  1. int WINAPI lstrcmpi(  
  2.   __in  LPCTSTR lpString1,  
  3.   __in  LPCTSTR lpString2  
  4. );  


這是一種方法,,另一種方法是比較函數(shù)地址,。我們可以對IAT進(jìn)行掃描,將得到的地址與我們給出的函數(shù)地址進(jìn)行比較,。這兩種方法是經(jīng)常使用的方法,。

      下面給出使用地址比較的方法。

  1. HMODULE hModule=GetModuleHandle(NULL);  
  2.   
  3. ULONG size;  
  4.   
  5. PIMAGE_IMPORT_DESCRIPTOR pImport=(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData  
  6.   
  7.                                       (hModule,true,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);  
  8.   
  9. UpdateData();  
  10. //獲得MessageBoxA的地址,。  
  11. PROC pfnOld=GetProcAddress(GetModuleHandle("User32.dll"),"MessageBoxA");  
  12.   
  13.       
  14. while(pImport->FirstThunk)  
  15.   
  16. {  
  17.   
  18.    char *ModuleName=(char*)((BYTE*)hModule+pImport->Name);  
  19.   
  20.    PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)((BYTE*)hModule+pImport->FirstThunk);  
  21.   
  22.    while(pThunk->u1.Function)  
  23.   
  24.    {  
  25.   
  26.      PROC *ppfn=(PROC*)&(pThunk->u1.Function);  
  27.   
  28.      if(*ppfn==pfnOld)pfnOld為要查詢的函數(shù)地址,。  
  29.   
  30.       {  
  31.   
  32.       MessageBox("找到給定的函數(shù)");  
  33.   
  34.        return ;  
  35.   
  36.      }  
  37.   
  38.     pThunk++;  
  39.   
  40.   }  
  41.   
  42.    pImport++;  
  43.   
  44. }  


     當(dāng)然以上僅僅是找到相應(yīng)的函數(shù)。要用我們期望的函數(shù)代替它,,還需要我們自己定義函數(shù),。

此處有一點要特別注意,當(dāng)我們對某函數(shù)進(jìn)行攔截時,,要替換的函數(shù)必須與被替換的函數(shù)的原型完全相同,。

比如此時我們要對MessageBoxA進(jìn)行攔截,我們定義自己的函數(shù)的原型與MessageBoxA原型是完全一致的:

  1. int WINAPI MyMessageBoxA(HWND hWnd,LPSTR  str,LPSTR caption ,UINT type)  
  2.   
  3. {  
  4.   
  5.      //定義函數(shù)的行為,。  
  6.   
  7. }  


     我們可以在函數(shù)中調(diào)用被攔截的函數(shù),,也可以不對攔截的函數(shù)進(jìn)行調(diào)用而進(jìn)行其他操作。

     注意:在攔截后,,原來的函數(shù)地址已經(jīng)被我們自定義的函數(shù)的地址覆蓋,,如果之后需要調(diào)用被攔截的函數(shù),就必須在覆蓋之前保存被攔截函數(shù)的地址,。如果我們沒有保存而直接調(diào)用,,調(diào)用的只是替換后的函數(shù)。

     以下代碼將對MessageBox的調(diào)用進(jìn)行攔截,,并用我們的自定義函數(shù)MyMessageBox替代,。

     g_addr用于存儲攔截之前MessageBox的地址

  1. Typedef int (WINAPI *PFNMESSAGEBOX(HWND,LPSTR,LPSTR,UINT);//定義函數(shù)指針。  
  2.   
  3.  PFNMESSAGEBOX g_addr=(PFNMESSAGEBOX)MessageBoxA;//存儲MessageBoxA的地址,。  
  4.   
  5. //自定義的函數(shù),。  
  6.   
  7. int WINAPI MyMessage(HWND hWnd,LPSTR a,LPSTR b,UINT type)  
  8.   
  9. {  
  10.   
  11.      return ((PFNMESSAGEBOX)g_addr)(hWnd,a,"替換后的函數(shù)!?",MB_YESNO);  
  12.   
  13. }  
  14.   
  15. //對 MessageBox進(jìn)行攔截,,用MyMessageBox進(jìn)行替換,。  
  16.   
  17. Void ReplaceOneFunc(PCSTR ModuleName,PFNMESSAGEBOX pfnOld,PFNMESSAGEBOX pfnNew)  
  18.   
  19. {  
  20.   
  21.      pfnOld=(PFNMESSAGEBOX)MessageBoxA;  
  22.   
  23.      pfnNew=(PFNMESSAGEBOX)MyMessageBox;  
  24.   
  25.      HMODULE hModule=GetModuleHandle(NULL);  
  26.   
  27.      ULONG size;  
  28.   
  29.      PIMAGE_IMPORT_DESCRIPTOR pImport=(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData  
  30.   
  31.                                                                       (hModule,true,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);  
  32.   
  33.      UpdateData();  
  34.   
  35.      while(pImport->FirstThunk)  
  36.   
  37.      {  
  38.   
  39.         char *ModuleName=(char*)((BYTE*)hModule+pImport->Name);  
  40.   
  41.         PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)((BYTE*)hModule+pImport->FirstThunk);  
  42.   
  43.         while(pThunk->u1.Function)  
  44.   
  45.         {  
  46.   
  47.           PFNMESSAGEBOX *ppfn=(PFNMESSAGEBOX*)&(pThunk->u1.Function);  
  48.   
  49.           if(*ppfn==pfnOld)  
  50.   
  51.           {  
  52.   
  53.              MessageBox("找到函數(shù)!恭喜你,!");  
  54.   
  55.              SIZE_T num;  
  56.   
  57.              WriteProcessMemory(GetCurrentProcess(),ppfn,&pfnNew,4,&num);  
  58.   
  59.              MessageBox(NULL,"現(xiàn)在調(diào)用的是替換后的API!","",MB_OK);  
  60.   
  61.              ((PFNMESSAGEBOX)g_addr)(NULL,"哈哈,,現(xiàn)在終于輪到你了","",MB_OK);  
  62.   
  63.             return ;  
  64.   
  65.          }  
  66.   
  67.         pThunk++;  
  68.   
  69.       }  
  70.   
  71.     pImport++;  
  72.   
  73.     }  
  74.   
  75.     MessageBox("沒有找到該函數(shù)!");  
  76.   
  77.  }  


     WriteProcessMemory(GetCurrentProcess(),ppfn,&pfnNew,4,&num);

     此函數(shù)用于修改內(nèi)存。實現(xiàn)用MyMessagebox的地址替換MessageBox的地址,。關(guān)于此函數(shù)的功能請參考MSDN,。

    ((PFNMESSAGEBOX)g_addr)(NULL,"哈哈,現(xiàn)在終于輪到你了","",MB_OK);

      此句用于調(diào)用在攔截之前MessageBox的地址,。此處的調(diào)用是調(diào)用的MessageBox函數(shù),,而不是MyMessageBox函數(shù)。

      至此關(guān)于修改導(dǎo)入段攔截API介紹完畢,。

 

 

 

 

       以上僅僅是個人總結(jié),。參考自《windows核心編程》第五版 ,《加密與解密》第三版 段鋼著,,《windows程序設(shè)計》第二版王艷平著,。如有紕漏,請不吝賜教。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多