日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

隐藏模块(无模块注入)

發(fā)布時(shí)間:2025/3/21 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 隐藏模块(无模块注入) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

模塊隱藏那節(jié)課要求完成兩個(gè)作業(yè),都是隱藏模塊,本文介紹兩種方法分別如何實(shí)現(xiàn)。

方法一:往自己的進(jìn)程注入游戲主模塊

這個(gè)題目的意思是將程序的基址設(shè)置成高地址,將0x400000空出來,然后將游戲主模塊拉伸,修復(fù)IAT之后,注入進(jìn)去。這樣做的好處主要是簡(jiǎn)單,因?yàn)椴恍枰迯?fù)重定位表了。缺點(diǎn)也很明顯,很多時(shí)候根本沒辦法在0x400000處申請(qǐng)足夠大的內(nèi)存容納游戲程序。,還有就是有些程序跳轉(zhuǎn)到OEP之后會(huì)卡住,具體原因我也不知道。我這里用dbgview.exe測(cè)試,能夠正常啟動(dòng),這足夠說明我的代碼沒有大的錯(cuò)誤。

任務(wù)管理器中只會(huì)看到控制臺(tái)的進(jìn)程,看不到dbgview的進(jìn)程:

所謂修復(fù)IAT,就是指,將游戲PE的IAT表修復(fù)成函數(shù)地址,做法也很簡(jiǎn)單,遍歷IAT表,loadlibary獲取dll句柄,然后遍歷函數(shù)名或函數(shù)序號(hào),一個(gè)個(gè)getprocaddress,將獲取到的函數(shù)地址寫入到IAT表就算修復(fù)好了。

下面是我的代碼,我只給出關(guān)鍵的兩個(gè)函數(shù),一個(gè)是修復(fù)IAT表,一個(gè)是注入的函數(shù),完整代碼放在文章最后。

注入代碼

// 將游戲模塊注入到我的進(jìn)程 // 修改ImageBase=0x20000000,使本程序在高地址運(yùn)行 // 這種方式非常不推薦,因?yàn)橛螒虺绦蛑灰晕⒋笠恍?#xff0c;就很可能無(wú)法在0x400000處申請(qǐng)內(nèi)存了 void GameInjectMe() { if ((DWORD)GetModuleHandle(NULL) != (DWORD)0x20000000){printf("當(dāng)前進(jìn)程句柄: 0x%X\n", (DWORD)GetModuleHandle(NULL));printf("請(qǐng)修改鏈接設(shè)置,將ImageBase設(shè)置為0x20000000\n");return;}// 讀取游戲PE,拉伸,修復(fù)IAT,寫入到其ImageBase處LPVOID pFileBuffer = NULL;//FileToMemory(TEXT("C:\\Documents and Settings\\nixiang\\桌面\\DTDebug(VT-O)專業(yè)版V1.0.025\\DTDebug\\DTDebug.exe"), &pFileBuffer);//FileToMemory(TEXT("c:\\program32\\Helloworld.exe"), &pFileBuffer);FileToMemory(TEXT("c:\\program32\\dbgview.exe"), &pFileBuffer);LPVOID pImageBuffer = NULL;DWORD dwImageSize = FileBufferToImageBuffer(pFileBuffer, &pImageBuffer);PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER)); LPVOID pImageBase = VirtualAlloc((LPVOID)pOptionHeader->ImageBase, dwImageSize,MEM_COMMIT, PAGE_READWRITE); if (pImageBase != (LPVOID)pOptionHeader->ImageBase){printf("錯(cuò)誤碼:0x%X 在ImageBase(0x%X)處VirtualAlloc失敗\n",GetLastError(),pOptionHeader->ImageBase);return;}// 修復(fù)IAT表RepairIAT(pImageBuffer); memcpy(pImageBase, pImageBuffer, dwImageSize);// 跳轉(zhuǎn)到游戲的入口點(diǎn)DWORD dwOEP = pOptionHeader->AddressOfEntryPoint + pOptionHeader->ImageBase;__asm{jmp dwOEP} }

修復(fù)IAT代碼

