逆向工程核心原理——第三十二章
阿新 • • 發佈:2020-10-09
計算器顯示中文數字
此實驗中使用的程式碼只適用於x86系統。
本章講解API鉤取技術時將以Windows計算器( calc.exe)為示例,向計算器程序插人使用者的
DLL檔案,鉤取IAT的user32.SetWindowTextW() API地址。
SetWindowTextW() API的作用是顯示計算器中的數字,而我們會將這個數字改為中文數字。
我們知道,當程式需要呼叫源程式之外的函式時,需要訪問匯入表(IAT),IAT中存放著需要呼叫的函式的地址,而這次的實驗,我們就需要鉤出這個地址,替換成別的地址,從而使阿拉伯數字變為漢字數字。
我們在圖中可以看到:
這裡計算器(cala.exe)執行到01002628時呼叫user32.dll,呼叫完成後回到cala.exe
而我們修改後的執行順序為:
EXE:
//InjectDll.exe #include "stdio.h" #include "windows.h" #include "tlhelp32.h" #include "winbase.h" #include "tchar.h" #include<iostream> using namespace std; void usage() { printf("\nInjectDll.exe by ReverseCore\n" "- USAGE : InjectDll.exe <i|e> <PID> <dll_path>\n\n"); } BOOL InjectDll(DWORD dwPID, LPCTSTR szDllName) { HANDLE hProcess, hThread; LPVOID pRemoteBufferData; //遠端程序中的記憶體 DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR); LPTHREAD_START_ROUTINE pThreadProc; if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) { DWORD dwErr = GetLastError(); return FALSE; } //申請記憶體 可讀可寫 pRemoteBufferData = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE); //像記憶體寫入dll路徑 WriteProcessMemory(hProcess, pRemoteBufferData, (LPVOID)szDllName, dwBufSize, NULL); //獲得loadlibraryw地址 pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); //建立遠端執行緒 hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBufferData, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; } BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName) { BOOL bMore = FALSE, bFound = FALSE; HANDLE hSnapshot, hProcess, hThread; MODULEENTRY32 me = { sizeof(me) }; LPTHREAD_START_ROUTINE pThreadProc; if (INVALID_HANDLE_VALUE == (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID))) { return FALSE; } bMore = Module32First(hSnapshot, &me); for (; bMore; bMore = Module32Next(hSnapshot, &me)) { if (!_tcsicmp(me.szModule, szDllName) || !_tcsicmp(me.szExePath, szDllName)) { bFound = TRUE; break; } } if (!bFound) { CloseHandle(hSnapshot); return FALSE; } if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))) { CloseHandle(hSnapshot); return FALSE; } pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary"); hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); CloseHandle(hSnapshot); return TRUE; } DWORD _EnableNTPrivilege(LPCTSTR szPrivilege, DWORD dwState) { DWORD dwRtn = 0; HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { LUID luid; if (LookupPrivilegeValue(NULL, szPrivilege, &luid)) { BYTE t1[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)]; BYTE t2[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)]; DWORD cbTP = sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES); PTOKEN_PRIVILEGES pTP = (PTOKEN_PRIVILEGES)t1; PTOKEN_PRIVILEGES pPrevTP = (PTOKEN_PRIVILEGES)t2; pTP->PrivilegeCount = 1; pTP->Privileges[0].Luid = luid; pTP->Privileges[0].Attributes = dwState; if (AdjustTokenPrivileges(hToken, FALSE, pTP, cbTP, pPrevTP, &cbTP)) dwRtn = pPrevTP->Privileges[0].Attributes; } CloseHandle(hToken); } return dwRtn; } int _tmain(int argc, TCHAR* argv[]) { if (argc != 4) { usage(); return 1; } // adjust privilege _EnableNTPrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED); // InjectDll.exe <i|e> <PID> <dll_path> if (!_tcsicmp(argv[1], L"i")) { InjectDll((DWORD)_tstoi(argv[2]), argv[3]); } else if (!_tcsicmp(argv[1], L"e")) { EjectDll((DWORD)_tstoi(argv[2]), argv[3]); } return 0; }
DLL:
//hookiat.dll #include "stdio.h" #include "wchar.h" #include "windows.h" // typedef typedef BOOL(WINAPI* PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString); //SetWindowsTextW()的地址 // 原函式地址 FARPROC g_pOrginalFunction = NULL; BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString) { wchar_t* pNum = L"零一二三四五六七八九"; wchar_t temp[2] = { 0, }; int i = 0, nLen = 0, nIndex = 0; nLen = wcslen(lpString); for (i = 0; i < nLen; i++) { // 將阿拉伯數字轉換為中文數字 // lpString是寬字元版本(2個位元組)字串 if (L'0' <= lpString[i] && lpString[i] <= L'9') { temp[0] = lpString[i]; nIndex = _wtoi(temp); lpString[i] = pNum[nIndex]; } } // 呼叫原函式;user32.SetWindowTextW // (修改lpString緩衝區中的內容) return ((PFSETWINDOWTEXTW)g_pOrginalFunction)(hWnd, lpString); } /**********************************/ // 函式名:hook_iat // 功能 :負責實施IAT鉤取的核心函式 /**********************************/ BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew) { HMODULE hMod; LPCSTR szLibName; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_THUNK_DATA pThunk; DWORD dwOldProtect, dwRVA; PBYTE pAddr; // hMod, pAddr = ImageBase of calc.exe // = VA to MZ signature (IMAGE_DOS_HEADER) hMod = GetModuleHandle(NULL); pAddr = (PBYTE)hMod; // pAddr = VA to PE signature (IMAGE_NT_HEADERS) pAddr += *((DWORD*)&pAddr[0x3C]); // dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table dwRVA = *((DWORD*)&pAddr[0x80]); // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod + dwRVA); for (; pImportDesc->Name; pImportDesc++) { // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name); if (!_stricmp(szLibName, szDllName)) { // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk // = VA to IAT(Import Address Table) pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + pImportDesc->FirstThunk); // pThunk->u1.Function = VA to API 匹配成功 for (; pThunk->u1.Function; pThunk++) { if (pThunk->u1.Function == (DWORD)pfnOrg) { // 更改為可讀寫模式 VirtualProtect((LPVOID)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 修改IAT的值 pThunk->u1.Function = (DWORD)pfnNew; //修改完成後,恢復原保護屬性 VirtualProtect((LPVOID)&pThunk->u1.Function, 4, dwOldProtect, &dwOldProtect); return TRUE; } } } } return FALSE; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: // 儲存原始API的地址 g_pOrginalFunction = GetProcAddress(GetModuleHandle(L"user32.dll"), "SetWindowTextW"); // # hook // 用hookiat.MySetWindowText鉤取user32.SetWindowTextW hook_iat("user32.dll", g_pOrginalFunction, (PROC)MySetWindowTextW); break; case DLL_PROCESS_DETACH: // # unhook // 將calc.exe的IAT恢復原值 hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrginalFunction); break; } return TRUE; }