求助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 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 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 |
```
即、输入错误时,错误信息显示真正的序列号。
飞猫大佬牛逼。 爱飞的猫 发表于 2023-9-10 03:09
首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:
```x86asm
每次结帖后权限都搞到80,让我们学习的机会都没了{:1_937:} 爱飞的猫 发表于 2023-9-10 00:37
首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:
```x86asm
原理是能看明白的,但是用FASM写汇编提取shellcode不熟悉,所以我在想,既然FASM能写,
那么vs应该也能写汇编吧,或裸函数内联汇编之类什么的也能实现吧,之后再提取shellcode吧。
必竟只是语言的不同吧。如果能实现,麻烦用VS写个代码,顺便说下VS下怎么提取shellcode,
我想用VS来实现一下。FASM不熟悉啊。 朱朱你堕落了 发表于 2023-9-10 12:41
原理是能看明白的,但是用FASM写汇编提取shellcode不熟悉,所以我在想,既然FASM能写,
那么vs应该也能 ...
编译出来就是一个 bin 文件,就是汇编部分转换为机器码。
在 C++ 里面写有点麻烦,我看看怎么搞。 爱飞的猫 发表于 2023-9-10 19:57
编译出来就是一个 bin 文件,就是汇编部分转换为机器码。
在 C++ 里面写有点麻烦,我看看怎么搞。
题主的第4点要求:通过EXE获取注册码。这也是个难点,我也想了解一下如何通过vc实现。 本帖最后由 爱飞的猫 于 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