// 傳入一個(gè)imagebuffer,修復(fù)它的IAT表 void RepairIAT(LPVOID pImageBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);// PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + \ // RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[1].VirtualAddress));PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImageBuffer + \pOptionHeader->DataDirectory[1].VirtualAddress);// 嚴(yán)格來說應(yīng)該是 sizeof(IMAGE_IMPORT_DESCRIPTOR) 個(gè)字節(jié)為0表示結(jié)束while (pImportTable->OriginalFirstThunk || pImportTable->FirstThunk){// 打印模塊名//printf("%s\n", (LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));// 獲取模塊句柄HMODULE hModule = LoadLibraryA((LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));if (NULL == hModule){printf("獲取模塊句柄失敗,模塊名: %s\n",(LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));}// 修復(fù)IAT表//printf("--------------FirstThunkRVA:%x--------------\n", pImportTable->FirstThunk); PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)((DWORD)pImageBuffer + \pImportTable->FirstThunk);while (*((PDWORD)pThunkData) != 0){// IMAGE_THUNK_DATA32 是一個(gè)4字節(jié)數(shù)據(jù)// 如果最高位是1,那么除去最高位就是導(dǎo)出序號(hào)// 如果最高位是0,那么這個(gè)值是RVA 指向 IMAGE_IMPORT_BY_NAMEif ((*((PDWORD)pThunkData) & 0x80000000) == 0x80000000){//printf("按序號(hào)導(dǎo)入 Ordinal:%04x\n", (*((PDWORD)pThunkData) & 0x7FFFFFFF));DWORD dwProcAddress = (DWORD)GetProcAddress(hModule,MAKEINTRESOURCE((*((PDWORD)pThunkData) & 0x7FFFFFFF))); *((PDWORD)pThunkData) = dwProcAddress;}else{PIMAGE_IMPORT_BY_NAME pIBN = (PIMAGE_IMPORT_BY_NAME)(*((PDWORD)pThunkData) + \(DWORD)pImageBuffer);//printf("按名字導(dǎo)入 Hint:%04x Name:%s\n", pIBN->Hint, pIBN->Name);DWORD dwProcAddress = (DWORD)GetProcAddress(hModule,(LPCSTR)pIBN->Name);*((PDWORD)pThunkData) = dwProcAddress;}pThunkData++;}pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR)); } }

其實(shí)方法一的局限性我在博客開頭已經(jīng)分析過了,不過我想了一下發(fā)現(xiàn),其實(shí)問題關(guān)鍵就是0x400000處可能會(huì)申請(qǐng)內(nèi)存失敗,實(shí)際上我們不需要非得在這個(gè)地方申請(qǐng)內(nèi)存,而是可以在任意地方申請(qǐng),然后根據(jù)重定位表,修復(fù)地址即可。而這種方式,在方法二里面用到了。

以上是第一種方法的做法,下面是第二種做法,往游戲里注入自己,然后跳轉(zhuǎn)到入口函數(shù):

方法二:往游戲進(jìn)程注入自己的主模塊


這種方式不需要手工修復(fù)IAT,因?yàn)樽陨磉M(jìn)程啟動(dòng)時(shí)操作系統(tǒng)幫我們修復(fù)了,我們只需要修復(fù)重定位表即可。

原理上圖已經(jīng)解釋的非常明白了,下面給出關(guān)鍵代碼:
重定位表修復(fù)代碼

// 修改 ImageBase 并修復(fù)重定位表 // 內(nèi)存鏡像版本 VOID SetNewImageBase2(LPVOID pImageBuffer, DWORD dwNewImageBase) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pImageBuffer + \pOptionHeader->DataDirectory[5].VirtualAddress);DWORD dwImageBaseDelta = dwNewImageBase - pOptionHeader->ImageBase; // 新舊ImageBase 的差值 // 重定位表的 VirtualAddress + 低12位偏移 = RVA// RVA + ImageBase 這個(gè)內(nèi)存里存儲(chǔ)了一個(gè)“指針”// 要修改的是這個(gè)“指針”的值,要讓這個(gè)“指針”加上兩個(gè)ImageBase的差值while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock){size_t n = (pRelocationTable->SizeOfBlock - 8) / 2; // 可能需要修改的地址數(shù)量(高4位==0011才要修改)PWORD pOffset = (PWORD)((DWORD)pRelocationTable + 8); // 2字節(jié)偏移的數(shù)組for (size_t i = 0; i < n; i++){// 高4位等于0011才需要重定位if ((pOffset[i] & 0xF000) == 0x3000){// 計(jì)算需要重定位的數(shù)據(jù)的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF); // 計(jì)算在鏡像中的地址PDWORD pData = (PDWORD)((DWORD)pImageBuffer + dwRva);// 重定位,即修正寫死的地址 *pData += dwImageBaseDelta;}} pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepOptionHeader->ImageBase = dwNewImageBase; }

