朱朱你堕落了 发表于 2023-9-10 00:37

求助C++大佬修改代码

本帖最后由 朱朱你堕落了 于 2023-9-10 00:45 编辑

CSDN文章:
https://blog.csdn.net/mozunx/article/details/89349178

源码我下载下来了
https://www.123pan.com/s/YL29-GC6Oh.html

测试发现编译出现的程序有问题,虽然结果正确,但是还是有问题的。
求助实现以下功能
1
如果,我说如果软件是动态基址,请把支持基址基址的代码也添加上,我没有测试作者这个代码在动态基址的软件上是否管用。
2
修复代码,使其完美运行,不出现崩溃或报错等问题,一定要稳定,在XP,win7,win10上都完美运行。
3
如果您的代码实现方法更好,代码优美高效,请用您的实现方法也行。不一定非要用作者的代码。
可以看出来,作者的代码有些看起来不好懂,而且貌似也不正确。
4
还是使用这种EXE获取方式来实现,麻烦添加下代码注释,不要使用DLLI注入方式,各位大佬不要理解错了。

爱飞的猫 发表于 2023-9-10 00:37

本帖最后由 爱飞的猫 于 2023-9-10 03:21 编辑

首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:

```x86asm
use32

; 使用 fasm 编译
; 然后使用 xxd 将二进制文件转换为 C++ 语法的数组

jmp __start

; 固定一下数据偏移
align 0x10
p_LoadLibraryA:
dd 0
p_GetProcAddress:
dd 0

sz_MessageBoxA:
db 'MessageBoxA',0
sz_User32DLL:
db 'User32.dll',0
sz_TitleKey:
db 'Serial',0

macro mov_pic reg_dst, offset {
call @f
@@:
    pop reg_dst
    sub reg_dst, (@b - offset)
}

macro push_pic reg_tmp, offset {
mov_pic reg_tmp, offset
push reg_tmp
}

macro call_pic offset {
mov_pic eax, offset
call dword
}

align 0x10
__start:

; 准备一下 MessageBoxA 需要的参数
push 0x40 ; MB_ICONINFORMATION
push_pic eax, sz_TitleKey
push dword ; 实际密钥地址
push 0

push_pic eax, sz_MessageBoxA
push_pic eax, sz_User32DLL
call_pic p_LoadLibraryA
push eax ; eax = hModule
call_pic p_GetProcAddress
call eax ; eax = MessageBoxA

; 还原一下原始指令的寄存器
mov edx, dword
mov eax, dword

; 计算原始 00403474 地址并跳回去
push dword
sub dword, 0x00421D3B + 5 - 0x00403474
ret
```

然后就是 C++ 的启动器代码:

