【问题标题】:How to use CreateRemoteThread to call the MessageBoxA function of the target program如何使用CreateRemoteThread调用目标程序的MessageBoxA函数
【发布时间】:2020-09-08 06:34:54
【问题描述】:

目标程序是x86程序,我尝试用下面的代码调用MessageBoxA,程序没有报错,但是MessageBoxA也没有执行

  const char* title = "hello";
  const char* content = "world";
  size_t titleLen = strlen(title) + 1;
  size_t contentLen = strlen(content) + 1;
  
  size_t size = titleLen + contentLen + sizeof(DWORD) * 4;
  BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  printf("newmem: %x\n", newmem);

  DWORD titleAddr = (DWORD)newmem;
  DWORD contentAddr = titleAddr + titleLen;
  DWORD paramsAddr = contentAddr + contentLen;

  WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);

  DWORD p1 = 0;
  DWORD p4 = 0;
  printf("paramsAddr %x\n", paramsAddr);
  WriteProcessMemory(gc.hProcess, (LPVOID)paramsAddr, (LPCVOID)&p1, sizeof(DWORD), 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 4), (LPCVOID)&titleAddr, sizeof(DWORD), 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 8), (LPCVOID)&contentAddr, sizeof(DWORD), 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 12), (LPCVOID)&p4, sizeof(DWORD), 0);

  HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
    (LPTHREAD_START_ROUTINE)MessageBoxA, (LPVOID)paramsAddr,
    0, 0);

  printf("hThread %d\n", hThread);

  WaitForSingleObject(hThread, INFINITE);
  VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
  CloseHandle(hThread);

这是运行时的一些信息:

newmem: 5f0000
paramsAddr 5f000c

5f0000: 68 65 6C 6C 6F 00 77 6F 72 6C 64 00 
00 00 00 00 
00 00 5F 00 
06 00 5F 00 
00 00 00 00

我尝试调用ExitProcess函数可以正常执行

  HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
    (LPTHREAD_START_ROUTINE)ExitProcess, 0,
    0, 0);

对 MessageBoxA 的调用是否因为传递了错误的参数而失败?我需要一些帮助,谢谢

【问题讨论】:

  • CreateRemoteThread在目标进程中运行的函数必须匹配LPTHREAD_START_ROUTINE的签名,MessageBoxA不匹配。
  • @januwa 由于MessageBoxA()CreateRemoteThread() 不兼容,要执行您正在尝试的操作,您将不得不 1) 使用CreateRemoteThread() 调用LoadLibraryA() 来注入一个DLL加载时调用MessageBoxA(),或者2)分配一个包含shellcode的远程函数调用MessageBox(),然后使用CreateRemoteThread()调用该函数。

标签: c++ winapi


【解决方案1】:

这是一个可以执行MessageBoxA的硬编码版本

  const char* title = "hello";
  const char* content = "world";
  size_t titleLen = strlen(title) + 1;
  size_t contentLen = strlen(content) + 1;
  
  BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  printf("newmem: %x\n", newmem);

  DWORD titleAddr = (DWORD)newmem;
  DWORD contentAddr = titleAddr + titleLen;
  DWORD funAddr = contentAddr + contentLen;

  WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);

    /*
     3 00000000 6A00                        push 0
     4 00000002 6878563412                  push 0x12345678
     5 00000007 6878563412                  push 0x12345678
     6 0000000C 6A00                        push 0
     7 0000000E E800000000                  call MessageBoxA
     8 00000013 C3                          ret
    */
    BYTE funcode[] = {
     0x6A, 0x00,
     0x68, 0x00,0x00,0x00,0x00,
     0x68, 0x00,0x00,0x00,0x00,
     0x6A, 0x00,
     0xE8, 0x00,0x00,0x00,0x00,
     0xC3
    };
  
  DWORD pMessageBoxA = 0x76E013D0;
  DWORD MessageBoxA = pMessageBoxA - (funAddr + 0xE) - 5;
  memcpy_s(funcode + 0x3, 4, &titleAddr, 4);
  memcpy_s(funcode + 0x8, 4, &contentAddr, 4);
  memcpy_s(funcode + 0xF, 4, &MessageBoxA, 4);

  WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);

  HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
    (LPTHREAD_START_ROUTINE)funAddr, 0, 0, 0);

  WaitForSingleObject(hThread, INFINITE);
  VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
  CloseHandle(hThread);

【讨论】:

  • 我无法使用您的示例正确调用 MessageBox。能否提供更多解释或代码信息?
  • 类似的解决方案,但没有asm代码,here
【解决方案2】:

这是 x86 和 x64 上的通用代码。如果你的目标程序是x86/x64,那么你的程序也需要编译成x86/x64。我测试了几个程序都可以正常工作。