注入代碼

// 將我的模塊注入到游戲進(jìn)程 void MeInjectGame() {// 獲取自己的ImageBase和SizeOfImageHMODULE hModule = GetModuleHandle(NULL);LPVOID pImageBuffer = (LPVOID)hModule; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER)); // 拷貝到新的緩沖區(qū)DWORD dwSizeOfImage = pOptionHeader->SizeOfImage;pImageBuffer = malloc(dwSizeOfImage);memcpy(pImageBuffer, hModule, dwSizeOfImage);// 在游戲進(jìn)程申請(qǐng)內(nèi)存HWND hWnd = FindWindowA(NULL, "LittleGame");DWORD dwPID = 0;GetWindowThreadProcessId(hWnd, &dwPID);printf("進(jìn)程id: %d\n", dwPID); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);LPVOID pGameImageBase = VirtualAllocEx(hProcess,NULL,dwSizeOfImage,MEM_COMMIT,PAGE_EXECUTE_READWRITE);if (NULL == pGameImageBase){printf("在游戲進(jìn)程申請(qǐng)內(nèi)存失敗,錯(cuò)誤碼: %d\n", GetLastError());return;}// 寫入到游戲進(jìn)程前,先修復(fù)重定位表SetNewImageBase2(pImageBuffer, (DWORD)pGameImageBase);WriteProcessMemory(hProcess,pGameImageBase,pImageBuffer,dwSizeOfImage,NULL);// 獲取當(dāng)前進(jìn)程中,入口函數(shù)的地址(希望在注入后運(yùn)行的那個(gè)函數(shù)),然后和基址相減得到偏移DWORD dwProcOffset = (DWORD)InjectEntry - (DWORD)hModule + (DWORD)pGameImageBase;// 創(chuàng)建遠(yuǎn)程線程,執(zhí)行入口代碼CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)dwProcOffset,NULL,NULL,NULL); }

入口代碼

DWORD WINAPI InjectEntry(LPVOID param) {while (TRUE){MessageBox(0,0,0,0);Sleep(5000);}return 0; }

完整代碼

最后,給出項(xiàng)目完整的代碼。
PE.H