```cpp
#include <Windows.h>
#include <cstdint>

// 使用 FASM 编译前文的汇编代码
unsigned char msgbox_shell_bin[] = {
0xeb, 0x3e, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x41, 0x00,
0x55, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x53,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x6a, 0x40, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58,
0x83, 0xe8, 0x18, 0x50, 0xff, 0x75, 0xf4, 0x6a, 0x00, 0xe8, 0x00, 0x00,
0x00, 0x00, 0x58, 0x83, 0xe8, 0x3e, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0xe8, 0x3c, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x83,
0xe8, 0x5a, 0xff, 0x10, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x83,
0xe8, 0x62, 0xff, 0x10, 0xff, 0xd0, 0x8b, 0x55, 0xe8, 0x8b, 0x45, 0xf4,
0xff, 0x34, 0x24, 0x81, 0x2c, 0x24, 0xcc, 0xe8, 0x01, 0x00, 0xc3
};
unsigned int msgbox_shell_bin_len = 143;

int main()
{
wchar_t szProcessPath[] = L"Dope2112.1.exe";
STARTUPINFOW si{};
PROCESS_INFORMATION pi{};
if (!CreateProcessW(nullptr, szProcessPath, nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
    MessageBoxW(nullptr, L"建立进程失败", L"失败", MB_ICONERROR);
    return 1;
}

DWORD unused{};
auto p_shellcode = reinterpret_cast<uint8_t*>(VirtualAllocEx(pi.hProcess, nullptr, msgbox_shell_bin_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (p_shellcode == nullptr) {
    TerminateProcess(pi.hProcess, 1);
    MessageBoxW(nullptr, L"开辟空间失败", L"失败", MB_ICONERROR);
    return 1;
}

// 写出 ShellCode
WriteProcessMemory(pi.hProcess, p_shellcode, &msgbox_shell_bin, msgbox_shell_bin_len, &unused);
void* ptr_temp;
WriteProcessMemory(pi.hProcess, p_shellcode + 0x10, &(ptr_temp = &LoadLibraryA), sizeof(void*), &unused);
WriteProcessMemory(pi.hProcess, p_shellcode + 0x14, &(ptr_temp = &GetProcAddress), sizeof(void*), &unused);

// 读取进程基地址
uint8_t* module_base_addr{};
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_INTEGER;
GetThreadContext(pi.hThread, &context);
ReadProcessMemory(pi.hProcess, (void*)(context.Ebx + 8), &module_base_addr, sizeof(PVOID), NULL);

// 写新的跳转
auto hook_loc = module_base_addr + 0x00421D3B - 0x00400000;
uint8_t inst_call_shellcode = { 0xE8 };
*reinterpret_cast<uint32_t*>(&inst_call_shellcode) = p_shellcode - (hook_loc + 5);
WriteProcessMemory(pi.hProcess, hook_loc, inst_call_shellcode, sizeof(inst_call_shellcode), &unused);

// 将 ShellCode 区域的内存改为可执行
VirtualProtectEx(pi.hProcess, p_shellcode, msgbox_shell_bin_len, PAGE_EXECUTE_READ, &unused);

// 继续执行
ResumeThread(pi.hThread);

// 等待进程结束,然后清理
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
```



