BC2023 发表于 2023-12-23 11:20

VMP下HOOK遇到的问题

关注了大神[@你与明日 ,ID:251657]的作品《DLL巧妙的绕过被VMP壳HOOK的ZwProtectVirtualMemory》一文,刚好在写一款从EXE导出数据的小工具,实际操作中碰到了闪退的问题,需要请大神们给予指志。
PBYTE CHook::LoadFileContext(CString filename, CString apifun)
{
    HANDLE hFile;
    PBYTE hDllContext = NULL;
    HMODULE ntdllAddr = NULL;
    CString libname = filename;
    UINT pos = filename.ReverseFind('\\');
    hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
      MessageBox(0, ("CreateFileError"), ("error"), MB_OK);
      return NULL;
    }

    if(pos != -1) {
      libname = filename.Right(filename.GetLength()-pos-1);
    }
    ntdllAddr = LoadLibrary(libname);
    PBYTE apiAddr = (PBYTE)GetProcAddress(ntdllAddr, apifun);
    if (apiAddr == NULL || ntdllAddr == NULL) {
      MessageBox(0, ("LoadLibrary|GetProcAddress,Error"), ("error"), MB_OK);
      CloseHandle(hFile);
      return NULL;
    }

    //把Ntdll读入进内存
    DWORD dwHighSize = 0;
    DWORD dwLowSize = GetFileSize(hFile, &dwHighSize);
    BYTE* pBuff = new BYTE();
    DWORDdwFileSize = 0;
    ReadFile(hFile, pBuff, dwLowSize + dwHighSize, &dwFileSize, NULL);

    //寻找所在区段
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
    PIMAGE_NT_HEADERS32 pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + ((SIZE_T)pDosHeader));
    PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(((SIZE_T)(pNtHeader)) + sizeof(IMAGE_NT_HEADERS32));
    DWORD Deviation = 0;
    //ZwProtectVirtualMemory 地址 - ntdll地址 = RVA
    SIZE_T Rva = (DWORD)apiAddr - (DWORD)ntdllAddr;

    // 先通过RVA找到所在区段,再用RVA-当前区段RVA+当前区段文件偏移 = F0A
    // 最后用F0A找到相对的opcode,复制到新内存执行再跳转
    for (WORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; ++i) {
      // 通过RVA找到所在区段,再用RVA-当前区段RVA+文件偏移 = F0A
      if (Rva >= pSectionHeader.VirtualAddress && Rva < pSectionHeader.VirtualAddress + pSectionHeader.SizeOfRawData) {
            Deviation = Rva - pSectionHeader.VirtualAddress + pSectionHeader.PointerToRawData;
            break;
      }
    }

    if (Deviation == 0) {
      MessageBoxA(0, "计算段内偏移错误", "error", MB_OK);
      delete[] pBuff;
      CloseHandle(hFile);
      return NULL;
    }

    // 最后用段内偏移找到相对的opcode
    // 申请一段堆空间执行被修改的汇编代码
    hDllContext = (PBYTE)VirtualAlloc(0, 0x10, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (hDllContext == NULL) {
      MessageBoxA(0, "VirtualAlloc Error", "error", MB_OK);
      delete[] pBuff;
      CloseHandle(hFile);
      return NULL;
    }

    WriteLogger("%s <%s> file vs vmp Context: \n", libname, apifun);
    for(int c=0; c<1; c++) {
      WriteLogger("===%d===\r\nSRC:", c);
      for(int i=0; i<16; i++) {
            WriteLogger("%02X ", pBuff);
      }
      WriteLogger("\r\nVMP:");

      for(int i=0; i<16; i++) {
            WriteLogger("%02X ", apiAddr);
      }
      WriteLogger("\r\n");
    }
    memcpy(hDllContext, pBuff + Deviation, 5);//x32下VMP修改了前5字节,把文件内的原5字节拷贝过去
    apiAddr += 5;
#if 0
    hDllContext = 0x68;//push
    memcpy(hDllContext + 6, &apiAddr, 4);//push的地址是ZwProtectVirtualMemory+5的地方
    hDllContext = 0xc3;//使用retn过去
#else
    // jmp ZwProtectVirtualMemory
    hDllContext = 0xE9;
    *((DWORD*)(hDllContext+6)) = (DWORD)apiAddr;
#endif
    /*****************************************
    0:b8 50 00 00 00          mov    eax,0x50
    5:e9 a5 30 52 77          jmp    0x775230af
    ************************************************/
    delete[] pBuff;
    CloseHandle(hFile);

    WriteLogger("\n\n%08x, RESULT: \n", apiAddr);
    for(int i=0; i<16; i++) {
      WriteLogger("%02X ", hDllContext);
    }
    WriteLogger("\r\n\r\n");

    return hDllContext;
}

