衡水企业网站建设费用,姜堰网页定制,杭州市建设工程造价管理协会网站,做购物微信网站Virtual Machine Protect. 虚拟机保护 #xff0c;可以将汇编指令转化为自定义指令集#xff0c;虚拟指令涉及上百万条汇编指令#xff0c;极大增强pj难度。由win版本的和linux#xff0c;安卓版本的。他们的软件实现方法和厂家都不一样#xff0c;但是原理相同。win具体的…Virtual Machine Protect. 虚拟机保护 可以将汇编指令转化为自定义指令集虚拟指令涉及上百万条汇编指令极大增强pj难度。由win版本的和linux安卓版本的。他们的软件实现方法和厂家都不一样但是原理相同。win具体的软件由pmvrotect2.x 3.x 3.5。vmp加密时只是对之前的so进行新增加密节区不修改节区。pmvrotect2软件加密的手段有很多最著名的是vmp技术。包含 指令虚拟化导入表加密反调试反dump指令和数据压缩vmpdumper可以脱出汇编代码但是不能修复vmp节区和导出表加密字符串。需要手动修复。导入表IAT不能修复代码压缩 (Packing)原理压缩代码段text原始PE结构:├─ .text (500KB) - 可执行代码├─ .data (100KB) - 数据└─ .rsrc (200KB) - 资源↓ 压缩后 ↓├─ .vmp0 (150KB) - 压缩的代码解压stub├─ .vmp1 (80KB) - 压缩的数据└─ .rsrc (200KB)运行时1. 解压.vmp0到内存2. 修复重定位3. 跳转执行压缩算法LZMA/自定义强度★★主要用途减小体积附带混淆效果代码虚拟化 (Virtualization) ⭐最强原理将x86指令转换为自定义虚拟机指令转换示例asm; 原始代码mov eax, 5add eax, 3ret; ↓ 虚拟化后 ↓push offset vm_bytecode ; VM字节码call vm_interpreter ; 调用VM解释器ret; vm_bytecode (自定义指令):; 0x45 0x05 0x00 0x00 0x00 ; VM_MOV eax, 5; 0x12 0x03 0x00 0x00 0x00 ; VM_ADD eax, 3; 0xFF ; VM_RETC代码示例C// 原始int add(int a, int b) {return a b;}// SDK标记#include VMProtectSDK.hint add(int a, int b) {VMProtectBeginVirtualization(Add);return a b;VMProtectEnd();}强度★★★★★性能损耗5-20倍代码变异 (Mutation/Obfuscation)原理用等价但复杂的指令替换原指令转换示例asm; 原始mov eax, 5; ↓ 变异后 ↓push 2push 3pop ecxpop edxlea eax, [ecxedx] ; 实际还是5; 或者xor eax, eaxadd eax, 3inc eaxinc eax ; 仍是5但复杂化典型变异技术asm; 1. 指令替换mov eax, 0 → xor eax, eax; 2. 花指令插入nopjmp $1db 0xE8 ; 无效字节add eax, ebx; 3. 寄存器替换mov eax, 5 → mov ebx, 5mov eax, ebx; 4. 常量加密mov eax, 100 → mov eax, 0x12345678xor eax, 0x123456DC ; 100强度★★★★性能损耗1.5-3倍导入表加密导入表保护 (Import Protection)原理隐藏真实的API调用转换示例C; 原始导入表IMPORT TABLE:kernel32.dll- CreateFileA- ReadFile; ↓ 保护后 ↓IMPORT TABLE:kernel32.dll- LoadLibraryA ; 只保留最基础的; 运行时动态获取char* encrypted \x3F\x12\x7A...; // 加密的 CreateFileAdecrypt(encrypted);pCreateFile GetProcAddress(LoadLibrary(kernel32), decrypted);pCreateFile(...); // 调用代码对比C// 原始MessageBoxA(NULL, Hello, Test, 0);// 保护后伪代码typedef int (WINAPI *pMsgBox)(HWND, LPCSTR, LPCSTR, UINT);pMsgBox MyMsgBox vmp_get_api(0x1A3F); // 内部索引MyMsgBox(NULL, vmp_str(0x2B4C), vmp_str(0x3D5E), 0);强度★★★★绕过难度中等可API Hook监控call后面是加密的iat表image字符串加密 (String Encryption)原理加密所有字符串常量示例C// 原始const char* key MySecretKey123;if (strcmp(input, key) 0) { ... }// ↓ 加密后 ↓// 数据段存储.dataencrypted_str db 0xA3,0x7F,0x2B,0x9C,... ; 加密的字符串// 代码中char* key vmp_decrypt_string(0x004050A0);if (strcmp(input, key) 0) {vmp_free_string(key); // 用完立即清除}反调试 (Anti-Debug)技术清单C// 1. IsDebuggerPresentif (IsDebuggerPresent()) {ExitProcess(0);}// 2. PEB检测bool CheckDebug() {__asm {mov eax, fs:[0x30] // PEBmovzx eax, byte ptr [eax2] // BeingDebuggedtest eax, eax}}// 3. NtQueryInformationProcessBOOL isDebug FALSE;NtQueryInformationProcess(GetCurrentProcess(),ProcessDebugPort, isDebug, sizeof(BOOL), NULL);// 4. 时间检测DWORD t1 GetTickCount();// 一些代码DWORD t2 GetTickCount();if (t2 - t1 1000) { /* 被调试 */ }// 5. 硬件断点检测CONTEXT ctx {0};ctx.ContextFlags CONTEXT_DEBUG_REGISTERS;GetThreadContext(GetCurrentThread(), ctx);if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) {/* 检测到硬件断点 */}// 6. INT 3检测__try {__asm int 3} __except(EXCEPTION_EXECUTE_HANDLER) {// 正常程序会走这里}// 7. 检测调试器窗口if (FindWindow(OLLYDBG, NULL) ||FindWindow(WinDbgFrameClass, NULL)) {ExitProcess(0);}反虚拟机 (Anti-VM)检测技术C// 1. CPUID检测void CheckVM() {int cpuInfo[4];__cpuid(cpuInfo, 1);if (cpuInfo[2] (1 31)) {// Hypervisor bit setExitProcess(0);}}// 2. 特征文件检测if (PathFileExists(C:\\Windows\\System32\\drivers\\vmmouse.sys) ||PathFileExists(C:\\Windows\\System32\\drivers\\vmhgfs.sys)) {// VMware检测}// 3. 注册表检测HKEY hKey;if (RegOpenKey(HKEY_LOCAL_MACHINE,SOFTWARE\\VMware, Inc.\\VMware Tools, hKey) ERROR_SUCCESS) {// VMware}// 4. MAC地址检测// VMware前缀: 00:05:69, 00:0C:29, 00:50:56// VirtualBox前缀: 08:00:27// 5. 指令时间检测DWORD t1 __rdtsc();// 执行一些指令DWORD t2 __rdtsc();if (t2 - t1 threshold) { /* VM环境 */ }强度★★★绕过修改VM配置内存保护 (Memory Protection)原理检测内存完整性C// 1. CRC校验DWORD original_crc 0x12345678;DWORD current_crc calc_crc32(code_section, size);if (current_crc ! original_crc) {ExitProcess(0); // 代码被修改}// 2. 定期校验void __stdcall CheckThread(LPVOID param) {while (true) {Sleep(1000);if (!verify_memory()) {TerminateProcess(GetCurrentProcess(), 0);}}}// 3. 页面保护VirtualProtect(code_section, size, PAGE_EXECUTE_READ, old);// 任何写入会触发异常资源加密 (Resource Encryption)原理加密PE资源段C// 原始HRSRC hRes FindResource(NULL, MAKEINTRESOURCE(101), RT_BITMAP);HGLOBAL hData LoadResource(NULL, hRes);void* pData LockResource(hData);// ↓ 保护后 ↓// 资源段全部加密.rsrc section: [encrypted data]// 运行时HRSRC hRes FindResource(...);// VMProtect拦截LoadResourceHGLOBAL hData LoadResource(...); // 内部解密void* pData LockResource(hData); // 返回解密数据强度★★★效果防止资源提取工具直接读取应用VMProtect后简化示意C// 编译后的保护代码逆向视角.text:00401000 ; VMP Entry.text:00401000 push ebp.text:00401001 call vmp_init_2FA3C.text:00401006 jmp vm_dispatcher_1// 原始的main函数代码已经不存在// 被转换为.vmp0:00501000 db 0x4A, 0x8F, 0x23, ... ; VM字节码.vmp0:00501100 db 0x7C, 0x12, 0xAB, ....vmp1:00502000 ; VM解释器.vmp1:00502000 vm_handler_0:.vmp1:00502000 mov al, [esi].vmp1:00502002 inc esi.vmp1:00502003 movzx eax, al.vmp1:00502006 jmp [vm_table eax*4]// 字符串也被加密.data:00601000 encrypted_str1 db 0xA4,0x7F,0x9C,....data:00601020 encrypted_str2 db 0x3E,0x12,0x88,...// 导入表被隐藏.idata:00701000 ; 只剩下.idata:00701000 dd offset LoadLibraryA.idata:00701004 dd offset GetProcAddress保护强度对比表方法 反静态分析 反动态分析 性能影响 推荐场景Virtualization ★★★★★ ★★★★★ -90% 核心算法Mutation ★★★★ ★★★ -30% 一般函数Import Protection ★★★★ ★★ -5% 全局开启String Encryption ★★★ ★ -5% 敏感字符串Anti-Debug ★ ★★★★ -1% 全局开启Anti-VM ★ ★★★ -1% 可选Memory Protection ★★ ★★★★ -10% 全局开启Packing ★★ ★ 5% 减小体积虚拟指令、虚拟栈、虚拟寄存器。imagemsdn。开发文档windows程序设计windows核心编程win32汇编语言程序设计PE 文件结构图例text----------------------------------- -- 文件开始 (Offset 0)| IMAGE_DOS_HEADER ||-----------------------------------|| - e_magic: MZ (0x5A4D) | - DOS 可执行文件签名| - e_lfanew: 指向 NT 头部的偏移量 | - 这是通往 PE 头的关键指针-----------------------------------| DOS Stub Program | - 一小段 DOS 程序通常显示 This program cannot be run in DOS mode.----------------------------------- -- e_lfanew 指向的位置| IMAGE_NT_HEADERS || ----------------------------- || | Signature | || | - PE\0\0 (0x00004550) | | - PE 文件签名| ----------------------------- || | IMAGE_FILE_HEADER | || |-----------------------------| || | - Machine: (e.g., 0x8664) | | - 目标 CPU 架构 (如 x64)| | - NumberOfSections: | | - 后面跟着的节区数量| | - TimeDateStamp: | | - 链接时间戳| | - SizeOfOptionalHeader: | | - 下一个头的大小| | - Characteristics: | | - 文件属性 (如 DLL, Executable)| ----------------------------- || | IMAGE_OPTIONAL_HEADER | | - 对于操作系统加载器至关重要| |-----------------------------| || | - Magic: (e.g., 0x20B) | | - 标识 PE32(0x10B) 或 PE32(0x20B)| | - AddressOfEntryPoint: | | - 程序执行入口 RVA| | - ImageBase: | | - 映像的首选加载地址| | - SectionAlignment: | | - 内存中节区的对齐方式| | - FileAlignment: | | - 文件中节区的对齐方式| | - SizeOfImage: | | - 内存中整个映像的大小| | - SizeOfHeaders: | | - 所有头部的总大小| | - Subsystem: (e.g., GUI/CUI) | | - 要求子系统 (如 Windows GUI)| | - NumberOfRvaAndSizes: | | - 数据目录项的数量| |-----------------------------| || | IMAGE_DATA_DIRECTORY | | - 一个结构体数组| | [0] Export Directory | || | [1] Import Directory | | - 指向导入函数信息| | [2] Resource Directory | | - 指向资源 (图标、字符串等)| | [3] Exception Directory | || | ... (共 16 个) ... | || ----------------------------- |-----------------------------------| IMAGE_SECTION_HEADER[0] | - 第一个节区头 (如 .text)| - Name: .text\0\0\0 | - 节区名称| - VirtualAddress: | - 内存中的 RVA| - SizeOfRawData: | - 在文件中的大小| - PointerToRawData: | - 在文件中的偏移| - Characteristics: | - 节区属性 (如 可执行、可读)-----------------------------------| IMAGE_SECTION_HEADER[1] | - 第二个节区头 (如 .data)| - Name: .data\0\0\0 || - ... |-----------------------------------| ... | - 其他节区头 (共 NumberOfSections 个)----------------------------------- -- SizeOfHeaders 标记的头部结束位置| 节区数据开始 || || .text 节区原始数据 | - 文件偏移由 PointerToRawData 指定| (存放代码) || || .data 节区原始数据 | - 文件偏移由 PointerToRawData 指定| (存放全局变量) || || .rsrc 节区原始数据 || (存放资源) || || ... |----------------------------------- -- 文件结束各组成部分的简明解释IMAGE_DOS_HEADER (DOS 头)目的为了保持与古老 DOS 系统的兼容性。关键成员e_lfanew 字段它包含了指向真正的 PE 头 (IMAGE_NT_HEADERS) 的文件偏移量。IMAGE_NT_HEADERS (NT 头)目的PE 文件的正式入口和核心描述符。包含三部分Signature一个 PE\0\0 的签名标识这是一个 PE 文件。IMAGE_FILE_HEADER (文件头)描述了文件的全局属性如目标机器类型、节区数量、创建时间等。IMAGE_OPTIONAL_HEADER (可选头)虽然叫可选但对于可执行文件是必需的。它包含了程序加载和运行所需的关键信息。IMAGE_OPTIONAL_HEADER (可选头)目的为操作系统加载器提供如何准备和执行程序的信息。关键成员入口点地址、映像基址、内存/文件对齐值、子系统等。它末尾的 IMAGE_DATA_DIRECTORY (数据目录) 是一个非常重要的表格它指出了其他重要数据结构如导入表、导出表、资源表在文件中的位置和大小。IMAGE_DATA_DIRECTORY (数据目录)目的作为指向其他重要数据的“目录”或“索引”。结构一个由16个相同结构组成的数组。每个结构包含一个 RVA相对虚拟地址 和 Size。例如第二个条目索引1是 Import Directory加载器通过它找到所有需要从其他DLL导入的函数列表。IMAGE_SECTION_HEADER (节区头)目的描述文件中的各个“节区”。节区是实际存储代码、数据、资源等内容的部分。数量由 IMAGE_FILE_HEADER 中的 NumberOfSections 指定。关键成员Name节区名称如 .text, .data, .rdata。VirtualAddress该节区加载到内存后的 RVA。PointerToRawData该节区在磁盘文件中的原始数据偏移。Characteristics节区属性如可读、可写、可执行。总结与流程操作系统加载一个 PE 文件的简化流程如下读取 IMAGE_DOS_HEADER找到 e_lfanew。跳到 e_lfanew 位置验证 PE 签名读取 IMAGE_NT_HEADERS。从 IMAGE_FILE_HEADER 知道有多少个节区。从 IMAGE_OPTIONAL_HEADER 获取关键信息如入口点、映像大小、数据目录。遍历 IMAGE_SECTION_HEADER 数组了解每个节区在文件和内存中的映射关系。根据节区头的信息将文件的各个节区代码、数据等映射到内存的相应位置。通过 IMAGE_DATA_DIRECTORY 找到导入表解析并填充所有需要的外部函数地址。最后跳转到 AddressOfEntryPoint 指向的地址程序开始执行。这个结构确保了 PE 文件既能在磁盘上高效存储又能在内存中正确加载和执行。PE文件头结构图解 白话文秒懂 完整结构总览text┌─────────────────────────────────────────────────────────┐│ DOS Header (64字节) │ ← 开头的MZ标记│ 这是个老式DOS程序 的伪装外壳 │├─────────────────────────────────────────────────────────┤│ DOS Stub (可变) ││ This program cannot be run in DOS mode │ ← 在DOS下运行会看到的提示├─────────────────────────────────────────────────────────┤│ PE Signature (4字节) ││ PE\0\0 │ ← 真正的PE文件标记├─────────────────────────────────────────────────────────┤│ File Header (20字节) ││ 记录机器类型、节数量、时间戳等基本信息 │├─────────────────────────────────────────────────────────┤│ Optional Header (224/240字节) ││ 记录程序入口点、内存布局、导入导出等关键信息 │├─────────────────────────────────────────────────────────┤│ Section Table (每节40字节) ││ .text .data .rdata .rsrc 等节的目录 │├─────────────────────────────────────────────────────────┤│ ││ Section 1 (.text) │ ← 代码区│ 你写的代码在这里 ││ │├─────────────────────────────────────────────────────────┤│ Section 2 (.data) │ ← 数据区│ 全局变量在这里 │├─────────────────────────────────────────────────────────┤│ Section 3 (.rsrc) │ ← 资源区│ 图标、对话框、字符串在这里 │└─────────────────────────────────────────────────────────┘ 详细结构拆解1️⃣ DOS Header (IMAGE_DOS_HEADER)text偏移 大小 字段名 白话文解释0x00 2字节 e_magic MZ 标记0x5A4D—— 所有PE文件必须以这两个字母开头0x02 58字节 [其他DOS字段] 基本没用为了兼容古董DOS系统0x3C 4字节 e_lfanew **超重要** 指向真正的PE头在哪里白话这是个假门面为了让Windows程序能在老DOS系统上显示错误提示而不是直接崩溃。最重要的是最后那个 e_lfanew它告诉系统真正的PE头在文件偏移XXX处。2️⃣ PE Signature (4字节)text0x00 4字节 Signature PE\0\0 (0x50450000)白话就像盖了个认证章证明我是正宗的Windows程序。3️⃣ File Header (IMAGE_FILE_HEADER - 20字节)text偏移 大小 字段名 白话文解释0x00 2字节 Machine CPU类型0x14Cx86, 0x8664x640x02 2字节 NumberOfSections 这个程序有几个节通常3-6个0x04 4字节 TimeDateStamp 程序编译的时间戳0x08 4字节 PointerToSymbolTable 调试符号表位置发布版通常是00x0C 4字节 NumberOfSymbols 符号数量0x10 2字节 SizeOfOptionalHeader 下一个头的大小32位224, 64位2400x12 2字节 Characteristics 文件属性标志白话这是身份证部分告诉系统这是32位还是64位程序有几个代码/数据分区什么时候编译的是个EXE还是DLLCharacteristics字段Characteristics 常见标志text0x0002 IMAGE_FILE_EXECUTABLE_IMAGE 可执行文件不是obj0x0100 IMAGE_FILE_32BIT_MACHINE 32位程序0x2000 IMAGE_FILE_DLL 这是个DLL文件4️⃣ Optional Header (IMAGE_OPTIONAL_HEADER - 最重要)标准字段部分text偏移 大小 字段名 白话文解释0x00 2字节 Magic 0x10B(32位) / 0x20B(64位)0x02 1字节 MajorLinkerVersion 编译器版本0x03 1字节 MinorLinkerVersion0x04 4字节 SizeOfCode 代码段总大小0x08 4字节 SizeOfInitializedData 已初始化数据大小0x0C 4字节 SizeOfUninitializedData未初始化数据大小0x10 4字节 AddressOfEntryPoint **入口点程序从这里开始执行**0x14 4字节 BaseOfCode 代码段起始地址0x18 4字节 BaseOfData 数据段起始地址仅32位Windows专用字段部分text偏移 大小 字段名 白话文解释0x1C 4/8字节 ImageBase 程序希望加载到内存的哪个地址0x20 4字节 SectionAlignment 节在内存中的对齐单位通常0x10004KB0x24 4字节 FileAlignment 节在文件中的对齐单位通常0x200512字节0x28 8字节 [操作系统版本号]0x30 8字节 [程序版本号]0x38 8字节 [子系统版本号]0x40 4字节 Win32VersionValue 保留总是00x44 4字节 SizeOfImage 程序加载到内存后的总大小0x48 4字节 SizeOfHeaders 所有头的总大小0x4C 4字节 CheckSum 校验和驱动必须正确普通程序可为00x50 2字节 Subsystem 子系统类型0x52 2字节 DllCharacteristics DLL特性标志0x54 16字节 [栈/堆大小设置]0x64 4字节 NumberOfRvaAndSizes 数据目录数量通常是16Subsystem 子系统text1 Native驱动程序2 GUI窗口程序3 CUI控制台程序黑框框DllCharacteristics 重要标志text0x0040 DYNAMIC_BASE 支持ASLR地址随机化0x0100 NX_COMPAT 支持DEP数据执行保护0x0400 NO_SEH 不使用SEH异常处理0x8000 TERMINAL_SERVER_AWARE 终端服务器感知5️⃣ 数据目录表 (Data Directory - 16个条目)text索引 名称 作用[0] Export Table 导出表DLL导出的函数列表[1] Import Table 导入表程序要用哪些DLL的哪些函数[2] Resource Table 资源表图标、字符串、对话框[3] Exception Table 异常处理表[4] Certificate Table 数字签名[5] Base Relocation Table 重定位表修正地址用[6] Debug 调试信息[7] Architecture 架构特定数据[8] Global Ptr 全局指针寄存器[9] TLS Table 线程局部存储[10] Load Config Table 加载配置[11] Bound Import 绑定导入[12] IAT 导入地址表最常被破解者关注[13] Delay Import Descriptor 延迟导入[14] CLR Runtime Header .NET程序专用[15] Reserved 保留每个条目结构text0x00 4字节 VirtualAddress 数据在内存中的RVA0x04 4字节 Size 数据的大小6️⃣ 节表 (Section Table - 每节40字节)text偏移 大小 字段名 白话文解释0x00 8字节 Name 节名称如.text、.data0x08 4字节 VirtualSize 在内存中的实际大小0x0C 4字节 VirtualAddress 在内存中的起始地址(RVA)0x10 4字节 SizeOfRawData 在文件中的大小0x14 4字节 PointerToRawData 在文件中的偏移0x18 12字节 [重定位/行号信息] 通常为00x24 4字节 Characteristics 节的属性可读/可写/可执行常见节名称text.text 代码段你的程序逻辑 可读可执行.data 已初始化数据全局变量 可读可写.rdata 只读数据常量字符串 只读.bss 未初始化数据 可读可写.rsrc 资源图标、菜单、字符串 只读.reloc 重定位信息 只读.idata 导入表需要的DLL函数 可读可写.edata 导出表DLL导出的函数 只读Characteristics 节属性text0x00000020 CODE 包含代码0x00000040 INITIALIZED_DATA 包含已初始化数据0x00000080 UNINITIALIZED_DATA 包含未初始化数据0x20000000 EXECUTE 可执行0x40000000 READ 可读0x80000000 WRITE 可写 关键概念白话解释RVA (Relative Virtual Address) - 相对虚拟地址text假设程序被加载到内存地址 0x00400000某个函数的RVA是 0x1000那么这个函数的实际内存地址 0x00400000 0x1000 0x00401000文件偏移 vs 内存地址text文件偏移在硬盘上的.exe文件中的位置内存地址程序运行时在内存中的位置需要通过节表来转换对齐 (Alignment)textFileAlignment 0x200 (512字节)→ 文件中每个节的起始位置必须是512的倍数SectionAlignment 0x1000 (4096字节)→ 内存中每个节的起始位置必须是4KB的倍数️ 实战用十六进制编辑器看PE头text偏移 十六进制 解释00000000: 4D 5A 90 00 03 00 00 00... MZ DOS头开始0000003C: E0 00 00 00 e_lfanew 0xE0000000E0: 50 45 00 00 PE签名000000E4: 4C 01 06 00 Machine0x014C(x86), Sections6000000F8: 0B 01 Magic0x10B(32位)00000100: 00 10 00 00 AddressOfEntryPoint0x1000 总结PE头三句话秒懂DOS头我伪装成DOS程序但真正的内容在后面PE头我是Windows程序32位/64位从地址XXX开始执行节表我的代码在.text节数据在.data节资源在.rsrc节 最关心的地方text✅ AddressOfEntryPoint → 程序从哪里开始跑✅ Import Table (IAT) → 调用了哪些关键APIMessageBox? RegCreateKey?✅ .text 节 → 注册验证代码藏在这里✅ Characteristics → 能不能改这个节的数据✅ Resource Table → 修改图标、字符串、对话框希望这个图解能帮你快速理解PE结构如果要深入学习推荐工具CFF Explorer (查看PE结构最直观)