C++ EAT / Hook

來源:互聯網
上載者:User

標籤:

EAT與IAT比較類似,我相信會IAT的肯定很多,起初我想寫在C#上面 不過與

C# 遍曆DLL匯出函數 的方法很相似,只是兩者在記憶體中的映射方式不同而已

Heh,首先我們需要把DLL映射到地址記憶體空間去 否則沒有辦法去置換函數,

當然EAT有一些缺點,它必須在軟體調用GetProcAddress函數之前替換DLL中

的函數,所以則出現了對GetProcAddress函數的一個Hook,否則只可改變

GetProcAddress返回的內容、是不是感到很惆悵

 

EAT全稱為“Export address table”其核心則是利用PE與DLL的一些相關特性

實現的一個技術 首先我們通過LoadLibraryA函數把一個有效DLL映射到內

存中,PE檔案中第一個位元組是MS-DOS資訊頭即IMAGE_DOS_HEADER

 

IMAGE_NT_HEADER = (pDosHearder + pDosHearder->e_lfanew);

// IMAGE_NT_HEADER::OptionalHeader

pOptionalHeader = (pDosHearder + pDosHearder->e_lfanew + 24);

上面是x86的一個OptionalHeader的對稱,這裡是不想再多做一次轉換直接

跳過去會很快捷、所以加上24但恰好指向OptionalHeader、而我們只需要

它其它的對我們而言根本沒有任何用、所以跳過就可以

#include "stdafx.h"#include <Windows.h>BOOL EATHook(LPCSTR strLibraryName, LPCSTR strMethodName, PVOID newMethodAddress){HMODULE hRemoteModule = LoadLibraryA(strLibraryName);PIMAGE_DOS_HEADER pDosHearder = (PIMAGE_DOS_HEADER)hRemoteModule;PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)hRemoteModule + pDosHearder->e_lfanew + 24);PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pDosHearder +pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);LPDWORD pAddressOfNames = (LPDWORD)((DWORD)hRemoteModule + pExportDirectory->AddressOfNames);LPDWORD pAddressOfFunctions = (LPDWORD)((DWORD)hRemoteModule + pExportDirectory->AddressOfFunctions);PUSHORT pAddressOfNameOrdinals = (PUSHORT)((DWORD)hRemoteModule + pExportDirectory->AddressOfNameOrdinals);for (int i = 0; i < pExportDirectory->NumberOfNames; i++){LPCSTR strInsideName = (LPCSTR)((DWORD)hRemoteModule + pAddressOfNames[i]);if (_stricmp(strInsideName, strMethodName) == 0){DWORD pflOldProtect;VirtualProtect(&pAddressOfFunctions[*pAddressOfNameOrdinals], 0x1000, PAGE_READWRITE, &pflOldProtect);pAddressOfFunctions[*pAddressOfNameOrdinals] = (DWORD)newMethodAddress - (DWORD)hRemoteModule;break;}pAddressOfNameOrdinals++;}return FALSE;}

既然是EAT,我們看第一個字母全名為Export那麼我們肯定要去找包含匯出的DLL函數的

PE中的資料目錄,恰好有那麼一個IMAGE_DIRECTORY_ENTRY_EXPORT但是拿出來

的地址是RVA / 相對虛擬位址所以你必須要ToVA / 到虛擬位址、但是DLL已經被映射到虛

擬記憶體中 所以我們不需要使用RvaToVa、我們只需要

 

 (DWORD)pDosHearder +  pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

(DWORD)hRemoteModule + DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

則可以得到,PIMAGE_EXPORT_DIRECTORY pExportDirectory函數匯出目錄,但是我

們得到了它卻不可以耍花架子,我們還有繼續下面的代碼否則沒法混、

LPDWORD pAddressOfNames = (LPDWORD)((DWORD)hRemoteModule + pExportDirectory->AddressOfNames);LPDWORD pAddressOfFunctions = (LPDWORD)((DWORD)hRemoteModule + pExportDirectory->AddressOfFunctions);PUSHORT pAddressOfNameOrdinals = (PUSHORT)((DWORD)hRemoteModule + pExportDirectory->AddressOfNameOrdinals);

