Windows进程注入:如何将有效负载部署到目标进程的内存空间中执行

服务器
有许多种方式部署和执行有效负载,但不是所有的方法用起来比较简单。首先关注的是传统的API,尽管它相对较容易检测,但在威胁行动者中仍然很流行。

介绍

本文的目的是探讨如何将有效负载部署到目标进程的内存空间中执行。可以使用传统的Win32 API完成该任务,大家对Win32 API已经比较熟悉。但是也有可能创造性的使用非传统的方法,例如,我们可以使用API执行它们最初不打算执行的读写操作,这可能有助于规避检测。有许多种方式部署和执行有效负载,但不是所有的方法用起来比较简单。首先关注的是传统的API,尽管它相对较容易检测,但在威胁行动者中仍然很流行。

下面是sysinternals提供的VMMap屏幕截图,显示了我将要处理的系统(Windows 10)的内存类型。该内存的某些部分可能用于有效负载的存储。

[[237640]]

分配虚拟内存

每个进程都有自己的虚拟地址空间。进程之间存在共享内存,但一般情况下,进程A不能在没有Kernel(内核)帮助的情况下查看进程B的虚拟内存。Kernel可以看到所有进程的虚拟内存,因为它必须执行虚拟到物理内存的转换。进程A可以使用由Kernel内部处理的虚拟内存API(Virtual Memory API)在进程B的地址空间中分配新的虚拟内存。有些人可能熟悉下面这个在另一个进程的虚拟内存中部署有效负载的步骤。

  1. 使用OpenProcess或NtOpenProcess打开目标进程。
  2. 使用virtuallocex或NtAllocateVirtualMemory在目标进程中分配eXecute-Read-Write (XRW)内存。
  3. 使用WriteProcessMemory或NtWriteVirtualMemory将有效负载复制到新内存。
  4. 执行有效负载。
  5. 使用VirtualFreeEx或NtFreeVirtualMemory在目标进程中解除分配XRW内存。
  6. 使用CloseHandle 或NtClose
  7. 关闭目标进程句柄。

使用Win32 API。这只显示了XRW内存的分配,以及将有效负载写入新的内存。

  1. PVOID CopyPayload1(HANDLE hp, LPVOID payload, ULONG payloadSize){ 
  2.     LPVOID ptr=NULL
  3.     SIZE_T tmp; 
  4.      
  5.     // 1. allocate memory 
  6.     ptr = VirtualAllocEx(hp, NULL,  
  7.       payloadSize, MEM_COMMIT|MEM_RESERVE, 
  8.       PAGE_EXECUTE_READWRITE); 
  9.        
  10.     // 2. write payload 
  11.     WriteProcessMemory(hp, ptr,  
  12.       payload, payloadSize, &tmp); 
  13.      
  14.     return ptr; 
  15.     } 

