为什么在执行我注入的有效负载后进程会崩溃?

逆向工程 视窗 部件 注射
2021-06-13 21:01:04

我在 Windows 中尝试了以下用于 APC 注入的有效负载。
它被成功执行(弹出一个 MessageBox)但在执行 payload 后进程崩溃
这可能是什么原因?

有效载荷:

push   ebp                     ;save ebp
mov    ebp,esp                 ;start new frame
sub    esp,0x8                 ;make space for strings
mov    BYTE PTR [ebp-0x4],0x48 ;store strings
mov    BYTE PTR [ebp-0x3],0x0
mov    BYTE PTR [ebp-0x8],0x46
mov    BYTE PTR [ebp-0x7],0x0
push   eax                     ;save registers to restore the values later
                               ;(I think that I need not save all registers
                               ;but only the ones I use,
                               ;but since the process kept crashing after the payload execution
                               ;I thought let's not take a chance! :P
push   ebx
push   ecx
push   edx
push   edi
push   esi
push   0x0                     ;push arguments for MessageBox()
lea    eax,[ebp-0x4]
push   eax
lea    eax,[ebp-0x8]
push   eax
push   0x0
call   DWORD PTR [ebp+0x8]     ;call MessageBox()
pop    esi                     ;restore registers
pop    edi
pop    edx
pop    ecx
pop    ebx
pop    eax
xor    eax, eax
mov    esp,ebp
pop    ebp                     ;restore ebp
ret                            ;return

注入代码:

QueueUserAPC((PAPCFUNC)p, hThread, messageBoxAddr); //p: address of payload(written to victim process)

错误消息(来自 IDA Pro、WinDbg):

The instruction at 0x771C63BD referenced memory at 0x75C2442D. The memory could not be read -> 75C2442D (exc.code c0000005, tid 2948)

它基本上说ediin mov ecx, [edi+2CCh](在有效负载执行之后)有一个无效地址。

崩溃附近的反汇编代码:

ntdll:771C63BD ; ---------------------------------------------------------------------------
ntdll:771C63BD mov     ecx, [edi+2CCh]    ;<--- It CRASHES here
ntdll:771C63C3 mov     large fs:0, ecx
ntdll:771C63CA push    1
ntdll:771C63CC push    edi
ntdll:771C63CD call    near ptr ntdll_ZwContinue
ntdll:771C63D2 mov     esi, eax
ntdll:771C63D4
ntdll:771C63D4 loc_771C63D4:                           ; CODE XREF: ntdll:ntdll_KiUserApcDispatcher+42j
ntdll:771C63D4 push    esi
ntdll:771C63D5 call    near ptr ntdll_RtlRaiseStatus
ntdll:771C63DA jmp     short loc_771C63D4

调用栈:

在此处输入图片说明

1个回答

这是发生崩溃的函数的其余部分:

_KiUserApcDispatcher@16 proc near
 lea     eax, [esp+2DCh]
 mov     ecx, large fs:0
 mov     edx, offset _KiUserApcExceptionHandler@16 ; KiUserApcExceptionHandler(x,x,x,x)
 mov     [eax], ecx
 mov     [eax+4], edx
 mov     large fs:0, eax
 pop     eax
 lea     edi, [esp+0Ch]
 call    eax

如您所见,edi是从 初始化的esp,因此崩溃很可能是由于调用后的错误 esp 而发生的。现在,让我们检查 API 标头:

WINBASEAPI
DWORD
WINAPI
QueueUserAPC(
    _In_ PAPCFUNC pfnAPC,
    _In_ HANDLE hThread,
    _In_ ULONG_PTR dwData
    );

并且PACPFUNC是:

typedef
VOID
(NTAPI *PAPCFUNC)(
    _In_ ULONG_PTR Parameter
    );

在哪里NTAPI

#define NTAPI __stdcall

__stdcall函数负责从传入的参数中清理堆栈,并且由于我们的函数接受一个类型的参数ULONG_PTR(一个指针,所以 4 个字节),它必须在返回时清理堆栈,即使用retn 4而不是仅对函数来说retn就足够了__cdecl.