uintptr_t pMessageBoxA = GetProcAddressEx(gc.hProcess, "user32.dll", "MessageBoxA");
  if (!pMessageBoxA)
  {
    printf("target not find MessageBoxA\n");
    return 0;
  }
  printf("pMessageBoxA: %lp\n", pMessageBoxA);

  const char* title = "hello";
  const char* content = "world";
  size_t titleLen = strlen(title) + 1;
  size_t contentLen = strlen(content) + 1;

  BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  printf("newmem: %x\n", newmem);

  uintptr_t titleAddr = (uintptr_t)newmem;
  uintptr_t contentAddr = titleAddr + titleLen;
  uintptr_t funAddr = contentAddr + contentLen + 8;
  printf("funAddr: %x\n", funAddr);

  WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
  WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);

#ifdef _WIN64

  /*
0000- 55                    - push rbp
0001- 48 8B EC              - mov rbp,rsp
0004- 48 83 EC 20           - sub rsp,20
0008- 48 B9 0000000000000000 - mov rcx,0000000000000000
0012- 48 BA 0000000000000000 - mov rdx,0000000000000000
001C- 49 B8 0000000000000000 - mov r8,0000000000000000
0026- 49 B9 0000000000000000 - mov r9,0000000000000000
0030- 48 B8 E02C643FFD7F0000 - mov rax,user32.MessageBoxA
003A- FF D0                 - call rax
003C- 48 83 C4 20           - add rsp,20
0040- 48 8B E5              - mov rsp,rbp
0043- 5D                    - pop rbp
0044- C3                    - ret
  */

  BYTE funcode[] = {
    0x55,
    0x48, 0x8B, 0xEC,
    0x48, 0x83, 0xEC, 0x20,
    0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x48, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x49, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x49, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0xD0,
    0x48, 0x83, 0xC4, 0x20,
    0x48, 0x8B, 0xE5,
    0x5D,
    0xC3,
  };
  memcpy_s(funcode + 0x14, sizeof(uintptr_t), &contentAddr, sizeof(uintptr_t)); // rdx
  memcpy_s(funcode + 0x1E, sizeof(uintptr_t), &titleAddr, sizeof(uintptr_t)); // r8
  memcpy_s(funcode + 0x32, sizeof(uintptr_t), &pMessageBoxA, sizeof(uintptr_t)); // rax
  WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#else
  /*
   3 00000000 6A00                        push 0
   4 00000002 6878563412                  push 0x12345678
   5 00000007 6878563412                  push 0x12345678
   6 0000000C 6A00                        push 0
   7 0000000E E800000000                  call MessageBoxA
   8 00000013 C3                          ret
  */
  BYTE funcode[] = {
   0x6A, 0x00,
   0x68, 0x00,0x00,0x00,0x00,
   0x68, 0x00,0x00,0x00,0x00,
   0x6A, 0x00,
   0xE8, 0x00,0x00,0x00,0x00,
   0xC3
  };
  DWORD MessageBoxA = pMessageBoxA - (funAddr + 0xE) - 5;
  memcpy_s(funcode + 0x3, sizeof(DWORD), &titleAddr, sizeof(DWORD));
  memcpy_s(funcode + 0x8, sizeof(DWORD), &contentAddr, sizeof(DWORD));
  memcpy_s(funcode + 0xF, sizeof(DWORD), &MessageBoxA, sizeof(DWORD));
  WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#endif // _WIN64

  HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, 0, 0, 0);
  WaitForSingleObject(hThread, INFINITE);
  VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
  CloseHandle(hThread);

GetProcAddressEx:

