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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用 ZwUnmapViewOfSection 卸载并替换内存镜像

發布時間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用 ZwUnmapViewOfSection 卸载并替换内存镜像 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

The ZwUnmapViewOfSection routine unmaps a view of a section from the virtual address space of a subject process.

NTSTATUS ZwUnmapViewOfSection(IN HANDLE ProcessHandle,IN PVOID BaseAddress );

這個函數在 wdm.h 里聲明,它的功能是卸載進程的內存鏡像(Image Buffer),內存鏡像是指進程4GB虛擬地址空間中從 ImageBase 開始,長度為 SizeOfImage 的內存。

卸載內存鏡像之后,就得到了一個“干凈”的4GB空間,然后我們可以用 VirtualAllocEx 往里面填數據,比如換成其他程序的內存鏡像。

這樣做的意義就是我們可以從內存中啟動一個程序,而不用涉及磁盤讀寫,因為常規的 CreateProcess 必須指定程序路徑,而利用這種技術可以避免這一點。

下面給出一個簡單的程序,演示如何創建一個掛起的“傀儡進程”,卸載其內存鏡像,并替換為另一個程序的內存鏡像,然后恢復運行。

該程序在32位XP可以正常運行,但是在64位WIN10 VirtualAllocEx 會返回0x1E7

main.cpp

// 程序功能:創建一個自己的傀儡進程并卸載內存鏡像,用另一個程序的imagebuffer替換 // 32位 多字節字符集#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <WINDOWS.H> #include <STRING.h> #include <MALLOC.H> #include "PE.hpp"BOOL EnableDebugPrivilege();int main(int argc, char *argv[]) {// 提權EnableDebugPrivilege();// 讀取源文件LPVOID pSrcFileBuffer = NULL;DWORD dwSrcFileSize = FileToMemory("D:\\Program32\\littlegame.exe", &pSrcFileBuffer);if (dwSrcFileSize == 0){printf("讀取文件失敗\n");return -1;}// 拉伸成內存鏡像LPVOID pSrcImageBuffer = NULL;DWORD dwSrcImageBufferSize = FileBufferToImageBuffer(pSrcFileBuffer, &pSrcImageBuffer);// 獲取當前進程主模塊路徑char szCurrentPaths[MAX_PATH] = { 0 };GetModuleFileName(NULL, szCurrentPaths, MAX_PATH);// 以掛起方式創建一個當前進程的傀儡進程,我們只需要它的4GB空間STARTUPINFO si = { 0 };si.cb = sizeof(si);PROCESS_INFORMATION pi;CreateProcess(NULL, szCurrentPaths, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);// 獲取新進程主線程上下文CONTEXT context;context.ContextFlags = CONTEXT_FULL;GetThreadContext(pi.hThread, &context);// 獲取 ZwUnmapViewOfSection 函數指針HMODULE hModuleNt = LoadLibrary("ntdll.dll");if (hModuleNt == NULL){printf("獲取ntdll句柄失敗\n");TerminateThread(pi.hThread, 0);return -1;}typedef DWORD(WINAPI *_TZwUnmapViewOfSection)(HANDLE, PVOID);_TZwUnmapViewOfSection pZwUnmapViewOfSection = (_TZwUnmapViewOfSection)GetProcAddress(hModuleNt, "ZwUnmapViewOfSection");if (pZwUnmapViewOfSection == NULL){printf("獲取 ZwUnmapViewOfSection 函數指針失敗\n");TerminateThread(pi.hThread, 0);return -1;}// 調用 ZwUnmapViewOfSection 卸載新進程內存鏡像pZwUnmapViewOfSection(pi.hProcess, GetModuleHandle(NULL));// 獲取源程序的ImageBasePIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pSrcImageBuffer;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));DWORD dwSrcImageBase = pOptionHeader->ImageBase;// 在傀儡進程的源程序的ImageBase處申請SizeOfImage大小的內存 LPVOID pImageBase = VirtualAllocEx(pi.hProcess, (LPVOID)dwSrcImageBase, dwSrcImageBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);if ((DWORD)pImageBase != dwSrcImageBase){printf("VirtualAllocEx 錯誤碼: 0x%X\n", GetLastError()); // 0x1e7 試圖訪問無效地址printf("申請到的指針: 0x%X, 期望的地址: 0x%X\n", (DWORD)pImageBase, dwSrcImageBase);TerminateThread(pi.hThread, 0);return -1;} // 將源程序內存鏡像復制到傀儡進程4GB中 if (0 == WriteProcessMemory(pi.hProcess, (LPVOID)dwSrcImageBase, pSrcImageBuffer, dwSrcImageBufferSize, NULL)){printf("寫入源程序內存鏡像失敗\n");TerminateThread(pi.hThread, 0);return -1;}// 修正入口點context.Eax = pOptionHeader->AddressOfEntryPoint + dwSrcImageBase;// 修正 ImageBaseWriteProcessMemory(pi.hProcess, (LPVOID)(context.Ebx + 8), &dwSrcImageBase, 4, NULL);context.ContextFlags = CONTEXT_FULL;SetThreadContext(pi.hThread, &context);// 恢復線程 ResumeThread(pi.hThread);// 脫殼成功printf("脫殼成功,源程序正在運行,敲任意字符退出\n");free(pSrcFileBuffer);free(pSrcImageBuffer);system("pause");return 0; }// 提權函數:提升為DEBUG權限 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; }