或者使用Nt/Zw API。

  1. LPVOID CopyPayload2(HANDLE hp, LPVOID payload, ULONG payloadSize){ 
  2.     LPVOID   ptr=NULL
  3.     ULONG    len=payloadSize; 
  4.     NTSTATUS nt; 
  5.     ULONG    tmp; 
  6.      
  7.     // 1. allocate memory 
  8.     NtAllocateVirtualMemory(hp, &ptr, 0,  
  9.       &len, MEM_COMMIT|MEM_RESERVE, 
  10.       PAGE_EXECUTE|PAGE_READWRITE); 
  11.        
  12.     // 2. write payload 
  13.     NtWriteVirtualMemory(hp, ptr,  
  14.       payload, payloadSize, &tmp); 
  15.      
  16.    return ptr; 

虽然这里没有显示,但是可能用到一个附加的操作来删除虚拟内存的Write权限。

创建区对象

另一种方法是使用区对象。Microsoft对此有何评论?

区对象表示可以共享的内存段。一个进程可以使用区对象与其他进程共享其内存地址空间(内存段)的一部分。区对象还提供了进程将文件映射到其内存地址空间的机制。

尽管在常规应用程序中使用这些API就意味着存在恶意,但威胁行动者将继续使用它们进行进程注入。

  1. 使用NtCreateSection创建一个新的区域对象,并将其分配给S。
  2. 使用NtMapViewOfSection映射S的视图来攻击进程,并分配给B1。
  3. 使用NtMapViewOfSection映射S的视图来瞄准进程,并分配给B2。
  4. 将有效负载复制到B1。
  5. 映射B1。
  6. 关闭S。
  7. 返回指针B2。
  1. LPVOID CopyPayload3(HANDLE hp, LPVOID payload, ULONG payloadSize){ 
  2.     HANDLE        s; 
  3.     LPVOID        ba1=NULL, ba2=NULL
  4.     ULONG         vs=0; 
  5.     LARGE_INTEGER li; 
  6.     li.HighPart = 0; 
  7.     li.LowPart  = payloadSize; 
  8.      
  9.     // 1. create a new section 
  10.     NtCreateSection(&s, SECTION_ALL_ACCESS,  
  11.       NULL, &li, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); 
  12.     // 2. map view of section for current process 
  13.     NtMapViewOfSection(s, GetCurrentProcess(), 
  14.       &ba1, 0, 0, 0, &vs, ViewShare, 
  15.       0, PAGE_EXECUTE_READWRITE); 
  16.      
  17.     // 3. map view of section for target process   
  18.     NtMapViewOfSection(s, hp, &ba2, 0, 0, 0,  
  19.       &vs, ViewShare, 0, PAGE_EXECUTE_READWRITE);  
  20.      
  21.     // 4. copy payload to section of memory 
  22.     memcpy(ba1, payload, payloadSize); 
  23.     // 5. unmap memory in the current process 
  24.     ZwUnmapViewOfSection(GetCurrentProcess(), ba1); 
  25.      
  26.     // 6. close section 
  27.     ZwClose(s); 
  28.      
  29.     // 7. return pointer to payload in target process space 
  30.    return (PBYTE)ba2; 

使用现有的区域对象和ROP链

Powerloader恶意软件使用了explorer.exe创建的现有共享对象存储有效负载,但是由于对象(读-写)的权限,如果不使用返回导向编程(ROP)链,则不能直接执行代码。可以将有效负载复制到内存中,但是需要额外的技巧来执行它。

PowerLoader使用以下区域名称进行代码注入。

  1. "\BaseNamedObjects\ShimSharedMemory" 
  2. "\BaseNamedObjects\windows_shell_global_counters" 
  3. "\BaseNamedObjects\MSCTF.Shared.SFM.MIH" 
  4. "\BaseNamedObjects\MSCTF.Shared.SFM.AMF" 
  5. "\BaseNamedObjects\UrlZonesSM_Administrator" 
  6. "\BaseNamedObjects\UrlZonesSM_SYSTEM" 
  1. 使用NtOpenSection打开目标进程中的现有内存区
  2. 使用NtMapViewOfSection映射内存区视图
  3. 有效载荷复制到内存
  4. 使用ROP链执行

UI共享内存

enSilo用PowerLoaderEx演示了如何使用UI共享内存执行进程。Steroids上的注入:无代码注入和0-day技术提供了更多关于它如何工作的细节。它使用桌面堆将有效负载注入到explorer.exe中。

在MSDN上阅读桌面堆概述,可以看到在用户界面的进程之间已经有了共享内存。

每个桌面对象都有一个与之关联的桌面堆。桌面堆存储某些用户界面对象,如windows、菜单和钩子。当应用程序需要用户界面对象时,则调用user32.dll中的函数来分配那些对象。如果应用程序不依赖user32.dll ,那么它就不使用桌面堆。让我们通过一个简单的例子来说明应用程序如何使用桌面堆。

使用代码洞

主机入侵预防系统(HIPS)将把使用virtuallocex /WriteProcessMemory识别为可疑活动,这可能是PowerLoader的作者使用现有区对象的原因。PowerLoader很可能启发了AtomBombing的作者,使用Dynamic-link Library (DLL)中的一个代码洞来存储有效负载,并使用ROP链来执行。

AtomBombing使用GlobalAddAtom、GlobalGetAtomName和NtQueueApcThread的组合将有效负载部署到目标进程中。使用ROP链和SetThreadContext完成执行。在不使用标准方法的情况下,还有什么方法可以部署有效负载?

进程间通信(IPC)可用于与另一个进程共享数据。实现这一目标的一些方法包括:

  • 剪贴板(WM_PASTE)
  • 数据复制(WM_COPYDATA)
  • 命名管道
  • 组件对象模型(COM)
  • 远程过程调用(RPC)
  • 动态数据交换(DDE)

检查了WM_COPYDATA后发现,COM可能是更好的查询。

数据可以通过WM_COPYDATA消息在GUI进程之间合法地共享,但是WM_COPYDATA消息可以用于进程注入吗?

SendMessage和PostMessage是两个,可用于将数据写入远程进程空间的API,而无需显式的打开目标进程然后再使用虚拟内存API将数据复制到远程进程空间。

Tarjei Mandt在2011年Blackhat大会上展示了通过用户模式回调(User-Mode Callback)进行的内核攻击(Kernel Attack),启发我研究了使用位于进程环境块(PEB)中的内核回调表(KernelCallbackTable)进行进程注入的可能性。当user32.dll被加载到GUI进程中,这个字段则被初始化为一个函数数组。这也是我在了解了窗口消息是如何被内核分派之后最先开始查看的地方。

在WinDbg连接到记事本的状态下,获取PEB的地址。

  1. 0:001> !peb 
  2. !peb 
  3. PEB at 0000009832e49000 

在windows调试器中转储此操作将显示以下细节。这里我们感兴趣的是KernelCallbackTable,所以我去掉了大部分字段。

  1. 0:001> dt !_PEB 0000009832e49000 
  2. ntdll!_PEB 
  3.    +0x000 InheritedAddressSpace : 0 '' 
  4.    +0x001 ReadImageFileExecOptions : 0 '' 
  5.    +0x002 BeingDebugged    : 0x1 '' 
  6. // details stripped out 
  7.    +0x050 ReservedBits0    : 0y0000000000000000000000000 (0) 
  8.    +0x054 Padding1         : [4]  "" 
  9.    +0x058 KernelCallbackTable : 0x00007ffd6afc3070 Void 
  10.    +0x058 UserSharedInfoPtr : 0x00007ffd6afc3070 Void 

如果使用dump符号命令转储地址0x00007ffd6afc3070,将得到对USER32!apfnDispatch的引用。

  1. 0:001> dps $peb+58 
  2. 0000009832e49058  00007ffd6afc3070 USER32!apfnDispatch 
  3. 0000009832e49060  0000000000000000 
  4. 0000009832e49068  0000029258490000 
  5. 0000009832e49070  0000000000000000 
  6. 0000009832e49078  00007ffd6c0fc2e0 ntdll!TlsBitMap 
  7. 0000009832e49080  000003ffffffffff 
  8. 0000009832e49088  00007df45c6a0000 
  9. 0000009832e49090  0000000000000000 
  10. 0000009832e49098  00007df45c6a0730 
  11. 0000009832e490a0  00007df55e7d0000 
  12. 0000009832e490a8  00007df55e7e0228 
  13. 0000009832e490b0  00007df55e7f0650 
  14. 0000009832e490b8  0000000000000001 
  15. 0000009832e490c0  ffffe86d079b8000 
  16. 0000009832e490c8  0000000000100000 
  17. 0000009832e490d0  0000000000002000 

仔细检查USER32 !apfnDispatch发现一个函数数组。

  1. 0:001> dps USER32!apfnDispatch 
  2.  
  3. 00007ffd6afc3070  00007ffd6af62bd0 USER32!_fnCOPYDATA 
  4. 00007ffd6afc3078  00007ffd6afbae70 USER32!_fnCOPYGLOBALDATA 
  5. 00007ffd6afc3080  00007ffd6af60420 USER32!_fnDWORD 
  6. 00007ffd6afc3088  00007ffd6af65680 USER32!_fnNCDESTROY 
  7. 00007ffd6afc3090  00007ffd6af696a0 USER32!_fnDWORDOPTINLPMSG 
  8. 00007ffd6afc3098  00007ffd6afbb4a0 USER32!_fnINOUTDRAG 
  9. 00007ffd6afc30a0  00007ffd6af65d40 USER32!_fnGETTEXTLENGTHS 
  10. 00007ffd6afc30a8  00007ffd6afbb220 USER32!_fnINCNTOUTSTRING 
  11. 00007ffd6afc30b0  00007ffd6afbb750 USER32!_fnINCNTOUTSTRINGNULL 
  12. 00007ffd6afc30b8  00007ffd6af675c0 USER32!_fnINLPCOMPAREITEMSTRUCT 
  13. 00007ffd6afc30c0  00007ffd6af641f0 USER32!__fnINLPCREATESTRUCT 
  14. 00007ffd6afc30c8  00007ffd6afbb2e0 USER32!_fnINLPDELETEITEMSTRUCT 
  15. 00007ffd6afc30d0  00007ffd6af6bc00 USER32!__fnINLPDRAWITEMSTRUCT 
  16. 00007ffd6afc30d8  00007ffd6afbb330 USER32!_fnINLPHELPINFOSTRUCT 
  17. 00007ffd6afc30e0  00007ffd6afbb330 USER32!_fnINLPHELPINFOSTRUCT 
  18. 00007ffd6afc30e8  00007ffd6afbb430 USER32!_fnINLPMDICREATESTRUCT 

当进程A将WM_COPYDATA消息发送到属于进程B的窗口时,将调用第一个函数,USER32!_fnCOPYDATA。内核将把消息(包括其他参数)发送到目标窗口句柄,该消息将由与之关联的windows过程处理。

  1. 0:001> u USER32!_fnCOPYDATA 
  2. USER32!_fnCOPYDATA: 
  3. 00007ffd6af62bd0 4883ec58        sub     rsp,58h 
  4. 00007ffd6af62bd4 33c0            xor     eax,eax 
  5. 00007ffd6af62bd6 4c8bd1          mov     r10,rcx 
  6. 00007ffd6af62bd9 89442438        mov     dword ptr [rsp+38h],eax 
  7. 00007ffd6af62bdd 4889442440      mov     qword ptr [rsp+40h],rax 
  8. 00007ffd6af62be2 394108          cmp     dword ptr [rcx+8],eax 
  9. 00007ffd6af62be5 740b            je      USER32!_fnCOPYDATA+0x22 (00007ffd6af62bf2) 
  10. 00007ffd6af62be7 48394120        cmp     qword ptr [rcx+20h],rax 

在此函数上设置断点并继续执行。

  1. 0:001> bp USER32!_fnCOPYDATA 
  2. 0:001> g 

下面的代码将把WM_COPYDATA消息发送到记事本。编译并运行它。

  1. int main(void){ 
  2.   COPYDATASTRUCT cds; 
  3.   HWND           hw; 
  4.   WCHAR          msg[]=L"I don't know what to say!\n"
  5.    
  6.   hw = FindWindowEx(0,0,L"Notepad",0); 
  7.    
  8.   if(hw!=NULL){    
  9.     cds.dwData = 1; 
  10.     cds.cbData = lstrlen(msg)*2; 
  11.     cds.lpData = msg; 
  12.      
  13.     // copy data to notepad memory space 
  14.     SendMessage(hw, WM_COPYDATA, (WPARAM)hw, (LPARAM)&cds); 
  15.   } 
  16.  return 0; 

一旦执行此代码,它将尝试在发送WM_COPYDATA消息之前找到Notepad的窗口句柄,这将触发调试器中的断点。调用堆栈显示调用来自何处,在本例中它来自KiUserCallbackDispatcherContinue。根据调用约定,参数被放置在RCX、RDX、R8和R9中。

  1. Breakpoint 0 hit 
  2. USER32!_fnCOPYDATA: 
  3. 00007ffd6af62bd0 4883ec58        sub     rsp,58h 
  4. 0:000> k 
  5.  # Child-SP          RetAddr           Call Site 
  6. 00 0000009832caf618 00007ffd6c03dbc4 USER32!_fnCOPYDATA 
  7. 01 0000009832caf620 00007ffd688d1144 ntdll!KiUserCallbackDispatcherContinue 
  8. 02 0000009832caf728 00007ffd6af61b0b win32u!NtUserGetMessage+0x14 
  9. 03 0000009832caf730 00007ff79cc13bed USER32!GetMessageW+0x2b 
  10. 04 0000009832caf790 00007ff79cc29333 notepad!WinMain+0x291 
  11. 05 0000009832caf890 00007ffd6bb23034 notepad!__mainCRTStartup+0x19f 
  12. 06 0000009832caf950 00007ffd6c011431 KERNEL32!BaseThreadInitThunk+0x14 
  13. 07 0000009832caf980 0000000000000000 ntdll!RtlUserThreadStart+0x21 
  14. 0:000> r 
  15. rax=00007ffd6af62bd0 rbx=0000000000000000 rcx=0000009832caf678 
  16. rdx=00000000000000b0 rsi=0000000000000000 rdi=0000000000000000 
  17. rip=00007ffd6af62bd0 rsp=0000009832caf618 rbp=0000009832caf829 
  18.  r8=0000000000000000  r9=00007ffd6afc3070 r10=0000000000000000 
  19. r11=0000000000000244 r12=0000000000000000 r13=0000000000000000 
  20. r14=0000000000000000 r15=0000000000000000 
  21. iopl=0         nv up ei pl nz na po nc 
  22. cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206 
  23. USER32!_fnCOPYDATA: 
  24. 00007ffd6af62bd0 4883ec58        sub     rsp,58h 

在RCX寄存器中转储第一个参数的内容显示示例程序发送的一些可识别的数据。notepad!NPWndProc显然是与接收WM_COPYDATA的目标窗口相关联的回调程序。

  1. 0:000> dps rcx 
  2. 0000009832caf678  00000038000000b0 
  3. 0000009832caf680  0000000000000001 
  4. 0000009832caf688  0000000000000000 
  5. 0000009832caf690  0000000000000070 
  6. 0000009832caf698  0000000000000000 
  7. 0000009832caf6a0  0000029258bbc070 
  8. 0000009832caf6a8  000000000000004a       // WM_COPYDATA 
  9. 0000009832caf6b0  00000000000c072e 
  10. 0000009832caf6b8  0000000000000001 
  11. 0000009832caf6c0  0000000000000001 
  12. 0000009832caf6c8  0000000000000034 
  13. 0000009832caf6d0  0000000000000078 
  14. 0000009832caf6d8  00007ff79cc131b0 notepad!NPWndProc 
  15. 0000009832caf6e0  00007ffd6c039da0 ntdll!NtdllDispatchMessage_W 
  16. 0000009832caf6e8  0000000000000058 
  17. 0000009832caf6f0  006f006400200049 

传递给fnCOPYDATA的结构不是调试符号的一部分,但是是我们要查看的内容。

  1. typedef struct _CAPTUREBUF { 
  2.     DWORD cbCallback; 
  3.     DWORD cbCapture; 
  4.     DWORD cCapturedPointers; 
  5.     PBYTE pbFree;               
  6.     DWORD offPointers; 
  7.     PVOID pvVirtualAddress;} CAPTUREBUF, *PCAPTUREBUF;typedef struct _FNCOPYDATAMSG { 
  8.     CAPTUREBUF     CaptureBuf; 
  9.     PWND           pwnd; 
  10.     UINT           msg; 
  11.     HWND           hwndFrom; 
  12.     BOOL           fDataPresent; 
  13.     COPYDATASTRUCT cds; 
  14.     ULONG_PTR      xParam; 
  15.     PROC           xpfnProc;} FNCOPYDATAMSG; 

继续通过代码单步(t)执行并检查寄存器的内容。

  1. 0:000> r 
  2. rax=00007ffd6c039da0 rbx=0000000000000000 rcx=00007ff79cc131b0 
  3. rdx=000000000000004a rsi=0000000000000000 rdi=0000000000000000 
  4. rip=00007ffd6af62c16 rsp=0000009832caf5c0 rbp=0000009832caf829 
  5.  r8=00000000000c072e  r9=0000009832caf6c0 r10=0000009832caf678 
  6. r11=0000000000000244 r12=0000000000000000 r13=0000000000000000 
  7. r14=0000000000000000 r15=0000000000000000 
  8. iopl=0         nv up ei pl nz na po nc 
  9. cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206 
  10. USER32!_fnCOPYDATA+0x46: 
  11. 00007ffd6af62c16 498b4a28        mov     rcx,qword ptr [r10+28h] ds:0000009832caf6a0=0000029258bbc070 
  12. 0:000> u rcx 
  13. notepad!NPWndProc: 
  14. 00007ff79cc131b0 4055            push    rbp 
  15. 00007ff79cc131b2 53              push    rbx 
  16. 00007ff79cc131b3 56              push    rsi 
  17. 00007ff79cc131b4 57              push    rdi 
  18. 00007ff79cc131b5 4154            push    r12 
  19. 00007ff79cc131b7 4155            push    r13 
  20. 00007ff79cc131b9 4156            push    r14 
  21. 00007ff79cc131bb 4157            push    r15 

我们看到一个指向COPYDATASTRUCT的指针被放在r9中。

  1. 0:000> dps r9 
  2. 0000009832caf6c0  0000000000000001 
  3. 0000009832caf6c8  0000000000000034 
  4. 0000009832caf6d0  0000009832caf6f0 
  5. 0000009832caf6d8  00007ff79cc131b0 notepad!NPWndProc 
  6. 0000009832caf6e0  00007ffd6c039da0 ntdll!NtdllDispatchMessage_W 
  7. 0000009832caf6e8  0000000000000058 
  8. 0000009832caf6f0  006f006400200049 
  9. 0000009832caf6f8  002000740027006e 
  10. 0000009832caf700  0077006f006e006b 
  11. 0000009832caf708  0061006800770020 
  12. 0000009832caf710  006f007400200074 
  13. 0000009832caf718  0079006100730020 
  14. 0000009832caf720  00000000000a0021 
  15. 0000009832caf728  00007ffd6af61b0b USER32!GetMessageW+0x2b 
  16. 0000009832caf730  0000009800000000 
  17. 0000009832caf738  0000000000000001 

这个结构是在调试符号中定义的,因此我们可以对其进行转储,以显示它包含的值。

  1. 0:000> dt uxtheme!COPYDATASTRUCT 0000009832caf6c0 
  2.    +0x000 dwData           : 1 
  3.    +0x008 cbData           : 0x34 
  4.    +0x010 lpData           : 0x0000009832caf6f0 Void 

最后,检查可能包含从进程A发送的字符串的lpData字段。

  1. 0:000> du poi(0000009832caf6c0+10) 
  2. 0000009832caf6f0  "I don't know what to say!." 

我们可以看到这个地址属于创建线程时分配的堆栈。

  1. 0:000> !address 0000009832caf6f0 
  2. Usage:                  Stack 
  3. Base Address:           0000009832c9f000 
  4. End Address:            0000009832cb0000 
  5. Region Size:            0000000000011000 (  68.000 kB) 
  6. State:                  00001000          MEM_COMMIT 
  7. Protect:                00000004          PAGE_READWRITE 
  8. Type:                   00020000          MEM_PRIVATE 
  9. Allocation Base:        0000009832c30000 
  10. Allocation Protect:     00000004          PAGE_READWRITE 
  11. More info:              ~0k 

检查位于线程环境块(TEB)中的线程信息块(TIB)为我们提供了StackBase和StackLimit。

  1. 0:001> dx -r1 (*((uxtheme!_NT_TIB *)0x9832e4a000)) 
  2. (*((uxtheme!_NT_TIB *)0x9832e4a000))                 [Type: _NT_TIB] 
  3.     [+0x000] ExceptionList    : 0x0 [Type: _EXCEPTION_REGISTRATION_RECORD *] 
  4.     [+0x008] StackBase        : 0x9832cb0000 [Type: void *] 
  5.     [+0x010] StackLimit       : 0x9832c9f000 [Type: void *] 
  6.     [+0x018] SubSystemTib     : 0x0 [Type: void *] 
  7.     [+0x020] FiberData        : 0x1e00 [Type: void *] 
  8.     [+0x020] Version          : 0x1e00 [Type: unsigned long] 
  9.     [+0x028] ArbitraryUserPointer : 0x0 [Type: void *] 
  10.     [+0x030] Self             : 0x9832e4a000 [Type: _NT_TIB *] 

总之,可以使用WM_COPYDATA将有效负载部署到目标进程中。但是,如果目标进程附带了GUI,除非能够执行它,否则并没有用处。此外,堆栈是内存的一个不稳定区域,因此不能作为代码洞使用。要执行此操作,需要找到确切的地址并使用ROP链。在执行ROP链时,不能保证有效载荷仍然完好无损。因此,我们或许不能在这种情况下使用WM_COPYDATA,但是值得记住的是,使用合法的API与其他进程共享负载的方法可能有很多,使用这些方法比使用WriteProcessMemory或NtWriteVirtualMemory被识别为可疑活动的可能性要小。

对于WM_COPYDATA,仍然需要确定有效负载堆栈中的确切地址。可以通过NtQueryThreadInformation API使用ThreadBasicInformation类,检索线程环境块(TEB)的内容。读取TebAddress之后,可以读取StackLimit和StackBase值。无论如何,堆栈的波动性意味着有效负载在被执行之前可能会被覆盖。

总结

避免使用常规API部署和执行有效负载会增加检测的难度。PowerLoader在现有区对象和ROP链中使用代码洞来执行。PowerLoaderEx是使用桌面堆的PoC,而atombomb PoC则使用DLL的.data部分中的代码洞。

 

责任编辑:武晓燕 来源: 4hou
相关推荐

2018-05-18 08:43:27

Linux内存空间

2024-01-08 08:42:43

2023-04-13 08:09:35

操作系统虚拟地址内存

2021-07-28 09:53:53

FalconEye注入安全检测

2024-02-22 17:08:03

腾讯架构RocketMQ

2021-11-23 10:30:35

Android技术代码

2019-01-29 10:10:09

Linux内存进程堆

2021-09-13 18:09:35

cThreadHija远程进程注入网络攻击

2023-12-06 07:22:36

2019-04-10 13:43:19

Linux内核进程负载

2021-09-13 09:21:51

InjectorWindows内存注入

2021-03-17 21:34:44

Linux内存管理

2012-05-03 08:27:20

Linux进程

2018-12-18 14:53:04

内存进程子进程

2021-04-22 07:47:46

Linux进程管理

2014-09-01 09:49:24

github

2019-12-16 10:43:38

Linux内存消耗进程

2021-09-30 10:45:33

Linux进程通信

2019-11-06 15:58:54

Linux内存消耗进程

2021-07-07 09:18:00

Java并发编程
点赞
收藏

51CTO技术栈公众号