PE工具函数(新)
說明
一些常見的PE操作。。
2021年3月7日
#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif // !_CRT_SECURE_NO_WARNINGS#include "PE.h" #include <stdio.h> #include <WINDOWS.H> #include <STRING.h> #include <MALLOC.H> #include "DebugTool.h" #include "Win32API.h"// 讀取文件到內(nèi)存中,返回讀取的字節(jié)數(shù);讀取失敗返回0 DWORD FileToMemory(LPCSTR lpszFile, LPVOID *pFileBuffer) {// 打開文件,權(quán)限是讀共享HANDLE hFile = pCreateFileA(lpszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (INVALID_HANDLE_VALUE == hFile){PrintDebugInfo("打開文件失敗\n");return 0;}// 判斷文件大小LARGE_INTEGER nFileSize = { 0 };pGetFileSizeEx(hFile, &nFileSize);if (nFileSize.QuadPart >= 0xFFFFFFFFull){PrintDebugInfo("源文件過大,無法處理(%lld)\n", nFileSize.QuadPart);pCloseHandle(hFile);return 0;}pSetFilePointer(hFile, 0, NULL, FILE_BEGIN);//PrintDebugInfo("文件大小:%d 字節(jié)\n", nFileSize.LowPart);LPVOID pFile = pVirtualAlloc(NULL, nFileSize.LowPart, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);if (pFile == NULL){PrintDebugInfo("申請內(nèi)存失敗\n");pCloseHandle(hFile);return 0;}memset(pFile, 0, nFileSize.LowPart);// 讀文件DWORD dwRead = 0;BOOL bRet = FALSE;bRet = pReadFile(hFile, pFile, nFileSize.LowPart, &dwRead, NULL);if (bRet == FALSE){PrintDebugInfo("讀取文件錯誤:%d\n", GetLastError());pVirtualFree(pFile, 0, MEM_RELEASE);pCloseHandle(hFile);return 0;}if (dwRead != nFileSize.LowPart){PrintDebugInfo("期望讀取:%d,實際讀取:%d\n", nFileSize.LowPart, dwRead);pVirtualFree(pFile, 0, MEM_RELEASE);pCloseHandle(hFile);return 0;}pCloseHandle(hFile);*pFileBuffer = pFile;return nFileSize.LowPart; }// 驗證是否是合法的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);if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){PrintDebugInfo("不是有效的MZ標(biāo)志 %x != %x", pDosHeader->e_magic, IMAGE_DOS_SIGNATURE);return FALSE;}if (pNtHeader->Signature != IMAGE_NT_SIGNATURE){PrintDebugInfo("不是有效的PE標(biāo)記");return FALSE;}if (pNtHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_I386){PrintDebugInfo("不是32位PE程序");return FALSE;}return TRUE; }// 將 FileBuffer 拉伸成 ImageBuffer 并寫入到新的緩沖區(qū) // 返回 ImageBuffer 的大小;失敗返回0 DWORD FileBufferToImageBuffer(LPVOID pFileBuffer, LPVOID *pImageBuffer, DWORD flProtect) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);*pImageBuffer = pVirtualAlloc(NULL, pNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, flProtect);if (*pImageBuffer == NULL){PrintDebugInfo("分配內(nèi)存失敗\n");return 0;}memset(*pImageBuffer, 0, pNtHeader->OptionalHeader.SizeOfImage);// 復(fù)制所有頭(DOS頭,PE頭,可選PE頭)和節(jié)表memcpy(*pImageBuffer, pFileBuffer, pNtHeader->OptionalHeader.SizeOfHeaders);// 遍歷節(jié)表,復(fù)制所有節(jié) for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++){memcpy((PBYTE)(*pImageBuffer) + pSectionHeader[i].VirtualAddress,(PBYTE)pFileBuffer + pSectionHeader[i].PointerToRawData,pSectionHeader[i].SizeOfRawData);}return pNtHeader->OptionalHeader.SizeOfImage; }// 將 ImageBuffer 變成文件對齊的 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_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);// 最后一個節(jié)表PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pNtHeader->FileHeader.NumberOfSections - 1;// 計算要復(fù)制的字節(jié)// 這一步有BUG,當(dāng)最后一個節(jié)后面還有數(shù)據(jù)時,這些數(shù)據(jù)會丟失DWORD dwFileBufferSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;*pFileBuffer = pVirtualAlloc(NULL, dwFileBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);if (*pFileBuffer == NULL){PrintDebugInfo("分配內(nèi)存失敗\n");return 0;}memset(*pFileBuffer, 0, dwFileBufferSize);// 復(fù)制所有頭(DOS頭,PE頭,可選PE頭)和節(jié)表memcpy(*pFileBuffer, pImageBuffer, pNtHeader->OptionalHeader.SizeOfHeaders);// 遍歷節(jié)表,復(fù)制所有節(jié) for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++){memcpy((PBYTE)(*pFileBuffer) + pSectionHeader[i].PointerToRawData,(PBYTE)pImageBuffer + pSectionHeader[i].VirtualAddress,pSectionHeader[i].SizeOfRawData);}return dwFileBufferSize; }// 內(nèi)存數(shù)據(jù)寫入文件 BOOL MemoryToFile(LPVOID pMemBuffer, DWORD dwSize, LPCSTR lpszFile) {// 打開文件,權(quán)限是獨占寫HANDLE hFile = pCreateFileA(lpszFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (INVALID_HANDLE_VALUE == hFile){PrintDebugInfo("打開文件失敗\n");return FALSE;}BOOL bRet = FALSE;DWORD dwWritten = 0;bRet = pWriteFile(hFile, pMemBuffer, dwSize, &dwWritten, NULL);if (!bRet){PrintDebugInfo("寫文件錯誤:%d\n", GetLastError());pCloseHandle(hFile);return FALSE;}pCloseHandle(hFile);return TRUE; }// 計算對齊的函數(shù),如偏移為900,對齊為1000h,返回1000h DWORD Align(DWORD dwOffset, DWORD dwAlign) {// 如果偏移小于對齊,向上取整if (dwOffset <= dwAlign) return dwAlign;// 如果偏移大于對齊且不能除盡,向上取整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_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);if (dwRva < pNtHeader->OptionalHeader.SizeOfHeaders){return dwRva;}// 遍歷節(jié)表,確定偏移屬于哪一個節(jié) for (int i = 0; i < pNtHeader->FileHeader.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;}}PrintDebugInfo("找不到RVA %x 對應(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_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);if (dwFoa < pNtHeader->OptionalHeader.SizeOfHeaders){return dwFoa;}// 遍歷節(jié)表,確定偏移屬于哪一個節(jié) for (int i = 0; i < pNtHeader->FileHeader.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;}}PrintDebugInfo("找不到FOA %x 對應(yīng)的 RVA,轉(zhuǎn)換失敗\n", dwFoa);return 0; }// 修改 ImageBase 并修復(fù)重定位表 BOOL SetNewImageBase(LPVOID pImageBuffer, DWORD dwNewImageBase) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pImageBuffer + \pNtHeader->OptionalHeader.DataDirectory[5].VirtualAddress);if (pRelocationTable == pImageBuffer){PrintDebugInfo("重定位表不存在\n");return FALSE;}// 重定位表的 VirtualAddress + 低12位偏移 = RVA// RVA + ImageBase 這個內(nèi)存里存儲了一個“指針”// 要修改的是這個“指針”的值,要讓這個“指針”加上兩個ImageBase的差值while (pRelocationTable->VirtualAddress != NULL && pRelocationTable->SizeOfBlock != NULL){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++){__try{// 高4位等于0011才需要重定位//if ((pOffset[i] & 0xF000) == 0x3000)if ((pOffset[i] & 0x3000) == 0x3000){// 計算需要重定位的數(shù)據(jù)的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF);// 計算在鏡像中的地址PDWORD pData = (PDWORD)((DWORD)pImageBuffer + dwRva);// 重定位,即修正寫死的地址 *pData = *pData - pNtHeader->OptionalHeader.ImageBase + dwNewImageBase;}}__except (EXCEPTION_EXECUTE_HANDLER){continue;}}pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepNtHeader->OptionalHeader.ImageBase = dwNewImageBase;return TRUE; }// 傳入一個imagebuffer,修復(fù)它的IAT表 void RepairIAT(LPVOID pImageBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeader +sizeof(pNtHeader->Signature) +sizeof(pNtHeader->FileHeader) +pNtHeader->FileHeader.SizeOfOptionalHeader);PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImageBuffer + \pNtHeader->OptionalHeader.DataDirectory[1].VirtualAddress);// 嚴(yán)格來說應(yīng)該是 sizeof(IMAGE_IMPORT_DESCRIPTOR) 個字節(jié)為0表示結(jié)束while (pImportTable->OriginalFirstThunk || pImportTable->FirstThunk)//while (memcmp(&EndFlag, pImportTable, sizeof(EndFlag)) != 0){HMODULE hModule = LoadLibraryA((LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));if (NULL == hModule){PrintDebugInfo("獲取模塊句柄失敗,模塊名: %s\n", (LPCSTR)(pImportTable->Name + (DWORD)pImageBuffer));continue;}// 修復(fù)IAT表PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)((DWORD)pImageBuffer + pImportTable->FirstThunk);while (*((PDWORD)pThunkData) != 0){// IMAGE_THUNK_DATA32 是一個4字節(jié)數(shù)據(jù)// 如果最高位是1,那么除去最高位就是導(dǎo)出序號// 如果最高位是0,那么這個值是RVA 指向 IMAGE_IMPORT_BY_NAMEif ((*((PDWORD)pThunkData) & 0x80000000) == 0x80000000){DWORD dwProcAddress = (DWORD)GetFunctionByName(hModule, MAKEINTRESOURCE((*((PDWORD)pThunkData) & 0x7FFFFFFF)));*((PDWORD)pThunkData) = dwProcAddress;}else{PIMAGE_IMPORT_BY_NAME pIBN = (PIMAGE_IMPORT_BY_NAME)(*((PDWORD)pThunkData) + (DWORD)pImageBuffer);DWORD dwProcAddress = (DWORD)GetFunctionByName(hModule, (LPCSTR)pIBN->Name);*((PDWORD)pThunkData) = dwProcAddress;}pThunkData++;}pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportTable + sizeof(IMAGE_IMPORT_DESCRIPTOR));} }// 寫入加密數(shù)據(jù)到資源節(jié) // 返回新文件的大小,失敗返回0 VOID WriteEncryptedDataToResourceSection(LPCSTR szFileName,LPVOID pData,DWORD nData ) {NaiveEncrypt(pData, nData, szEncKey, sizeof(szEncKey));Rc4Encrypt(pData, nData, szEncKey, sizeof(szEncKey));HANDLE hFile = BeginUpdateResourceA(szFileName, TRUE);UpdateResourceA(hFile,RT_RCDATA,MAKEINTRESOURCEA(SRCPE),GetSystemDefaultLangID(),pData,nData);EndUpdateResourceA(hFile, FALSE); }// ----------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------- // 加密相關(guān)的函數(shù) // ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------void Rc4Encrypt(void *pData, size_t byteDataLen, const void *pKey, const size_t byteKeyLen) {unsigned char s[256] = { 0 }; //S-boxrc4_init(s, (unsigned char *)pKey, byteKeyLen); //初始化密鑰rc4_crypt(s, (unsigned char *)pData, byteDataLen);//解密 }void Rc4Decrypt(void *pData, size_t byteDataLen, const void *pKey, const size_t byteKeyLen) {unsigned char s[256] = { 0 }; //S-boxrc4_init(s, (unsigned char *)pKey, byteKeyLen); //已經(jīng)完成了初始化rc4_crypt(s, (unsigned char *)pData, byteDataLen);//加密 }void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //初始化函數(shù) {int i = 0, j = 0;unsigned char k[256] = { 0 };unsigned char tmp = 0;for (i = 0; i < 256; i++) {s[i] = i;k[i] = key[i % Len];}for (i = 0; i < 256; i++) {j = (j + s[i] + k[i]) % 256;tmp = s[i];s[i] = s[j]; //交換s[i]和s[j]s[j] = tmp;} }void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //加解密 {int i = 0, j = 0, t = 0;unsigned long k = 0;unsigned char tmp;for (k = 0; k < Len; k++) {i = (i + 1) % 256;j = (j + s[i]) % 256;tmp = s[i];s[i] = s[j]; //交換s[x]和s[y]s[j] = tmp;t = (s[i] + s[j]) % 256;Data[k] ^= s[t];} }// 字節(jié)循環(huán)右移 unsigned char RorByte(unsigned char bData, size_t shift) {unsigned char temp = bData >> (8 - shift);bData = bData << shift;bData |= temp;return bData; }// 加密函數(shù):先與密鑰異或,然后取反,然后右移3位 void NaiveEncrypt(void *pData, size_t byteDataLen, const void *pKey, const size_t byteKeyLen) {size_t uDataIndex = 0, uKeyIndex = 0;for (; uDataIndex < byteDataLen; uDataIndex++){((char *)pData)[uDataIndex] = ((char *)pData)[uDataIndex] ^ ((char *)pKey)[uKeyIndex];((char *)pData)[uDataIndex] = ~((char *)pData)[uDataIndex];RorByte(((unsigned char *)pData)[uDataIndex], 3);uKeyIndex++;if (uKeyIndex == byteKeyLen) uKeyIndex = 0;} }// 解密函數(shù):先右移5位,再取反,在與密鑰異或 void NaiveDecrypt(void *pData, size_t byteDataLen, const void *pKey, const size_t byteKeyLen) {size_t uDataIndex = 0, uKeyIndex = 0;for (; uDataIndex < byteDataLen; uDataIndex++){RorByte(((unsigned char *)pData)[uDataIndex], 5);((char *)pData)[uDataIndex] = ~((char *)pData)[uDataIndex];((char *)pData)[uDataIndex] = ((char *)pData)[uDataIndex] ^ ((char *)pKey)[uKeyIndex];uKeyIndex++;if (uKeyIndex == byteKeyLen) uKeyIndex = 0;} }舊
編譯環(huán)境:32位 多字節(jié)字符集
PE.hpp
總結(jié)
- 上一篇: 使用 ZwUnmapViewOfSect
- 下一篇: 基于异或,取反和循环移位实现一个简单的加