SIZE_T CHook::ZwProtectVirtualMemory(
    HANDLE ProcessHandle,          // 进程句柄
    PVOID* BaseAddress,            // 地址的指针
    SIZE_T* NumberOfBytesToProtect,// 修改的大小,函数调用后会改成成功修改的大小
    ULONG NewAccessProtection,   // 新的内存属性
    PULONG OldAccessProtection)    // 旧的内存属性
{
    // ZwProtectVirtualMemory
    /******************************************
    0:b8 50 00 00 00          mov    eax,0x50
    5:ba 40 8a 30 4b          mov    edx,0x4b308a40
    a:ff d2                   call   edx
    c:c2 14 00                ret    0x14
    f:90                      nop
    /******************************************
    0:e9 6a cf b4 8c          jmp    0x8cb4cf6f
    5:ba 40 8a 53 77          mov    edx,0x77538a40
    a:ff d2                   call   edx
    c:c2 14 00                ret    0x14
    f:90                      nop
    ************************************************/
    if(hProtectVirtualMemory == NULL) {
      hProtectVirtualMemory = (fZwProtectVirtualMemory)LoadFileContext("C:\\Windows\\System32\\ntdll.dll", "ZwProtectVirtualMemory");
      if (hProtectVirtualMemory == NULL) {
            MessageBox(0, ("LoadFileContext|ntdll.dll,Error"), ("error"), MB_OK);
            return 0;
      }
    }

    return hProtectVirtualMemory(
      ProcessHandle,
      BaseAddress,
      NumberOfBytesToProtect,
      NewAccessProtection,
      OldAccessProtection
    );
}BOOL CHook::ReadProcessMemory(
    HANDLE hProcess,
    LPCVOID lpBaseAddress,
    LPVOID lpBuffer,
    SIZE_T nSize,
    SIZE_T *lpNumberOfBytesRead )
{
    // ReadProcessMemory
    /******************************************
    0:8b ff                   mov    edi,edi
    2:55                      push   ebp
    3:8b ec                   mov    ebp,esp
    5:5d                      pop    ebp
    6:ff 25 58 13 88 6b       jmp    DWORD PTR ds:0x6b881358
    /******************************************
    0:8b ff                   mov    edi,edi
    2:55                      push   ebp
    3:8b ec                   mov    ebp,esp
    5:5d                      pop    ebp
    6:ff 25 58 13 72 75       jmp    DWORD PTR ds:0x75721358
    ************************************************/
    // if(hReadProcessMemory == NULL) {
    //   hReadProcessMemory = (fReadProcessMemory)LoadFileContext("C:\\Windows\\System32\\Kernel32.dll", "ReadProcessMemory");
    //   if (hReadProcessMemory == NULL) {
    //         MessageBox(0, ("LoadFileContext|Kernel32.dll,Error"), ("error"), MB_OK);
    //         return 0;
    //   }
    // }

    return ::ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
}


BOOL CHook::VMP_ReadData(DWORD address, DWORD* dwNews, UINT len)
{
    BOOL ret = FALSE;
    DWORD dwOldProtect = 0; //旧保护属性

    // MyMessageBox();

    // 去内存保护
    WriteLogger("%s:%d modify memory.\n", __FUNCTION__, __LINE__);
    this->ZwProtectVirtualMemory(INVALID_HANDLE_VALUE, (PVOID*)&address, (SIZE_T*)&len, PAGE_READWRITE, &dwOldProtect); //修改属性

    // Hook 读指定长度的内存
    WriteLogger("%s:%d ReadProcessMemory.\n", __FUNCTION__, __LINE__);
    // if (ReadProcessMemory(INVALID_HANDLE_VALUE, (LPCVOID)address, dwNews, len, NULL) == 0) {
    ret = this->ReadProcessMemory(INVALID_HANDLE_VALUE, (LPCVOID)address, dwNews, len, NULL);

    // 写内存保护
    WriteLogger("%s:%d restore memory.\n", __FUNCTION__, __LINE__);
    this->ZwProtectVirtualMemory(INVALID_HANDLE_VALUE, (PVOID*)&address, (SIZE_T*)&len, dwOldProtect, &dwOldProtect);

    if(ret) {
      WriteLogger("VMP_ReadData Good, Result:%02X.\n", (BYTE)*dwNews);
    } else {
      WriteLogger("VMP_ReadData Faild, Cause:%s.\n", CTools::GetLastErrorString());
    }
    return ret;
}


注入VMP程序并执行后,VMP程序便闪退了。

代码执行后生成的记录为:CHook::VMP_ReadData:381 modify memory.
ntdll.dll <ZwProtectVirtualMemory> file vs vmp Context:
===0===
SRC:B8 50 00 00 00 BA 40 8A 30 4B FF D2 C2 14 00 90
VMP:E9 6A CF B6 8A BA 40 8A 53 77 FF D2 C2 14 00 90


775230a5, RESULT:
B8 50 00 00 00 E9 A5 30 52 77 00 00 00 00 00 00
B8 50 00 00 00 BA 40 8A 30 4B FF D2 C2 14 00 90
页: [1]
查看完整版本: VMP下HOOK遇到的问题