题外话:别锁帖,给我个以后回味的机会 _(:3__

爱飞的猫 发表于 2023-9-10 00:54

本帖最后由 爱飞的猫 于 2023-9-10 03:08 编辑

基本上 4 步走:

1. 编写一段 ShellCode(字节码)
- 根据自己的需要加载 API 并获取对应的地址(通过 PEB 数据结构可以获取)
- 执行你的自定义代码(如 Hook)
- 通常用汇编编写然后编译后得到。也可以用 C 或其他底层语言写一些函数编译,抠出来用。

2. 启动进程(带上 CreateProcess/CREATE_SUSPENDED),注入你的 ShellCode
3. 利用 APC Queue 或类似技术让你的 ShellCode 先执行,优先执行 Hook。
4. ResumeProcess 继续进程执行。

---

其实和内存注入 DLL 的方式基本一样,只是 ShellCode 部分改成了模拟 DLL 加载过程,对内存中的 DLL 数据进行修正(解析区块并申请内存,调整重定向代码、修正 IAT 等)。

修正 IAT(或 API 地址解析)基本上代码都写的挺丑陋的,这个没办法。

或者更简单一点,你可以利用 `kernel32.dll` 的模块地址在不同进程下是固定值的特性,直接在启动器获取 LoadLibraryA/GetProcAddress 的地址,然后填充到你的 ShellCode 内一并写出。这样就不需要在 ShellCode 内爬 PEB 结构了。

---

如果只是让他弹出序列号,修改这一条指令就行:

```x86asm
00421D5A | 8B55 F0                  | mov edx,dword ptr ss:                |
00421D5D | 90                     | nop                                          |
00421D5E | 90                     | nop                                          |
```

即、输入错误时,错误信息显示真正的序列号。

mystwyp 发表于 2023-9-10 01:14

飞猫大佬牛逼。

wgz001 发表于 2023-9-10 07:47

爱飞的猫 发表于 2023-9-10 03:09
首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:

```x86asm


每次结帖后权限都搞到80,让我们学习的机会都没了{:1_937:}

kantal 发表于 2023-9-10 09:15

朱朱你堕落了 发表于 2023-9-10 12:41

爱飞的猫 发表于 2023-9-10 00:37
首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:

```x86asm


原理是能看明白的,但是用FASM写汇编提取shellcode不熟悉,所以我在想,既然FASM能写,
那么vs应该也能写汇编吧,或裸函数内联汇编之类什么的也能实现吧,之后再提取shellcode吧。
必竟只是语言的不同吧。如果能实现,麻烦用VS写个代码,顺便说下VS下怎么提取shellcode,
我想用VS来实现一下。FASM不熟悉啊。

爱飞的猫 发表于 2023-9-10 19:57

朱朱你堕落了 发表于 2023-9-10 12:41
原理是能看明白的,但是用FASM写汇编提取shellcode不熟悉,所以我在想,既然FASM能写,
那么vs应该也能 ...

编译出来就是一个 bin 文件,就是汇编部分转换为机器码。

在 C++ 里面写有点麻烦,我看看怎么搞。

董督秀 发表于 2023-9-10 20:10

爱飞的猫 发表于 2023-9-10 19:57
编译出来就是一个 bin 文件,就是汇编部分转换为机器码。

在 C++ 里面写有点麻烦,我看看怎么搞。

题主的第4点要求:通过EXE获取注册码。这也是个难点,我也想了解一下如何通过vc实现。

爱飞的猫 发表于 2023-9-10 22:39

本帖最后由 爱飞的猫 于 2023-9-10 22:59 编辑

在 MSVC 做相对比较麻烦,因为一不小心就会用到 cpp 自带的实现(引用宿主程序地址)。

勉强改了个能用的版本,顺便在纯 MSVC 版本实现了个比较基础的跨进程交互(IPC)。

```cpp
#include <Windows.h>
#include <cstdint>
#include <string>
#include <vector>
#include <cassert>

// true:使用新的 msvc payload
// false: 使用之前 fasm 编译的 payload
constexpr bool kUseNewPayload = true;

// 使用 FASM 编译前文的汇编代码
unsigned char msgbox_shell_bin[] = {
0xeb, 0x3e, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x41, 0x00,
0x55, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x53,
0x65, 0x72, 0x69, 0x61, 0x6c, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x6a, 0x40, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58,
0x83, 0xe8, 0x18, 0x50, 0xff, 0x75, 0xf4, 0x6a, 0x00, 0xe8, 0x00, 0x00,
0x00, 0x00, 0x58, 0x83, 0xe8, 0x3e, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0xe8, 0x3c, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x83,
0xe8, 0x5a, 0xff, 0x10, 0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x83,
0xe8, 0x62, 0xff, 0x10, 0xff, 0xd0, 0x8b, 0x55, 0xe8, 0x8b, 0x45, 0xf4,
0xff, 0x34, 0x24, 0x81, 0x2c, 0x24, 0xcc, 0xe8, 0x01, 0x00, 0xc3
};
unsigned int msgbox_shell_bin_len = 143;

typedef decltype(&LoadLibraryA) tLoadLibraryA;
typedef decltype(&GetProcAddress) tGetProcAddress;
typedef decltype(&GetModuleHandleA) tGetModuleHandleA;
typedef decltype(&MessageBoxA) tMessageBoxA;
typedef decltype(&OpenProcess) tOpenProcess;
typedef decltype(&VirtualAllocEx) tVirtualAllocEx;
typedef decltype(&calloc) tcalloc;
typedef decltype(&WriteProcessMemory) tWriteProcessMemory;
typedef decltype(&free) tfree;
typedef decltype(&CreateRemoteThread) tCreateRemoteThread;
typedef decltype(&WaitForSingleObject) tWaitForSingleObject;
typedef decltype(&VirtualFreeEx) tVirtualFreeEx;
typedef decltype(&CloseHandle) tCloseHandle;

// 必须关闭优化,否则会向量化一些变量
#pragma optimize( "", off )
__declspec(safebuffers)
void* __cdecl injected_fn_start_inner(const char* user_serial, const char* real_serial);

__declspec(naked)
void* injected_fn_start() {
    // 因为 naked 函数不能使用变量,所以要跳到下一个函数
    __asm {
      // 备份寄存器,顺便作为参数传给下一个函数
      push eax
      push edx
      call injected_fn_start_inner

      // 返回值其实是下一个要调用的地址
      mov ecx, eax

      // 还原现场
      pop edx
      pop eax
      call ecx
      ret
    }
}

__declspec(safebuffers)
void* __cdecl injected_fn_start_inner(const char* user_serial, const char* real_serial) {
    // ShellCode 参数
    auto pLoadLibraryA = (tLoadLibraryA)0x12345678;
    auto pGetProcAddress = (tGetProcAddress)0x22345678;
    auto pGetModuleHandleA = (tGetModuleHandleA)0x32345678;
    auto pHostProcessId = (DWORD)0x42345678;
    auto pHostProcessHandler = (DWORD)0x52345678;

    char szUser32Dll[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
    char szMessageBoxA[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };

    char szKernel32Dll[] = { 'K', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0 };
    char szGetModuleHandleA[] = { 'G', 'e', 't', 'M', 'o', 'd', 'u', 'l', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 'A', 0 };
    char szOpenProcess[] = { 'O', 'p', 'e', 'n', 'P', 'r', 'o', 'c', 'e', 's', 's', 0 };
    char szVirtualAllocEx[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 'E', 'x', 0 };
    char szWriteProcessMemory[] = { 'W', 'r', 'i', 't', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', 'M', 'e', 'm', 'o', 'r', 'y', 0 };
    char szCreateRemoteThread[] = { 'C', 'r', 'e', 'a', 't', 'e', 'R', 'e', 'm', 'o', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 0 };
    char szWaitForSingleObject[] = { 'W', 'a', 'i', 't', 'F', 'o', 'r', 'S', 'i', 'n', 'g', 'l', 'e', 'O', 'b', 'j', 'e', 'c', 't', 0 };
    char szVirtualFreeEx[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', 'E', 'x', 0 };
    char szCloseHandle[] = { 'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 0 };

    char szMsvcrtDll[] = { 'm', 's', 'v', 'c', 'r', 't', '.', 'd', 'l', 'l', 0 };
    char szcalloc[] = { 'c', 'a', 'l', 'l', 'o', 'c', 0 };
    char szfree[] = { 'f', 'r', 'e', 'e', 0 };

    char szTitleSerial[] = { 'S', 'e', 'r', 'i', 'a', 'l', ' ', '(', 'F', 'r', 'o', 'm', ' ', 'C', 'r', 'a', 'c', 'k', 'm', 'e', ')', 0 };

    DWORD unused{};

    // 定义几个方便用的宏
    auto hKernel32 = pLoadLibraryA(szKernel32Dll);
    auto hMsvcrt = pLoadLibraryA(szMsvcrtDll);
#define k32(name) t##name(pGetProcAddress(hKernel32, sz##name))
#define vcrt(name) t##name(pGetProcAddress(hMsvcrt, sz##name))

    // 实现几个简单的文本操作函数
    auto strlen_inline = [](const char* src) {
      int result = 0;
      while (*src++) {
            result++;
      }
      return result;
    };
    auto strcpy_inline = [](char* dst, const char* src) {
      while(*src) {
            *dst++ = *src++;
      }
      *dst = 0;
    };

    // 传递信息到宿主程序
    // 这是一个简单粗暴的 IPC 实现,效率不一定高
    auto hProcess = k32(OpenProcess)(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pHostProcessId);
    if (hProcess != INVALID_HANDLE_VALUE) {
      // payload 格式
      //
      // cmd_01 "serial"
      auto payload_data_size = strlen_inline(real_serial) + 1;
      auto payload_size = 1 + sizeof(uint32_t) + payload_data_size;
      auto p_payload = (char*)vcrt(calloc)(payload_size, sizeof(char));

      if (p_payload != nullptr) {
            // 填充载荷
            p_payload = 0x01;
            *(uint32_t*)&p_payload = payload_data_size;
            strcpy_inline(&p_payload, real_serial);

            // 拷贝载荷到宿主程序
            auto p_remote_data = k32(VirtualAllocEx)(hProcess, nullptr, payload_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            if (p_remote_data != nullptr) {
                k32(WriteProcessMemory)(hProcess, p_remote_data, p_payload, payload_size, &unused);

                // 建立新线程通知,并等待结束
                DWORD thread_id{};
                auto hThread = k32(CreateRemoteThread)(hProcess, nullptr, 0, LPTHREAD_START_ROUTINE(pHostProcessHandler), p_remote_data, 0, &unused);
                if (hThread != nullptr) {
                  // 等待运行结束
                  k32(WaitForSingleObject)(hThread, INFINITE);
                  k32(CloseHandle)(hThread);

                  // 此处使用 "GetExitCodeThread" 还可以获取返回值,与宿主程序进一步交互
                }
                k32(VirtualFreeEx)(hProcess, p_remote_data, 0, MEM_RELEASE);
            }
            vcrt(free)(p_payload);
      }
      k32(CloseHandle)(hProcess);
    }

    // 弹出信息框
    auto hUser32 = pLoadLibraryA(szUser32Dll);
    tMessageBoxA(pGetProcAddress(hUser32, szMessageBoxA))(nullptr, real_serial, szTitleSerial, MB_ICONINFORMATION);

    // 找回原始的函数
    auto pImageBase = (uint8_t*)k32(GetModuleHandleA)(nullptr);
    return pImageBase + 0x00403474 - 0x00400000;
#undef k32
#undef vcrt
}

void injected_fn_end() {
    // do nothing
}
#pragma optimize( "", on )

std::wstring A2W(const char* text) {
    std::wstring result;
    if (text && *text) {
      auto new_size = 1 + MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0);
      result.resize(new_size + 1);
      auto chr_written = MultiByteToWideChar(CP_ACP, 0, text, -1, &result.at(0), new_size);
      result.resize(chr_written);
    }
    return result;
}

void hexdump(const void* data, size_t size) {
    char ascii;
    size_t i, j;
    ascii = '\0';
    for (i = 0; i < size; ++i) {
      printf("%02X ", ((unsigned char*)data));
      if (((unsigned char*)data) >= ' ' && ((unsigned char*)data) <= '~') {
            ascii = ((unsigned char*)data);
      }
      else {
            ascii = '.';
      }
      if ((i + 1) % 8 == 0 || i + 1 == size) {
            printf(" ");
            if ((i + 1) % 16 == 0) {
                printf("|%s \n", ascii);
            }
            else if (i + 1 == size) {
                ascii[(i + 1) % 16] = '\0';
                if ((i + 1) % 16 <= 8) {
                  printf(" ");
                }
                for (j = (i + 1) % 16; j < 16; ++j) {
                  printf("   ");
                }
                printf("|%s \n", ascii);
            }
      }
    }
}

void __stdcall thread_callback(uint8_t* payload) {
    printf("recv payload: %p\n", payload);
    if (payload == nullptr) {
      return;
    }
    auto cmd_id = payload;
    uint32_t data_len = *(uint32_t*)&payload;
    auto p_data = &payload;
    printf("cmd_id(%02x) data_len(0x%04x)\n", cmd_id, data_len);
    hexdump(p_data, data_len);

    switch (cmd_id) {
    case 0x01: {
      // 处理 01 指令
      std::wstring serial;
      serial += L"序列号是: ";
      serial += A2W((const char*)p_data);
      MessageBoxW(nullptr, serial.c_str(), L"序列号信息 (来自宿主程序)", MB_ICONINFORMATION);
      break;
    }
    }
}

std::vector<uint8_t> get_shellcode_payload() {
    assert(("调试模式无法正常使用,你需要切换至编译模式运行", !_DEBUG));

    auto p_begin = (uint8_t*)injected_fn_start;
    auto p_end = (uint8_t*)injected_fn_end;
    std::vector<uint8_t> data(p_begin, p_end);

    auto find_and_replace_u32 = [&](uint32_t search, uint32_t replacement) {
      for (size_t i = 0; i < data.size() - sizeof(uint32_t); i++) {
            if (*(uint32_t*)&data.at(i) == search) {
                *(uint32_t*)&data.at(i) = replacement;
            }
      }
      };
    find_and_replace_u32(0x12345678, (uint32_t)LoadLibraryA);
    find_and_replace_u32(0x22345678, (uint32_t)GetProcAddress);
    find_and_replace_u32(0x32345678, (uint32_t)GetModuleHandleA);
    find_and_replace_u32(0x42345678, (uint32_t)GetProcessId(GetCurrentProcess()));
    find_and_replace_u32(0x52345678, (uint32_t)(thread_callback));
    return data;
}

int main()
{
    wchar_t szProcessPath[] = L"Dope2112.1.exe";
    STARTUPINFOW si{};
    PROCESS_INFORMATION pi{};
    if (!CreateProcessW(nullptr, szProcessPath, nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
      MessageBoxW(nullptr, L"建立进程失败", L"失败", MB_ICONERROR);
      return 1;
    }

    std::vector<uint8_t> payload;
    if (kUseNewPayload) {
      payload = get_shellcode_payload();
    }
    else {
      payload.assign(&msgbox_shell_bin, &msgbox_shell_bin);
    }


    DWORD unused{};
    auto p_shellcode = reinterpret_cast<uint8_t*>(VirtualAllocEx(pi.hProcess, nullptr, payload.size(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
    if (p_shellcode == nullptr) {
      TerminateProcess(pi.hProcess, 1);
      MessageBoxW(nullptr, L"开辟空间失败", L"失败", MB_ICONERROR);
      return 1;
    }

    // 写出 ShellCode
    WriteProcessMemory(pi.hProcess, p_shellcode, &payload.front(), payload.size(), &unused);

    if (!kUseNewPayload) {
      void* ptr_temp;
      WriteProcessMemory(pi.hProcess, p_shellcode + 0x10, &(ptr_temp = &LoadLibraryA), sizeof(void*), &unused);
      WriteProcessMemory(pi.hProcess, p_shellcode + 0x14, &(ptr_temp = &GetProcAddress), sizeof(void*), &unused);
    }

    // 读取进程基地址
    uint8_t* module_base_addr{};
    CONTEXT context;
    memset(&context, 0, sizeof(CONTEXT));
    context.ContextFlags = CONTEXT_INTEGER;
    GetThreadContext(pi.hThread, &context);
    ReadProcessMemory(pi.hProcess, (void*)(context.Ebx + 8), &module_base_addr, sizeof(PVOID), NULL);

    // 写新的跳转
    auto hook_loc = module_base_addr + 0x00421D3B - 0x00400000;
    uint8_t inst_call_shellcode = { 0xE8 };
    *reinterpret_cast<uint32_t*>(&inst_call_shellcode) = p_shellcode - (hook_loc + 5);
    WriteProcessMemory(pi.hProcess, hook_loc, inst_call_shellcode, sizeof(inst_call_shellcode), &unused);

    // 将 ShellCode 区域的内存改为可执行
    VirtualProtectEx(pi.hProcess, p_shellcode, payload.size(), PAGE_EXECUTE_READ, &unused);

    // 继续执行
    ResumeThread(pi.hThread);

    // 等待进程结束,然后清理
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
}
```



编译好的示例(解压密码 `52pojie`):
https://pan.baidu.com/s/1FZClTK1f8z4gBpW8_zIKWQ?pwd=g81d


@董督秀 你要的 EXE 跨进程通信也写了
页: [1] 2
查看完整版本: 求助C++大佬修改代码