<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      GKLBB

      當(dāng)你經(jīng)歷了暴風(fēng)雨,你也就成為了暴風(fēng)雨

      導(dǎo)航

      應(yīng)用安全 --- win安全 之 VMP初體驗(yàn)

      VMP是一種軟件加固方法

      Virtual Machine Protect. 虛擬機(jī)保護(hù) ,可以將匯編指令轉(zhuǎn)化為自定義指令集,虛擬指令涉及上百萬(wàn)條匯編指令,極大增強(qiáng)pj難度。

       

      由win版本的和linux,安卓版本的。他們的軟件實(shí)現(xiàn)方法和廠(chǎng)家都不一樣,但是原理相同。

      win具體的軟件由pmvrotect2.x 3.x 3.5。vmp加密時(shí)只是對(duì)之前的so進(jìn)行新增加密節(jié)區(qū),不修改節(jié)區(qū)。

      pmvrotect2軟件加密的手段有很多最著名的是vmp技術(shù)。包含 指令虛擬化,導(dǎo)入表加密,反調(diào)試,反dump,指令和數(shù)據(jù)壓縮

       vmpdumper可以脫出匯編代碼但是不能修復(fù)vmp節(jié)區(qū)和導(dǎo)出表,加密字符串。需要手動(dòng)修復(fù)。導(dǎo)入表(IAT)不能修復(fù)

       

      代碼壓縮 (Packing)

      原理:壓縮代碼段

      text
      原始PE結(jié)構(gòu):
      ├─ .text  (500KB) - 可執(zhí)行代碼
      ├─ .data  (100KB) - 數(shù)據(jù)
      └─ .rsrc  (200KB) - 資源
      
      ↓ 壓縮后 ↓
      
      ├─ .vmp0  (150KB) - 壓縮的代碼+解壓stub
      ├─ .vmp1  (80KB)  - 壓縮的數(shù)據(jù)  
      └─ .rsrc  (200KB)
      
      運(yùn)行時(shí):
      1. 解壓.vmp0到內(nèi)存
      2. 修復(fù)重定位
      3. 跳轉(zhuǎn)執(zhí)行

      壓縮算法:LZMA/自定義

      強(qiáng)度:★★
      主要用途:減小體積(附帶混淆效果)

       

       

      代碼虛擬化 (Virtualization) ?最強(qiáng)

      原理:將x86指令轉(zhuǎn)換為自定義虛擬機(jī)指令

      轉(zhuǎn)換示例:

      asm
      ; 原始代碼
      mov eax, 5
      add eax, 3
      ret
      
      ; ↓ 虛擬化后 ↓
      
      push offset vm_bytecode  ; VM字節(jié)碼
      call vm_interpreter      ; 調(diào)用VM解釋器
      ret
      
      ; vm_bytecode (自定義指令):
      ; 0x45 0x05 0x00 0x00 0x00  ; VM_MOV eax, 5
      ; 0x12 0x03 0x00 0x00 0x00  ; VM_ADD eax, 3
      ; 0xFF                      ; VM_RET

      C代碼示例:

      C++
      // 原始
      int add(int a, int b) {
          return a + b;
      }
      
      // SDK標(biāo)記
      #include "VMProtectSDK.h"
      int add(int a, int b) {
          VMProtectBeginVirtualization("Add");
          return a + b;
          VMProtectEnd();
      }

      強(qiáng)度:★★★★★
      性能損耗:5-20倍

       

      代碼變異 (Mutation/Obfuscation)

      原理:用等價(jià)但復(fù)雜的指令替換原指令

      轉(zhuǎn)換示例:

      asm
      ; 原始
      mov eax, 5
      
      ; ↓ 變異后 ↓
      
      push 2
      push 3
      pop ecx
      pop edx
      lea eax, [ecx+edx]  ; 實(shí)際還是5
      
      ; 或者
      
      xor eax, eax
      add eax, 3
      inc eax
      inc eax            ; 仍是5,但復(fù)雜化

      典型變異技術(shù):

      asm
      ; 1. 指令替換
      mov eax, 0  →  xor eax, eax
      
      ; 2. 花指令插入
      nop
      jmp $+1
      db 0xE8  ; 無(wú)效字節(jié)
      add eax, ebx
      
      ; 3. 寄存器替換
      mov eax, 5  →  mov ebx, 5
                      mov eax, ebx
      
      ; 4. 常量加密
      mov eax, 100  →  mov eax, 0x12345678
                       xor eax, 0x123456DC  ; = 100

      強(qiáng)度:★★★★
      性能損耗:1.5-3倍

       

       導(dǎo)入表加密

      導(dǎo)入表保護(hù) (Import Protection)

      原理:隱藏真實(shí)的API調(diào)用

      轉(zhuǎn)換示例:

      C++
      ; 原始導(dǎo)入表
      IMPORT TABLE:
        kernel32.dll
          - CreateFileA
          - ReadFile
      
      ; ↓ 保護(hù)后 ↓
      
      IMPORT TABLE:
        kernel32.dll
          - LoadLibraryA  ; 只保留最基礎(chǔ)的
      
      ; 運(yùn)行時(shí)動(dòng)態(tài)獲取
      char* encrypted = "\x3F\x12\x7A...";  // 加密的 "CreateFileA"
      decrypt(encrypted);
      pCreateFile = GetProcAddress(LoadLibrary("kernel32"), decrypted);
      pCreateFile(...);  // 調(diào)用

      代碼對(duì)比:

      C++
      // 原始
      MessageBoxA(NULL, "Hello", "Test", 0);
      
      // 保護(hù)后(偽代碼)
      typedef int (WINAPI *pMsgBox)(HWND, LPCSTR, LPCSTR, UINT);
      pMsgBox MyMsgBox = vmp_get_api(0x1A3F);  // 內(nèi)部索引
      MyMsgBox(NULL, vmp_str(0x2B4C), vmp_str(0x3D5E), 0);

      強(qiáng)度:★★★★
      繞過(guò)難度:中等(可API Hook監(jiān)控)

       call后面是加密的iat表

      image

       

       

      字符串加密 (String Encryption)

      原理:加密所有字符串常量

      示例:

      C++
      // 原始
      const char* key = "MySecretKey123";
      if (strcmp(input, key) == 0) { ... }
      
      // ↓ 加密后 ↓
      
      // 數(shù)據(jù)段存儲(chǔ)
      .data
      encrypted_str db 0xA3,0x7F,0x2B,0x9C,... ; 加密的字符串
      
      // 代碼中
      char* key = vmp_decrypt_string(0x004050A0);
      if (strcmp(input, key) == 0) {
          vmp_free_string(key);  // 用完立即清除
      }

       

      反調(diào)試 (Anti-Debug)

      技術(shù)清單:

      C++
      // 1. IsDebuggerPresent
      if (IsDebuggerPresent()) {
          ExitProcess(0);
      }
      
      // 2. PEB檢測(cè)
      bool CheckDebug() {
          __asm {
              mov eax, fs:[0x30]      // PEB
              movzx eax, byte ptr [eax+2]  // BeingDebugged
              test eax, eax
          }
      }
      
      // 3. NtQueryInformationProcess
      BOOL isDebug = FALSE;
      NtQueryInformationProcess(GetCurrentProcess(), 
          ProcessDebugPort, &isDebug, sizeof(BOOL), NULL);
      
      // 4. 時(shí)間檢測(cè)
      DWORD t1 = GetTickCount();
      // 一些代碼
      DWORD t2 = GetTickCount();
      if (t2 - t1 > 1000) { /* 被調(diào)試 */ }
      
      // 5. 硬件斷點(diǎn)檢測(cè)
      CONTEXT ctx = {0};
      ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
      GetThreadContext(GetCurrentThread(), &ctx);
      if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) {
          /* 檢測(cè)到硬件斷點(diǎn) */
      }
      
      // 6. INT 3檢測(cè)
      __try {
          __asm int 3
      } __except(EXCEPTION_EXECUTE_HANDLER) {
          // 正常程序會(huì)走這里
      }
      
      // 7. 檢測(cè)調(diào)試器窗口
      if (FindWindow("OLLYDBG", NULL) || 
          FindWindow("WinDbgFrameClass", NULL)) {
          ExitProcess(0);
      }


      反虛擬機(jī) (Anti-VM)

      檢測(cè)技術(shù):

      C++
      // 1. CPUID檢測(cè)
      void CheckVM() {
          int cpuInfo[4];
          __cpuid(cpuInfo, 1);
          if (cpuInfo[2] & (1 << 31)) {
              // Hypervisor bit set
              ExitProcess(0);
          }
      }
      
      // 2. 特征文件檢測(cè)
      if (PathFileExists("C:\\Windows\\System32\\drivers\\vmmouse.sys") ||
          PathFileExists("C:\\Windows\\System32\\drivers\\vmhgfs.sys")) {
          // VMware檢測(cè)
      }
      
      // 3. 注冊(cè)表檢測(cè)
      HKEY hKey;
      if (RegOpenKey(HKEY_LOCAL_MACHINE, 
          "SOFTWARE\\VMware, Inc.\\VMware Tools", &hKey) == ERROR_SUCCESS) {
          // VMware
      }
      
      // 4. MAC地址檢測(cè)
      // VMware前綴: 00:05:69, 00:0C:29, 00:50:56
      // VirtualBox前綴: 08:00:27
      
      // 5. 指令時(shí)間檢測(cè)
      DWORD t1 = __rdtsc();
      // 執(zhí)行一些指令
      DWORD t2 = __rdtsc();
      if (t2 - t1 > threshold) { /* VM環(huán)境 */ }

      強(qiáng)度:★★★
      繞過(guò):修改VM配置

       
       

      內(nèi)存保護(hù) (Memory Protection)

      原理:檢測(cè)內(nèi)存完整性

      C++
      // 1. CRC校驗(yàn)
      DWORD original_crc = 0x12345678;
      DWORD current_crc = calc_crc32(code_section, size);
      if (current_crc != original_crc) {
          ExitProcess(0);  // 代碼被修改
      }
      
      // 2. 定期校驗(yàn)
      void __stdcall CheckThread(LPVOID param) {
          while (true) {
              Sleep(1000);
              if (!verify_memory()) {
                  TerminateProcess(GetCurrentProcess(), 0);
              }
          }
      }
      
      // 3. 頁(yè)面保護(hù)
      VirtualProtect(code_section, size, PAGE_EXECUTE_READ, &old);
      // 任何寫(xiě)入會(huì)觸發(fā)異常



       資源加密 (Resource Encryption)

      原理:加密PE資源段

      C++
      // 原始
      HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(101), RT_BITMAP);
      HGLOBAL hData = LoadResource(NULL, hRes);
      void* pData = LockResource(hData);
      
      // ↓ 保護(hù)后 ↓
      
      // 資源段全部加密
      .rsrc section: [encrypted data]
      
      // 運(yùn)行時(shí)
      HRSRC hRes = FindResource(...);
      // VMProtect攔截LoadResource
      HGLOBAL hData = LoadResource(...);  // 內(nèi)部解密
      void* pData = LockResource(hData);  // 返回解密數(shù)據(jù)

      強(qiáng)度:★★★
      效果:防止資源提取工具直接讀取

      
      

      應(yīng)用VMProtect后(簡(jiǎn)化示意)

      C++
      // 編譯后的保護(hù)代碼(逆向視角)
      
      .text:00401000  ; VMP Entry
      .text:00401000  push    ebp
      .text:00401001  call    vmp_init_2FA3C
      .text:00401006  jmp     vm_dispatcher_1
      
      // 原始的main函數(shù)代碼已經(jīng)不存在
      // 被轉(zhuǎn)換為:
      
      .vmp0:00501000  db 0x4A, 0x8F, 0x23, ...  ; VM字節(jié)碼
      .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,...
      
      // 導(dǎo)入表被隱藏
      .idata:00701000  ; 只剩下
      .idata:00701000  dd offset LoadLibraryA
      .idata:00701004  dd offset GetProcAddress

      保護(hù)強(qiáng)度對(duì)比表

      方法反靜態(tài)分析反動(dòng)態(tài)分析性能影響推薦場(chǎng)景
      Virtualization ★★★★★ ★★★★★ -90% 核心算法
      Mutation ★★★★ ★★★ -30% 一般函數(shù)
      Import Protection ★★★★ ★★ -5% 全局開(kāi)啟
      String Encryption ★★★ -5% 敏感字符串
      Anti-Debug ★★★★ -1% 全局開(kāi)啟
      Anti-VM ★★★ -1% 可選
      Memory Protection ★★ ★★★★ -10% 全局開(kāi)啟
      Packing ★★ +5% 減小體積

       




      虛擬指令、虛擬棧、虛擬寄存器。

        

      image

       

       

       

      msdn。開(kāi)發(fā)文檔
      <windows程序設(shè)計(jì)>
      <windows核心編程>
      <win32匯編語(yǔ)言程序設(shè)計(jì)>

       

       

       

      PE 文件結(jié)構(gòu)圖例

      text
      +-----------------------------------+  <-- 文件開(kāi)始 (Offset 0)
      |        IMAGE_DOS_HEADER           |
      |-----------------------------------|
      |   - e_magic: "MZ" (0x5A4D)        |  <- DOS 可執(zhí)行文件簽名
      |   - e_lfanew: 指向 NT 頭部的偏移量 |  <- 這是通往 PE 頭的關(guān)鍵指針!
      +-----------------------------------+
      |         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)   |  |  <- 目標(biāo) CPU 架構(gòu) (如 x64)
      |   | - NumberOfSections:         |  |  <- 后面跟著的節(jié)區(qū)數(shù)量
      |   | - TimeDateStamp:            |  |  <- 鏈接時(shí)間戳
      |   | - SizeOfOptionalHeader:     |  |  <- 下一個(gè)頭的大小
      |   | - Characteristics:          |  |  <- 文件屬性 (如 DLL, Executable)
      |   +-----------------------------+  |
      |   |  IMAGE_OPTIONAL_HEADER      |  |  <- 對(duì)于操作系統(tǒng)加載器至關(guān)重要
      |   |-----------------------------|  |
      |   | - Magic: (e.g., 0x20B)      |  |  <- 標(biāo)識(shí) PE32(0x10B) 或 PE32+(0x20B)
      |   | - AddressOfEntryPoint:      |  |  <- 程序執(zhí)行入口 RVA
      |   | - ImageBase:                |  |  <- 映像的首選加載地址
      |   | - SectionAlignment:         |  |  <- 內(nèi)存中節(jié)區(qū)的對(duì)齊方式
      |   | - FileAlignment:            |  |  <- 文件中節(jié)區(qū)的對(duì)齊方式
      |   | - SizeOfImage:              |  |  <- 內(nèi)存中整個(gè)映像的大小
      |   | - SizeOfHeaders:            |  |  <- 所有頭部的總大小
      |   | - Subsystem: (e.g., GUI/CUI) |  |  <- 要求子系統(tǒng) (如 Windows GUI)
      |   | - NumberOfRvaAndSizes:      |  |  <- 數(shù)據(jù)目錄項(xiàng)的數(shù)量
      |   |-----------------------------|  |
      |   |   IMAGE_DATA_DIRECTORY      |  |  <- 一個(gè)結(jié)構(gòu)體數(shù)組
      |   |   [0] Export Directory      |  |
      |   |   [1] Import Directory      |  |  <- 指向?qū)牒瘮?shù)信息
      |   |   [2] Resource Directory    |  |  <- 指向資源 (圖標(biāo)、字符串等)
      |   |   [3] Exception Directory   |  |
      |   |   ... (共 16 個(gè)) ...        |  |
      |   +-----------------------------+  |
      +-----------------------------------+
      |     IMAGE_SECTION_HEADER[0]       |  <- 第一個(gè)節(jié)區(qū)頭 (如 .text)
      |   - Name: ".text\0\0\0"           |  <- 節(jié)區(qū)名稱(chēng)
      |   - VirtualAddress:               |  <- 內(nèi)存中的 RVA
      |   - SizeOfRawData:                |  <- 在文件中的大小
      |   - PointerToRawData:             |  <- 在文件中的偏移
      |   - Characteristics:              |  <- 節(jié)區(qū)屬性 (如 可執(zhí)行、可讀)
      +-----------------------------------+
      |     IMAGE_SECTION_HEADER[1]       |  <- 第二個(gè)節(jié)區(qū)頭 (如 .data)
      |   - Name: ".data\0\0\0"           |
      |   - ...                           |
      +-----------------------------------+
      |             ...                   |  <- 其他節(jié)區(qū)頭 (共 NumberOfSections 個(gè))
      +-----------------------------------+  <-- SizeOfHeaders 標(biāo)記的頭部結(jié)束位置
      |         節(jié)區(qū)數(shù)據(jù)開(kāi)始               |
      |                                   |
      |        .text 節(jié)區(qū)原始數(shù)據(jù)          |  <- 文件偏移由 PointerToRawData 指定
      |        (存放代碼)                  |
      |                                   |
      |        .data 節(jié)區(qū)原始數(shù)據(jù)          |  <- 文件偏移由 PointerToRawData 指定
      |        (存放全局變量)              |
      |                                   |
      |        .rsrc 節(jié)區(qū)原始數(shù)據(jù)          |
      |        (存放資源)                  |
      |                                   |
      |             ...                   |
      +-----------------------------------+  <-- 文件結(jié)束

      各組成部分的簡(jiǎn)明解釋

      1. IMAGE_DOS_HEADER (DOS 頭)

        • 目的:為了保持與古老 DOS 系統(tǒng)的兼容性。

        • 關(guān)鍵成員:e_lfanew 字段,它包含了指向真正的 PE 頭 (IMAGE_NT_HEADERS) 的文件偏移量。

      2. IMAGE_NT_HEADERS (NT 頭)

        • 目的:PE 文件的正式入口和核心描述符。

        • 包含三部分:

          • Signature:一個(gè) "PE\0\0" 的簽名,標(biāo)識(shí)這是一個(gè) PE 文件。

          • IMAGE_FILE_HEADER (文件頭):描述了文件的全局屬性,如目標(biāo)機(jī)器類(lèi)型、節(jié)區(qū)數(shù)量、創(chuàng)建時(shí)間等。

          • IMAGE_OPTIONAL_HEADER (可選頭):雖然叫"可選",但對(duì)于可執(zhí)行文件是必需的。它包含了程序加載和運(yùn)行所需的關(guān)鍵信息。

      3. IMAGE_OPTIONAL_HEADER (可選頭)

        • 目的:為操作系統(tǒng)加載器提供如何準(zhǔn)備和執(zhí)行程序的信息。

        • 關(guān)鍵成員:入口點(diǎn)地址、映像基址、內(nèi)存/文件對(duì)齊值、子系統(tǒng)等。

        • 它末尾的 IMAGE_DATA_DIRECTORY (數(shù)據(jù)目錄) 是一個(gè)非常重要的表格,它指出了其他重要數(shù)據(jù)結(jié)構(gòu)(如導(dǎo)入表、導(dǎo)出表、資源表)在文件中的位置和大小。

      4. IMAGE_DATA_DIRECTORY (數(shù)據(jù)目錄)

        • 目的:作為指向其他重要數(shù)據(jù)的“目錄”或“索引”。

        • 結(jié)構(gòu):一個(gè)由16個(gè)相同結(jié)構(gòu)組成的數(shù)組。每個(gè)結(jié)構(gòu)包含一個(gè) RVA(相對(duì)虛擬地址) 和 Size。

        • 例如:第二個(gè)條目(索引1)是 Import Directory,加載器通過(guò)它找到所有需要從其他DLL導(dǎo)入的函數(shù)列表。

      5. IMAGE_SECTION_HEADER (節(jié)區(qū)頭)

        • 目的:描述文件中的各個(gè)“節(jié)區(qū)”。節(jié)區(qū)是實(shí)際存儲(chǔ)代碼、數(shù)據(jù)、資源等內(nèi)容的部分。

        • 數(shù)量:由 IMAGE_FILE_HEADER 中的 NumberOfSections 指定。

        • 關(guān)鍵成員:

          • Name:節(jié)區(qū)名稱(chēng)(如 .text.data.rdata)。

          • VirtualAddress:該節(jié)區(qū)加載到內(nèi)存后的 RVA。

          • PointerToRawData:該節(jié)區(qū)在磁盤(pán)文件中的原始數(shù)據(jù)偏移。

          • Characteristics:節(jié)區(qū)屬性(如可讀、可寫(xiě)、可執(zhí)行)。

      總結(jié)與流程

      操作系統(tǒng)加載一個(gè) PE 文件的簡(jiǎn)化流程如下:

      1. 讀取 IMAGE_DOS_HEADER,找到 e_lfanew

      2. 跳到 e_lfanew 位置,驗(yàn)證 "PE" 簽名,讀取 IMAGE_NT_HEADERS

      3. 從 IMAGE_FILE_HEADER 知道有多少個(gè)節(jié)區(qū)。

      4. 從 IMAGE_OPTIONAL_HEADER 獲取關(guān)鍵信息(如入口點(diǎn)、映像大小、數(shù)據(jù)目錄)。

      5. 遍歷 IMAGE_SECTION_HEADER 數(shù)組,了解每個(gè)節(jié)區(qū)在文件和內(nèi)存中的映射關(guān)系。

      6. 根據(jù)節(jié)區(qū)頭的信息,將文件的各個(gè)節(jié)區(qū)(代碼、數(shù)據(jù)等)映射到內(nèi)存的相應(yīng)位置。

      7. 通過(guò) IMAGE_DATA_DIRECTORY 找到導(dǎo)入表,解析并填充所有需要的外部函數(shù)地址。

      8. 最后,跳轉(zhuǎn)到 AddressOfEntryPoint 指向的地址,程序開(kāi)始執(zhí)行。

      這個(gè)結(jié)構(gòu)確保了 PE 文件既能在磁盤(pán)上高效存儲(chǔ),又能在內(nèi)存中正確加載和執(zhí)行。

       

       

       

      PE文件頭結(jié)構(gòu)圖解 + 白話(huà)文秒懂

      ?? 完整結(jié)構(gòu)總覽

      text
      ┌─────────────────────────────────────────────────────────┐
      │                    DOS Header (64字節(jié))                   │  ← 開(kāi)頭的"MZ"標(biāo)記
      │  "這是個(gè)老式DOS程序" 的偽裝外殼                           │
      ├─────────────────────────────────────────────────────────┤
      │                    DOS Stub (可變)                       │
      │  "This program cannot be run in DOS mode"               │  ← 在DOS下運(yùn)行會(huì)看到的提示
      ├─────────────────────────────────────────────────────────┤
      │                    PE Signature (4字節(jié))                  │
      │                    "PE\0\0"                             │  ← 真正的PE文件標(biāo)記
      ├─────────────────────────────────────────────────────────┤
      │                 File Header (20字節(jié))                     │
      │  記錄機(jī)器類(lèi)型、節(jié)數(shù)量、時(shí)間戳等基本信息                    │
      ├─────────────────────────────────────────────────────────┤
      │              Optional Header (224/240字節(jié))               │
      │  記錄程序入口點(diǎn)、內(nèi)存布局、導(dǎo)入導(dǎo)出等關(guān)鍵信息              │
      ├─────────────────────────────────────────────────────────┤
      │              Section Table (每節(jié)40字節(jié))                  │
      │  .text  .data  .rdata  .rsrc 等節(jié)的"目錄"              │
      ├─────────────────────────────────────────────────────────┤
      │                                                         │
      │                   Section 1 (.text)                     │  ← 代碼區(qū)
      │                   你寫(xiě)的代碼在這里                        │
      │                                                         │
      ├─────────────────────────────────────────────────────────┤
      │                   Section 2 (.data)                     │  ← 數(shù)據(jù)區(qū)
      │                   全局變量在這里                          │
      ├─────────────────────────────────────────────────────────┤
      │                   Section 3 (.rsrc)                     │  ← 資源區(qū)
      │                   圖標(biāo)、對(duì)話(huà)框、字符串在這里               │
      └─────────────────────────────────────────────────────────┘

      ?? 詳細(xì)結(jié)構(gòu)拆解

      1?? DOS Header (IMAGE_DOS_HEADER)

      text
      偏移    大小    字段名              白話(huà)文解釋
      +0x00   2字節(jié)   e_magic            "MZ" 標(biāo)記(0x5A4D)—— 所有PE文件必須以這兩個(gè)字母開(kāi)頭
      +0x02   58字節(jié)  [其他DOS字段]       基本沒(méi)用,為了兼容古董DOS系統(tǒng)
      +0x3C   4字節(jié)   e_lfanew           **超重要!** 指向真正的PE頭在哪里

      白話(huà):

      這是個(gè)"假門(mén)面",為了讓W(xué)indows程序能在老DOS系統(tǒng)上顯示錯(cuò)誤提示,而不是直接崩潰。
      最重要的是最后那個(gè) e_lfanew,它告訴系統(tǒng):"真正的PE頭在文件偏移XXX處"。


      2?? PE Signature (4字節(jié))

      text
      +0x00   4字節(jié)   Signature          "PE\0\0" (0x50450000)

      白話(huà):

      就像蓋了個(gè)"認(rèn)證章",證明"我是正宗的Windows程序"。


      3?? File Header (IMAGE_FILE_HEADER - 20字節(jié))

      text
      偏移    大小    字段名                  白話(huà)文解釋
      +0x00   2字節(jié)   Machine                CPU類(lèi)型(0x14C=x86, 0x8664=x64)
      +0x02   2字節(jié)   NumberOfSections       這個(gè)程序有幾個(gè)"節(jié)"(通常3-6個(gè))
      +0x04   4字節(jié)   TimeDateStamp          程序編譯的時(shí)間戳
      +0x08   4字節(jié)   PointerToSymbolTable   調(diào)試符號(hào)表位置(發(fā)布版通常是0)
      +0x0C   4字節(jié)   NumberOfSymbols        符號(hào)數(shù)量
      +0x10   2字節(jié)   SizeOfOptionalHeader   下一個(gè)頭的大小(32位=224, 64位=240)
      +0x12   2字節(jié)   Characteristics        文件屬性標(biāo)志

      白話(huà):

      這是"身份證"部分:

      • 告訴系統(tǒng)這是32位還是64位程序
      • 有幾個(gè)代碼/數(shù)據(jù)分區(qū)
      • 什么時(shí)候編譯的
      • 是個(gè)EXE還是DLL(Characteristics字段)

      Characteristics 常見(jiàn)標(biāo)志:

      text
      0x0002  IMAGE_FILE_EXECUTABLE_IMAGE     可執(zhí)行文件(不是obj)
      0x0100  IMAGE_FILE_32BIT_MACHINE        32位程序
      0x2000  IMAGE_FILE_DLL                  這是個(gè)DLL文件

      4?? Optional Header (IMAGE_OPTIONAL_HEADER - 最重要!)

      標(biāo)準(zhǔn)字段部分

      text
      偏移    大小    字段名                  白話(huà)文解釋
      +0x00   2字節(jié)   Magic                  0x10B(32位) / 0x20B(64位)
      +0x02   1字節(jié)   MajorLinkerVersion     編譯器版本
      +0x03   1字節(jié)   MinorLinkerVersion
      +0x04   4字節(jié)   SizeOfCode             代碼段總大小
      +0x08   4字節(jié)   SizeOfInitializedData  已初始化數(shù)據(jù)大小
      +0x0C   4字節(jié)   SizeOfUninitializedData未初始化數(shù)據(jù)大小
      +0x10   4字節(jié)   AddressOfEntryPoint    **入口點(diǎn)!程序從這里開(kāi)始執(zhí)行**
      +0x14   4字節(jié)   BaseOfCode             代碼段起始地址
      +0x18   4字節(jié)   BaseOfData             數(shù)據(jù)段起始地址(僅32位)

      Windows專(zhuān)用字段部分

      text
      偏移    大小    字段名                  白話(huà)文解釋
      +0x1C   4/8字節(jié) ImageBase              程序希望加載到內(nèi)存的哪個(gè)地址
      +0x20   4字節(jié)   SectionAlignment       節(jié)在內(nèi)存中的對(duì)齊單位(通常0x1000=4KB)
      +0x24   4字節(jié)   FileAlignment          節(jié)在文件中的對(duì)齊單位(通常0x200=512字節(jié))
      +0x28   8字節(jié)   [操作系統(tǒng)版本號(hào)]
      +0x30   8字節(jié)   [程序版本號(hào)]
      +0x38   8字節(jié)   [子系統(tǒng)版本號(hào)]
      +0x40   4字節(jié)   Win32VersionValue      保留(總是0)
      +0x44   4字節(jié)   SizeOfImage            程序加載到內(nèi)存后的總大小
      +0x48   4字節(jié)   SizeOfHeaders          所有頭的總大小
      +0x4C   4字節(jié)   CheckSum               校驗(yàn)和(驅(qū)動(dòng)必須正確,普通程序可為0)
      +0x50   2字節(jié)   Subsystem              子系統(tǒng)類(lèi)型
      +0x52   2字節(jié)   DllCharacteristics     DLL特性標(biāo)志
      +0x54   16字節(jié)  [棧/堆大小設(shè)置]
      +0x64   4字節(jié)   NumberOfRvaAndSizes    數(shù)據(jù)目錄數(shù)量(通常是16)

      Subsystem 子系統(tǒng):

      text
      1 = Native(驅(qū)動(dòng)程序)
      2 = GUI(窗口程序)
      3 = CUI(控制臺(tái)程序,黑框框)

      DllCharacteristics 重要標(biāo)志:

      text
      0x0040  DYNAMIC_BASE           支持ASLR(地址隨機(jī)化)
      0x0100  NX_COMPAT              支持DEP(數(shù)據(jù)執(zhí)行保護(hù))
      0x0400  NO_SEH                 不使用SEH異常處理
      0x8000  TERMINAL_SERVER_AWARE  終端服務(wù)器感知

      5?? 數(shù)據(jù)目錄表 (Data Directory - 16個(gè)條目)

      text
      索引  名稱(chēng)                        作用
      [0]   Export Table              導(dǎo)出表(DLL導(dǎo)出的函數(shù)列表)
      [1]   Import Table              導(dǎo)入表(程序要用哪些DLL的哪些函數(shù))
      [2]   Resource Table            資源表(圖標(biāo)、字符串、對(duì)話(huà)框)
      [3]   Exception Table           異常處理表
      [4]   Certificate Table         數(shù)字簽名
      [5]   Base Relocation Table     重定位表(修正地址用)
      [6]   Debug                     調(diào)試信息
      [7]   Architecture              架構(gòu)特定數(shù)據(jù)
      [8]   Global Ptr                全局指針寄存器
      [9]   TLS Table                 線(xiàn)程局部存儲(chǔ)
      [10]  Load Config Table         加載配置
      [11]  Bound Import              綁定導(dǎo)入
      [12]  IAT                       導(dǎo)入地址表(最常被破解者關(guān)注!)
      [13]  Delay Import Descriptor   延遲導(dǎo)入
      [14]  CLR Runtime Header        .NET程序?qū)S?[15]  Reserved                  保留

      每個(gè)條目結(jié)構(gòu):

      text
      +0x00  4字節(jié)  VirtualAddress    數(shù)據(jù)在內(nèi)存中的RVA
      +0x04  4字節(jié)  Size              數(shù)據(jù)的大小

      6?? 節(jié)表 (Section Table - 每節(jié)40字節(jié))

      text
      偏移    大小    字段名              白話(huà)文解釋
      +0x00   8字節(jié)   Name               節(jié)名稱(chēng)(如".text"、".data")
      +0x08   4字節(jié)   VirtualSize        在內(nèi)存中的實(shí)際大小
      +0x0C   4字節(jié)   VirtualAddress     在內(nèi)存中的起始地址(RVA)
      +0x10   4字節(jié)   SizeOfRawData      在文件中的大小
      +0x14   4字節(jié)   PointerToRawData   在文件中的偏移
      +0x18   12字節(jié)  [重定位/行號(hào)信息]   通常為0
      +0x24   4字節(jié)   Characteristics    節(jié)的屬性(可讀/可寫(xiě)/可執(zhí)行)

      常見(jiàn)節(jié)名稱(chēng):

      text
      .text   代碼段(你的程序邏輯)          可讀+可執(zhí)行
      .data   已初始化數(shù)據(jù)(全局變量)        可讀+可寫(xiě)
      .rdata  只讀數(shù)據(jù)(常量字符串)          只讀
      .bss    未初始化數(shù)據(jù)                   可讀+可寫(xiě)
      .rsrc   資源(圖標(biāo)、菜單、字符串)      只讀
      .reloc  重定位信息                     只讀
      .idata  導(dǎo)入表(需要的DLL函數(shù))        可讀+可寫(xiě)
      .edata  導(dǎo)出表(DLL導(dǎo)出的函數(shù))        只讀

      Characteristics 節(jié)屬性:

      text
      0x00000020  CODE                 包含代碼
      0x00000040  INITIALIZED_DATA     包含已初始化數(shù)據(jù)
      0x00000080  UNINITIALIZED_DATA   包含未初始化數(shù)據(jù)
      0x20000000  EXECUTE              可執(zhí)行
      0x40000000  READ                 可讀
      0x80000000  WRITE                可寫(xiě)

      ?? 關(guān)鍵概念白話(huà)解釋

      RVA (Relative Virtual Address) - 相對(duì)虛擬地址

      text
      假設(shè)程序被加載到內(nèi)存地址 0x00400000
      某個(gè)函數(shù)的RVA是 0x1000
      那么這個(gè)函數(shù)的實(shí)際內(nèi)存地址 = 0x00400000 + 0x1000 = 0x00401000

      文件偏移 vs 內(nèi)存地址

      text
      文件偏移:在硬盤(pán)上的.exe文件中的位置
      內(nèi)存地址:程序運(yùn)行時(shí)在內(nèi)存中的位置
      需要通過(guò)節(jié)表來(lái)轉(zhuǎn)換!

      對(duì)齊 (Alignment)

      text
      FileAlignment = 0x200 (512字節(jié))
      → 文件中每個(gè)節(jié)的起始位置必須是512的倍數(shù)
      
      SectionAlignment = 0x1000 (4096字節(jié))
      → 內(nèi)存中每個(gè)節(jié)的起始位置必須是4KB的倍數(shù)

      ??? 實(shí)戰(zhàn):用十六進(jìn)制編輯器看PE頭

      text
      偏移      十六進(jìn)制                            解釋
      00000000: 4D 5A 90 00 03 00 00 00...         MZ = DOS頭開(kāi)始
      0000003C: E0 00 00 00                         e_lfanew = 0xE0
      000000E0: 50 45 00 00                         PE簽名
      000000E4: 4C 01 06 00                         Machine=0x014C(x86), Sections=6
      000000F8: 0B 01                               Magic=0x10B(32位)
      00000100: 00 10 00 00                         AddressOfEntryPoint=0x1000

      ?? 總結(jié):PE頭三句話(huà)秒懂

      1. DOS頭:"我偽裝成DOS程序,但真正的內(nèi)容在后面"
      2. PE頭:"我是Windows程序,32位/64位,從地址XXX開(kāi)始執(zhí)行"
      3. 節(jié)表:"我的代碼在.text節(jié),數(shù)據(jù)在.data節(jié),資源在.rsrc節(jié)"

      ?? 最關(guān)心的地方

      text
      ? AddressOfEntryPoint    → 程序從哪里開(kāi)始跑
      ? Import Table (IAT)     → 調(diào)用了哪些關(guān)鍵API(MessageBox? RegCreateKey?)
      ? .text 節(jié)               → 注冊(cè)驗(yàn)證代碼藏在這里
      ? Characteristics        → 能不能改這個(gè)節(jié)的數(shù)據(jù)
      ? Resource Table         → 修改圖標(biāo)、字符串、對(duì)話(huà)框

      希望這個(gè)圖解能幫你快速理解PE結(jié)構(gòu)!如果要深入學(xué)習(xí),推薦工具:

      • CFF Explorer (查看PE結(jié)構(gòu)最直觀)
      • PE-bear
      • 010 Editor (配合PE模板)
      • windowspe 權(quán)威指南

       

      了解所有編譯器和反匯編特征

      了解vmp入口,區(qū)段,反匯編特征

       

      看特征的方法主要有兩個(gè),一個(gè)是入口代碼的在節(jié)區(qū)中的位置,入口代碼中包含的指令和調(diào)用的外部接口

      vc6特征和易語(yǔ)言

      image

       

      image

       

       

      image

       

      image

       

       

      image

       

      image

       

      image

       

      image

       

      64-ia-32-architectures-software-developer-manualintel開(kāi)發(fā)手冊(cè)
      <加密與解密>
      揭秘><C++反匯編與逆向分析技術(shù)

       

      image

       

      Stud PE
      exeinfoExeinfo PE是一款專(zhuān)業(yè)的程序查殼工具
      LordPE
      PE Tools 1.9

      WinHex
      UltraEdit
      Beyond Compare數(shù)據(jù)比較工具。

       

      iat修復(fù)工具

      ImportREC
      Scylla
      Universal lmport Fixer
      Imports Fixer

       

      vmp指令轉(zhuǎn)化器軟件

      將匯編轉(zhuǎn)vmp自定義指令,在轉(zhuǎn)化為真實(shí)指令集

       

       

       

       

      好的,我們來(lái)詳細(xì)說(shuō)明如何嘗試使用 VMPDump 來(lái)處理一個(gè)被 VMProtect 2 加密的程序。

      但在開(kāi)始之前,我必須先強(qiáng)調(diào)一個(gè)至關(guān)重要的事實(shí),這能為你節(jié)省大量的時(shí)間和精力:

      ?? 第一部分:必讀的現(xiàn)實(shí)情況與重要提醒

      1. VMPDump 并非萬(wàn)能神藥:VMPDump 是一個(gè)比較早期的、針對(duì)特定舊版本 VMProtect 的自動(dòng)化分析工具。它無(wú)法真正地“還原所有代碼”。它的主要功能是嘗試自動(dòng)完成“尋找OEP”和“Dump內(nèi)存”這兩個(gè)初級(jí)階段的工作。

      2. 它不能“去虛擬化”:VMPDump 絕對(duì)無(wú)法將 VMProtect 的核心——虛擬化字節(jié)碼(Bytecode)——翻譯回原始的 x86/x64 匯編代碼。被虛擬化的關(guān)鍵代碼(如注冊(cè)算法)在 VMPDump 處理后,依然是虛擬化的,你用IDA打開(kāi)看仍然是一團(tuán)亂麻。

      3. 成功率極低:對(duì)于現(xiàn)代版本的 VMProtect 2 (例如 2.13 及以后) 或者即使是舊版本但開(kāi)啟了高強(qiáng)度保護(hù)選項(xiàng)的程序,VMPDump 的成功率趨近于零。它很可能會(huì)失敗、卡死、或者生成一個(gè)完全無(wú)法運(yùn)行的垃圾文件。

      4. 它的真正作用:在極少數(shù)情況下(例如面對(duì)非常古老的、保護(hù)設(shè)置很弱的VMP版本),它可能可以幫你快速脫掉外層的殼,省去你手動(dòng)尋找OEP和Dump的幾分鐘時(shí)間。請(qǐng)把它看作一個(gè)“快速?lài)L試的彩票”,而不是一個(gè)“解決方案”。

      結(jié)論: 不要期望 VMPDump 能幫你“一鍵還原”所有代碼。它只是一個(gè)輔助性的、成功率很低的入門(mén)級(jí)工具。


      第二部分:準(zhǔn)備工作

      在你開(kāi)始之前,請(qǐng)確保你已經(jīng)準(zhǔn)備好以下環(huán)境和工具:

      1. 虛擬機(jī) (VM):強(qiáng)烈建議在 VMware 或 VirtualBox 等虛擬機(jī)中進(jìn)行所有操作。這可以防止目標(biāo)程序或工具損壞你的物理機(jī)系統(tǒng)。
      2. 目標(biāo)程序:你想要分析的那個(gè)被VMP2加密的 .exe 文件。
      3. VMPDump 工具:你需要從一些逆向工程論壇或網(wǎng)站下載這個(gè)工具。請(qǐng)注意,這些工具可能被殺毒軟件報(bào)毒,這是因?yàn)樗鼈兊男袨椋ㄈ缱⑷脒M(jìn)程、讀取內(nèi)存)與惡意軟件相似。請(qǐng)?jiān)谔摂M機(jī)中謹(jǐn)慎使用。
      4. 調(diào)試器:x64dbg (強(qiáng)烈推薦)。VMPDump 經(jīng)常需要附加到一個(gè)正在運(yùn)行的進(jìn)程上,所以你需要先運(yùn)行目標(biāo)程序。
      5. PE 編輯器:CFF Explorer 或 010 Editor。用于后續(xù)檢查生成的文件是否結(jié)構(gòu)正常。

      第三部分:使用 VMPDump 的詳細(xì)步驟

      假設(shè)你已經(jīng)找到了一個(gè)可以運(yùn)行的 VMPDump 版本,并且你的目標(biāo)程序是一個(gè)32位的EXE(VMPDump主要支持32位)。

      步驟 1:運(yùn)行目標(biāo)程序

      首先,雙擊運(yùn)行你要分析的那個(gè) .exe 文件。讓它正常運(yùn)行起來(lái),比如顯示出主窗口或?qū)υ?huà)框。

      步驟 2:以管理員身份運(yùn)行 VMPDump

      右鍵點(diǎn)擊 VMPDump.exe,選擇 “以管理員身份運(yùn)行”。這能確保它有足夠的權(quán)限去讀取其他進(jìn)程的內(nèi)存。

      步驟 3:附加到目標(biāo)進(jìn)程

      1. 在 VMPDump 的主界面上,你會(huì)看到一個(gè) “...” 按鈕,旁邊是 "Process" 或 "PID" 字段。
      2. 點(diǎn)擊這個(gè) “...” 按鈕,會(huì)彈出一個(gè)當(dāng)前正在運(yùn)行的進(jìn)程列表。
      3. 在列表中找到你的目標(biāo)程序進(jìn)程(例如 target.exe),選中它,然后點(diǎn)擊 “OK” 或 “Select”。

      步驟 4:智能掃描 (Smart Scan)

      這是 VMPDump 嘗試分析虛擬機(jī)的關(guān)鍵一步。

      1. 在界面上找到一個(gè)名為 “Smart Scan of Handlers” 的復(fù)選框,勾選它。
      2. 這一步會(huì)讓 VMPDump 嘗試在程序的內(nèi)存空間中搜索它認(rèn)為是 VMProtect 虛擬機(jī)處理器(VM Handlers)的代碼塊。這是它最容易失敗的地方。

      步驟 5:設(shè)置 OEP (Original Entry Point)

      VMPDump 會(huì)嘗試自動(dòng)檢測(cè) OEP。

      • 自動(dòng)檢測(cè):通常你不需要手動(dòng)設(shè)置 OEP 字段。VMPDump 會(huì)利用一些內(nèi)置的特征碼去定位。
      • 手動(dòng)設(shè)置:如果自動(dòng)檢測(cè)失敗,你需要自己通過(guò)其他方法(如 x64dbg 的 ESP 定律)找到 OEP 的相對(duì)虛擬地址(RVA),然后手動(dòng)填入 OEP 字段。對(duì)于初學(xué)者來(lái)說(shuō),如果 VMPDump 無(wú)法自動(dòng)找到 OEP,基本可以宣告失敗了。

      步驟 6:執(zhí)行 Dump(轉(zhuǎn)儲(chǔ))

      1. 在 VMPDump 界面上,點(diǎn)擊 “Unpack” 或 “Dump” 按鈕。
      2. VMPDump 會(huì)開(kāi)始它的工作流程:
        • 尋找 OEP。
        • 掃描 VM Handlers。
        • 轉(zhuǎn)儲(chǔ)內(nèi)存中的所有節(jié)區(qū)(Sections)。
        • 嘗試重建導(dǎo)入地址表(IAT)。
      3. 如果一切順利(概率很小),它會(huì)提示你保存文件。通常會(huì)默認(rèn)保存為 [原文件名]_unpacked.exe

      步驟 7:驗(yàn)證生成的文件

      這是最重要的一步,用來(lái)判斷 VMPDump 是否真的起作用了。

      1. 嘗試運(yùn)行:雙擊運(yùn)行生成的 _unpacked.exe 文件。

        • 直接崩潰? -> 失敗。很可能是 IAT 修復(fù)失敗或代碼段Dump不完整。
        • 可以運(yùn)行但功能異常? -> 部分失敗。可能某些保護(hù)代碼沒(méi)有被移除。
        • 可以正常運(yùn)行? -> 恭喜,你完成了最基礎(chǔ)的“脫殼”。但這不代表代碼被還原了。
      2. 使用 PE 工具檢查:用 CFF Explorer 打開(kāi) _unpacked.exe 文件。

        • 檢查 “Import Directory”(導(dǎo)入目錄),看看函數(shù)列表是否看起來(lái)正常,有沒(méi)有大量的無(wú)效或亂碼條目。
        • 檢查節(jié)表(Section Headers),看看 .text.data 等節(jié)的大小和權(quán)限是否合理。
      3. 使用 IDA Pro 分析:這是最終的檢驗(yàn)。用 IDA Pro 打開(kāi) _unpacked.exe 文件。

        • 找到你關(guān)心的關(guān)鍵功能(比如注冊(cè)按鈕的點(diǎn)擊事件)。
        • 按 F5 嘗試反編譯。
        • 結(jié)果是什么?
          • 如果依然是無(wú)法反編譯、跳轉(zhuǎn)關(guān)系混亂、充滿(mǎn)了奇怪計(jì)算的代碼 -> 這就證明了 VMPDump 沒(méi)有去虛擬化。它只是把內(nèi)存里的東西原封不動(dòng)地Dump了出來(lái)。關(guān)鍵邏輯依然被VM保護(hù)著。
          • 如果能看到清晰的C代碼邏輯 -> 這種情況幾乎不可能發(fā)生,除非你的目標(biāo)程序用的不是VMP的虛擬化保護(hù)。

      第四部分:當(dāng) VMPDump 失敗時(shí)(99% 的情況)

      你很可能會(huì)遇到以下情況,這都意味著 VMPDump 對(duì)你的目標(biāo)無(wú)效:

      • VMPDump 無(wú)法找到 OEP 或 Handlers:直接報(bào)錯(cuò),提示分析失敗。
      • VMPDump 在掃描過(guò)程中卡死或崩潰:說(shuō)明 VMP 的反分析機(jī)制觸發(fā)了。
      • 生成的 Dump 文件無(wú)法運(yùn)行:最常見(jiàn)的結(jié)果,說(shuō)明 Dump 或修復(fù)過(guò)程出錯(cuò)了。
      • 生成的 Dump 文件雖然能運(yùn)行,但關(guān)鍵功能(如注冊(cè))依然被保護(hù):證明了核心邏輯仍是虛擬化的。

      當(dāng) VMPDump 失敗后,你必須回到正統(tǒng)的、手動(dòng)的逆向工程流程上來(lái):

      1. 手動(dòng)尋找 OEP:使用 x64dbg 和 ESP 定律。
      2. 手動(dòng) Dump:使用 Scylla 插件,在 OEP 處進(jìn)行內(nèi)存轉(zhuǎn)儲(chǔ)。
      3. 手動(dòng)修復(fù) IAT:使用 Scylla 的 IAT 搜索和修復(fù)功能。
      4. 手動(dòng)去虛擬化:這才是真正的挑戰(zhàn)。在 IDA 和 x64dbg 中,花費(fèi)數(shù)天、數(shù)周甚至數(shù)月的時(shí)間去:
        • 分析 VM Entry 和 Dispatcher。
        • 逐個(gè)逆向 VM Handlers 的功能。
        • 編寫(xiě)腳本翻譯字節(jié)碼。
        • 找到關(guān)鍵邏輯并進(jìn)行 Patch。

      總結(jié)

      使用 VMPDump 是一個(gè)“死馬當(dāng)活馬醫(yī)”的嘗試。你可以按照上述步驟操作一遍,體驗(yàn)一下自動(dòng)化工具的工作流程。但這趟旅程的終點(diǎn),大概率是讓你明白:沒(méi)有捷徑可走,對(duì)抗高強(qiáng)度的軟件保護(hù),唯有扎實(shí)的逆向工程基礎(chǔ)和巨大的耐心。

       

       

       

      好的,我們來(lái)非常詳細(xì)地拆解和說(shuō)明 VMProtect 2 的加密功能和脫殼流程。這是一個(gè)極其復(fù)雜但非常有趣的技術(shù)話(huà)題。

      ?? 鄭重聲明:本內(nèi)容僅用于安全研究、技術(shù)學(xué)習(xí)和防御策略探討。對(duì)商業(yè)軟件進(jìn)行逆向工程、破解和傳播是違法行為,可能導(dǎo)致嚴(yán)重的法律后果。請(qǐng)?jiān)诜稍试S的范圍內(nèi)使用這些知識(shí),并尊重軟件開(kāi)發(fā)者的勞動(dòng)成果。


      Part 1: VMProtect 2 的核心加密功能(它做了什么?)

      VMProtect (VMP) 不是一個(gè)簡(jiǎn)單的“殼”,它是一個(gè)深度代碼混淆和虛擬化系統(tǒng)。其核心思想是讓你寫(xiě)的代碼,在你的電腦上都看不懂。

      1. 虛擬化保護(hù) (Virtualization) - VMP的王牌

      這是VMP最強(qiáng)大、最核心的功能。它能將你指定的代碼片段從標(biāo)準(zhǔn)的 x86/x64 匯編指令,轉(zhuǎn)換成一種自定義的、每次編譯都不一樣的字節(jié)碼(Bytecode)。

      工作原理圖解

      text
      你的原始代碼 (x86匯編):
      ┌──────────────────────────────┐
      │ MOV EAX, [EBP+8]  ; 取一個(gè)參數(shù)  │
      │ ADD EAX, 10       ; 加上 10     │
      │ CMP EAX, 1234     ; 和 1234 比較 │
      │ JNE loc_failed    ; 不相等就跳走  │
      │ CALL CheckLicense ; 相等就調(diào)用授權(quán) │
      └──────────────────────────────┘
                      ↓ 經(jīng)過(guò) VMProtect 處理后...
      ┌──────────────────────────────────────────────────────┐
      │            VM Entry(虛擬機(jī)入口)                      │
      │  功能: 保存當(dāng)前CPU的真實(shí)寄存器狀態(tài) (PUSHAD/PUSHFD),     │
      │        初始化虛擬機(jī)的環(huán)境(虛擬寄存器、虛擬棧指針等)。      │
      ├──────────────────────────────────────────────────────┤
      │        Bytecode(自定義的字節(jié)碼)                       │
      │  內(nèi)容: 0x47 0x12 0x89 0xAA 0x3F 0x91 0x05 ...         │
      │  特點(diǎn): 這串字節(jié)碼不是x86指令,只有VMP自己生成的虛擬機(jī)能看懂。│
      ├──────────────────────────────────────────────────────┤
      │            VM Dispatcher(調(diào)度器 / 指令分發(fā)器)         │
      │  功能: 這是一個(gè)循環(huán),不斷地讀取下一個(gè)字節(jié)碼,然后根據(jù)這個(gè) │
      │        字節(jié)碼的值,跳轉(zhuǎn)到對(duì)應(yīng)的處理器(Handler)去執(zhí)行。  │
      ├──────────────────────────────────────────────────────┤
      │         VM Handlers(處理器集合)                     │
      │  功能: 每一個(gè)Handler都是一小段真實(shí)的x86代碼,負(fù)責(zé)實(shí)現(xiàn) │
      │        一個(gè)字節(jié)碼的功能。例如:                       │
      │  - Handler_0x47: 實(shí)現(xiàn)“虛擬加法”功能。                 │
      │  - Handler_0x12: 實(shí)現(xiàn)“虛擬數(shù)據(jù)加載”功能。             │
      │  - Handler_0x89: 實(shí)現(xiàn)“虛擬比較”功能。                 │
      │  特點(diǎn): 這些Handler之間互相穿插,充滿(mǎn)了垃圾指令,讓你難以分析。│
      ├──────────────────────────────────────────────────────┤
      │            VM Exit(虛擬機(jī)退出)                      │
      │  功能: 執(zhí)行完虛擬化代碼后,從虛擬機(jī)環(huán)境退出,恢復(fù)之前保存的│
      │        真實(shí)CPU寄存器狀態(tài),然后返回到正常的x86代碼繼續(xù)執(zhí)行。│
      └──────────────────────────────────────────────────────┘

      為什么這讓破解變得極其困難?

      1. 獨(dú)一無(wú)二的指令集:每個(gè)被VMP保護(hù)的程序,其內(nèi)部的虛擬機(jī)、字節(jié)碼、Handler都是隨機(jī)生成的。你在A程序上分析得到的經(jīng)驗(yàn),完全無(wú)法用于B程序。
      2. 分析成本極高:你無(wú)法再用IDA Pro的F5功能直接看到C代碼。你必須先逆向分析出這套虛擬機(jī)的幾十甚至上百個(gè)Handler的功能,才能像翻譯密碼一樣,一點(diǎn)點(diǎn)地把字節(jié)碼“翻譯”回原始邏輯。這個(gè)過(guò)程可能需要數(shù)周甚至數(shù)月。
      3. 高度混淆:一個(gè)簡(jiǎn)單的 ADD EAX, 10 指令,在VM里可能被分解成V_PUSH 10 -> V_PUSH EAX -> V_ADD -> V_POP EAX 等多條虛擬指令,而每個(gè)虛擬指令的Handler本身又是高度混淆的真實(shí)x86代碼。

      2. 變異混淆 (Mutation)

      即使是不被虛擬化的代碼,VMP也會(huì)對(duì)其進(jìn)行“變異”,讓代碼變得臃腫、難以閱讀。

      • 等價(jià)指令替換:ADD EAX, 1 會(huì)被替換成 SUB EAX, -1 或 LEA EAX, [EAX+1]
      • 指令膨脹:MOV EAX, EBX 會(huì)變成 PUSH EBX; POP EAX
      • 插入垃圾代碼:在有效指令之間插入大量無(wú)用的、迷惑性的指令,這些指令不影響程序執(zhí)行結(jié)果,但會(huì)嚴(yán)重干擾靜態(tài)分析。
      • 控制流平坦化:將正常的 if-else 或 switch-case 結(jié)構(gòu),變成一個(gè)巨大的 while 循環(huán)和狀態(tài)機(jī),每次都通過(guò)一個(gè)調(diào)度器來(lái)決定下一步執(zhí)行哪個(gè)代碼塊,打亂原始的邏輯順序。

      3. 加殼與壓縮 (Packing)

      這是VMP的基礎(chǔ)功能。它會(huì)將程序的原始代碼段(.text)、數(shù)據(jù)段(.data)等進(jìn)行加密和壓縮,然后包裹在一個(gè)“加載器”(Loader)外殼里。

      • 運(yùn)行時(shí)解密:程序啟動(dòng)時(shí),首先執(zhí)行的是VMP的Loader。它會(huì)在內(nèi)存中解密、解壓原始的代碼和數(shù)據(jù)。
      • 入口點(diǎn)修改:程序的入口點(diǎn)(OEP, Original Entry Point)被隱藏起來(lái),指向了VMP的Loader。
      • 導(dǎo)入表保護(hù):程序調(diào)用的Windows API(如 MessageBoxA)地址不再靜態(tài)存儲(chǔ)在導(dǎo)入地址表(IAT)中,而是在運(yùn)行時(shí)動(dòng)態(tài)獲取,這使得分析者很難直接看到程序調(diào)用了哪些關(guān)鍵函數(shù)。

      4. 反調(diào)試與反分析 (Anti-Debug)

      VMP內(nèi)置了海量的反調(diào)試技術(shù),像地雷一樣遍布在代碼中,一旦發(fā)現(xiàn)自己被調(diào)試器(如x64dbg, IDA Pro)附加,就會(huì)改變行為。

      • 調(diào)試器檢測(cè):通過(guò) IsDebuggerPresentCheckRemoteDebuggerPresent 等API檢測(cè)。
      • 時(shí)間檢測(cè):使用 RDTSC 指令或 GetTickCount API,通過(guò)計(jì)算兩段代碼執(zhí)行的時(shí)間差來(lái)判斷是否在單步調(diào)試(單步執(zhí)行會(huì)花費(fèi)更長(zhǎng)的時(shí)間)。
      • 硬件斷點(diǎn)檢測(cè):檢查 DR0-DR7 調(diào)試寄存器。
      • 異常處理技巧:故意觸發(fā)一個(gè)異常,然后用 SEH(結(jié)構(gòu)化異常處理)來(lái)捕獲并執(zhí)行正常代碼。如果調(diào)試器干預(yù)了異常處理流程,程序就會(huì)崩潰。
      • 完整性檢查:在運(yùn)行時(shí)計(jì)算自身代碼的校驗(yàn)和(CRC),如果發(fā)現(xiàn)代碼被修改(比如被打了補(bǔ)丁),就會(huì)退出。

      Part 2: VMProtect 2 的脫殼流程(如何應(yīng)對(duì)?)

      “脫殼”對(duì)于VMP來(lái)說(shuō)是一個(gè)非常寬泛的概念。完整的流程極其復(fù)雜,通常分為以下幾個(gè)階段。

      階段一:準(zhǔn)備工作與環(huán)境配置

      這是所有工作的基礎(chǔ)。你需要一個(gè)“干凈”且“武裝到牙齒”的分析環(huán)境。

      1. 工具清單:

        • 調(diào)試器: x64dbg (主流選擇,插件豐富)
        • 反匯編器: IDA Pro 7.x (靜態(tài)分析的王者)
        • 反反調(diào)試插件: ScyllaHide (x64dbg插件,用于對(duì)抗各種反調(diào)試技術(shù))
        • Dump工具: Scylla (集成在ScyllaHide中,用于dump內(nèi)存和修復(fù)IAT)
        • PE工具: CFF Explorer 或 010 Editor (用于查看和編輯PE文件結(jié)構(gòu))
      2. 環(huán)境配置:

        • 虛擬機(jī):強(qiáng)烈建議在VMware或VirtualBox中進(jìn)行分析,防止搞垮物理機(jī)。
        • 配置ScyllaHide:在x64dbg中加載ScyllaHide插件,并盡可能多地勾選對(duì)抗選項(xiàng),如 NtQueryInformationProcessGetTickCount 等。

      階段二:尋找OEP (Original Entry Point - 真實(shí)入口點(diǎn))

      由于VMP加了殼,第一步就是找到VMP的Loader執(zhí)行完畢,即將跳轉(zhuǎn)到程序原始代碼的那個(gè)點(diǎn)(OEP)。

      常用方法:ESP定律

      1. 用x64dbg加載目標(biāo)程序,程序會(huì)停在系統(tǒng)斷點(diǎn)。
      2. 在x64dbg的命令行輸入 bp GetModuleHandleA,然后按F9運(yùn)行。程序會(huì)在加載系統(tǒng)DLL時(shí)斷下。
      3. 找到ESP寄存器的值,右鍵 -> 在內(nèi)存窗口中轉(zhuǎn)到。
      4. 在內(nèi)存窗口中,選中ESP指向的前4個(gè)字節(jié),右鍵 -> 斷點(diǎn) -> 硬件, 訪(fǎng)問(wèn) (Dword)。
      5. 按F9繼續(xù)運(yùn)行。程序會(huì)在VMP的殼代碼即將RETJMP到OEP之前,訪(fǎng)問(wèn)這個(gè)棧地址時(shí)斷下。
      6. 此時(shí),單步執(zhí)行(F7/F8),很大概率就會(huì)跳轉(zhuǎn)到OEP。

      如何判斷找到了OEP?

      • 代碼看起來(lái)像是正常的函數(shù)開(kāi)頭(如 PUSH EBP; MOV EBP, ESP)。
      • 可以看到清晰的API調(diào)用。
      • IDA Pro能夠很好地分析這部分代碼。

      階段三:Dump內(nèi)存鏡像

      在OEP處,程序的代碼和數(shù)據(jù)已經(jīng)在內(nèi)存中解密,此時(shí)需要將它們從內(nèi)存中“倒”出來(lái),存成一個(gè)新的EXE文件。

      1. 在x64dbg中,停在OEP處。
      2. 打開(kāi)插件菜單 -> Scylla。
      3. 在Scylla窗口中,確保進(jìn)程已附加,OEP地址已自動(dòng)填好(如果不對(duì),手動(dòng)修改為OEP的RVA)。
      4. 點(diǎn)擊 "IAT Autosearch" 按鈕,Scylla會(huì)自動(dòng)尋找并定位導(dǎo)入地址表。
      5. 點(diǎn)擊 "Get Imports" 獲取所有導(dǎo)入函數(shù)。
      6. 點(diǎn)擊 "Dump" 將內(nèi)存轉(zhuǎn)儲(chǔ)到文件(例如 dumped.exe)。
      7. 點(diǎn)擊 "Fix Dump",選擇剛才的 dumped.exe,Scylla會(huì)嘗試修復(fù)導(dǎo)入表,并生成一個(gè)新文件(例如 dumped_SCY.exe)。

      階段四:去虛擬化 (De-virtualization) - 最核心、最艱難的一步

      僅僅Dump出文件是遠(yuǎn)遠(yuǎn)不夠的,因?yàn)殛P(guān)鍵邏輯(如注冊(cè)碼驗(yàn)證)仍然是被虛擬化的字節(jié)碼。去虛擬化的目標(biāo)就是理解虛擬機(jī)的設(shè)計(jì)并還原原始邏輯。

      1. 識(shí)別VM Entry:在dump出的文件中,用IDA Pro打開(kāi)。找到調(diào)用虛擬化代碼的地方。通常這個(gè)地方會(huì)有一系列PUSH指令(保存環(huán)境),然后是一個(gè)JMP到一個(gè)非常復(fù)雜混亂的區(qū)域,這個(gè)區(qū)域就是VM Entry。

      2. 分析VM架構(gòu):這是純粹的逆向工程體力活。

        • 定位Dispatcher:VM Entry之后,你會(huì)找到一個(gè)核心的指令分發(fā)器。它通常是一個(gè)循環(huán),根據(jù)字節(jié)碼的值跳轉(zhuǎn)到不同的Handler。
        • 分析Handlers:以Dispatcher為中心,逐個(gè)分析它跳轉(zhuǎn)到的每一個(gè)Handler。
          • 在x64dbg中對(duì)某個(gè)Handler下斷點(diǎn),觀察它執(zhí)行前后對(duì)虛擬環(huán)境(通常在棧上分配的一塊內(nèi)存)做了什么修改。
          • 例如,你發(fā)現(xiàn)某個(gè)Handler總是把虛擬棧頂?shù)膬蓚€(gè)值相加,那么你就可以把它標(biāo)記為 V_ADD
          • 另一個(gè)Handler可能是從某個(gè)地方加載一個(gè)常量,你可以標(biāo)記為 V_LOAD_CONST
        • 重復(fù)此過(guò)程:你需要分析出盡可能多的Handler的功能,為它們命名。這個(gè)過(guò)程極其枯燥,可能需要分析幾十到上百個(gè)Handlers。
      3. 提取并反編譯字節(jié)碼:

        • 當(dāng)你大致搞清楚了虛擬機(jī)的指令集后,就可以在x64dbg中dump出被虛擬化的那段字節(jié)碼。
        • 編寫(xiě)一個(gè)簡(jiǎn)單的腳本(如Python),根據(jù)你分析出的Handler功能,將字節(jié)碼“翻譯”成可讀的偽代碼。
        Python
        # 偽代碼示例
        bytecode = [0x10, 0x04, 0x12, 0x34, 0x56, 0x78, 0x25, 0x30, 0x01]
        # 翻譯后可能得到
        # V_LOAD_CONST 0x12345678  (指令0x10)
        # V_CMP_WITH_INPUT        (指令0x25)
        # V_JNE_FAIL              (指令0x30)
      4. 還原邏輯并Patch:

        • 從翻譯出的偽代碼中,你就能看懂原始的驗(yàn)證邏輯了。
        • 暴力破解:找到關(guān)鍵的跳轉(zhuǎn),例如 V_JNE_FAIL,然后在實(shí)現(xiàn)這個(gè)虛擬跳轉(zhuǎn)的真實(shí)x64代碼處,將其修改(如 JNE 改成 JMP 或 NOP),從而繞過(guò)驗(yàn)證。這通常是最高效的方法。
        • 算法還原:如果你的目標(biāo)是寫(xiě)注冊(cè)機(jī),那就需要完全逆向整個(gè)算法,這難度極高。

      階段五:修復(fù)與清理

      1. 修復(fù)其他VMP“陷阱”:如完整性檢查(CRC Check)。你需要找到計(jì)算CRC的地方,然后將其N(xiāo)OP掉,或者在Patch后重新計(jì)算正確的CRC值并填回去。
      2. 測(cè)試:運(yùn)行你最終patch過(guò)的文件,確保所有功能正常,并且破解有效。

      總結(jié)

      步驟目標(biāo)難度常用工具關(guān)鍵技巧
      階段一: 準(zhǔn)備 搭建穩(wěn)定的分析環(huán)境 ★☆☆☆☆ VMware, x64dbg, ScyllaHide 反反調(diào)試配置
      階段二: 尋OEP 找到殼執(zhí)行完后的真實(shí)入口 ★★★☆☆ x64dbg ESP定律、硬件斷點(diǎn)
      階段三: Dump 將內(nèi)存中的解密代碼存盤(pán) ★★☆☆☆ Scylla, PE-sieve 修復(fù)IAT
      階段四: 去虛擬化 分析VM,還原原始邏輯 ★★★★★ IDA Pro, x64dbg 耐心、毅力、逆向思維
      階段五: 修復(fù) 移除其他保護(hù),完成破解 ★★★☆☆ x64dbg, 010 Editor 定位CRC校驗(yàn)

      結(jié)論:對(duì)VMP2進(jìn)行所謂的“暴力破解”幾乎是不可能的。真正的“破解”是一個(gè)極其漫長(zhǎng)且復(fù)雜的逆向工程過(guò)程,其核心是對(duì) VMProtect的虛擬機(jī)進(jìn)行“去虛擬化”分析。這需要深厚的匯編、操作系統(tǒng)底層知識(shí),以及超乎常人的耐心和毅力。對(duì)于大多數(shù)情況,分析者會(huì)選擇最簡(jiǎn)單的路徑,即只分析到能繞過(guò)驗(yàn)證的關(guān)鍵跳轉(zhuǎn),然后進(jìn)行Patch,而不會(huì)嘗試去完整地還原所有被虛擬化的代碼。

       

       

       

      VMProtect 2 加密功能與脫殼流程詳解

      ?? 法律聲明:以下內(nèi)容僅供安全研究和學(xué)習(xí)用途。未經(jīng)授權(quán)對(duì)軟件進(jìn)行逆向工程可能違反法律和軟件許可協(xié)議。


      ?? Part 1: VMProtect 2 的核心加密功能

      1.1 三大核心保護(hù)技術(shù)

      text
      ┌─────────────────────────────────────────────────────┐
      │          VMProtect 2 保護(hù)技術(shù)架構(gòu)圖                  │
      ├─────────────────────────────────────────────────────┤
      │                                                     │
      │  ┌─────────────┐  ┌──────────────┐  ┌───────────┐ │
      │  │ Virtualization│  │  Mutation    │  │  Packing  │ │
      │  │   虛擬化      │  │   變異混淆    │  │   加殼    │ │
      │  └─────────────┘  └──────────────┘  └───────────┘ │
      │         ↓                ↓                 ↓        │
      │  ┌─────────────────────────────────────────────┐   │
      │  │         Anti-Debug & Anti-Dump              │   │
      │  │         反調(diào)試 & 反轉(zhuǎn)儲(chǔ)                      │   │
      │  └─────────────────────────────────────────────┘   │
      │                                                     │
      └─────────────────────────────────────────────────────┘

      1.2 虛擬化保護(hù) (Virtualization) - 最強(qiáng)大的功能

      原理圖解

      text
      原始代碼(x86匯編):
      ┌──────────────────────────────┐
      │ MOV EAX, [EBP+8]             │
      │ ADD EAX, 10                  │
      │ CMP EAX, 64                  │
      │ JNE loc_failed               │
      │ CALL CheckLicense            │
      └──────────────────────────────┘
                      ↓ VMProtect 處理
      ┌──────────────────────────────────────────────────────┐
      │            VM Entry(虛擬機(jī)入口)                      │
      │  ? 保存真實(shí)寄存器狀態(tài)                                 │
      │  ? 初始化虛擬寄存器                                   │
      │  ? 加載字節(jié)碼指針                                     │
      ├──────────────────────────────────────────────────────┤
      │        Bytecode(自定義字節(jié)碼)                       │
      │  0x47 0x12 0x89 0xAA 0x3F 0x91 0x05 ...            │
      │  (每次編譯都不同!)                                 │
      ├──────────────────────────────────────────────────────┤
      │            VM Dispatcher(調(diào)度器)                    │
      │  while (true) {                                     │
      │    opcode = *bytecode_ptr++;                       │
      │    jump handlers[opcode];  // 跳轉(zhuǎn)到處理器           │
      │  }                                                  │
      ├──────────────────────────────────────────────────────┤
      │         VM Handlers(處理器集合)                     │
      │  Handler_0x47:  // 可能是 PUSH                      │
      │    vm_stack[++sp] = vm_regs[...];                  │
      │    混淆代碼...                                       │
      │    return to dispatcher;                           │
      │                                                     │
      │  Handler_0x12:  // 可能是 ADD                       │
      │    vm_regs[a] = vm_regs[b] + decrypt(...);         │
      │    垃圾代碼...                                       │
      │    return to dispatcher;                           │
      │  ...(可能有 50-200+ 個(gè) handlers)                   │
      ├──────────────────────────────────────────────────────┤
      │            VM Exit(虛擬機(jī)退出)                      │
      │  ? 恢復(fù)真實(shí)寄存器                                     │
      │  ? 返回到未保護(hù)代碼                                   │
      └──────────────────────────────────────────────────────┘

      虛擬化的"恐怖"之處

      C
      // 原始代碼:1條指令
      if (serial == 0x12345678) return true;
      
      // 虛擬化后:可能變成 100+ 條等價(jià)操作
      vm_reg[0] = decrypt_constant(bytecode[0]);  // 獲取 serial
      vm_reg[1] = 0x12;
      vm_reg[1] = (vm_reg[1] << 8) | 0x34;
      vm_reg[1] = (vm_reg[1] << 8) | 0x56;
      vm_reg[1] = (vm_reg[1] << 8) | 0x78;
      vm_reg[2] = vm_reg[0] ^ vm_reg[1];
      vm_reg[3] = ~vm_reg[2];
      vm_reg[3] = vm_reg[3] + 1;
      if (vm_reg[3] == 0) vm_flag = 1;
      // ... 還有幾十行垃圾指令

      1.3 變異混淆 (Mutation)

      代碼膨脹技術(shù)

      asm
      原始代碼:
          ADD EAX, 5
      
      變異后(可能變成以下任意一種):
      
      方式1: 等價(jià)替換
          SUB EAX, -5
      
      方式2: 多步驟分解
          ADD EAX, 3
          ADD EAX, 2
      
      方式3: 加入垃圾指令
          PUSH EBX
          MOV EBX, 5
          ADD EAX, EBX
          POP EBX
      
      方式4: 使用復(fù)雜運(yùn)算
          LEA EAX, [EAX + 5]
          
      方式5: 插入無(wú)效代碼
          JMP $+5
          DB 0xE8, 0xFF, 0xFF  // 看起來(lái)像CALL,但跳過(guò)了
          ADD EAX, 5

      控制流平坦化 (Control Flow Flattening)

      text
      原始代碼:
          A → B → C → D
      
      平坦化后:
               ┌→ Dispatcher ←┐
               │      ↓       │
               │   switch(state) {
               │   case 1: A; state=3; break;
               │   case 2: C; state=4; break;
               │   case 3: B; state=2; break;
               │   case 4: D; state=0; break;
               │   }         │
               └─────────────┘

      1.4 加殼與壓縮 (Packing)

      text
      原始PE文件結(jié)構(gòu):
      ┌────────────────┐
      │  PE Headers    │
      ├────────────────┤
      │  .text (100KB) │  ← 代碼段
      ├────────────────┤
      │  .data (50KB)  │  ← 數(shù)據(jù)段
      ├────────────────┤
      │  .rsrc (200KB) │  ← 資源
      └────────────────┘
      
              ↓ VMP 加殼處理
      
      加殼后的文件:
      ┌──────────────────────┐
      │  Original PE Headers │  ← 保留原始頭(部分修改)
      ├──────────────────────┤
      │  VMP Loader          │  ← 解密解壓代碼
      ├──────────────────────┤
      │  Encrypted .text     │  ← 加密的代碼段
      │  (壓縮 + 加密)        │
      ├──────────────────────┤
      │  Encrypted .data     │
      ├──────────────────────┤
      │  VM Core Engine      │  ← 虛擬機(jī)引擎代碼
      ├──────────────────────┤
      │  Encrypted Bytecode  │  ← 虛擬化后的字節(jié)碼
      ├──────────────────────┤
      │  Anti-Debug Code     │  ← 反調(diào)試模塊
      ├──────────────────────┤
      │  Import Protection   │  ← 導(dǎo)入表保護(hù)
      └──────────────────────┘

      1.5 反調(diào)試與反分析

      多層反調(diào)試技術(shù)清單

      text
      ╔══════════════════════════════════════════════════════════╗
      ║              VMProtect 2 反調(diào)試技術(shù)大全                   ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [硬件層]                                                 ║
      ║ ? 硬件斷點(diǎn)檢測(cè) (DR0-DR7寄存器)                           ║
      ║ ? 單步檢測(cè) (Trap Flag)                                  ║
      ║ ? 性能計(jì)數(shù)器檢測(cè)                                         ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [API層]                                                  ║
      ║ ? IsDebuggerPresent                                     ║
      ║ ? CheckRemoteDebuggerPresent                            ║
      ║ ? NtQueryInformationProcess (ProcessDebugPort)          ║
      ║ ? NtSetInformationThread (HideFromDebugger)             ║
      ║ ? OutputDebugString 技巧                                ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [時(shí)間檢測(cè)]                                               ║
      ║ ? RDTSC 指令(檢測(cè)時(shí)間差)                               ║
      ║ ? GetTickCount / QueryPerformanceCounter                ║
      ║ ? 兩次執(zhí)行間隔異常 → 判定為單步調(diào)試                      ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [進(jìn)程/線(xiàn)程檢測(cè)]                                          ║
      ║ ? 檢測(cè)調(diào)試器進(jìn)程名(OllyDbg.exe, x64dbg.exe等)          ║
      ║ ? 檢測(cè)調(diào)試器窗口類(lèi)名                                     ║
      ║ ? 父進(jìn)程檢測(cè)(是否被調(diào)試器啟動(dòng))                         ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [內(nèi)存檢測(cè)]                                               ║
      ║ ? PEB.BeingDebugged 標(biāo)志檢測(cè)                            ║
      ║ ? PEB.NtGlobalFlag 檢測(cè)                                 ║
      ║ ? Heap Flags 檢測(cè)                                       ║
      ║ ? 校驗(yàn)和檢測(cè)(代碼被修改)                               ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [異常處理]                                               ║
      ║ ? SEH 反調(diào)試(異常處理鏈)                               ║
      ║ ? VEH 反調(diào)試(向量化異常)                               ║
      ║ ? INT 3 / INT 2D 檢測(cè)                                   ║
      ║ ? 故意觸發(fā)異常,檢查處理流程                             ║
      ╠══════════════════════════════════════════════════════════╣
      ║ [虛擬機(jī)檢測(cè)]                                             ║
      ║ ? VMware / VirtualBox 檢測(cè)                              ║
      ║ ? CPUID 指令檢測(cè)                                        ║
      ║ ? 虛擬化環(huán)境特征檢測(cè)                                     ║
      ╚══════════════════════════════════════════════════════════╝

      ?? Part 2: VMProtect 2 脫殼流程詳解

      2.1 脫殼總體流程圖

      text
      ┌─────────────────────────────────────────────────────────────┐
      │                    VMProtect 2 脫殼流程                      │
      └─────────────────────────────────────────────────────────────┘
      
      階段一:環(huán)境準(zhǔn)備
        ├─ 安裝必要工具
        ├─ 配置反反調(diào)試環(huán)境
        └─ 樣本初步分析
      階段二:定位 OEP (Original Entry Point)
        ├─ 方法1: ESP定律
        ├─ 方法2: 內(nèi)存斷點(diǎn)
        ├─ 方法3: 最后一次異常
        └─ 方法4: SFX自解壓特征
      階段三:Dump內(nèi)存鏡像
        ├─ 使用 Scylla / OllyDumpEx
        ├─ 完整dump進(jìn)程內(nèi)存
        └─ 修正 ImageSize
      階段四:修復(fù)導(dǎo)入表 (IAT)
        ├─ 自動(dòng)搜索IAT
        ├─ 修復(fù)Thunk
        └─ 重建導(dǎo)入表
      階段五:去虛擬化 (最難!)
        ├─ 識(shí)別VM Entry
        ├─ 分析VM架構(gòu)
        ├─ 提取Handler
        ├─ 反編譯字節(jié)碼
        └─ 重建原始邏輯
      階段六:修復(fù)與測(cè)試
        ├─ 修復(fù)重定位表
        ├─ 修復(fù)資源
        ├─ 刪除反調(diào)試代碼
        └─ 測(cè)試運(yùn)行

      2.2 階段一:環(huán)境準(zhǔn)備與工具配置

      必備工具清單

      text
      ┌──────────────────────────────────────────────────────────┐
      │ 工具類(lèi)型          工具名稱(chēng)                  用途           │
      ├──────────────────────────────────────────────────────────┤
      │ 調(diào)試器            x64dbg                   主力調(diào)試        │
      │                  OllyDbg 2.01             32位程序備用    │
      │                  WinDbg                   內(nèi)核態(tài)調(diào)試      │
      ├──────────────────────────────────────────────────────────┤
      │ 反匯編器          IDA Pro 7.x              靜態(tài)分析        │
      │                  Ghidra                   開(kāi)源替代品      │
      ├──────────────────────────────────────────────────────────┤
      │ 反反調(diào)試          ScyllaHide              對(duì)抗反調(diào)試      │
      │                  TitanHide                驅(qū)動(dòng)級(jí)隱藏      │
      │                  HideOD                   隱藏OllyDbg     │
      ├──────────────────────────────────────────────────────────┤
      │ Dump工具          Scylla                   dump+IAT修復(fù)   │
      │                  OllyDumpEx               Olly插件        │
      │                  PE-sieve                 內(nèi)存掃描        │
      ├──────────────────────────────────────────────────────────┤
      │ PE工具            CFF Explorer             PE結(jié)構(gòu)查看     │
      │                  LordPE                   PE編輯         │
      │                  StudPE                   PE分析         │
      ├──────────────────────────────────────────────────────────┤
      │ 去虛擬化          VMPDump (部分有效)       自動(dòng)化工具      │
      │                  Code Virtualizer Tools   輔助分析        │
      │                  自寫(xiě)腳本                  IDAPython等     │
      ├──────────────────────────────────────────────────────────┤
      │ 監(jiān)控工具          Process Monitor          文件/注冊(cè)表監(jiān)控 │
      │                  API Monitor              API調(diào)用監(jiān)控     │
      │                  WinAPIOverride           API Hook       │
      └──────────────────────────────────────────────────────────┘

      x64dbg 配置示例

      text
      1. 安裝 ScyllaHide 插件
         - 下載 ScyllaHide.zip
         - 解壓到 x64dbg\plugins\
         - 重啟 x64dbg
         - 插件 → ScyllaHide → Options
         - 勾選所有反調(diào)試對(duì)抗選項(xiàng):
           ? NtQueryInformationProcess
           ? NtQuerySystemInformation
           ? NtSetInformationThread
           ? NtClose
           ? OutputDebugString
           ? GetTickCount
           ? ...
      
      2. 配置選項(xiàng)
         - 選項(xiàng) → 首選項(xiàng) → 異常
           ? 忽略所有異常(第一輪)
         - 選項(xiàng) → 首選項(xiàng) → 引擎
           ? 禁用調(diào)試特權(quán)
           ? 保存數(shù)據(jù)庫(kù)
      
      3. 安裝 Scylla
         - 插件 → Scylla → Hide from PEB

      2.3 階段二:定位 OEP (真實(shí)入口點(diǎn))

      方法1: ESP 定律(最常用)

      text
      原理:
      VMP的殼代碼執(zhí)行完后,會(huì)用類(lèi)似 RETN 的指令跳轉(zhuǎn)到OEP
      此時(shí)ESP指向的棧位置存放著OEP地址
      
      步驟:
      1. x64dbg 加載程序(暫停在系統(tǒng)斷點(diǎn))
      
      2. 命令行執(zhí)行:
         bp GetProcAddress  // 或者 bp LoadLibraryA
         F9 運(yùn)行
      
      3. 斷下后,在命令行:
         hr esp             // 對(duì)ESP指向的內(nèi)存地址下硬件訪(fǎng)問(wèn)斷點(diǎn)
         
      4. F9 繼續(xù)運(yùn)行
      
      5. 程序會(huì)在訪(fǎng)問(wèn)這個(gè)棧地址時(shí)斷下
         觀察此時(shí)的指令,通常是:
         PUSH xxxxxxxx
         RETN              ← 斷在這里
         
      6. 單步執(zhí)行 (F7),會(huì)跳轉(zhuǎn)到一個(gè)新地址
         此時(shí)查看代碼,如果看到:
         - 正常的函數(shù)序言(PUSH EBP; MOV EBP,ESP)
         - 或者開(kāi)始調(diào)用API
         - 代碼段名稱(chēng)變成 .text
         → 這就是 OEP!
      
      7. 記錄當(dāng)前地址,例如:00401000

      方法2: 內(nèi)存斷點(diǎn)法

      text
      步驟:
      1. 運(yùn)行程序,在 x64dbg 中打開(kāi)內(nèi)存映射 (Alt+M)
      
      2. 找到 .text 節(jié)(代碼段)
         - 名稱(chēng):.text
         - 權(quán)限:ER-(可執(zhí)行,可讀)
         - 大小:通常最大的可執(zhí)行段
      
      3. 右鍵 → 在反匯編中轉(zhuǎn)到 → 地址
         記錄起始地址,例如:00401000
      
      4. 在命令行設(shè)置內(nèi)存訪(fǎng)問(wèn)斷點(diǎn):
         bpm 00401000, 1, x    // 在00401000地址,1字節(jié),執(zhí)行時(shí)中斷
         
      5. F9 運(yùn)行,當(dāng)?shù)谝淮螆?zhí)行 .text 段代碼時(shí)會(huì)斷下
         → 這通常就是 OEP 附近
      
      注意:VMP可能會(huì)在OEP前多次訪(fǎng)問(wèn).text段進(jìn)行完整性檢查

      方法3: 異常斷點(diǎn)法

      text
      原理:VMP使用大量異常作為混淆手段,最后一個(gè)異常通常在OEP附近
      
      步驟:
      1. x64dbg → 選項(xiàng) → 首選項(xiàng) → 異常
         - 取消"忽略所有異常"
         - 只保留"忽略INT 3"
      
      2. F9 運(yùn)行,每次異常斷下時(shí):
         - 查看當(dāng)前位置是否在 .text 段
         - 如果不是,按 Shift+F9 傳遞異常
         
      3. 重復(fù)多次后,最終會(huì)停在接近OEP的地方
      
      4. 配合反匯編判斷是否為OEP

      如何確認(rèn)找到的是真正的 OEP?

      text
      特征檢查清單:
      ? 代碼段名稱(chēng)是 .text 或 CODE
      ? 可以看到清晰的函數(shù)調(diào)用(CALL API)
      ? 有正常的函數(shù)序言:
          PUSH EBP
          MOV EBP, ESP
          SUB ESP, xxx
      ? 或者是 WinMain 的標(biāo)準(zhǔn)開(kāi)頭:
          PUSH EBX
          PUSH ESI
          PUSH EDI
      ? 附近有字符串引用
      ? IDA Pro F5能正常反編譯
      ? 地址接近PE頭中的 AddressOfEntryPoint(但不完全相同)

      2.4 階段三:Dump 內(nèi)存鏡像

      使用 Scylla 進(jìn)行 Dump

      text
      步驟:
      1. 在 OEP 處暫停程序(上一步已找到)
      
      2. x64dbg → 插件 → Scylla
      
      3. Scylla 窗口設(shè)置:
         [*] Attach to: [選擇目標(biāo)進(jìn)程]
         [*] OEP: 00001000    ← 輸入相對(duì)于ImageBase的偏移
         [*] IAT AutoSearch   ← 自動(dòng)搜索導(dǎo)入表
         
      4. 點(diǎn)擊 "IAT Autosearch"
         - 如果成功,會(huì)顯示:
           Found IAT: 00402000 (Size: 0x400)
      
      5. 點(diǎn)擊 "Get Imports"
         - Scylla會(huì)分析IAT,列出所有導(dǎo)入函數(shù)
         - 檢查是否有 "invalid" 標(biāo)記的項(xiàng)
         
      6. 如果有invalid項(xiàng):
         - 右鍵 → Cut Thunk
         - 或手動(dòng)修復(fù)
      
      7. 點(diǎn)擊 "Dump"
         - 選擇保存位置,例如:dumped.exe
      
      8. 點(diǎn)擊 "Fix Dump"
         - 選擇剛才保存的 dumped.exe
         - Scylla會(huì)修復(fù)IAT并生成 dumped_SCY.exe

      手動(dòng) Dump (OllyDumpEx)

      text
      在 OllyDbg 中:
      1. 插件 → OllyDumpEx
      
      2. 設(shè)置參數(shù):
         Base Address: 00400000    ← 從內(nèi)存窗口查看
         Entry Point:  00001000    ← OEP的RVA
         Size:         00050000    ← 從PE頭SizeOfImage獲取
         
      3. 勾選選項(xiàng):
         ? Rebuild Import
         ? Fix Dump
         
      4. 點(diǎn)擊 "Dump" 保存
      
      注意:手動(dòng)dump可能需要后續(xù)修復(fù)重定位表

      2.5 階段四:修復(fù)導(dǎo)入表 (IAT Fix)

      IAT修復(fù)原理

      text
      正常程序的IAT:
      ┌──────────────────────────┐
      │ .idata 節(jié)                 │
      ├──────────────────────────┤
      │ Import Directory         │
      │  DLL: kernel32.dll       │
      │  Thunk Array:            │
      │    → CreateFileA         │
      │    → ReadFile            │
      │    → CloseHandle         │
      ├──────────────────────────┤
      │ IAT (導(dǎo)入地址表)          │
      │  0x402000: 76A81234  ← CreateFileA的真實(shí)地址
      │  0x402004: 76A85678  ← ReadFile的真實(shí)地址
      │  0x402008: 76A89ABC  ← CloseHandle的真實(shí)地址
      └──────────────────────────┘
      
      VMP加密后:
      ┌──────────────────────────┐
      │ Import Directory 被破壞   │
      │  或指向假數(shù)據(jù)             │
      ├──────────────────────────┤
      │ IAT 被加密/動(dòng)態(tài)生成       │
      │  0x402000: 00000000      │
      │  運(yùn)行時(shí)才填充真實(shí)地址     │
      └──────────────────────────┘
      
      修復(fù)目標(biāo):
      重建 Import Directory 和 IAT,使dump出的文件能獨(dú)立運(yùn)行

      Scylla 自動(dòng)修復(fù)

      text
      1. "IAT Autosearch" 原理:
         - 在OEP附近掃描內(nèi)存
         - 查找連續(xù)的、指向DLL代碼段的指針
         - 識(shí)別為IAT
      
      2. "Get Imports" 原理:
         - 讀取IAT中的地址
         - 通過(guò)地址找到對(duì)應(yīng)的DLL模塊
         - 在DLL的導(dǎo)出表中查找函數(shù)名
         - 重建導(dǎo)入表
      
      3. 常見(jiàn)問(wèn)題及解決:
         
         問(wèn)題1: "Found invalid imports"
         原因:某些地址不是真正的API地址
         解決:右鍵 → Cut Thunk (刪除)
         
         問(wèn)題2: "IAT not found"
         原因:IAT被嚴(yán)重混淆
         解決:手動(dòng)搜索
           - 在OEP處下斷點(diǎn)
           - 運(yùn)行程序,觀察哪些API被調(diào)用
           - 在內(nèi)存中搜索這些API的地址
           - 找到IAT的大致范圍后,手動(dòng)指定

      手動(dòng)修復(fù) IAT(高級(jí))

      text
      工具:IDA Pro + IDAPython
      
      腳本示例:
      import idaapi
      import idc
      
      def rebuild_iat(start, end):
          """重建IAT"""
          addr = start
          imports = []
          
          while addr < end:
              # 讀取指針
              ptr = idc.get_qword(addr) if idaapi.get_inf_structure().is_64bit() \
                    else idc.get_wide_dword(addr)
              
              # 檢查是否指向DLL代碼
              seg = idaapi.getseg(ptr)
              if seg and seg.type == idaapi.SEG_XTRN:
                  # 獲取函數(shù)名
                  name = idc.get_name(ptr)
                  if name:
                      imports.append((addr, name))
                      print(f"{hex(addr)}: {name}")
              
              addr += 4 if not idaapi.get_inf_structure().is_64bit() else 8
          
          return imports
      
      # 使用
      iat_start = 0x00402000  # 手動(dòng)確定的IAT起始
      iat_end = 0x00402400    # 手動(dòng)確定的IAT結(jié)束
      rebuild_iat(iat_start, iat_end)

      2.6 階段五:去虛擬化 (De-virtualization) - 核心難點(diǎn)

      5.1 識(shí)別 VM Entry

      text
      特征碼搜索法:
      在IDA Pro中搜索以下特征:
      
      特征1: 大量 PUSHFD / PUSHAD (保存寄存器)
      60                    PUSHAD
      9C                    PUSHFD
      ...
      大量MOV/PUSH操作
      ...
      
      特征2: 跳轉(zhuǎn)到動(dòng)態(tài)計(jì)算的地址
      MOV EAX, [EBP+var_XX]
      JMP [EAX*4+table_base]   ← VM Dispatcher
      
      特征3: 大量的RET鏈
      RETN
      RETN
      RETN  ← 每個(gè)Handler結(jié)束都用RETN返回Dispatcher
      
      手動(dòng)識(shí)別:
      1. 從OEP開(kāi)始F5查看
      2. 如果看到極其復(fù)雜的代碼,無(wú)法理解的嵌套
      3. 大量單字節(jié)變量操作
      4. 頻繁的函數(shù)調(diào)用但沒(méi)有明顯邏輯
      → 這些都是VM化的代碼

      5.2 分析 VM 架構(gòu)

      text
      目標(biāo):理解這個(gè)虛擬機(jī)的"指令集"
      
      ┌─────────────────────────────────────────┐
      │          VM 架構(gòu)分析清單                 │
      ├─────────────────────────────────────────┤
      │ 1. 虛擬寄存器 (Virtual Registers)        │
      │    - 在哪里存儲(chǔ)?(棧上/全局內(nèi)存)       │
      │    - 有多少個(gè)?(通常8-16個(gè))            │
      │    - 如何訪(fǎng)問(wèn)?                          │
      ├─────────────────────────────────────────┤
      │ 2. 虛擬棧 (Virtual Stack)                │
      │    - Stack Pointer 在哪?                │
      │    - PUSH/POP 如何實(shí)現(xiàn)?                 │
      ├─────────────────────────────────────────┤
      │ 3. 字節(jié)碼 (Bytecode)                     │
      │    - 存儲(chǔ)位置                            │
      │    - 讀取方式                            │
      │    - 格式:定長(zhǎng)?變長(zhǎng)?                  │
      ├─────────────────────────────────────────┤
      │ 4. Dispatcher (調(diào)度器)                   │
      │    - 入口地址                            │
      │    - 解碼邏輯                            │
      │    - 跳轉(zhuǎn)表結(jié)構(gòu)                          │
      ├─────────────────────────────────────────┤
      │ 5. Handlers (處理器)                     │
      │    - 數(shù)量統(tǒng)計(jì)                            │
      │    - 功能分類(lèi)                            │
      │    - 參數(shù)傳遞方式                        │
      └─────────────────────────────────────────┘

      5.3 提取 VM Handlers

      text
      方法:動(dòng)態(tài)跟蹤 + 靜態(tài)分析結(jié)合
      
      x64dbg 腳本示例:
      --------------------
      // 在 Dispatcher 下斷點(diǎn)
      bp 00401234  // Dispatcher地址
      
      // 記錄每個(gè)Handler
      var handler_list
      log "Opcode, Handler Address"
      
      loop:
          run
          mov eax, [esp]        // 假設(shè)棧頂是返回地址
          mov ebx, [ebp+opcode] // 假設(shè)EBP+offset存放opcode
          log "{ebx}, {eax}"
          esti                  // 執(zhí)行直到返回
          jmp loop
      --------------------
      
      輸出示例:
      Opcode, Handler Address
      0x01, 0x00401500  ← Handler_01
      0x02, 0x00401650  ← Handler_02
      0x03, 0x004017A0  ← Handler_03
      ...
      
      然后在IDA中逐個(gè)分析這些地址的代碼

      5.4 反編譯字節(jié)碼

      text
      步驟一:提取字節(jié)碼
      -----------------
      x64dbg內(nèi)存dump:
      1. 運(yùn)行到VM Entry后斷下
      2. 在dump窗口,找到字節(jié)碼起始地址(通常從某個(gè)寄存器得到)
         例如:EBP+0x100 指向字節(jié)碼
      3. 右鍵 → Dump Memory to File
      4. 保存為 bytecode.bin
      
      步驟二:編寫(xiě)反編譯器
      -------------------
      Python示例:
      
      class VMDecompiler:
          def __init__(self, bytecode_file):
              with open(bytecode_file, 'rb') as f:
                  self.bytecode = f.read()
              self.pc = 0  # Program Counter
              
              # Handler映射表(需手動(dòng)填充)
              self.handlers = {
                  0x01: self.vm_push,
                  0x02: self.vm_pop,
                  0x03: self.vm_add,
                  0x04: self.vm_sub,
                  0x05: self.vm_mov,
                  0x10: self.vm_cmp,
                  0x11: self.vm_jne,
                  # ... 更多
              }
          
          def read_byte(self):
              val = self.bytecode[self.pc]
              self.pc += 1
              return val
          
          def read_dword(self):
              val = int.from_bytes(self.bytecode[self.pc:self.pc+4], 'little')
              self.pc += 4
              return val
          
          def vm_push(self):
              val = self.read_dword()
              print(f"PUSH {hex(val)}")
          
          def vm_add(self):
              print("ADD vreg0, vreg1")
          
          def vm_jne(self):
              offset = self.read_dword()
              print(f"JNE {hex(offset)}")
          
          # ... 實(shí)現(xiàn)所有handler
          
          def decompile(self):
              while self.pc < len(self.bytecode):
                  opcode = self.read_byte()
                  if opcode in self.handlers:
                      self.handlers[opcode]()
                  else:
                      print(f"Unknown opcode: {hex(opcode)}")
                      break
      
      # 使用
      dec = VMDecompiler('bytecode.bin')
      dec.decompile()

      5.5 重建原始邏輯(最終目標(biāo))

      text
      輸入:反編譯的字節(jié)碼
      
      PUSH 0x12345678
      PUSH [ebp+8]
      CALL vm_hash
      CMP vreg0, vreg1
      JNE fail_label
      PUSH 1
      RET
      
      輸出:還原的C代碼
      
      int check_serial(char* input) {
          int hashed = vm_hash(input);
          if (hashed == 0x12345678) {
              return 1;
          }
          return 0;
      }
      
      然后可以:
      1. 用nop掉驗(yàn)證邏輯
      2. 或者寫(xiě)注冊(cè)機(jī)(基于還原的算法)
      3. 或者直接patch跳轉(zhuǎn)

      2.7 階段六:修復(fù)與測(cè)試

      6.1 刪除反調(diào)試代碼(暴力法)

      text
      在IDA Pro中搜索并NOP以下代碼:
      
      1. IsDebuggerPresent
         搜索:CALL IsDebuggerPresent
         替換:NOP x 5
      
      2. 時(shí)間檢測(cè)
         搜索:RDTSC / CPUID
         替換:XOR EAX,EAX (清零結(jié)果)
      
      3. 檢查BeingDebugged
         搜索:MOV AL, [FS:0x30] + 0x02
         替換:MOV AL, 0
      
      4. 異常反調(diào)試
         搜索:INT 3 / INT 2D
         替換:NOP

      6.2 修復(fù)重定位表

      text
      使用 CFF Explorer:
      1. 打開(kāi) dump_fixed.exe
      2. Relocation Editor
      3. 如果顯示 "No relocations":
         - 可能需要手動(dòng)重建
         - 或者將ImageBase固定為原始值
      
      手動(dòng)fix (如果必要):
      使用 LordPE:
      1. PE Editor
      2. Section Headers → .reloc
      3. 如果損壞,從原始文件復(fù)制.reloc節(jié)

      6.3 測(cè)試流程

      text
      1. 靜態(tài)測(cè)試
         - CFF Explorer 打開(kāi),檢查PE結(jié)構(gòu)完整性
         - ImportREC 驗(yàn)證導(dǎo)入表
         
      2. 沙箱測(cè)試
         - 虛擬機(jī)中運(yùn)行
         - 檢查是否崩潰
         - Process Monitor 監(jiān)控行為
         
      3. 功能測(cè)試
         - 主要功能是否正常
         - 是否還有反調(diào)試觸發(fā)
         - 是否有完整性檢查
      
      4. 對(duì)比測(cè)試
         - 與原始程序?qū)Ρ華PI調(diào)用序列
         - 對(duì)比關(guān)鍵算法輸出

      ?? Part 3: 實(shí)戰(zhàn)案例分析

      案例:破解一個(gè)簡(jiǎn)單的VMP2保護(hù)程序

      text
      目標(biāo)程序:CrackMe_VMP2.exe
      保護(hù)方式:VMProtect 2.08
      目標(biāo):繞過(guò)序列號(hào)驗(yàn)證
      
      =======================================
      步驟記錄:
      =======================================
      
      1. 查殼
         ? PEID: VMProtect 2.0x
         ? DIE: VMProtect 2.08
      
      2. 初步運(yùn)行
         ? 彈出對(duì)話(huà)框:"Enter Serial"
         ? 輸入錯(cuò)誤顯示:"Wrong Serial!"
         ? 推測(cè):驗(yàn)證邏輯被VM保護(hù)
      
      3. x64dbg加載 + ScyllaHide
         ? 所有反調(diào)試選項(xiàng)全開(kāi)
         ? F9運(yùn)行,程序正常彈窗
         
      4. 定位驗(yàn)證函數(shù)
         方法:API斷點(diǎn)
         ? bp GetDlgItemTextA  // 獲取輸入的API
         ? F9運(yùn)行,在輸入框輸入"test",點(diǎn)確定
         ? 斷下!
      
      5. 回溯查找驗(yàn)證邏輯
         ? 單步返回(Ctrl+F9)到調(diào)用者
         ? 發(fā)現(xiàn)代碼段:
           CALL GetDlgItemTextA
           LEA EAX, [EBP-0x100]
           PUSH EAX
           CALL 00401234        ← 可疑的驗(yàn)證函數(shù)
           TEST EAX, EAX
           JZ   fail_label
         
         ? 00401234 就是驗(yàn)證函數(shù)入口
      
      6. 分析驗(yàn)證函數(shù)
         ? 跟入 CALL 00401234
         ? 發(fā)現(xiàn)大量混淆代碼:
           PUSH ECX
           PUSH EDX
           MOV EAX, [ESP+8]
           JMP 00405678        ← 跳轉(zhuǎn)到VM Entry!
           
      7. 識(shí)別VM Entry
         地址:00405678
         特征:
           PUSHAD
           PUSHFD
           MOV EBP, ESP
           SUB ESP, 0x200
           MOV ESI, [大量初始化]
           ...
           JMP [EAX*4+0x00406000]  ← Dispatcher!
      
      8. 簡(jiǎn)化破解法:爆破跳轉(zhuǎn)
         ? 不去虛擬化了,直接改跳轉(zhuǎn)
         ? 在第5步的代碼處:
           TEST EAX, EAX
           JZ   fail_label    ← 改成 JNZ
         
         ? 使用x64dbg修改:
           選中 JZ 指令
           空格 → 編輯
           改成:JNZ fail_label
           右鍵 → Patch → Patch File
           保存為 CrackMe_VMP2_cracked.exe
      
      9. 測(cè)試
         ? 運(yùn)行 CrackMe_VMP2_cracked.exe
         ? 輸入任意序列號(hào)
         ? 成功彈出:"Correct!"
      
      =======================================
      總結(jié):
      對(duì)于簡(jiǎn)單目標(biāo),不需要完全去虛擬化
      找到關(guān)鍵跳轉(zhuǎn)直接patch即可
      但對(duì)于復(fù)雜的License系統(tǒng),可能需要完整分析
      =======================================

      ?? Part 4: 進(jìn)階技術(shù)

      4.1 自動(dòng)化去虛擬化工具

      text
      工具1: VMPAttack
      - GitHub開(kāi)源項(xiàng)目
      - 支持部分VMP版本
      - 能自動(dòng)識(shí)別Handler
      
      使用:
      python vmpattack.py target.exe --trace --devirt
      
      工具2: Kryptonite
      - IDA Pro插件
      - 符號(hào)執(zhí)行 + 污點(diǎn)分析
      - 半自動(dòng)去虛擬化
      
      工具3: 自己用Unicorn引擎寫(xiě)模擬器
      from unicorn import *
      from unicorn.x86_const import *
      
      # 模擬VM執(zhí)行
      uc = Uc(UC_ARCH_X86, UC_MODE_32)
      uc.mem_map(0x00400000, 2 * 1024 * 1024)
      uc.mem_write(0x00400000, code)
      uc.emu_start(0x00401000, 0x00401234)

      4.2 對(duì)抗完整性檢查

      text
      VMP的CRC校驗(yàn):
      1. 在運(yùn)行時(shí)計(jì)算代碼段的校驗(yàn)和
      2. 與內(nèi)置值比較
      3. 不匹配則退出
      
      對(duì)策:
      方法1:Hook校驗(yàn)函數(shù)
        bp [校驗(yàn)函數(shù)地址]
        修改返回值為"正確"
        
      方法2:修復(fù)校驗(yàn)值
        計(jì)算patch后的新CRC
        在內(nèi)存中搜索舊CRC值
        替換為新值
        
      方法3:NOP掉校驗(yàn)代碼
        找到CRC計(jì)算和比較代碼
        全部NOP

      總結(jié)

      VMProtect 2 的脫殼是逆向工程中的終極挑戰(zhàn)之一:

      難度評(píng)級(jí): ????? (5/5)

      時(shí)間成本:

      • 簡(jiǎn)單patch:1-3小時(shí)
      • 完整dump:1-2天
      • 去虛擬化:1周-數(shù)月

      成功率:

      • 基本脫殼:90%
      • IAT修復(fù):70%
      • 完全去虛擬化:<20%

      關(guān)鍵建議:

      1. 從簡(jiǎn)單目標(biāo)開(kāi)始練習(xí)
      2. 理論+實(shí)踐結(jié)合
      3. 善用自動(dòng)化工具
      4. 專(zhuān)注于關(guān)鍵邏輯,不要試圖還原全部
      5. 考慮替代方案(如內(nèi)存patch而不是文件patch)

      最后強(qiáng)調(diào):將知識(shí)用于合法的安全研究和學(xué)習(xí),尊重軟件版權(quán)!

       

       

       

      這是一個(gè)非常好的問(wèn)題,也是無(wú)數(shù)逆向工程愛(ài)好者和安全研究人員夢(mèng)寐以求的“圣杯”。

      答案非常明確且殘酷:不存在,也幾乎不可能存在一個(gè)能夠自動(dòng)化、通用、完美修復(fù)VMProtect加密程序的“萬(wàn)能工具”。

      下面我將詳細(xì)解釋為什么這在技術(shù)上是一個(gè)近乎無(wú)解的難題,以及為什么你看到的所謂“工具”都只是輔助性的。


      第一部分:為什么“萬(wàn)能工具”是一個(gè)幻想?

      要理解這一點(diǎn),我們必須區(qū)分**“加殼器 (Packer)”** 和 “虛擬化保護(hù)器 (Virtualizer)” 的根本區(qū)別。

      1. 簡(jiǎn)單的加殼器 (如 UPX)

      • 工作原理:像一個(gè)zip壓縮程序。它有一套固定的算法來(lái)壓縮原始代碼,然后在程序入口點(diǎn)放一小段固定的解壓代碼。
      • 脫殼原理:因?yàn)榻鈮核惴ㄊ枪潭ǖ模钥梢詫?xiě)一個(gè)固定的“解壓”工具(脫殼機(jī))。UPX -d 就是這樣一個(gè)萬(wàn)能脫殼工具,因?yàn)樗耆私?code class="rounded px-1.5 py-0.5 bg-surface-tertiary font-mono text-[0.9em] text-text-primary font-medium">UPX的壓縮算法。

      2. VMProtect (虛擬化保護(hù)器)

      • 工作原理:它不是一個(gè)zip程序,而是一個(gè)**“語(yǔ)言發(fā)明工廠(chǎng)”**。
        • 當(dāng)你用VMProtect保護(hù)你的程序時(shí),VMP會(huì)為你程序的關(guān)鍵代碼發(fā)明一種全新的、獨(dú)一無(wú)二的、隨機(jī)的編程語(yǔ)言(字節(jié)碼)。
        • 同時(shí),它還會(huì)為你**生成一個(gè)唯一的解釋器(虛擬機(jī)VM)**來(lái)執(zhí)行這種新語(yǔ)言。
      • 核心特性:無(wú)限變種 (Infinite Variation)
        • 不同的程序,不同的VM:用VMP保護(hù)A.exeB.exe,會(huì)得到兩個(gè)完全不同的虛擬機(jī)。A.exe里的VM不認(rèn)識(shí)B.exe的字節(jié)碼,反之亦然。
        • 同一程序,每次編譯都不同:你用完全相同的設(shè)置,兩次保護(hù)同一個(gè)A.exe,得到的A_v1.exeA_v2.exe,它們內(nèi)部的虛擬機(jī)和字節(jié)碼也是不一樣的。

      把這個(gè)概念具象化:

      想象一下,你想寫(xiě)一個(gè)“萬(wàn)能翻譯器”。

      • 對(duì)于UPX,這很簡(jiǎn)單,因?yàn)槟阒恍枰g一種公開(kāi)的語(yǔ)言(比如英語(yǔ)翻譯成中文),算法是固定的。
      • 對(duì)于VMProtect,這相當(dāng)于要求你的“萬(wàn)能翻譯器”能夠自動(dòng)翻譯地球上從未出現(xiàn)過(guò)的、由外星人剛剛隨機(jī)發(fā)明的、且每一個(gè)外星人說(shuō)的都不一樣的神秘語(yǔ)言。

      你會(huì)發(fā)現(xiàn),你根本無(wú)法制造這樣一個(gè)“萬(wàn)能翻譯器”。你只能逐個(gè)去接觸每一個(gè)外星人,花費(fèi)大量時(shí)間學(xué)習(xí)并破解他那套獨(dú)有的語(yǔ)言體系。


      第二部分:三大技術(shù)壁壘,讓“萬(wàn)能工具”無(wú)法實(shí)現(xiàn)

      1. 虛擬機(jī)架構(gòu)的無(wú)限隨機(jī)性

      一個(gè)自動(dòng)化工具需要依賴(lài)固定的模式(Pattern)來(lái)識(shí)別和處理代碼。但VMP的設(shè)計(jì)哲學(xué)就是消滅一切固定模式。

      每次保護(hù),以下所有元素都是隨機(jī)生成的:

      • 虛擬指令集 (Bytecode):0x01在A程序里可能是“加法”,在B程序里可能是“跳轉(zhuǎn)”。
      • 虛擬機(jī)處理器 (VM Handlers):執(zhí)行“加法”的真實(shí)x86代碼,在A和B程序里完全不同,充滿(mǎn)了各種垃圾指令和混淆。
      • 虛擬寄存器:虛擬機(jī)的寄存器數(shù)量、存儲(chǔ)位置(在棧上還是在特定內(nèi)存區(qū)域)都是隨機(jī)的。
      • 調(diào)度器 (Dispatcher):分發(fā)指令的核心邏輯也是千變?nèi)f化。

      一個(gè)工具無(wú)法通過(guò)靜態(tài)分析找到任何可依賴(lài)的“簽名”或“特征碼”來(lái)自動(dòng)化還原這個(gè)過(guò)程。

      2. 代碼變異與深度混淆 (Mutation & Obfuscation)

      即使是虛擬機(jī)本身的代碼(那些VM Handlers),也是經(jīng)過(guò)VMP深度混淆的。一個(gè)簡(jiǎn)單的 ADD EAX, EBX 會(huì)被變成幾十條甚至上百條等價(jià)但難以理解的指令。自動(dòng)化工具無(wú)法分辨哪些是有效代碼,哪些是垃圾代碼,更無(wú)法將其還原成最簡(jiǎn)形式。

      3. 無(wú)處不在的反分析陷阱 (Anti-Analysis Traps)

      VMP會(huì)在代碼中埋下無(wú)數(shù)“地雷”,專(zhuān)門(mén)用來(lái)對(duì)抗自動(dòng)化分析工具。

      • 完整性檢查 (CRC Check):自動(dòng)化工具在分析和修改代碼時(shí),會(huì)改變文件的校驗(yàn)和。VMP的自校驗(yàn)代碼一旦發(fā)現(xiàn)文件被修改,就會(huì)導(dǎo)致程序崩潰或行為異常。一個(gè)“萬(wàn)能工具”除非能智能地定位并修復(fù)所有校驗(yàn)點(diǎn),否則生成的程序就是個(gè)廢品。
      • 反調(diào)試和時(shí)序攻擊:自動(dòng)化工具的某些分析技術(shù)(如符號(hào)執(zhí)行)可能會(huì)被VMP的時(shí)鐘檢測(cè)、API行為檢測(cè)等機(jī)制發(fā)現(xiàn),從而觸發(fā)對(duì)抗。

      第三部分:那市面上的“VMP工具”是做什么的?

      你可能聽(tīng)過(guò)或用過(guò)一些名字里帶“VMP”的工具,比如VMPDumpVMP Unpacker by VT,或者一些開(kāi)源腳本。它們都不是“萬(wàn)能工具”,而是輔助分析的腳本或小程序,作用非常有限。

      1. 自動(dòng)化Dump工具 (如VMPDump)

        • 能做什么:嘗試自動(dòng)完成“尋找OEP”和“內(nèi)存轉(zhuǎn)儲(chǔ)”這兩個(gè)最最基礎(chǔ)的步驟。
        • 不能做什么:完全不能去虛擬化。它Dump出來(lái)的文件,關(guān)鍵代碼依然是VMP的字節(jié)碼。
        • 成功率:對(duì)非常古老、保護(hù)選項(xiàng)弱的VMP版本可能有效。對(duì)現(xiàn)代VMP版本基本100%失敗。
      2. 分析輔助腳本 (如IDAPython腳本)

        • 能做什么:幫助人類(lèi)分析師提高效率。例如,一個(gè)腳本可以自動(dòng)地:
          • 追蹤VM Dispatcher,并列出所有VM Handler的地址。
          • 為每個(gè)Handler打上標(biāo)簽,方便你逐個(gè)分析。
          • 嘗試對(duì)字節(jié)碼進(jìn)行初步的染色或分組。
        • 不能做什么:它不能告訴你某個(gè)Handler是“加法”還是“減法”。這個(gè)最關(guān)鍵的、需要智力判斷的工作,仍然需要你手動(dòng)完成。
      3. 學(xué)術(shù)研究型工具 (基于符號(hào)執(zhí)行、污點(diǎn)分析)

        • 能做什么:這是最前沿的嘗試。通過(guò)模擬執(zhí)行每一條指令,并追蹤數(shù)據(jù)的流動(dòng)(污點(diǎn)分析),理論上有可能推斷出部分代碼的原始邏輯。
        • 不能做什么:
          • 極度緩慢:分析一小段VMP代碼可能需要幾個(gè)小時(shí)甚至幾天。
          • 路徑爆炸:遇到復(fù)雜的分支,需要探索的路徑呈指數(shù)級(jí)增長(zhǎng),很快就會(huì)耗盡所有計(jì)算資源。
          • 使用復(fù)雜:需要博士級(jí)別的專(zhuān)業(yè)知識(shí)來(lái)配置和使用,絕非“一鍵運(yùn)行”。

      結(jié)論

      放棄尋找“自動(dòng)化脫殼VMP的萬(wàn)能工具”的想法。

      對(duì)抗VMProtect的唯一途徑,是將其視為一場(chǎng)人與機(jī)器的智力對(duì)抗。真正的“工具”是:

      1. 你的大腦:你的逆向工程知識(shí)、邏輯推理能力和分析經(jīng)驗(yàn)。
      2. 強(qiáng)大的調(diào)試器和反匯編器:如 x64dbg 和 IDA Pro,它們是你的眼睛和手術(shù)刀。
      3. 無(wú)盡的耐心:去虛擬化是一個(gè)極其枯燥和漫長(zhǎng)的過(guò)程,以周或月為單位計(jì)算。

      如果你真的想攻克它,正確的道路是學(xué)習(xí)扎實(shí)的逆向工程基礎(chǔ),而不是在網(wǎng)上尋找那個(gè)不存在的“魔法按鈕”。

       

      加密程序的執(zhí)行流程

      解密流程

      1.脫殼流程

      進(jìn)入程序的真實(shí)入口

      dump內(nèi)存文件

      修復(fù)pe數(shù)據(jù)、修復(fù)iat

      重定位及其他檢查

      image

       

      這里殼的作用就是解壓和解密代碼段和數(shù)據(jù)段和資源段。入口點(diǎn)變?yōu)榱颂摷俚臍と肟冢皇谴a段的mian函數(shù)。

      什么是修復(fù)

      目標(biāo)是使ida可以正常工作,可以靜態(tài)分析。
      保證pe結(jié)構(gòu)關(guān)鍵數(shù)據(jù)的完整及正確。
      保證對(duì)數(shù)據(jù)的引用正確,全局變量涉及重定位。
      保證跳轉(zhuǎn)指令的跳轉(zhuǎn)地址正確,cal、jmp指令涉及重定位。
      保證api的調(diào)用正確,涉及iat的修復(fù)

      image

       

       

      image

       

      到OEP如何
      特征法:根據(jù)原程序入口特征查找些編譯器編譯程序的入口特征

      image

       同時(shí)我們知道OEP的位置在dump中的ida程序中是沒(méi)有建立函數(shù)識(shí)別的,因?yàn)闆](méi)有任何一段函數(shù)會(huì)引用這段函數(shù),基本可以定位到這個(gè)OEP位置

      殼分析法:根據(jù)殼代碼查找這里需要我們熟悉殼代碼的流程,知道殼代碼將控制權(quán)轉(zhuǎn)交給OEP的位置。

      API方法;

      image

       

       

      image

       我識(shí)別是什么程序我們可以dump內(nèi)存獲取特征

      這里我用

      https://www.unpac.me/results/556bdbc0-32f7-467f-ad28-42d5cf9112be

      上傳樣本自動(dòng)分析流程發(fā)現(xiàn)特折

       

      image

       

       

      image

       vmp檢測(cè)軟件和硬件斷點(diǎn)就無(wú)法設(shè)置oep處的斷點(diǎn)

       

       

      image

       

       

      image

       

       1.執(zhí)行后第一次會(huì)自動(dòng)斷點(diǎn)到系統(tǒng)庫(kù)nt停止,點(diǎn)擊執(zhí)行后第二次第三次,執(zhí)行是gdi庫(kù),第四此就進(jìn)入到了軟件的vmp段,也就是正式進(jìn)入了殼中。

      image

       2.ctrl+g 輸入 vs2017的入口函數(shù)特征 GetSystemTimeAsFileTime,點(diǎn)擊定位后雙擊進(jìn)入這個(gè)api,

      image

       雙擊進(jìn)入這個(gè)api,在第二個(gè)匯編雙擊下斷點(diǎn)。因?yàn)関mp會(huì)檢測(cè)第一句代碼。 然后運(yùn)行

      3.繼續(xù)運(yùn)行,我們?cè)诙褩7祷睾瘮?shù)地址,檢查段區(qū)域,發(fā)現(xiàn)在vmp中,說(shuō)明vmp中也用了這個(gè)api,我們跳過(guò)這個(gè)

      4.繼續(xù)運(yùn)行,我們?cè)诙褩7祷睾瘮?shù)地址,檢查段區(qū)域,發(fā)現(xiàn)在text段中,我們右鍵在反匯編展示這個(gè)段匯編定位到返回地址,也就是說(shuō)調(diào)用這個(gè)api的入口函數(shù)就在這里附近。

      image

       我們?cè)谡鎸?shí)入口OEP下斷即可,并記錄oep地址,取消api斷點(diǎn),重啟這個(gè)程序并重新執(zhí)行到這個(gè)斷點(diǎn)處,也就是text的用f4執(zhí)行到GetSystemTimeAsFileTime的下一條指令f4。我們也就完成了vmp段的執(zhí)行將text段的代碼解壓也就完成了。這里為什么我們要下斷后重啟程序,因?yàn)槲覀兿聰嗟膐ep位置已經(jīng)執(zhí)行完畢了代碼,數(shù)據(jù)已經(jīng)發(fā)生了變化,為了保持原始數(shù)據(jù),我們必須在oep處下斷重啟執(zhí)行。

      image

       我們查看上一個(gè)棧的返回值,我們右鍵同步反匯編試圖發(fā)現(xiàn)這里就是真正的oep位置

      因此我們清楚了調(diào)用流程是

      vmp到 txt的oep 再到 txt的api,我們現(xiàn)在在api下。

      為了驗(yàn)證猜想,我們下斷回退代碼。

      我們?cè)趖xt的api下一個(gè)返回地址下端,執(zhí)行,單步執(zhí)行,發(fā)現(xiàn)返回到了oep,同樣的操作就返回的了殼子的調(diào)用oep的位置。這里就不演示了。

       

      dump文件整數(shù)據(jù)保存在文件中。相當(dāng)于模塊內(nèi)存的將加載到內(nèi)存中的模塊的完一個(gè)拷貝。
      查看dump文件需要16進(jìn)制編輯器,如winhex

       因?yàn)榧恿藲さ某绦颍a和數(shù)據(jù)是以壓縮或者加密的形式保存在文件中。只有程序運(yùn)行到OEP時(shí),內(nèi)存中才會(huì)有完整的原代碼和原數(shù)據(jù)。所以我們需要在OEP處dump模塊。

       

      思考一個(gè)問(wèn)題:是不是OEP以后的位置都可以dump?
      答案:不是的,需要在處理數(shù)據(jù)之前,我們還要保證數(shù)據(jù)段是初始的狀態(tài)。

       當(dāng)EIP在EP時(shí)原代碼段是沒(méi)有數(shù)據(jù)的,所以這里dump它,是沒(méi)有意義的。

       當(dāng)EIP在OEP時(shí),其實(shí)OEP就在text段說(shuō)明代碼段已經(jīng)有了數(shù)據(jù)。

       我們已經(jīng)找到了OEP的位置我們直接到這里,通過(guò)比較框架代碼,OEP的指令是"call,jmp我們通過(guò)棧回溯到OEPMVIO OA/S

       

       第二部修復(fù)ida

       

      image

       因?yàn)関mp保護(hù)的程序,它的導(dǎo)入表是殼的導(dǎo)入表,不是原程序的導(dǎo)入表。我們dump下來(lái)后,代碼和數(shù)據(jù)有了,但是代碼中的API調(diào)用是錯(cuò)誤的。脫殼后,殼的導(dǎo)入表就失去作用,可以去掉它,

      image

       

      image

       

       

       

      修復(fù)vmcall,就是修復(fù)代碼中的call調(diào)用

      xx vm iat x32插件發(fā),主要用于修復(fù)vmp保護(hù)的API調(diào)用。

      我們?cè)趏d里操作因?yàn)椴寮趚64dbg有問(wèn)題,打開(kāi)軟件運(yùn)行目標(biāo)程序。

      ctrl+g 輸入api名稱(chēng)GetSystemTimeAsFileTime,下一個(gè)匯編處下斷點(diǎn)運(yùn)行

      發(fā)現(xiàn)在vmp段里,再次運(yùn)行發(fā)現(xiàn)在text段內(nèi)

      在棧返回地址右鍵同步匯編代碼,在匯編試圖右鍵取消分析顯示匯編代碼,我們?cè)?eb處下斷點(diǎn)

      開(kāi)始修復(fù)call

      image

       

      image

       

      image

       在按鈕區(qū)域點(diǎn)擊I,查看日志,顯示成功

      image

       我們點(diǎn)擊窗口標(biāo)題后完成所有修復(fù)

      image

       

       

      dump內(nèi)存

      https://down.52pojie.cn/Tools/PEtools/?amp%3BO=A

      Scylla.v.0.9.8.rar

      這有兩種方法,一個(gè)插件,一個(gè)可執(zhí)行,

      我們用右鍵管理員執(zhí)行可執(zhí)行的32或64位exe,具體位數(shù)取決于你的目標(biāo)程序位數(shù),打開(kāi)選擇這個(gè)程序,并填入oep虛擬地址地址,點(diǎn)擊dump

      image

       

      修復(fù)pe

      image

       這里的模塊基地址和內(nèi)存的一致。因?yàn)橹囟ㄎ灰潭K地址,不在修復(fù)模塊偏移。

       

       

       

      image

       將40改為00,去除dll屬性重定位。

       

      image

       我們看到DlCharacteristics是0x8140,有模塊重定位標(biāo)志0x40,我們?nèi)サ羲某稍斍槲覀冊(cè)诘?節(jié)0x8100,講解。

       

      修復(fù)IAT

      uifUniversal lmport Fixer,在內(nèi)存中重建導(dǎo)入地址表if,

      image

       修復(fù)完成后不要關(guān)閉

       

       

       

       

      修復(fù)IT
      lmports Fixer,重建dump文件的導(dǎo)入表

      image

       

      image

      注意上面是oep是偏移  

      點(diǎn)擊修復(fù)dump,選這上次的dump出的文件,修復(fù)即可生成if.dump文件

       

       

      image

       

      image

       

      image

       

      image

       

      image

       我們上一節(jié)中,修復(fù)完iat,程序就已經(jīng)可以運(yùn)行了,看起來(lái)不用修復(fù)重定位了,其實(shí)我們是使用了比較簡(jiǎn)便的辦法。我們回想一下ageBase是0x00400000,并且我我們修復(fù)PE數(shù)據(jù)時(shí),看到Im的模塊重定位標(biāo)志,dump文件時(shí)們?nèi)サ袅薉lCharacteristics中內(nèi)存中模塊地址是0x00400000,而dump文件的尋址指令中的立000對(duì)應(yīng)的,所以我們只要讓dump即數(shù)都是和模塊地址0x00400文件加載到0x00400000這個(gè)也址,所有的尋址指令就都對(duì)上了,就可以正常運(yùn)行了。

       指令中API的調(diào)用我們也是因?yàn)楣潭四K地址。

       

      殼代碼隱藏了原程序的重定位數(shù)據(jù),我們看不到重定位表
      想要找到原程序的重定位表會(huì)非常困難,學(xué)會(huì)了虛擬代碼還原之后我們就可以做到。
      對(duì)于exe,我們可以使用固定模塊地址的方法,d則不可以。
      重定表的結(jié)構(gòu)是一樣的。前面我vmp修改了的重定位的數(shù)據(jù)定義,們看到正常的重定位數(shù)據(jù)是16位,高4位為標(biāo)志,低12位為頁(yè)偏移vmp自己的重定位數(shù)據(jù),高12位為頁(yè)偏移,低4位為標(biāo)志

       

      資源檢查
      例子中沒(méi)有使用vmp資源加密。關(guān)于資源的方面的知識(shí)點(diǎn),可以查看相關(guān)文檔資料進(jìn)行學(xué)習(xí)。

       

      image

       

       

      image

       

       

       

       

      image

       

       

      image

       

      image

       

      image

       

      image

       

      image

       

      image

       

      image

       

      image

       

       

      image

       

      image

       

      破解VMProtect v.1.6x – 1.7殼
      1.附加進(jìn)程
      2.輸入要跟隨的表達(dá)式:VirtualProtect
      3.找到Call VirtualProtectEx下端點(diǎn)
      4.運(yùn)行,至堆棧窗口顯示ReadOnly。(即代碼釋放完畢)
      5.打開(kāi)內(nèi)存窗口,在第一個(gè)代碼段設(shè)置內(nèi)存訪(fǎng)問(wèn)斷點(diǎn)
      6.運(yùn)行后停下來(lái),右鍵斷點(diǎn)–刪除內(nèi)存短點(diǎn)
      7.找到寄存器的ESP,數(shù)據(jù)窗口中跟隨
      8.從最低找,找到第一個(gè)“返回Kernel32…”,在其上一行設(shè)置硬件寫(xiě)入斷點(diǎn)(Byte)
      9.運(yùn)行,打開(kāi)內(nèi)存窗口,第一個(gè)代碼段設(shè)置內(nèi)存訪(fǎng)問(wèn)斷點(diǎn)。
      10.繼續(xù)運(yùn)行,到達(dá)OEP。
      11.可以使用od自帶插件,也可用LordPE脫殼,再用ImportREC修復(fù)轉(zhuǎn)存。

      posted on 2025-10-25 18:41  GKLBB  閱讀(98)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 日本高清中文字幕一区二区三区| 亚洲一区二区三区四区| 国产成人av电影在线观看第一页| 国产毛片欧美毛片久久久| 一区二区三区成人| 色久综合色久综合色久综合| 欧美亚洲国产日韩电影在线| 东莞市| 国产精品午夜福利在线观看| 中文字幕国产精品自拍| 天美传媒一区二区| 精品国产一区二区在线视| 亚洲国产精品综合久久20| 亚洲成av人片天堂网老年人| 中文字幕久久六月色综合| 亚洲av无码乱码在线观看野外| 国产精品国产三级国快看| 国产精品麻豆va在线播放| 色九月亚洲综合网| 国产高潮国产高潮久久久| 人人妻人人妻人人片色av| 天天拍夜夜添久久精品大| 国产精品久久中文字幕| 国产成人高清亚洲一区二区| 久久综合九色综合97欧美| 国产av午夜精品福利| 亚洲丶国产丶欧美一区二区三区| 国产69精品久久久久久妇女迅雷| 中文字幕日韩有码一区| 亚洲精品在线视频自拍| 18禁国产一区二区三区| 亚洲精品无amm毛片| 精品一区二区三区少妇蜜臀| 人人爽人人爽人人片a免费| 亚洲少妇人妻无码视频| 亚洲欧洲av人一区二区| 久久国产精品精品国产色婷婷| 亚洲乱码精品久久久久..| 奶头好大揉着好爽视频| 久久久无码精品午夜| 国产激情无码一区二区三区|