uintptr_t GetProcAddressEx(HANDLE hProcess, string modName, string exportFunName)
    {
      MODULEINFO mi = GetModuleBase(modName, GetProcessId(hProcess));
      uintptr_t moduleBaseAddr = (uintptr_t)mi.lpBaseOfDll;

      // is PE FILE ?
      WORD e_magic = 0;
      ReadProcessMemory(hProcess, (LPCVOID)moduleBaseAddr, &e_magic, sizeof(WORD), 0);
      if (e_magic != 0x5A4D)
      {
        printf("not PE file.\n");
        return 0;
      }

      // get ntHeader offset
      DWORD e_lfanew = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(moduleBaseAddr + 0x3C), &e_lfanew, sizeof(DWORD), 0);

      uintptr_t ntHeaderAddr = moduleBaseAddr + e_lfanew;
      uintptr_t fileHeaderAddr = ntHeaderAddr + sizeof(DWORD);

      // x86 is 0xE0, x64 is 0xF0
      WORD optHeaderSize = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(fileHeaderAddr + 0x10), &optHeaderSize, sizeof(WORD), 0);

      // tables
      uintptr_t DataDirectoryAddr = fileHeaderAddr + sizeof(IMAGE_FILE_HEADER) + optHeaderSize - sizeof(IMAGE_DATA_DIRECTORY) * 16;

      // tables[0] is export table
      IMAGE_DATA_DIRECTORY exportEntry;
      ReadProcessMemory(hProcess, (LPCVOID)DataDirectoryAddr, &exportEntry, sizeof(IMAGE_DATA_DIRECTORY), 0);
      if (!exportEntry.Size)
      {
        printf("not export table. \n");
        return 0;
      }
      auto RVA2VA = [&](uintptr_t rva) -> uintptr_t
      {
        return moduleBaseAddr + rva;
      };

      uintptr_t exportDirDataAddr = RVA2VA(exportEntry.VirtualAddress);

      // the number of use name export function
      DWORD NumberOfNames = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x18), &NumberOfNames, sizeof(DWORD), 0);

      DWORD AddressOfFunctions = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x1C), &AddressOfFunctions, sizeof(DWORD), 0);
      DWORD* AddressOfFunctionsVA = (DWORD*)RVA2VA(AddressOfFunctions);

      // function name table
      DWORD AddressOfNames = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x20), &AddressOfNames, sizeof(DWORD), 0);
      DWORD* AddressOfNamesVA = (DWORD*)RVA2VA(AddressOfNames);

      DWORD AddressOfNameOrdinals = 0;
      ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x24), &AddressOfNameOrdinals, sizeof(DWORD), 0);
      WORD* AddressOfNameOrdinalsVA = (WORD*)RVA2VA(AddressOfNameOrdinals);

      auto readASCII = [&](uintptr_t addr, char* name) -> void
      {
        size_t i = 0;
        char c;
        while (true)
        {
          ReadProcessMemory(hProcess, (LPCVOID)(addr + i), &c, sizeof(BYTE), 0);
          name[i] = c;
          if (!c) break;
          i++;
        }
      };

      DWORD itRVA = 0;
      char funName[1024];
      size_t funNameIndex = 0;
      for (; funNameIndex < NumberOfNames; funNameIndex++)
      {
        ReadProcessMemory(hProcess, AddressOfNamesVA + funNameIndex, &itRVA, sizeof(DWORD), 0);
        readASCII(moduleBaseAddr + itRVA, funName);
        if (!strcmp(funName, exportFunName.c_str()))
          break;
      }

      if (strlen(funName) == 0)
      {
        return 0;
      }

      // get function address index
      WORD AddressOfFunctionsIndex = 0;
      ReadProcessMemory(hProcess, AddressOfNameOrdinalsVA + funNameIndex, &AddressOfFunctionsIndex, sizeof(WORD), 0);

      // get function address
      DWORD funAddrRVA = 0;
      ReadProcessMemory(hProcess, AddressOfFunctionsVA + AddressOfFunctionsIndex, &funAddrRVA, sizeof(DWORD), 0);
      return RVA2VA(funAddrRVA);
    }

GetModuleBase:

MODULEINFO GetModuleBase(string moduleName, DWORD pid)
    {
      MODULEINFO mi{ 0 };
      HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);

      if (hSnap != INVALID_HANDLE_VALUE)
      {
        MODULEENTRY32 me;
        me.dwSize = sizeof(me);
        if (Module32First(hSnap, &me))
        {
          do {
            if (!_wcsicmp(me.szModule, toWstring(moduleName).c_str()))
            {
              mi.lpBaseOfDll = me.modBaseAddr;
              mi.SizeOfImage = me.modBaseSize;
              break;
            }
          } while (Module32Next(hSnap, &me));
        }
      }
      CloseHandle(hSnap);
      return mi;
    }

与硬编码相比,这更复杂。


如果要获取CreateRemoteThread传递的参数

  BYTE* lpParam = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 8, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  DWORD p1 = 1;
  DWORD p2 = 2;
  WriteProcessMemory(gc.hProcess, lpParam, &p1, sizeof(DWORD), 0);
  WriteProcessMemory(gc.hProcess, lpParam + 4, &p2, sizeof(DWORD), 0);
  printf("lpParam: %lp\n", lpParam);
  HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, lpParam, 0, 0);
  • 如果目标程序是x86,那么你可以在[esp+4]中得到lpParam
  • 如果目标程序是x64,那么你可以在rcx中得到lpParam

【讨论】:

  • 很高兴您得到了解决方案,感谢您的分享,如果您将它们标记为答案,我将不胜感激,这将对其他社区有益。
猜你喜欢
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
相关资源
最近更新 更多