使用 ZwUnmapViewOfSection 卸载并替换内存镜像
生活随笔
收集整理的這篇文章主要介紹了
使用 ZwUnmapViewOfSection 卸载并替换内存镜像
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
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 );這個函數(shù)在 wdm.h 里聲明,它的功能是卸載進程的內(nèi)存鏡像(Image Buffer),內(nèi)存鏡像是指進程4GB虛擬地址空間中從 ImageBase 開始,長度為 SizeOfImage 的內(nèi)存。
卸載內(nèi)存鏡像之后,就得到了一個“干凈”的4GB空間,然后我們可以用 VirtualAllocEx 往里面填數(shù)據(jù),比如換成其他程序的內(nèi)存鏡像。
這樣做的意義就是我們可以從內(nèi)存中啟動一個程序,而不用涉及磁盤讀寫,因為常規(guī)的 CreateProcess 必須指定程序路徑,而利用這種技術(shù)可以避免這一點。
下面給出一個簡單的程序,演示如何創(chuàng)建一個掛起的“傀儡進程”,卸載其內(nèi)存鏡像,并替換為另一個程序的內(nèi)存鏡像,然后恢復(fù)運行。
該程序在32位XP可以正常運行,但是在64位WIN10 VirtualAllocEx 會返回0x1E7
main.cpp
// 程序功能:創(chuàng)建一個自己的傀儡進程并卸載內(nèi)存鏡像,用另一個程序的imagebuffer替換 // 32位 多字節(jié)字符集#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[]) {// 提權(quán)EnableDebugPrivilege();// 讀取源文件LPVOID pSrcFileBuffer = NULL;DWORD dwSrcFileSize = FileToMemory("D:\\Program32\\littlegame.exe", &pSrcFileBuffer);if (dwSrcFileSize == 0){printf("讀取文件失敗\n");return -1;}// 拉伸成內(nèi)存鏡像LPVOID pSrcImageBuffer = NULL;DWORD dwSrcImageBufferSize = FileBufferToImageBuffer(pSrcFileBuffer, &pSrcImageBuffer);// 獲取當(dāng)前進程主模塊路徑char szCurrentPaths[MAX_PATH] = { 0 };GetModuleFileName(NULL, szCurrentPaths, MAX_PATH);// 以掛起方式創(chuàng)建一個當(dāng)前進程的傀儡進程,我們只需要它的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 函數(shù)指針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 函數(shù)指針失敗\n");TerminateThread(pi.hThread, 0);return -1;}// 調(diào)用 ZwUnmapViewOfSection 卸載新進程內(nèi)存鏡像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大小的內(nèi)存 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;} // 將源程序內(nèi)存鏡像復(fù)制到傀儡進程4GB中 if (0 == WriteProcessMemory(pi.hProcess, (LPVOID)dwSrcImageBase, pSrcImageBuffer, dwSrcImageBufferSize, NULL)){printf("寫入源程序內(nèi)存鏡像失敗\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);// 恢復(fù)線程 ResumeThread(pi.hThread);// 脫殼成功printf("脫殼成功,源程序正在運行,敲任意字符退出\n");free(pSrcFileBuffer);free(pSrcImageBuffer);system("pause");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; }PE.hpp
#ifndef PE_HPP_ #define PE_HPP_/******************************************************************************** 時間: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); DWORD WriteEncryptedDataToNewSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pNewFileBuffer, LPVOID pData, DWORD dwDataSize); DWORD ReadEncryptedDataFromLastSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pData);// 讀取文件到內(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; }// 驗證是否是合法的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 并寫入到新的緩沖區(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é)表+文件對齊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 變成文件對齊的 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);// 最后一個節(jié)表PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pPEHeader->NumberOfSections - 1;// 計算要復(fù)制的字節(jié)// 這一步有BUG,當(dāng)最后一個節(jié)后面還有數(shù)據(jù)時(多見于控制臺程序),丟失數(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é)表+文件對齊memcpy(*pFileBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);// 遍歷節(jié)表,復(fù)制文件對齊后的節(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; }// 計算對齊的函數(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_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在文件頭中或者文件對齊==內(nèi)存對齊時,RVA==FOA 錯!第一句是對的,第二句是錯的if (dwRva < pOptionHeader->SizeOfHeaders){return dwRva;}// 遍歷節(jié)表,確定偏移屬于哪一個節(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 對應(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在文件頭中或者文件對齊==內(nèi)存對齊時,RVA==FOA 錯!第一句是對的,第二句是錯的if (dwFoa < pOptionHeader->SizeOfHeaders){return dwFoa;}// 遍歷節(jié)表,確定偏移屬于哪一個節(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 對應(yīng)的 RVA,轉(zhuǎn)換失敗\n", dwFoa);return 0; }// 移動NT頭和節(jié)表到DOS STUB,該函數(shù)在新增節(jié)時節(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頭插入點DWORD dwRet = (DWORD)pNTHeader - (DWORD)pDst; // 返回地址減小的值DWORD dwSize = 4 + sizeof(IMAGE_FILE_HEADER) + pPEHeader->SizeOfOptionalHeader + \sizeof(IMAGE_SECTION_HEADER) * pPEHeader->NumberOfSections; // 移動的字節(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); // 移動數(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 這個內(nèi)存里存儲了一個“指針”// 要修改的是這個“指針”的值,要讓這個“指針”加上兩個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){// 計算需要重定位的數(shù)據(jù)的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; }// 將數(shù)據(jù)添加到新增節(jié)中 // 返回新緩沖區(qū)的大小,失敗返回0 // 這個數(shù)據(jù)節(jié)前N個字節(jié)是一串十進制字符串,表示數(shù)據(jù)大小,以NULL結(jié)束 DWORD WriteEncryptedDataToNewSection(LPVOID pFileBuffer, DWORD dwFileBufferSize, LPVOID *pNewFileBuffer, LPVOID pData, DWORD dwDataSize) {// 復(fù)制一份 pFileBuffer,不要修改原來的數(shù)據(jù)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); // 節(jié)的數(shù)量PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節(jié)表PIMAGE_SECTION_HEADER pNewSectionHeader = pSectionHeader + *pNumberOfSections; // 新節(jié)表插入點DWORD newFileBufferSize = 0; // 新文件的大小// 判斷最后一個節(jié)表后面是否有空閑的80字節(jié)if (80 > (DWORD)pFileBuffer + pOptionHeader->SizeOfHeaders - (DWORD)pNewSectionHeader){printf("沒有足夠的80字節(jié)插入新節(jié)表\n");free(pFileBuffer);return 0;}// 判斷空閑的80字節(jié)是否全為0,如果不是,則把整個NT頭往上挪覆蓋dos stub以空出空間插入節(jié)表for (int i = 0; i < 80; i++){if (((PBYTE)pNewSectionHeader)[i] != 0){DWORD dwRet = MoveNTHeaderAndSectionHeadersToDosStub(pFileBuffer);printf("節(jié)表空間不足,NT頭和節(jié)表向低地址移動了 %d 字節(jié)\n", dwRet);if (dwRet < 80){printf("移動后仍沒有足夠的80字節(jié)空間插入新節(jié)表\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); // 節(jié)的數(shù)量pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節(jié)表pNewSectionHeader = pSectionHeader + *pNumberOfSections; // 新節(jié)表插入點break;}}// 創(chuàng)建數(shù)據(jù)大小標記char sSizeFlag[100] = { 0 };sprintf(sSizeFlag, "%d", dwDataSize);DWORD dwFlagLen = strlen(sSizeFlag) + 1; // 拷貝長度包括NULL// 定義一個 IMAGE_SECTION_HEADER 結(jié)構(gòu),計算里面的屬性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 分配內(nèi)存,把 pFileBuffer 復(fù)制過去,后面的修改都在 pNewFileBuffer 進行 *pNewFileBuffer = malloc(dwFileBufferSize + newSectionHeader.SizeOfRawData);memcpy(*pNewFileBuffer, pFileBuffer, dwFileBufferSize);memset((LPVOID)((DWORD)*pNewFileBuffer + dwFileBufferSize), 0, newSectionHeader.SizeOfRawData); // 新增節(jié)數(shù)據(jù)清0// 更新指針,指向新內(nèi)存 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;// 節(jié)的數(shù)量+1,SizeOfImage是內(nèi)存中拉伸后的大小*pNumberOfSections += 1;pOptionHeader->SizeOfImage += Align(newSectionHeader.Misc.VirtualSize, pOptionHeader->SectionAlignment);// 拷貝 newSectionHeadermemcpy(pNewSectionHeader, &newSectionHeader, sizeof(newSectionHeader));// 拷貝數(shù)據(jù)到新增節(jié)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; }// 從最后一個節(jié)里讀取數(shù)據(jù),返回數(shù)據(jù)大小 // 最后一個節(jié)名字必須是.encsrc,開頭N個字節(jié)必須是十進制數(shù)字符串,NULL結(jié)尾,表示后面的數(shù)據(jù)字節(jié)數(shù) // pNewFileBuffer 輸出數(shù)據(jù)內(nèi)容,不包含開頭大小標記 // 數(shù)據(jù)通過 pData 返回,與pFileBuffer 共享一塊內(nèi)存 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); // 節(jié)的數(shù)量PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + *pNumberOfSections - 1; // 最后一個節(jié)表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總結(jié)
以上是生活随笔為你收集整理的使用 ZwUnmapViewOfSection 卸载并替换内存镜像的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用GetProcAddress获取Zw
- 下一篇: PE工具函数(新)