吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 978|回复: 12
收起左侧

[已解决] 求助C++大佬修改代码

[复制链接]
朱朱你堕落了 发表于 2023-9-10 00:37
818吾爱币
本帖最后由 朱朱你堕落了 于 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注入方式,各位大佬不要理解错了。

最佳答案

查看完整内容

[md]首先编写 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 { ...

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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

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

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[eax]
}

align 0x10
__start:

  ; 准备一下 MessageBoxA 需要的参数
  push 0x40 ; MB_ICONINFORMATION
  push_pic eax, sz_TitleKey
  push dword[ebp-0x0C] ; 实际密钥地址
  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[ebp-0x18]
  mov eax, dword[ebp-0x0C]

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

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

#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[0], 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[5] = { 0xE8 };
  *reinterpret_cast<uint32_t*>(&inst_call_shellcode[1]) = 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);
}

dope2112_100%.png

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

点评

原理是能看明白的,但是用FASM写汇编提取shellcode不熟悉,所以我在想,既然FASM能写, 那么vs应该也能写汇编吧,或裸函数内联汇编之类什么的也能实现吧,之后再提取shellcode吧。 必竟只是语言的不同吧。如果能实  详情 回复 发表于 2023-9-10 12:41
每次结帖后权限都搞到80,让我们学习的机会都没了  详情 回复 发表于 2023-9-10 07:47

免费评分

参与人数 2吾爱币 +3 热心值 +2 收起 理由
苏紫方璇 + 2 + 1 用心讨论,共获提升!
wgz001 + 1 + 1 热心回复!

查看全部评分

爱飞的猫 发表于 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 结构了。


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

00421D5A | 8B55 F0                  | mov edx,dword ptr ss:[ebp-10]                |
00421D5D | 90                       | nop                                          |
00421D5E | 90                       | nop                                          |

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

免费评分

参与人数 1吾爱币 +3 热心值 +1 收起 理由
朱朱你堕落了 + 3 + 1 大佬什么时候空闲时,帮写一下吧。哈哈。

查看全部评分

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

```x86asm

每次结帖后权限都搞到80,让我们学习的机会都没了
头像被屏蔽
kantal 发表于 2023-9-10 09:15
提示: 该帖被管理员或版主屏蔽
 楼主| 朱朱你堕落了 发表于 2023-9-10 12:41
爱飞的猫 发表于 2023-9-10 00:37
[md]首先编写 shellcode。我这个是 FASM 语法,所以使用它编译即可:

```x86asm

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

点评

编译出来就是一个 bin 文件,就是汇编部分转换为机器码。 在 C++ 里面写有点麻烦,我看看怎么搞。  详情 回复 发表于 2023-9-10 19:57

免费评分

参与人数 1热心值 +1 收起 理由
董督秀 + 1 谢谢@Thanks!

查看全部评分

爱飞的猫 发表于 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)。

#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 格式
        // [command_id] [dword_sizeof_data] [data]
        // cmd_01 [sizeof("serial")] "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[0] = 0x01;
            *(uint32_t*)&p_payload[1] = payload_data_size;
            strcpy_inline(&p_payload[5], 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[17];
    size_t i, j;
    ascii[16] = '\0';
    for (i = 0; i < size; ++i) {
        printf("%02X ", ((unsigned char*)data)[i]);
        if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
            ascii[i % 16] = ((unsigned char*)data)[i];
        }
        else {
            ascii[i % 16] = '.';
        }
        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[0];
    uint32_t data_len = *(uint32_t*)&payload[1];
    auto p_data = &payload[5];
    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[0], &msgbox_shell_bin[msgbox_shell_bin_len]);
    }

    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[5] = { 0xE8 };
    *reinterpret_cast<uint32_t*>(&inst_call_shellcode[1]) = 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);
}

1.png

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



@董督秀 你要的 EXE 跨进程通信也写了

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
董督秀 + 1 + 1 谢谢@Thanks!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止回复与主题无关非技术内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-28 20:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表