#ifndef PE_HPP_ #define PE_HPP_/******************************************************************************** 時(shí)間:2020年7月14日 作者:hambaga 說明:重新整理的PE工具函數(shù),僅適用于32位程序 ********************************************************************************/#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif // !_CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <WINDOWS.H> #include <STRING.h> #include <MALLOC.H>DWORD FileToMemory(LPCSTR lpszFile, LPVOID *pFileBuffer); BOOL MemoryToFile(LPVOID pMemBuffer, DWORD dwSize, LPCSTR lpszFile); BOOL Is32PEFile(LPVOID pFileBuffer, DWORD dwSize); DWORD FileBufferToImageBuffer(LPVOID pFileBuffer, LPVOID *pImageBuffer); DWORD ImageBufferToFileBuffer(LPVOID pImageBuffer, LPVOID *pFileBuffer); DWORD Align(DWORD dwOffset, DWORD dwAlign); DWORD RvaToFoa(LPVOID pFileBuffer, DWORD dwRva); DWORD FoaToRva(LPVOID pFileBuffer, DWORD dwFoa); DWORD MoveNTHeaderAndSectionHeadersToDosStub(LPVOID pFileBuffer); VOID SetNewImageBase(LPVOID pFileBuffer, DWORD dwNewImageBase); void RepairIAT(LPVOID pImageBuffer);// 讀取文件到內(nèi)存中,返回讀取的字節(jié)數(shù);讀取失敗返回0 DWORD FileToMemory(LPCSTR lpszFile, LPVOID *pFileBuffer) {FILE *pFile = NULL;DWORD dwFileSize = 0;pFile = fopen(lpszFile, "rb");if (pFile == NULL){printf("打開文件失敗\n");return 0;}fseek(pFile, 0, SEEK_END);dwFileSize = ftell(pFile);fseek(pFile, 0, SEEK_SET);*pFileBuffer = malloc(dwFileSize);if (*pFileBuffer == NULL){printf("分配內(nèi)存失敗\n");fclose(pFile);return 0;}DWORD dwRead = fread(*pFileBuffer, 1, dwFileSize, pFile);fclose(pFile);if (dwRead != dwFileSize){free(*pFileBuffer);return 0;}return dwRead; }// 驗(yàn)證是否是合法的32位PE文件 BOOL Is32PEFile(LPVOID pFileBuffer, DWORD dwSize) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);if (*((PWORD)pDosHeader) != IMAGE_DOS_SIGNATURE){printf("不是有效的MZ標(biāo)志\n");return FALSE;}if (pNTHeader->Signature != IMAGE_NT_SIGNATURE){printf("不是有效的PE標(biāo)記\n");return FALSE;}return TRUE; }// 將 FileBuffer 拉伸成 ImageBuffer 并寫入到新的緩沖區(qū) // 返回 ImageBuffer 的大小;失敗返回0 DWORD FileBufferToImageBuffer(LPVOID pFileBuffer, LPVOID *pImageBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);*pImageBuffer = malloc(pOptionHeader->SizeOfImage);if (*pImageBuffer == NULL){printf("分配內(nèi)存失敗\n");return 0;}memset(*pImageBuffer, 0, pOptionHeader->SizeOfImage);// 復(fù)制DOS頭+PE頭+可選PE頭+節(jié)表+文件對(duì)齊memcpy(*pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);// 遍歷節(jié)表,復(fù)制所有節(jié) for (int i = 0; i < pPEHeader->NumberOfSections; i++){memcpy((LPVOID)((DWORD)(*pImageBuffer) + pSectionHeader[i].VirtualAddress), \(LPVOID)((DWORD)pFileBuffer + pSectionHeader[i].PointerToRawData), \pSectionHeader[i].SizeOfRawData);}return pOptionHeader->SizeOfImage; }// 將 ImageBuffer 變成文件對(duì)齊的 FileBuffer 寫入新的緩沖區(qū) // 返回復(fù)制的大小,失敗返回0 DWORD ImageBufferToFileBuffer(LPVOID pImageBuffer, LPVOID *pFileBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);// 最后一個(gè)節(jié)表PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pPEHeader->NumberOfSections - 1;// 計(jì)算要復(fù)制的字節(jié)// 這一步有BUG,當(dāng)最后一個(gè)節(jié)后面還有數(shù)據(jù)時(shí)(多見于控制臺(tái)程序),丟失數(shù)據(jù)DWORD dwFileBufferSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;*pFileBuffer = malloc(dwFileBufferSize);if (*pFileBuffer == NULL){printf("分配內(nèi)存失敗\n");return 0;}memset(*pFileBuffer, 0, dwFileBufferSize);// 復(fù)制DOS頭+PE頭+可選PE頭+節(jié)表+文件對(duì)齊memcpy(*pFileBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);// 遍歷節(jié)表,復(fù)制文件對(duì)齊后的節(jié) for (int i = 0; i < pPEHeader->NumberOfSections; i++){memcpy((LPVOID)((DWORD)(*pFileBuffer) + pSectionHeader[i].PointerToRawData), \(LPVOID)((DWORD)pImageBuffer + pSectionHeader[i].VirtualAddress), \pSectionHeader[i].SizeOfRawData);}return dwFileBufferSize; }// 內(nèi)存數(shù)據(jù)寫入文件 BOOL MemoryToFile(LPVOID pMemBuffer, DWORD dwSize, LPCSTR lpszFile) {FILE *fp = NULL;fp = fopen(lpszFile, "wb+");if (fp == NULL){printf("打開文件失敗\n");return FALSE;}DWORD dwWritten = fwrite(pMemBuffer, 1, dwSize, fp);if (dwWritten != dwSize){printf("寫入了 %d 字節(jié),不等于 %d\n", dwWritten, dwSize);fclose(fp);return FALSE;}fclose(fp);return TRUE; }// 計(jì)算對(duì)齊的函數(shù),如偏移為900,對(duì)齊為1000h,返回1000h DWORD Align(DWORD dwOffset, DWORD dwAlign) {// 如果偏移小于對(duì)齊,向上取整if (dwOffset <= dwAlign) return dwAlign;// 如果偏移大于對(duì)齊且不能除盡,向上取整if (dwOffset % dwAlign){return (dwOffset / dwAlign + 1) * dwAlign;}// 如果能除盡,直接返回offsetreturn dwOffset; }// RVA 轉(zhuǎn) FOA DWORD RvaToFoa(LPVOID pFileBuffer, DWORD dwRva) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pFileBuffer + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);// RVA在文件頭中或者文件對(duì)齊==內(nèi)存對(duì)齊時(shí),RVA==FOA 錯(cuò)!第一句是對(duì)的,第二句是錯(cuò)的if (dwRva < pOptionHeader->SizeOfHeaders){return dwRva;}// 遍歷節(jié)表,確定偏移屬于哪一個(gè)節(jié) for (int i = 0; i < pPEHeader->NumberOfSections; i++){if (dwRva >= pSectionHeader[i].VirtualAddress && \dwRva < pSectionHeader[i].VirtualAddress + pSectionHeader[i].Misc.VirtualSize){int offset = dwRva - pSectionHeader[i].VirtualAddress;return pSectionHeader[i].PointerToRawData + offset;}}printf("找不到RVA %x 對(duì)應(yīng)的 FOA,轉(zhuǎn)換失敗\n", dwRva);return 0; }// FOA 轉(zhuǎn) RVA DWORD FoaToRva(LPVOID pFileBuffer, DWORD dwFoa) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pFileBuffer + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);// RVA在文件頭中或者文件對(duì)齊==內(nèi)存對(duì)齊時(shí),RVA==FOA 錯(cuò)!第一句是對(duì)的,第二句是錯(cuò)的if (dwFoa < pOptionHeader->SizeOfHeaders){return dwFoa;}// 遍歷節(jié)表,確定偏移屬于哪一個(gè)節(jié) for (int i = 0; i < pPEHeader->NumberOfSections; i++){if (dwFoa >= pSectionHeader[i].PointerToRawData && \dwFoa < pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData){int offset = dwFoa - pSectionHeader[i].PointerToRawData;return pSectionHeader[i].VirtualAddress + offset;}}printf("找不到FOA %x 對(duì)應(yīng)的 RVA,轉(zhuǎn)換失敗\n", dwFoa);return 0; }// 移動(dòng)NT頭和節(jié)表到DOS STUB,該函數(shù)在新增節(jié)時(shí)節(jié)表空間不足的情況下調(diào)用;返回地址減小值 DWORD MoveNTHeaderAndSectionHeadersToDosStub(LPVOID pFileBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);LPVOID pDst = (LPVOID)((DWORD)pDosHeader + sizeof(IMAGE_DOS_HEADER)); // NT頭插入點(diǎn)DWORD dwRet = (DWORD)pNTHeader - (DWORD)pDst; // 返回地址減小的值DWORD dwSize = 4 + sizeof(IMAGE_FILE_HEADER) + pPEHeader->SizeOfOptionalHeader + \sizeof(IMAGE_SECTION_HEADER) * pPEHeader->NumberOfSections; // 移動(dòng)的字節(jié)數(shù)LPVOID pSrc = malloc(dwSize);if (pSrc == NULL){printf("分配內(nèi)存失敗\n");return 0;}memcpy(pSrc, (LPVOID)pNTHeader, dwSize); // 保存要復(fù)制的數(shù)據(jù)memset((LPVOID)pNTHeader, 0, dwSize); // 清空原數(shù)據(jù)memcpy(pDst, pSrc, dwSize); // 移動(dòng)數(shù)據(jù)free(pSrc);pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); // 更新 e_lfanewreturn dwRet; }// 修改 ImageBase 并修復(fù)重定位表 // 文件版本 VOID SetNewImageBase(LPVOID pFileBuffer, DWORD dwNewImageBase) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));DWORD dwImageBaseDelta = dwNewImageBase - pOptionHeader->ImageBase; // 新舊ImageBase 的差值 // 重定位表的 VirtualAddress + 低12位偏移 = RVA// RVA + ImageBase 這個(gè)內(nèi)存里存儲(chǔ)了一個(gè)“指針”// 要修改的是這個(gè)“指針”的值,要讓這個(gè)“指針”加上兩個(gè)ImageBase的差值while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock){size_t n = (pRelocationTable->SizeOfBlock - 8) / 2; // 可能需要修改的地址數(shù)量(高4位==0011才要修改)PWORD pOffset = (PWORD)((DWORD)pRelocationTable + 8); // 2字節(jié)偏移的數(shù)組for (size_t i = 0; i < n; i++){// 高4位等于0011才需要重定位if ((pOffset[i] & 0xF000) == 0x3000){// 計(jì)算需要重定位的數(shù)據(jù)的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF);// 計(jì)算在文件中的偏移DWORD dwFoa = RvaToFoa(pFileBuffer, dwRva);// 計(jì)算在文件中的地址PDWORD pData = (PDWORD)((DWORD)pFileBuffer + dwFoa);// 重定位,即修正寫死的地址 *pData += dwImageBaseDelta;}}pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepOptionHeader->ImageBase = dwNewImageBase; }// 修改 ImageBase 并修復(fù)重定位表 // 內(nèi)存鏡像版本 VOID SetNewImageBase2(LPVOID pImageBuffer, DWORD dwNewImageBase) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pImageBuffer + \pOptionHeader->DataDirectory[5].VirtualAddress);DWORD dwImageBaseDelta = dwNewImageBase - pOptionHeader->ImageBase; // 新舊ImageBase 的差值 // 重定位表的 VirtualAddress + 低12位偏移 = RVA// RVA + ImageBase 這個(gè)內(nèi)存里存儲(chǔ)了一個(gè)“指針”// 要修改的是這個(gè)“指針”的值,要讓這個(gè)“指針”加上兩個(gè)ImageBase的差值while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock){size_t n = (pRelocationTable->SizeOfBlock - 8) / 2; // 可能需要修改的地址數(shù)量(高4位==0011才要修改)PWORD pOffset = (PWORD)((DWORD)pRelocationTable + 8); // 2字節(jié)偏移的數(shù)組for (size_t i = 0; i < n; i++){// 高4位等于0011才需要重定位if ((pOffset[i] & 0xF000) == 0x3000){// 計(jì)算需要重定位的數(shù)據(jù)的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF); // 計(jì)算在鏡像中的地址PDWORD pData = (PDWORD)((DWORD)pImageBuffer + dwRva);// 重定位,即修正寫死的地址 *pData += dwImageBaseDelta;}} pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepOptionHeader->ImageBase = dwNewImageBase; }// 傳入一個(gè)imagebuffer,修復(fù)它的IAT表 void RepairIAT(LPVOID pImageBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImageBuffer + \pOptionHeader->DataDirectory[1].VirtualAddress); // 嚴(yán)格來說應(yīng)該是 sizeof(IMAGE_IMPORT_DESCRIPTOR) 個(gè)字節(jié)為0表示結(jié)束while (pImportTable->OriginalFirstThunk || pImportTable->FirstThunk){// 打印模塊名//printf("%s\n", (LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));// 獲取模塊句柄HMODULE hModule = LoadLibraryA((LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));if (NULL == hModule){printf("獲取模塊句柄失敗,模塊名: %s\n",(LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));}// 修復(fù)IAT表//printf("--------------FirstThunkRVA:%x--------------\n", pImportTable->FirstThunk); PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)((DWORD)pImageBuffer + \pImportTable->FirstThunk);while (*((PDWORD)pThunkData) != 0){// IMAGE_THUNK_DATA32 是一個(gè)4字節(jié)數(shù)據(jù)// 如果最高位是1,那么除去最高位就是導(dǎo)出序號(hào)// 如果最高位是0,那么這個(gè)值是RVA 指向 IMAGE_IMPORT_BY_NAMEif ((*((PDWORD)pThunkData) & 0x80000000) == 0x80000000){//printf("按序號(hào)導(dǎo)入 Ordinal:%04x\n", (*((PDWORD)pThunkData) & 0x7FFFFFFF));DWORD dwProcAddress = (DWORD)GetProcAddress(hModule,MAKEINTRESOURCE((*((PDWORD)pThunkData) & 0x7FFFFFFF))); *((PDWORD)pThunkData) = dwProcAddress;}else{PIMAGE_IMPORT_BY_NAME pIBN = (PIMAGE_IMPORT_BY_NAME)(*((PDWORD)pThunkData) + \(DWORD)pImageBuffer);//printf("按名字導(dǎo)入 Hint:%04x Name:%s\n", pIBN->Hint, pIBN->Name);DWORD dwProcAddress = (DWORD)GetProcAddress(hModule,(LPCSTR)pIBN->Name);*((PDWORD)pThunkData) = dwProcAddress;}pThunkData++;}pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR)); } }#endif