PE.hpp

#ifndef PE_HPP_ #define PE_HPP_/******************************************************************************** 時間:2020年7月14日 作者:hambaga 說明:重新整理的PE工具函數,僅適用于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); DWORD WriteEncryptedDataToNewSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pNewFileBuffer, LPVOID pData, DWORD dwDataSize); DWORD ReadEncryptedDataFromLastSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pData);// 讀取文件到內存中,返回讀取的字節數;讀取失敗返回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");fclose(pFile);return 0;}DWORD dwRead = fread(*pFileBuffer, 1, dwFileSize, pFile);fclose(pFile);if (dwRead != dwFileSize){free(*pFileBuffer);return 0;}return dwRead; }// 驗證是否是合法的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標志\n");return FALSE;}if (pNTHeader->Signature != IMAGE_NT_SIGNATURE){printf("不是有效的PE標記\n");return FALSE;}return TRUE; }// 將 FileBuffer 拉伸成 ImageBuffer 并寫入到新的緩沖區 // 返回 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");return 0;}memset(*pImageBuffer, 0, pOptionHeader->SizeOfImage);// 復制DOS頭+PE頭+可選PE頭+節表+文件對齊memcpy(*pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);// 遍歷節表,復制所有節 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 變成文件對齊的 FileBuffer 寫入新的緩沖區 // 返回復制的大小,失敗返回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);// 最后一個節表PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pPEHeader->NumberOfSections - 1;// 計算要復制的字節// 這一步有BUG,當最后一個節后面還有數據時(多見于控制臺程序),丟失數據DWORD dwFileBufferSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;*pFileBuffer = malloc(dwFileBufferSize);if (*pFileBuffer == NULL){printf("分配內存失敗\n");return 0;}memset(*pFileBuffer, 0, dwFileBufferSize);// 復制DOS頭+PE頭+可選PE頭+節表+文件對齊memcpy(*pFileBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);// 遍歷節表,復制文件對齊后的節 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; }// 內存數據寫入文件 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 字節,不等于 %d\n", dwWritten, dwSize);fclose(fp);return FALSE;}fclose(fp);return TRUE; }// 計算對齊的函數,如偏移為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 轉 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在文件頭中或者文件對齊==內存對齊時,RVA==FOA 錯!第一句是對的,第二句是錯的if (dwRva < pOptionHeader->SizeOfHeaders){return dwRva;}// 遍歷節表,確定偏移屬于哪一個節 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 對應的 FOA,轉換失敗\n", dwRva);return 0; }// FOA 轉 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在文件頭中或者文件對齊==內存對齊時,RVA==FOA 錯!第一句是對的,第二句是錯的if (dwFoa < pOptionHeader->SizeOfHeaders){return dwFoa;}// 遍歷節表,確定偏移屬于哪一個節 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 對應的 RVA,轉換失敗\n", dwFoa);return 0; }// 移動NT頭和節表到DOS STUB,該函數在新增節時節表空間不足的情況下調用;返回地址減小值 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頭插入點DWORD dwRet = (DWORD)pNTHeader - (DWORD)pDst; // 返回地址減小的值DWORD dwSize = 4 + sizeof(IMAGE_FILE_HEADER) + pPEHeader->SizeOfOptionalHeader + \sizeof(IMAGE_SECTION_HEADER) * pPEHeader->NumberOfSections; // 移動的字節數LPVOID pSrc = malloc(dwSize);if (pSrc == NULL){printf("分配內存失敗\n");return 0;}memcpy(pSrc, (LPVOID)pNTHeader, dwSize); // 保存要復制的數據memset((LPVOID)pNTHeader, 0, dwSize); // 清空原數據memcpy(pDst, pSrc, dwSize); // 移動數據free(pSrc);pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); // 更新 e_lfanewreturn dwRet; }// 修改 ImageBase 并修復重定位表 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 這個內存里存儲了一個“指針”// 要修改的是這個“指針”的值,要讓這個“指針”加上兩個ImageBase的差值while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock){size_t n = (pRelocationTable->SizeOfBlock - 8) / 2; // 可能需要修改的地址數量(高4位==0011才要修改)PWORD pOffset = (PWORD)((DWORD)pRelocationTable + 8); // 2字節偏移的數組for (size_t i = 0; i < n; i++){// 高4位等于0011才需要重定位if ((pOffset[i] & 0xF000) == 0x3000){// 計算需要重定位的數據的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF);// 計算在文件中的偏移DWORD dwFoa = RvaToFoa(pFileBuffer, dwRva);// 計算在文件中的地址PDWORD pData = (PDWORD)((DWORD)pFileBuffer + dwFoa);// 重定位,即修正寫死的地址 *pData += dwImageBaseDelta;}}pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepOptionHeader->ImageBase = dwNewImageBase; }// 將數據添加到新增節中 // 返回新緩沖區的大小,失敗返回0 // 這個數據節前N個字節是一串十進制字符串,表示數據大小,以NULL結束 DWORD WriteEncryptedDataToNewSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pNewFileBuffer, LPVOID pData, DWORD dwDataSize) {// 復制一份 pFileBuffer,不要修改原來的數據LPVOID pFileBuffer3 = malloc(dwFileBufferSize);memcpy(pFileBuffer3, pFileBuffer, dwFileBufferSize);pFileBuffer = pFileBuffer3;pFileBuffer3 = NULL;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);PWORD pNumberOfSections = &(pPEHeader->NumberOfSections); // 節的數量PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節表PIMAGE_SECTION_HEADER pNewSectionHeader = pSectionHeader + *pNumberOfSections; // 新節表插入點DWORD newFileBufferSize = 0; // 新文件的大小// 判斷最后一個節表后面是否有空閑的80字節if (80 > (DWORD)pFileBuffer + pOptionHeader->SizeOfHeaders - (DWORD)pNewSectionHeader){printf("沒有足夠的80字節插入新節表\n");free(pFileBuffer);return 0;}// 判斷空閑的80字節是否全為0,如果不是,則把整個NT頭往上挪覆蓋dos stub以空出空間插入節表for (int i = 0; i < 80; i++){if (((PBYTE)pNewSectionHeader)[i] != 0){DWORD dwRet = MoveNTHeaderAndSectionHeadersToDosStub(pFileBuffer);printf("節表空間不足,NT頭和節表向低地址移動了 %d 字節\n", dwRet);if (dwRet < 80){printf("移動后仍沒有足夠的80字節空間插入新節表\n");free(pFileBuffer);return 0;}// 更新指針pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);pNumberOfSections = &(pPEHeader->NumberOfSections); // 節的數量pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節表pNewSectionHeader = pSectionHeader + *pNumberOfSections; // 新節表插入點break;}}// 創建數據大小標記char sSizeFlag[100] = { 0 };sprintf(sSizeFlag, "%d", dwDataSize);DWORD dwFlagLen = strlen(sSizeFlag) + 1; // 拷貝長度包括NULL// 定義一個 IMAGE_SECTION_HEADER 結構,計算里面的屬性IMAGE_SECTION_HEADER newSectionHeader;memcpy(newSectionHeader.Name, ".encsrc", 8);newSectionHeader.Misc.VirtualSize = Align(dwDataSize + dwFlagLen, pOptionHeader->SectionAlignment);newSectionHeader.VirtualAddress = pLastSectionHeader->VirtualAddress + \Align(pLastSectionHeader->Misc.VirtualSize, pOptionHeader->SectionAlignment);newSectionHeader.SizeOfRawData = Align(dwDataSize + dwFlagLen, pOptionHeader->FileAlignment);newSectionHeader.PointerToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;newSectionHeader.PointerToRelocations = 0;newSectionHeader.PointerToLinenumbers = 0;newSectionHeader.NumberOfRelocations = 0;newSectionHeader.NumberOfLinenumbers = 0;newSectionHeader.Characteristics = 0xC0000040;// pNewFileBuffer 分配內存,把 pFileBuffer 復制過去,后面的修改都在 pNewFileBuffer 進行 *pNewFileBuffer = malloc(dwFileBufferSize + newSectionHeader.SizeOfRawData);memcpy(*pNewFileBuffer, pFileBuffer, dwFileBufferSize);memset((LPVOID)((DWORD)*pNewFileBuffer + dwFileBufferSize), 0, newSectionHeader.SizeOfRawData); // 新增節數據清0// 更新指針,指向新內存 pDosHeader = (PIMAGE_DOS_HEADER)*pNewFileBuffer;pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);pNumberOfSections = &(pPEHeader->NumberOfSections);pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1;pNewSectionHeader = pSectionHeader + *pNumberOfSections;// 節的數量+1,SizeOfImage是內存中拉伸后的大小*pNumberOfSections += 1;pOptionHeader->SizeOfImage += Align(newSectionHeader.Misc.VirtualSize, pOptionHeader->SectionAlignment);// 拷貝 newSectionHeadermemcpy(pNewSectionHeader, &newSectionHeader, sizeof(newSectionHeader));// 拷貝數據到新增節LPVOID pNewSec = (LPVOID)((DWORD)*pNewFileBuffer + (DWORD)(pSectionHeader[*pNumberOfSections - 1].PointerToRawData));memcpy(pNewSec, sSizeFlag, dwFlagLen);memcpy((LPVOID)((PBYTE)pNewSec + dwFlagLen), pData, dwDataSize);//printf("插入成功\n");free(pFileBuffer);return dwFileBufferSize + newSectionHeader.SizeOfRawData; }// 從最后一個節里讀取數據,返回數據大小 // 最后一個節名字必須是.encsrc,開頭N個字節必須是十進制數字符串,NULL結尾,表示后面的數據字節數 // pNewFileBuffer 輸出數據內容,不包含開頭大小標記 // 數據通過 pData 返回,與pFileBuffer 共享一塊內存 DWORD ReadEncryptedDataFromLastSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pData) {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);PWORD pNumberOfSections = &(pPEHeader->NumberOfSections); // 節的數量PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節表if (memcmp(".encsrc", pLastSectionHeader->Name, 8) != 0){printf("不是有效的加密程序\n");int i = 0;for (; i < 8; i++){printf("%c", pLastSectionHeader->Name[i]);}puts("");return 0;}LPVOID pLastSection = (LPVOID)(pLastSectionHeader->PointerToRawData + (PBYTE)pFileBuffer);DWORD dwDataSize = -1;sscanf((char *)pLastSection, "%d", &dwDataSize);*pData = (PBYTE)pLastSection + strlen((char *)pLastSection) + 1;return dwDataSize; }#endif

總結

以上是生活随笔為你收集整理的使用 ZwUnmapViewOfSection 卸载并替换内存镜像的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。