pAddressOfNames // 匯出函數名

pAddressOfFunctions // 匯出函數地址

pAddressOfNameOrdinals // 匯出函數序列

 

上面定義三種不同的指標,但是都預先把地址進行了一個處理,這是為了方便後面的使用

而不必一直加上(DOWRD)hRemoteModule那樣子會很累的、

pExportDirectory->NumberOfNames // 匯出函數計數(Length)

 

LPCSTR strInsideName = (LPCSTR)((DWORD)hRemoteModule + pAddressOfNames[i]);

上面是擷取DLL匯出的函數名,pAddressOfNames[i] 返回的地址為虛擬相對位址(Rva)

在這裡只需要如下去做、則可以得到DLL匯出的函數名是什麼,當然這個是c_str風格字

符串,你懂的‘\0‘結尾,_strlen對其有效,不過在本代碼中也用不到_strlen、

下面是首先比較兩個字串是否相等,主要看看需要具體去Hook那個函數

for (int i = 0; i < pExportDirectory->NumberOfNames; i++){LPCSTR strInsideName = (LPCSTR)((DWORD)hRemoteModule + pAddressOfNames[i]);if (_stricmp(strInsideName, strMethodName) == 0){DWORD pflOldProtect;VirtualProtect(&pAddressOfFunctions[*pAddressOfNameOrdinals], 0x1000, PAGE_READWRITE, &pflOldProtect);pAddressOfFunctions[*pAddressOfNameOrdinals] = (DWORD)newMethodAddress - (DWORD)hRemoteModule;break;}pAddressOfNameOrdinals++;}

 

&pAddressOfFunctions[*pAddressOfNameOrdinals] 從上面的代碼你應該看出了端倪

對的,DLL函數匯出的地址你不可以直接通過&pAddressOfFunctions[i]解決問題,因

為在PE中,它是通過Ordinals定位函數位置,但是它與i=0; i++是相序的、有點繞哈

 

VirtualProtect(&pAddressOfFunctions[*pAddressOfNameOrdinals],

                         0x1000, PAGE_READWRITE, &pflOldProtect);

上面是修改函數的記憶體保護,0x1000沒有太大意義、填4 / 8也是可以的

 

pAddressOfFunctions[*pAddressOfNameOrdinals] =

                      (DWORD)newMethodAddress - (DWORD)hRemoteModule;

好吧,這裡填寫相對虛擬位址、指的是新的函數地址與這個模組的地址做一個加減

不管返回的是負數還是正數都可以,沒有那麼多講究、後面這句話也是必要的

pAddressOfNameOrdinals++; 你可以任性的把使用 *pAddressOfNameOrdinals

修改為pAddressOfNameOrdinals[i]但是絕對不可以不寫,這是原則性上的問題、

 

HANDLE WINAPI CB_GetModuleHandleW(LPCTSTR strLibraryName){return NULL;}

我們寫一個Hook的處理函數,GetModuleHandleW函數的一個處理函數,什麼都不

用寫,只需要打個斷點看看有沒有執行就可以了,因為沒有太大的意義重點在這裡

int _tmain(int argc, _TCHAR* argv[]){EATHook("kernel32.dll", "GetModuleHandleW", CB_GetModuleHandleW);LPDWORD pfnGetModuleHandleW = (LPDWORD)GetProcAddress(GetModuleHandleA("kernel32"), "GetModuleHandleW");_asm{push 0call pfnGetModuleHandleW}return 0;}

上面是利用EAT先把GetModuleHandleW函數進行掛鈎,然後通過GetProcAddress

函數得到pfnGetModuleHandleW,為了方便不想使用函數指標,直接嵌入兩行彙編

代碼進去直接解決問題,然後F5調試,如果CB_GetModuleHandleW函數被執行 那

麼恭喜你成功了,如果沒有說明你出錯了、哈哈

 

 

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

C++ EAT / Hook

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.