壳2
创建MFC-基于对话框项目。
绘制界面
图片插入,添加工具-picture control-属性
属性-设置
一键加壳按钮实现
void CMFCShellDlg::OnBnClickedButton1(){ //设置过滤器 TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||"); // 构造打开文件对话框 CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this); CString strFilePath, strText; // 显示打开文件对话框 if (IDOK == fileDlg.DoModal()) { strFilePath = fileDlg.GetPathName(); //获取文件路径 CMyPack MyPack; // 读取一个 PE 文件 USES_CONVERSION; MyPack.LoadFile(W2A(strFilePath.GetBuffer())); // 读取 stub 文件 MyPack.LoadStub("my_stub.dll"); // 将 stub 中的 .text 拷贝到 pe 文件的 .mypack MyPack.CopySection(".mypack", ".text"); // 重新设置被加壳程序的 OEP,必须在这个位置,因为需要知道新的RVA MyPack.SetOep(); // 修复 stub 代码的重定位项 MyPack.FixRealoc(); // 加密代码段 MyPack.XorFileSection(".text"); // 压缩所有的段 MyPack.PackCode(".text"); // 修正压缩后的区段位置 MyPack.FixSection(); // 清除一些表项 MyPack.ClearDataDir(); // 拷贝区段数据 MyPack.CopySectionData(".mypack", ".text"); // 将修改后的PE保存 MyPack.SaveFile("demo_pack.exe"); MessageBoxW(L"加壳成功"); return; }
CMypack.cpp
#include "stdafx.h"//#include "pch.h"#include "CMyPack.h"#include <time.h>#include <DbgHelp.h>#pragma comment(lib, "DbgHelp.lib")#include "aplib.h"#pragma comment(lib,"aPlib.lib")struct TypeOffset{ WORD Offset : 12; WORD Type : 4;};// 获取各种头的函数PIMAGE_DOS_HEADER CMyPack::DosHeader(DWORD Base){ return (PIMAGE_DOS_HEADER)Base;}PIMAGE_NT_HEADERS CMyPack::NTHeader(DWORD Base){ return (PIMAGE_NT_HEADERS)(Base + DosHeader(Base)->e_lfanew);}PIMAGE_FILE_HEADER CMyPack::FileHeader(DWORD Base){ return &NTHeader(Base)->FileHeader;}PIMAGE_OPTIONAL_HEADER CMyPack::OptHeader(DWORD Base){ return &NTHeader(Base)->OptionalHeader;}// 将传入的数值对齐到指定力度的倍数DWORD CMyPack::Aligment(DWORD Item, DWORD Align){ // 35000 % 1000 != 0 -> (3500 / 1000 + 1)*1000 return Item % Align ? (Item / Align + 1)*Align : Item;}// 获取指定名称的区段头表地址PIMAGE_SECTION_HEADER CMyPack::GetSection(DWORD Base, LPCSTR Name){ // 获取到区段头表的首地址 auto SectionTable = IMAGE_FIRST_SECTION(NTHeader(Base)); // 获取区段头表的元素个数 WORD Count = FileHeader(Base)->NumberOfSections; // 遍历区段头表,并比对名称 for (WORD i = 0; i < Count; ++i) { // 区段的有效名称长度是8,理论应该单独拷贝出来再比较 if (!strcmp((char*)SectionTable[i].Name, Name)) return &SectionTable[i]; } return nullptr;}// 加载一个 PE 文件void CMyPack::LoadFile(LPCSTR FileName){ // 打开一个文件,理论上应该对文件进行判断,是否是一个 PE 文件,位数是多少 HANDLE FileHandle = CreateFileA(FileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // 获取到文件的大小,并申请相应的堆空间 FileSize = GetFileSize(FileHandle, NULL); FileBase = (DWORD)malloc(sizeof(BYTE) * FileSize); // 读取 PE 文件的内容 DWORD BytesRead = 0; ReadFile(FileHandle, (LPVOID)FileBase, FileSize, &BytesRead, NULL); // 关闭句柄,防止句柄泄露 CloseHandle(FileHandle);}// 加载一个 dll 文件void CMyPack::LoadStub(LPCSTR FileName){ // 以不调用 dllmain 的方式加载 dll 到当前的内存,会展开 StubBase = (DWORD)LoadLibraryExA(FileName, NULL, DONT_RESOLVE_DLL_REFERENCES); // 获取 start 函数在 .text 的段内偏移 DWORD Start = (DWORD)GetProcAddress((HMODULE)StubBase, "start"); StartOffset = Start - StubBase - GetSection(StubBase, ".text")->VirtualAddress; // 加载stub数据对象,向其中填充内容 StubData = (ShareData*)GetProcAddress((HMODULE)StubBase, "StubData");}// 拷贝区段,从 stub 拷贝 SrcName 区段到 exe 中并命名为 DestNamevoid CMyPack::CopySection(LPCSTR DestName, LPCSTR SrcName){ // 从 dll 中获取到需要拷贝的区段对应的区段头结构 auto SrcSection = GetSection(StubBase, SrcName); // 获取到最后一个区段的位置,下标从0开始,区段数量-1 auto LastSection = &IMAGE_FIRST_SECTION(NTHeader(FileBase)) [FileHeader(FileBase)->NumberOfSections - 1]; // 将文件头中的区段数量+1 FileHeader(FileBase)->NumberOfSections += 1; // 获取新添加的区段头表的首地址 auto DestSection = LastSection + 1; // 将源区段的属性直接拷贝到新的区段 memcpy(DestSection, SrcSection, sizeof(IMAGE_SECTION_HEADER)); // 设置区段的名称,可以是用 memcpy strcpy memcpy(DestSection->Name, DestName, 7); // 设置区段起始位置的 RVA = 上一个区段 RVA + 对齐的内存大小 DestSection->VirtualAddress = LastSection->VirtualAddress + Aligment(LastSection->Misc.VirtualSize, OptHeader(FileBase)->SectionAlignment); // 设置区段起始位置的 FOA = 上一个区段 FOA + 对齐的文件大小 DestSection->PointerToRawData = LastSection->PointerToRawData + Aligment(LastSection->SizeOfRawData, OptHeader(FileBase)->FileAlignment); // 重新的分配空间,大小是 最后一个区段的FOA + 最后一个区段的文件大小 FileSize = DestSection->PointerToRawData + DestSection->SizeOfRawData; // 使用 realloc 的时候,它新的地址会作为返回值进行返回 FileBase = (DWORD)realloc((LPVOID)FileBase, FileSize); // 重新设置映像大小 = 最后一个区段的 RVA + 最后一个区段的内存大小 OptHeader(FileBase)->SizeOfImage = DestSection->VirtualAddress + DestSection->Misc.VirtualSize;}// 保存修改后的 PE 文件void CMyPack::SaveFile(LPCSTR NewName){ // 打开一个文件,理论上应该对文件进行判断,是否是一个 PE 文件,位数是多少 HANDLE FileHandle = CreateFileA(NewName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // 写入 PE 文件的内容 DWORD BytesWrite = 0; WriteFile(FileHandle, (LPVOID)FileBase, FileSize, &BytesWrite, NULL); // 关闭句柄,防止句柄泄露 CloseHandle(FileHandle);}// 拷贝区段的内容,需要指定区段的名称void CMyPack::CopySectionData(LPCSTR DestName, LPCSTR SrcName){ // 获取到源区段的区段头表结构并计算出偏移(DLL加载到了内存,使用的是内存偏移) auto SrcSection = GetSection(StubBase, SrcName); BYTE* SrcData = (BYTE*)(SrcSection->VirtualAddress + StubBase); // 获取到目标区段的区段头表结构并计算出偏移(PE文件没有对齐,使用的是文件偏移) auto DestSection = GetSection(FileBase, DestName); BYTE* DestData = (BYTE*)(DestSection->PointerToRawData + FileBase); // 以文件大小进行拷贝 memcpy(DestData, SrcData, SrcSection->SizeOfRawData);}// 设置入口点为新区段中的 start 的位置(RVA)void CMyPack::SetOep(){ // 保存原始的 OEP StubData->OldOEP = OptHeader(FileBase)->AddressOfEntryPoint; // 因为获取到的 start 函数的地址是在dll中的地址,现在这个区段被拷贝到了 // 被加壳程序中,所以需要重新计算 start 的 RVA 并设置为 OEP OptHeader(FileBase)->AddressOfEntryPoint = GetSection(FileBase, ".mypack")->VirtualAddress + StartOffset;}// 修复壳代码的重定位void CMyPack::FixRealoc(){ ULONG Size = 0, OldProtect = 0,OldRelocProtect = 0; // 获取到程序的重定位表 auto RealocTable = (PIMAGE_BASE_RELOCATION) ImageDirectoryEntryToData((PVOID)StubBase, TRUE, 5, &Size); // 遍历重定位表,重定位表以一个空表结尾 while (RealocTable->SizeOfBlock) { // 获取重定位项,并依次修复重定位项 auto Item = (TypeOffset*)(RealocTable + 1); // 获取到重定位项的个数 DWORD Count = (RealocTable->SizeOfBlock - 8) / 2; // 遍历重定位项并修复 for (DWORD i = 0; i < Count; ++i) { // 修改整个分页的属性,使它能够被写入 VirtualProtect((LPVOID)(RealocTable->VirtualAddress + StubBase), 0x1000, PAGE_READWRITE, &OldProtect); // 只需要关注 type == 3 的类型 if (Item[i].Type == 3) { // 需要重定位的数据所在的地址 dll所在的基址Base + 重定位表的RVA + 重定位块所在的Offset DWORD* ItemAddr = (DWORD*)(StubBase + RealocTable->VirtualAddress + Item[i].Offset); // 计算出不会改变(会改变的有基址和段的RVA)的偏移 // 不会改变的是重定位块在重定位段里面的相对偏移。 // 重定位块在重定位段里面的相对偏移=重定位块当前所在地址-dll所在的基址Base-在dll内重定位段的RVA DWORD Offset = *ItemAddr - StubBase - GetSection(StubBase, ".text")->VirtualAddress; // 要替换掉原本程序的重定位的位置。 // 相对偏移+段地址RVA(在exe内拷到了.mypack段)+exe基址 *ItemAddr = Offset + GetSection(FileBase, ".mypack")->VirtualAddress + OptHeader(FileBase)->ImageBase; } // 还原属性 VirtualProtect((LPVOID)(RealocTable->VirtualAddress + StubBase), 0x1000, OldProtect, &OldProtect); } // 上面的行为,是因为exe的mypack直接是拷贝的dll的text。 // 直接拷贝的话,dll里面的text里面的重定位存的重定位表的地址是相对于dll基址的地址。 // 所以要先更改成以exe为基址的地址。 // 修改整个分页的属性,使它能够被写入 VirtualProtect((LPVOID)((DWORD)RealocTable&0xFFFFF000), 0x1000, PAGE_READWRITE, &OldProtect); // dll的重定位表在exe的位置= dll重定位表-dll的text段RVA+exe的mypack段RVA // RealocTable->VirtualAddress = // (GetSection(FileBase, ".mypack")->VirtualAddress - GetSection(StubBase, ".text")->VirtualAddress)+RealocTable->VirtualAddress; RealocTable->VirtualAddress += (GetSection(FileBase, ".mypack")->VirtualAddress - GetSection(StubBase, ".text")->VirtualAddress); // 找到下一个重定位块 RealocTable = (PIMAGE_BASE_RELOCATION)((DWORD)RealocTable + RealocTable->SizeOfBlock); } // 手动的关闭动态基址,否则程序无法运行 //OptHeader(FileBase)->DllCharacteristics = 0; // 但是现在,程序运行的还是原本exe的重定位表,所以接下来要把原程序的重定位表替换成dll的 // 在exe中重新做一个新的重定位表 // 从stub 拷贝 壳的重定位内容.reloc 到 exe中。 CopySection(".sreloc", ".reloc"); CopySectionData(".sreloc", ".reloc"); // 修改整个分页的属性,使它能够被写入 VirtualProtect((LPVOID)(RealocTable->VirtualAddress + FileBase), 0x1000, PAGE_READWRITE, &OldRelocProtect); // 让stub的重定位代替exe的。 OptHeader(FileBase)->DataDirectory[5].VirtualAddress = GetSection(FileBase, ".sreloc")->VirtualAddress; OptHeader(FileBase)->DataDirectory[5].Size = GetSection(FileBase, ".sreloc")->Misc.VirtualSize; // 恢复整个分页的属性 VirtualProtect((LPVOID)(RealocTable->VirtualAddress + FileBase), 0x1000, OldRelocProtect, &OldRelocProtect); // 保存被加壳程序的重定位表 StubData->RelocRVA = GetSection(FileBase, ".reloc")->VirtualAddress; StubData->ImageBase = OptHeader(FileBase)->ImageBase; StubData->ImportRVA= OptHeader(FileBase)->DataDirectory[1].VirtualAddress; StubData->TlsRVA= OptHeader(FileBase)->DataDirectory[9].VirtualAddress; if (StubData->TlsRVA!=0) { StubData->HideTLS =false; } //StubData->TlsRVA= 1000;}// 异或指定区段的数据void CMyPack::XorFileSection(LPCSTR SectionName){ // 获取指定的区段 auto Section = GetSection(FileBase, SectionName); // 保存区段的 RVA 以及 Size StubData->XorRVA = Section->VirtualAddress; StubData->XorSize = Section->SizeOfRawData; // 计算出区段的位置 BYTE* Buffer = (BYTE*)(FileBase + Section->PointerToRawData); // 随机生成一个加密的 key srand((unsigned int)time(0)); StubData->XorKey = rand() % 0x100; // 根据文件大小对它进行异或 for (DWORD i = 0; i < Section->SizeOfRawData; ++i) Buffer[i] ^= StubData->XorKey;}// 清除一些表项void CMyPack::ClearDataDir(){ auto Dir = OptHeader(FileBase)->DataDirectory; for (int i=0;i<16;++i) { if (i!=0&&i!=5) { Dir[i].Size = 0; Dir[i].VirtualAddress = 0; } }}void CMyPack::PackCode(LPCSTR SectionName){ // 获取指定的区段 // auto Section = GetSection(FileBase, SectionName); // 获取到第一个代码段 auto Section = IMAGE_FIRST_SECTION(NTHeader(FileBase)); // 保存区段的 RVA 以及 Size StubData->PackRVA = Section->VirtualAddress; StubData->PackSize = Section->SizeOfRawData; // 区段数量 DWORD dwScnCount = FileHeader(FileBase)->NumberOfSections; // 进度条控件 //CMFCShellDlg::m_ProgressCtrl.SetStep(dwScnCount); for (DWORD i = 0; i < dwScnCount - 2; i++)//mypack,新的reloc段不压缩 { // 进度条 //CMFCShellDlg::m_ProgressCtrl.StepIt(); // 所在区段大小 DWORD nDataSize = Section->SizeOfRawData; if (nDataSize) { // 计算出区段的位置 char* nSectionByte = (char*)(FileBase + Section->PointerToRawData); // 要压缩前的准备工作。 char *nWorkMem = (char*)malloc(aP_workmem_size(nDataSize)); char *nPackData = (char*)malloc(aP_max_packed_size(nDataSize)); // 压缩成功返回压缩的大小 size_t nPackSize = aPsafe_pack(nSectionByte, nPackData, nDataSize, nWorkMem, NULL, NULL); // 将原本位置上的数据清除 memset(nSectionByte, 0, Section->SizeOfRawData); // 将新压缩完的nPackSize大小的nPackData内容放入原本位置 memcpy_s(nSectionByte, Section->SizeOfRawData, nPackData, nPackSize); // 将原本文件区段大小更新 Section->SizeOfRawData = nPackSize; // 释放 free(nPackData); free(nWorkMem); } // 下一个段 Section++; } //清除资源表 OptHeader(FileBase)->DataDirectory[2].VirtualAddress = 0; OptHeader(FileBase)->DataDirectory[2].Size = 0;}//获取最后一个区段头IMAGE_SECTION_HEADER* CMyPack::GetLastSection()// 获取最后一个区段{ // 获取区段个数 DWORD dwScnCount = FileHeader(FileBase)->NumberOfSections; // 获取第一个区段 IMAGE_SECTION_HEADER* pScn = IMAGE_FIRST_SECTION(NTHeader(FileBase)); // 得到最后一个有效的区段 return pScn + (dwScnCount - 1);}// 修复压缩后的区段void CMyPack::FixSection(){ // 获取区段数 DWORD dwScnCount = FileHeader(FileBase)->NumberOfSections; // 获取区段头 auto pScn = IMAGE_FIRST_SECTION(NTHeader(FileBase)); // 获取文件对其力度 DWORD nFileAligment = OptHeader(FileBase)->FileAlignment; // 循环 for (DWORD i = 0; i < dwScnCount - 1; i++) { // 如果有文件内容 if (pScn->PointerToRawData) { // 对其 DWORD nSectionAligment = Aligment(pScn->SizeOfRawData, nFileAligment); // 下一个区段 IMAGE_SECTION_HEADER* pTempScn = pScn + 1; // 下一个区段的大小 DWORD nTempDataSize = pTempScn->SizeOfRawData; // 申请新的空间 CHAR *nTempData = new CHAR[nTempDataSize]{}; // 先保存下一个区段的内容 memcpy_s(nTempData, nTempDataSize,(BYTE*)(FileBase + pTempScn->PointerToRawData), nTempDataSize); // 根据新的力度重新定位下个区段的位置 pTempScn->PointerToRawData = pScn->PointerToRawData + nSectionAligment; // 把刚刚保存的下个区段的内容还原 memcpy_s((BYTE*)(FileBase + pTempScn->PointerToRawData), nTempDataSize, nTempData, nTempDataSize); // 释放 delete[]nTempData; } // 下一个段 pScn++; } // 获取最后一个区段位置 pScn = GetLastSection(); // 计算出新的文件大小 FileSize = pScn->PointerToRawData + pScn->SizeOfRawData;}
CMypack.h
#include <windows.h>#include "MFCShellDlg.h"struct ShareData{ DWORD OldOEP = 0; BYTE XorKey = 0; DWORD XorRVA = 0; DWORD XorSize = 0; DWORD RelocRVA = 0; DWORD ImageBase = 0; DWORD ImportRVA = 0; DWORD TlsRVA = 0; DWORD PackRVA = 0; DWORD PackSize = 0; bool HideTLS = true;};class CMyPack{private: // 文件相关的属性 DWORD FileSize = 0; DWORD FileBase = 0; // Stub 相关的属性 DWORD StubBase = 0; DWORD StartOffset = 0; ShareData* StubData = nullptr;private: // 获取各种头的函数 PIMAGE_DOS_HEADER DosHeader(DWORD Base); PIMAGE_NT_HEADERS NTHeader(DWORD Base); PIMAGE_FILE_HEADER FileHeader(DWORD Base); PIMAGE_OPTIONAL_HEADER OptHeader(DWORD Base); // 将传入的数值对齐到指定力度的倍数 DWORD Aligment(DWORD Item, DWORD Align); // 获取指定名称的区段头表地址 PIMAGE_SECTION_HEADER GetSection(DWORD Base, LPCSTR Name);public: // 加载一个 PE 文件 void LoadFile(LPCSTR FileName); // 加载一个 PE 文件 void LoadStub(LPCSTR FileName); // 拷贝区段,从 stub 拷贝 SrcName 区段到 exe 中并命名为 DestName void CopySection(LPCSTR DestName, LPCSTR SrcName); // 拷贝区段的内容,需要指定区段的名称 void CopySectionData(LPCSTR DestName, LPCSTR SrcName); // 保存修改后的 PE 文件 void SaveFile(LPCSTR NewName); // 设置入口点为新区段中的 start 的位置(RVA) void SetOep(); // 修复壳代码的重定位 void FixRealoc(); // 异或指定区段的数据 void XorFileSection(LPCSTR SectionName); // 清除一些表项 void ClearDataDir(); // 压缩代码 void PackCode(LPCSTR SectionName); // 修复压缩后的区段 void FixSection(); // 获取最后一个段 IMAGE_SECTION_HEADER * GetLastSection();};
my_stub
main.cpp
#include <windows.h>#include "header.h"// 将 .data 和 .rdata 合并到 .text 区域#pragma comment(linker, "/merge:.data=.text") #pragma comment(linker, "/merge:.rdata=.text")// 并且设置 .text 区属性为壳读壳写壳执行#pragma comment(linker, "/section:.text,RWE")#include "aplib.h"#pragma comment(lib,"aPlib.lib")DWORD g_Bass = 0;#define STATIC_TIP 0x999#define EDIT_PASSWORD 0x1000#define BUTTON_OK 0x1001#define Process32First Process32FirstW#define Process32Next Process32NextW#define PROCESSENTRY32 PROCESSENTRY32W#define PPROCESSENTRY32 PPROCESSENTRY32W#define LPPROCESSENTRY32 LPPROCESSENTRY32W// 获取各种头的函数PIMAGE_DOS_HEADER DosHeader(DWORD Base){ return (PIMAGE_DOS_HEADER)Base;}PIMAGE_NT_HEADERS NTHeader(DWORD Base){ return (PIMAGE_NT_HEADERS)(Base + DosHeader(Base)->e_lfanew);}PIMAGE_FILE_HEADER FileHeader(DWORD Base){ return &NTHeader(Base)->FileHeader;}PIMAGE_OPTIONAL_HEADER OptHeader(DWORD Base){ return &NTHeader(Base)->OptionalHeader;}// 获取函数地址DWORD MyGetProcAddress(DWORD Module, LPCSTR FunName){ // 获取 Dos 头和 Nt 头 auto DosHeader = (PIMAGE_DOS_HEADER)Module; auto NtHeader = (PIMAGE_NT_HEADERS)(Module + DosHeader->e_lfanew); // 获取导出表结构 DWORD ExportRva = NtHeader->OptionalHeader.DataDirectory[0].VirtualAddress; auto ExportTable = (PIMAGE_EXPORT_DIRECTORY)(Module + ExportRva); // 找到导出名称表、序号表、地址表 auto NameTable = (DWORD*)(ExportTable->AddressOfNames + Module); auto FuncTable = (DWORD*)(ExportTable->AddressOfFunctions + Module); auto OrdinalTable = (WORD*)(ExportTable->AddressOfNameOrdinals + Module); // 遍历找名字 for (DWORD i = 0; i < ExportTable->NumberOfNames; ++i) { // 获取名字 char* Name = (char*)(NameTable[i] + Module); if (!strcmp(Name, FunName)) return FuncTable[OrdinalTable[i]] + Module; } return -1;}// 跳转到 OEP_declspec(naked) void JmpOep(){ __asm { mov eax, StubData.OldOEP; 原始 OEP 的RVA mov ebx, dword ptr FS : [0x30]; PEB mov ebx, dword ptr[ebx + 0x08]; 当前加载基址 add eax, ebx; 计算出 OEP // 花指令1 push ebp mov ebp, esp push - 1 push 111111 push 222222 mov ebx, fs:[0] push eax mov fs : [0], esp pop ebx mov fs : [0], eax pop ebx pop ebx pop ebx pop ebx mov ebp, eax // 花指令2 nop nop nop nop nop nop push ebp mov ebp, esp inc ecx push edx nop pop edx dec ecx pop ebp inc ecx mov eax,eax //原入口地址 jmp eax //jmp eax; 跳转 OEP }}// 获取KernelBase_declspec(naked) DWORD GetKernelBase(){ __asm { // 按照加载顺序 mov eax, dword ptr fs : [0x30] mov eax, dword ptr[eax + 0x0C] mov eax, dword ptr[eax + 0x0C] mov eax, dword ptr[eax] mov eax, dword ptr[eax] mov eax, dword ptr[eax + 0x18] ret }}// 解密数据void XorData(){ DWORD ImageBase = 0, OldProtect = 0; __asm { mov ebx, dword ptr FS : [0x30]; PEB mov ebx, dword ptr[ebx + 0x08]; 当前加载基址 mov ImageBase, ebx } // 获取到被加密区段的起始位置 BYTE* Data = (BYTE*)(ImageBase + StubData.XorRVA); pVirtualProtect(Data, StubData.XorSize, PAGE_READWRITE, &OldProtect); // 循环进行解密 for (DWORD i = 0; i < StubData.XorSize; ++i) Data[i] ^= StubData.XorKey; pVirtualProtect(Data, StubData.XorSize, OldProtect, &OldProtect);}// 获取所有想要使用的函数void GetApis(){ pVirtualProtect = (fnVirtualProtect)MyGetProcAddress(GetKernelBase(), "VirtualProtect"); pLoadLibraryExA = (fnLoadLibraryExA)MyGetProcAddress(GetKernelBase(), "LoadLibraryExA"); // 获取User32.dll HMODULE GetUser32=pLoadLibraryExA("User32.dll", 0, 0); DWORD dwUser32 = (DWORD)GetUser32; pCreateWindowExA = (fnCreateWindowExA)MyGetProcAddress(dwUser32, "CreateWindowExA"); pRegisterClassA = (fnRegisterClassA)MyGetProcAddress(dwUser32, "RegisterClassA"); pShowWindow = (fnShowWindow)MyGetProcAddress(dwUser32, "ShowWindow"); pExitProcess = (fnExitProcess)MyGetProcAddress(GetKernelBase(), "ExitProcess"); pDefWindowProcA = (fnDefWindowProcA)MyGetProcAddress(dwUser32, "DefWindowProcA"); pGetStockObject = (fnGetStockObject)MyGetProcAddress(dwUser32, "GetStockObject"); pGetMessageA = (fnGetMessageA)MyGetProcAddress(dwUser32, "GetMessageA"); pTranslateMessage = (fnTranslateMessage)MyGetProcAddress(dwUser32, "TranslateMessage"); pDispatchMessageA = (fnDispatchMessageA)MyGetProcAddress(dwUser32, "DispatchMessageA"); pMessageBoxW = (fnMessageBoxW)MyGetProcAddress(dwUser32, "MessageBoxW"); pGetDlgItem = (fnGetDlgItem)MyGetProcAddress(dwUser32, "GetDlgItem"); pGetWindowTextA = (fnGetWindowTextA)MyGetProcAddress(dwUser32, "GetWindowTextA"); pGetWindowTextW = (fnGetWindowTextW)MyGetProcAddress(dwUser32, "GetWindowTextW"); pMessageBoxA = (fnMessageBoxA)MyGetProcAddress(dwUser32, "MessageBoxA"); pPostQuitMessage = (fnPostQuitMessage)MyGetProcAddress(dwUser32, "PostQuitMessage"); pGetModuleHandleA = (fnGetModuleHandleA)MyGetProcAddress(GetKernelBase(), "GetModuleHandleA"); pGetProcAddress = (fnGetProcAddress)MyGetProcAddress(GetKernelBase(), "GetProcAddress"); pVirtualAlloc = (fnVirtualAlloc)MyGetProcAddress(GetKernelBase(), "VirtualAlloc"); HMODULE GetNtdll = pLoadLibraryExA("ntdll.dll", 0, 0); DWORD dwNtdll = (DWORD)GetNtdll; pNtQueryInformationProcess = (fnNtQueryInformationProcess)MyGetProcAddress(dwNtdll, "NtQueryInformationProcess"); pGetCurrentProcess = (fnGetCurrentProcess)MyGetProcAddress(GetKernelBase(), "GetCurrentProcess"); pVirtualFree = (fnVirtualFree)MyGetProcAddress(GetKernelBase(), "VirtualFree"); pRtlZeroMemory = (fnRtlZeroMemory)MyGetProcAddress(GetKernelBase(), "RtlZeroMemory"); pRtlMoveMemory = (fnRtlMoveMemory)MyGetProcAddress(GetKernelBase(), "RtlMoveMemory"); pCreateToolhelp32Snapshot = (fnCreateToolhelp32Snapshot)MyGetProcAddress(GetKernelBase(), "CreateToolhelp32Snapshot"); pProcess32FirstW = (fnProcess32FirstW)MyGetProcAddress(GetKernelBase(), "Process32FirstW"); pProcess32NextW = (fnProcess32NextW)MyGetProcAddress(GetKernelBase(), "Process32NextW"); pCloseHandle = (fnCloseHandle)MyGetProcAddress(GetKernelBase(), "CloseHandle"); }// 获取当前加载基址void GetPeModuleHandle(){ __asm { mov eax, FS:[0x30] mov eax, [eax + 0xc] mov eax, [eax + 0xc] mov eax, [eax + 0x18] mov g_Bass, eax; }}//窗口回调函数LRESULT CALLBACK WNDMYPROC(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ WORD wHigh = HIWORD(wParam); WORD wLow = LOWORD(wParam); // 分配消息 switch (uMsg) { case WM_CLOSE:{pExitProcess(0);}break; case WM_COMMAND: { switch (wLow) { case BUTTON_OK:{ // 获取输入框内字符串 HWND hEdit=pGetDlgItem(hWnd, EDIT_PASSWORD); CHAR nBuff[MAX_PATH] = {0}; pGetWindowTextA(hEdit, nBuff, MAX_PATH); if (!strcmp(nBuff,"1515")) { pMessageBoxA(0, "密码正确", "密码正确", 0); pShowWindow(hWnd, SW_HIDE); pPostQuitMessage(0); } else { pMessageBoxA(0, "密码错误,请重新输入", "密码错误", 0); } }break; } break; }break; } return pDefWindowProcA(hWnd, uMsg, wParam, lParam); }// 显示输入密码对话框 void ShowMyDialog(){ // 注册窗口类 WNDCLASSA wc = { 0 }; wc.lpszClassName = "Password"; wc.lpfnWndProc = &WNDMYPROC; //wc.hbrBackground = (HBRUSH)pGetStockObject(WHITE_BRUSH); pRegisterClassA(&wc); // 创建窗口 HWND hWnd = NULL; hWnd=pCreateWindowExA(0,"Password","CheckPassWord",WS_OVERLAPPEDWINDOW,600,300,180,200,0,0,(HINSTANCE)g_Bass,0); // 设置子窗口信息 pCreateWindowExA(0, "Edit", "请输入密码:", SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 20, 20, 120, 30, hWnd, (HMENU)STATIC_TIP, (HINSTANCE)g_Bass, NULL); pCreateWindowExA(WS_EX_CLIENTEDGE, "Edit", "", ES_NUMBER | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 20, 50, 120, 30, hWnd, (HMENU)EDIT_PASSWORD, (HINSTANCE)g_Bass, NULL); pCreateWindowExA(0, "Button", "确认密码", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 20, 100, 120, 30, hWnd, (HMENU)BUTTON_OK, (HINSTANCE)g_Bass, NULL); // 显示窗口 pShowWindow(hWnd, SW_SHOW); // 分配消息 MSG msg = { 0 }; while (pGetMessageA(&msg, 0, 0, 0)) { pTranslateMessage(&msg); pDispatchMessageA(&msg); } } //修复被加壳重定位 void FixReloc() { DWORD ImageBase = (DWORD)pGetModuleHandleA(NULL); DWORD OldProtect = 0; auto RealocTable = (PIMAGE_BASE_RELOCATION)(ImageBase+ StubData.RelocRVA); // 遍历重定位表,重定位表以一个空表结尾 while (RealocTable->SizeOfBlock) { // 获取重定位项,并依次修复重定位项 auto Item = (TypeOffset*)(RealocTable + 1); // 获取到重定位项的个数 DWORD Count = (RealocTable->SizeOfBlock - 8) / 2; // 遍历重定位项并修复 for (DWORD i = 0; i < Count; ++i) { // 修改整个分页的属性,使它能够被写入 pVirtualProtect((LPVOID)(RealocTable->VirtualAddress + ImageBase), 0x1000, PAGE_READWRITE, &OldProtect); // 只需要关注 type == 3 的类型 if (Item[i].Type == 3) { // 需要重定位的数据所在的地址 Base + RVA + Offset DWORD* ItemAddr = (DWORD*)(ImageBase + RealocTable->VirtualAddress + Item[i].Offset); // 计算出新的 VA *ItemAddr = *ItemAddr - 0x400000 + ImageBase; } // 还原属性 pVirtualProtect((LPVOID)(RealocTable->VirtualAddress + ImageBase), 0x1000, OldProtect, &OldProtect); } // 找到下一个重定位块 RealocTable = (PIMAGE_BASE_RELOCATION)((DWORD)RealocTable + RealocTable->SizeOfBlock); } } // 未加密修复导入表// void FixImport()// {// char shellcode[] = { "\x68\x63\xE9\x8C\xC3\xC3" };// LPVOID Addr = pVirtualAlloc(NULL, 0X1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);// DWORD ImageBase = (DWORD)pGetModuleHandleA(NULL), OldProtect = 0;// auto ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + StubData.ImportRVA);// // // 循环,以0结尾// while (ImportTable->Name)// {// // 获取模块名称,根据名称调用loadlibrary// char* Name = (char*)(ImageBase + ImportTable->Name);// HMODULE Module = pLoadLibraryExA(Name,0,0);// // 根据IAT内保存的名字修复IAT// auto Iat = (PIMAGE_THUNK_DATA)(ImportTable->FirstThunk + ImageBase);// for (int i=0;Iat[i].u1.Function!=0;++i)// {// LPCSTR FuncName = nullptr;// // 判断当前的函数是否有名称// if (IMAGE_SNAP_BY_ORDINAL32(Iat[i].u1.Ordinal))// {// FuncName = (LPCSTR)IMAGE_ORDINAL32(Iat[i].u1.Ordinal);// // }// else// {// FuncName = ((PIMAGE_IMPORT_BY_NAME)(Iat[i].u1.AddressOfData + ImageBase))->Name;// }// // // 获取到函数地址// DWORD FunAddr = (DWORD)pGetProcAddress(Module, FuncName);// // // 生成新的shellcode// *(DWORD*)& shellcode[1] = FunAddr;// memcpy(Addr, shellcode, 12);// pVirtualProtect((LPVOID)((DWORD)&Iat[i]&0xFFFFF000), 0x1000, PAGE_READWRITE, &OldProtect);// // // 修复到IAT// Iat[i].u1.Function = (DWORD)Addr;// pVirtualProtect((LPVOID)((DWORD)&Iat[i]&0xFFFFF000), 0x1000, OldProtect, &OldProtect);// Addr = (LPVOID)((DWORD)Addr + 6);// }// ImportTable++;// }// } // 将传入的数值对齐到指定力度的倍数 DWORD Aligment(DWORD Item, DWORD Align) { // 35000 % 1000 != 0 -> (3500 / 1000 + 1)*1000 return Item % Align ? (Item / Align + 1)*Align : Item; } // 加密修复导入表 void FixImport() { // char shellcode[] = { "\x68\x63\xE9\x8C\xC3\xC3" }; // LPVOID Addr = pVirtualAlloc(NULL, 0X1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); DWORD ImageBase = (DWORD)pGetModuleHandleA(NULL), OldProtect = 0; auto ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(ImageBase + StubData.ImportRVA); // 循环,以0结尾 while (ImportTable->Name) { // 获取模块名称,根据名称调用loadlibrary char* Name = (char*)(ImageBase + ImportTable->Name); HMODULE Module = pLoadLibraryExA(Name, 0, 0); // 根据IAT内保存的名字修复IAT auto Iat = (PIMAGE_THUNK_DATA)(ImportTable->FirstThunk + ImageBase); for (int i = 0; Iat[i].u1.Function != 0; ++i) { LPCSTR FuncName = nullptr; // 判断当前的函数是否有名称 if (IMAGE_SNAP_BY_ORDINAL32(Iat[i].u1.Ordinal)) { FuncName = (LPCSTR)IMAGE_ORDINAL32(Iat[i].u1.Ordinal); } else { FuncName = ((PIMAGE_IMPORT_BY_NAME)(Iat[i].u1.AddressOfData + ImageBase))->Name; } // 获取到函数地址 DWORD dwFunAddr = (DWORD)pGetProcAddress(Module, FuncName); // **加密函数地址** dwFunAddr ^= 0x13973575; LPVOID Addr = (PDWORD)pVirtualAlloc(NULL, 0x20, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //构造一段花指令解密的ShellCode byte shellcode[] = { 0xe8, 0x01, 0x00, 0x00, 0x00, 0xe9, 0x58, 0xeb, 0x01, 0xe8, 0xb8, 0x8d, 0xe4, 0xd8, 0x62, 0xeb, 0x01, 0x15, 0x35, 0x75, 0x35, 0x97, 0x13, 0xeb, 0x01, 0xff, 0x50, 0xeb, 0x02, 0xff, 0x15, 0xc3 }; //把dwFunAddr写入到解密的ShellCode中 shellcode[11] = dwFunAddr; shellcode[12] = dwFunAddr >> 0x8; shellcode[13] = dwFunAddr >> 0x10; shellcode[14] = dwFunAddr >> 0x18; //拷贝数据到申请的内存 memcpy(Addr, shellcode, 0x20); //修改保护属性 pVirtualProtect((LPVOID)((DWORD)&Iat[i] & 0xFFFFF000), 0x1000, PAGE_READWRITE, &OldProtect); //把获取到的加密函数地址填充在导入地址表里面 Iat[i].u1.Function = (DWORD)Addr; pVirtualProtect((LPVOID)((DWORD)&Iat[i] & 0xFFFFF000), 0x1000, OldProtect, &OldProtect); } ImportTable++; } } // 反调试 bool NQIP_ProcessDebugPort() { int nDebugPort = 0; pNtQueryInformationProcess( pGetCurrentProcess(),//目标进程句柄 ProcessDebugPort, //查询信息的类型 &nDebugPort, //输出查询的信息 sizeof(nDebugPort), //查询类型的大小 NULL); return nDebugPort == 0xFFFFFFFF ? true : false; } // 判断是否被调试 void IsBeingDebug() { if (NQIP_ProcessDebugPort()) { pMessageBoxA(0, "正在被调试", 0, 0); return ; } } // 调用Tls void CallTls() { DWORD ImageBase = (DWORD)pGetModuleHandleA(NULL), OldProtect = 0; auto TlsTable = (PIMAGE_TLS_DIRECTORY)(ImageBase + StubData.TlsRVA); if (StubData.HideTLS==true) { pMessageBoxA(0, "未发现", "TLS", 0); return; } DWORD dwTlsCallBack = *(DWORD*)TlsTable->AddressOfCallBacks; __asm { cmp dwTlsCallBack, 0 je ENDCALL push 0 push 1 push ImageBase call dwTlsCallBack ENDCALL: } pMessageBoxA(0, "成功调用", "TLS", 0); } // 解压 void UpackCode() { // 获取到第一个代码段 DWORD ImageBase = (DWORD)pGetModuleHandleA(NULL); DWORD dwScnCount = FileHeader(ImageBase)->NumberOfSections; auto pScn = IMAGE_FIRST_SECTION(NTHeader(ImageBase)); for (DWORD i = 0; i < dwScnCount-2 ; i++) { // 如果代码段里有数据 if (pScn->SizeOfRawData) { // 定位到压缩代码的位置 char *nSectionByte = (char*)(pScn->VirtualAddress + (DWORD)ImageBase); // 区段的大小 DWORD nPackSize = pScn->SizeOfRawData; // 获取到被压缩代码的大小 size_t nUPackSize = aPsafe_get_orig_size(nSectionByte); // 申请被压缩代码大小的空间用来存储数据 char *nUPackData = (char*)pVirtualAlloc(NULL, nUPackSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 解压数据,返回解压完大小。(1.源文件地址,区段大小,存放的目的文件地址,压缩代码大小) nPackSize = aPsafe_depack(nSectionByte, nPackSize, nUPackData, nUPackSize); DWORD nOldProtect = 0; // 更改页属性 pVirtualProtect((char*)((DWORD)nSectionByte & 0xfffff000), pScn->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &nOldProtect); // 清空原本区段内容 memset(nSectionByte, 0, nPackSize); //pRtlZeroMemory(nSectionByte, nPackSize); // 拷贝解压完的内容到原本位置 memcpy(nSectionByte, nUPackData, nUPackSize); //pRtlMoveMemory(nSectionByte, nUPackData, nUPackSize); pVirtualProtect((char*)((DWORD)nSectionByte & 0xfffff000), pScn->Misc.VirtualSize, nOldProtect, &nOldProtect); //释放 pVirtualFree(nUPackData, nUPackSize, MEM_RELEASE); // 更改页属性 pVirtualProtect((LPVOID)ImageBase, 0x1000, PAGE_EXECUTE_READWRITE, &nOldProtect); //更新代码段大小 pScn->SizeOfRawData = nUPackSize; // 更改页属性 pVirtualProtect((LPVOID)ImageBase, 0x1000, nOldProtect, &nOldProtect); } pScn++; } } // 反虚拟机 void AntiVMare() { //保存进程信息 PROCESSENTRY32 ProcInfo; ProcInfo.dwSize = sizeof(ProcInfo); //进程快照 HANDLE hProcessSnap = pCreateToolhelp32Snapshot(0x00000002, 0); //遍历所有快照 BOOL FindFlags = pProcess32FirstW(hProcessSnap, &ProcInfo); while (FindFlags) { WCHAR target[] = L"vmtoolsd.exe"; //虚拟机标志 int flags = 0; //比较 if (!wcscmp(target, ProcInfo.szExeFile)) { flags = true; } //如果存在指定名称的进程,则结束 if (flags) { pMessageBoxA(0, "发现虚拟机", "虚拟机", 0); pExitProcess(0); } else { FindFlags = pProcess32NextW(hProcessSnap, &ProcInfo); } } //关闭句柄 pMessageBoxA(0, "未发现虚拟机", "虚拟机", 0); pCloseHandle(hProcessSnap); }// 导出且是一个裸函数,不会自动生成代码_declspec(dllexport) _declspec(naked) void start(){ // 获取所需函数 GetApis(); // 是否被调试 IsBeingDebug(); // 反虚拟机 AntiVMare();// 弹出密码框 ShowMyDialog(); // 解压 UpackCode(); // 开始解密 XorData(); // 修复被加壳重定位 FixReloc(); // 修复导入表 FixImport(); // 调用TLS CallTls(); // 跳回OEP JmpOep();}
header.h
#include <windows.h>typedef struct tagPROCESSENTRY32W{ DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; // this process ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; // associated exe DWORD cntThreads; DWORD th32ParentProcessID; // this process's parent process LONG pcPriClassBase; // Base priority of process's threads DWORD dwFlags; WCHAR szExeFile[MAX_PATH]; // Path} PROCESSENTRY32W;typedef PROCESSENTRY32W * PPROCESSENTRY32W;typedef PROCESSENTRY32W * LPPROCESSENTRY32W;// 查询调式用typedef enum _PROCESSINFOCLASS { ProcessBasicInformation = 0, ProcessDebugPort = 7, ProcessWow64Information = 26, ProcessImageFileName = 27, ProcessBreakOnTermination = 29} PROCESSINFOCLASS;// 提供一个结构体,这里的数据应该由加壳器填充struct ShareData{ DWORD OldOEP = 0; BYTE XorKey = 0; DWORD XorRVA = 0; DWORD XorSize = 0; DWORD RelocRVA = 0; DWORD ImageBase = 0; DWORD ImportRVA = 0; DWORD TlsRVA = 0; DWORD PackRVA = 0; DWORD PackSize = 0; bool HideTLS = true;};struct TypeOffset{ WORD Offset : 12; WORD Type : 4;};extern "C"{ // 导出这个结构体的一个变量,提供给加壳器 _declspec(dllexport) ShareData StubData; // 导出且是一个裸函数,不会自动生成代码 _declspec(dllexport) void start();}typedef BOOL(WINAPI* fnVirtualProtect)( _In_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flNewProtect, _Out_ PDWORD lpflOldProtect );fnVirtualProtect pVirtualProtect;typedef HWND (WINAPI* fnCreateWindowExA)( _In_ DWORD dwExStyle, _In_opt_ LPCSTR lpClassName, _In_opt_ LPCSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam);fnCreateWindowExA pCreateWindowExA;typedef ATOM (WINAPI * fnRegisterClassA)( _In_ CONST WNDCLASSA *lpWndClass);fnRegisterClassA pRegisterClassA;typedef BOOL (WINAPI* fnShowWindow)( _In_ HWND hWnd, _In_ int nCmdShow);fnShowWindow pShowWindow;typedef VOID (WINAPI* fnExitProcess)( _In_ UINT uExitCode);fnExitProcess pExitProcess;typedef LRESULT(WINAPI*fnDefWindowProcA)( _In_ HWND hWnd, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam);fnDefWindowProcA pDefWindowProcA;typedef HMODULE (WINAPI*fnLoadLibraryExA)( _In_ LPCSTR lpLibFileName, _Reserved_ HANDLE hFile, _In_ DWORD dwFlags);fnLoadLibraryExA pLoadLibraryExA;typedef HGDIOBJ (WINAPI* fnGetStockObject)(_In_ int i);fnGetStockObject pGetStockObject;typedef BOOL (WINAPI* fnGetMessageA)( _Out_ LPMSG lpMsg, _In_opt_ HWND hWnd, _In_ UINT wMsgFilterMin, _In_ UINT wMsgFilterMax);fnGetMessageA pGetMessageA;typedef BOOL(WINAPI* fnTranslateMessage)( _In_ CONST MSG *lpMsg);fnTranslateMessage pTranslateMessage;typedef LRESULT(WINAPI*fnDispatchMessageA)( _In_ CONST MSG *lpMsg);fnDispatchMessageA pDispatchMessageA;typedef int (WINAPI* fnMessageBoxW)( _In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);fnMessageBoxW pMessageBoxW;typedef int (WINAPI*fnMessageBoxA)( _In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType);fnMessageBoxA pMessageBoxA;typedef HWND (WINAPI*fnGetDlgItem)( _In_opt_ HWND hDlg, _In_ int nIDDlgItem);fnGetDlgItem pGetDlgItem;typedef int(WINAPI* fnGetWindowTextA)( _In_ HWND hWnd, _Out_writes_(nMaxCount) LPSTR lpString, _In_ int nMaxCount);fnGetWindowTextA pGetWindowTextA;typedef int (WINAPI*fnGetWindowTextW)( _In_ HWND hWnd, _Out_writes_(nMaxCount) LPWSTR lpString, _In_ int nMaxCount);fnGetWindowTextW pGetWindowTextW;typedef VOID (WINAPI* fnPostQuitMessage)( _In_ int nExitCode);fnPostQuitMessage pPostQuitMessage;typedef HMODULE(WINAPI*fnGetModuleHandleA)( _In_opt_ LPCSTR lpModuleName);fnGetModuleHandleA pGetModuleHandleA;typedef FARPROC (WINAPI* fnGetProcAddress)( _In_ HMODULE hModule, _In_ LPCSTR lpProcName);fnGetProcAddress pGetProcAddress;typedef LPVOID(WINAPI*fnVirtualAlloc)( _In_opt_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flAllocationType, _In_ DWORD flProtect);fnVirtualAlloc pVirtualAlloc;typedef NTSTATUS(NTAPI*fnNtQueryInformationProcess)( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL);fnNtQueryInformationProcess pNtQueryInformationProcess;typedef HANDLE(WINAPI* fnGetCurrentProcess)( VOID);fnGetCurrentProcess pGetCurrentProcess;typedef LPVOID(WINAPI* fnVirtualFree)(LPVOID, SIZE_T, DWORD);fnVirtualFree pVirtualFree;typedef VOID(WINAPI* fnRtlZeroMemory)(LPVOID, SIZE_T);fnRtlZeroMemory pRtlZeroMemory;typedef VOID(WINAPI* fnRtlMoveMemory)(LPVOID, LPVOID, SIZE_T);fnRtlMoveMemory pRtlMoveMemory;typedef HANDLE (WINAPI* fnCreateToolhelp32Snapshot)( DWORD dwFlags, DWORD th32ProcessID);fnCreateToolhelp32Snapshot pCreateToolhelp32Snapshot;typedef BOOL(WINAPI*fnProcess32FirstW)( HANDLE hSnapshot, LPPROCESSENTRY32W lppe);fnProcess32FirstW pProcess32FirstW;typedef BOOL(WINAPI*fnProcess32NextW)( HANDLE hSnapshot, LPPROCESSENTRY32W lppe);fnProcess32NextW pProcess32NextW;typedef BOOL(WINAPI*fnCloseHandle)( _In_ HANDLE hObject);fnCloseHandle pCloseHandle;