main.cpp

// MemoryInject.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include "PE.h" #include <MALLOC.H>void GameInjectMe(); void MeInjectGame(); BOOL EnableDebugPrivilege(); DWORD WINAPI InjectEntry(LPVOID param);int main(int argc, char* argv[]) {EnableDebugPrivilege(); //GameInjectMe();MeInjectGame();return 0; }// 將游戲模塊注入到我的進(jìn)程 // 修改ImageBase=0x20000000,使本程序在高地址運(yùn)行 // 這種方式非常不推薦,因?yàn)橛螒虺绦蛑灰晕⒋笠恍?#xff0c;就很可能無(wú)法在0x400000處申請(qǐng)內(nèi)存了 void GameInjectMe() { if ((DWORD)GetModuleHandle(NULL) != (DWORD)0x20000000){printf("當(dāng)前進(jìn)程句柄: 0x%X\n", (DWORD)GetModuleHandle(NULL));printf("請(qǐng)修改鏈接設(shè)置,將ImageBase設(shè)置為0x20000000\n");return;}// 讀取游戲PE,拉伸,修復(fù)IAT,寫入到其ImageBase處LPVOID pFileBuffer = NULL;FileToMemory(TEXT("c:\\program32\\dbgview.exe"), &pFileBuffer);LPVOID pImageBuffer = NULL;DWORD dwImageSize = FileBufferToImageBuffer(pFileBuffer, &pImageBuffer);PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER)); LPVOID pImageBase = VirtualAlloc((LPVOID)pOptionHeader->ImageBase, dwImageSize,MEM_COMMIT, PAGE_READWRITE); if (pImageBase != (LPVOID)pOptionHeader->ImageBase){printf("錯(cuò)誤碼:0x%X 在ImageBase(0x%X)處VirtualAlloc失敗\n",GetLastError(),pOptionHeader->ImageBase);return;}// 修復(fù)IAT表RepairIAT(pImageBuffer); memcpy(pImageBase, pImageBuffer, dwImageSize);// 跳轉(zhuǎn)到游戲的入口點(diǎn)DWORD dwOEP = pOptionHeader->AddressOfEntryPoint + pOptionHeader->ImageBase;__asm{jmp dwOEP} }// 將我的模塊注入到游戲進(jìn)程 void MeInjectGame() {// 獲取自己的ImageBase和SizeOfImageHMODULE hModule = GetModuleHandle(NULL);LPVOID pImageBuffer = (LPVOID)hModule; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER)); // 拷貝到新的緩沖區(qū)DWORD dwSizeOfImage = pOptionHeader->SizeOfImage;pImageBuffer = malloc(dwSizeOfImage);memcpy(pImageBuffer, hModule, dwSizeOfImage);// 在游戲進(jìn)程申請(qǐng)內(nèi)存HWND hWnd = FindWindowA(NULL, "LittleGame");DWORD dwPID = 0;GetWindowThreadProcessId(hWnd, &dwPID);printf("進(jìn)程id: %d\n", dwPID); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);LPVOID pGameImageBase = VirtualAllocEx(hProcess,NULL,dwSizeOfImage,MEM_COMMIT,PAGE_EXECUTE_READWRITE);if (NULL == pGameImageBase){printf("在游戲進(jìn)程申請(qǐng)內(nèi)存失敗,錯(cuò)誤碼: %d\n", GetLastError());return;}// 寫入到游戲進(jìn)程前,先修復(fù)重定位表SetNewImageBase2(pImageBuffer, (DWORD)pGameImageBase);WriteProcessMemory(hProcess,pGameImageBase,pImageBuffer,dwSizeOfImage,NULL);// 獲取當(dāng)前進(jìn)程中,入口函數(shù)的地址(希望在注入后運(yùn)行的那個(gè)函數(shù)),然后和基址相減得到偏移DWORD dwProcOffset = (DWORD)InjectEntry - (DWORD)hModule + (DWORD)pGameImageBase;// 創(chuàng)建遠(yuǎn)程線程,執(zhí)行入口代碼CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)dwProcOffset,NULL,NULL,NULL); }DWORD WINAPI InjectEntry(LPVOID param) {while (TRUE){MessageBox(0,0,0,0);Sleep(5000);}return 0; }// 提權(quán)函數(shù):提升為DEBUG權(quán)限 BOOL EnableDebugPrivilege() {HANDLE hToken;BOOL fOk=FALSE;if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken)){TOKEN_PRIVILEGES tp;tp.PrivilegeCount=1;LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);fOk=(GetLastError()==ERROR_SUCCESS);CloseHandle(hToken);}return fOk; }

總結(jié)

以上是生活随笔為你收集整理的隐藏模块(无模块注入)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。