嗨嗨嗨
1.位于xhunter1.sys的驱动回调内部有对dwm进程注入shellcode的操作,具体操作如下。
__int64 __fastcall CheckDwm_CreateThreadShellCode(__int64 a1, __int64 a2)
{
*(_DWORD *)a2 = 0x270;
*(_DWORD *)(a2 + 4) = 0x12121212;
*(_DWORD *)(a2 + 12) = 0xC0000001;
*(_DWORD *)(a2 + 8) = ~*(_DWORD *)(a1 + 8);
*(_DWORD *)(a2 + 12) = sub_1400087DC(a1 + 24, (PVOID *)(a2 + 16));
return 0i64;
}
2.关于获取DWM的几种方式,猜测可能因为样本对DWM进程处理,导致AC无法注入DWM进程。
__int64 __fastcall sub_1400087DC(__int64 a1, PVOID *a2)
{
int v4; // ebx
void *Handle; // rcx
void *tid; // rcx
PVOID Object; // [rsp+40h] [rbp+20h] BYREF
PETHREAD Thread; // [rsp+50h] [rbp+30h] BYREF
Object = 0i64;
v4 = 0xC000000D;
if ( (*(_BYTE *)(a1 + 72) & 1) != 0 )
{
Handle = *(void **)a1; // 通过句柄查DWM
if ( Handle )
{
v4 = HandleToObject(Handle, 0x1000u, &Object);
if ( v4 >= 0 )
{
v4 = ShellCodeCheckDwm(a1, a2, Object);
ObfDereferenceObject(Object);
if ( v4 >= 0 )
goto LABEL_18;
}
}
}
if ( (*(_BYTE *)(a1 + 72) & 4) != 0 )
{
tid = *(void **)(a1 + 16); // 通过线程查DWM
if ( tid )
{
v4 = PsLookupThreadByThreadId(tid, &Thread);
if ( v4 >= 0 )
{
Object = IoThreadToProcess(Thread);
ObfReferenceObject(Object);
v4 = ShellCodeCheckDwm(a1, a2, Object);
ObfDereferenceObject(Object);
ObfDereferenceObject(Thread);
if ( v4 >= 0 )
goto LABEL_18;
}
}
}
if ( (*(_BYTE *)(a1 + 72) & 2) != 0 )
{
v4 = PsLookupProcessByProcessId(*(HANDLE *)(a1 + 8), (PEPROCESS *)&Object);// 通过进程ID查DWM
if ( v4 >= 0 )
{
v4 = ShellCodeCheckDwm(a1, a2, Object);
ObfDereferenceObject(Object);
if ( v4 >= 0 )
goto LABEL_18;
}
}
if ( (*(_BYTE *)(a1 + 72) & 8) != 0
&& (v4 = sub_14000AF40(*(_QWORD *)(a1 + 8), &Object), v4 >= 0)// 遍历进程获取Csrss名字的进程ID 在查DWM
&& (v4 = ShellCodeCheckDwm(a1, a2, Object), ObfDereferenceObject(Object), v4 >= 0)
|| (*(_BYTE *)(a1 + 72) & 0x10) != 0
&& (v4 = sub_14000B2F4(*(_QWORD *)(a1 + 8), &Object), v4 >= 0)// 遍历获取Winlogon进程ID
&& (v4 = ShellCodeCheckDwm(a1, a2, Object), ObfDereferenceObject(Object), v4 >= 0) )
{
LABEL_18:
_mm_lfence();
}
return (unsigned int)v4;
}
3.组装ShellCode并在目标进程内部运行
__int64 __fastcall ShellCodeCheckDwm(__int64 a1, PVOID *a2, void *processObj)
{
void *R0Buf_2; // r13
unsigned int v7; // edi
unsigned __int64 len_1; // rsi
void *R0Buf_1; // r14
int v11; // esi
char *v12; // rcx
ULONG len; // edi
_OWORD *R0Buf; // rax
int v15; // eax
_BYTE *v16; // rax
__int64 v17; // r8
char v18; // bl
_BYTE *v19; // rdi
PVOID BaseAddress; // [rsp+60h] [rbp-79h] BYREF
HANDLE ProcessHandle; // [rsp+68h] [rbp-71h] BYREF
unsigned int v22; // [rsp+70h] [rbp-69h]
HANDLE v23; // [rsp+78h] [rbp-61h] BYREF
ULONG_PTR RegionSize; // [rsp+80h] [rbp-59h] BYREF
__int128 v25; // [rsp+88h] [rbp-51h] BYREF
__int128 v26; // [rsp+98h] [rbp-41h]
__int128 v27; // [rsp+A8h] [rbp-31h]
__int128 v28; // [rsp+B8h] [rbp-21h] BYREF
struct _KAPC_STATE ApcState; // [rsp+C8h] [rbp-11h] BYREF
RegionSize = 16772i64;
R0Buf_2 = &unk_140012430;
v7 = 8976;
ProcessHandle = 0i64;
BaseAddress = 0i64;
len_1 = 12288i64;
v22 = 8976;
R0Buf_1 = 0i64;
if ( !qword_140018080 )
return 3759800330i64;
if ( !RtlCreateUserThread && !qword_140018158 )
return 3759862303i64;
if ( ObOpenObjectByPointer(processObj, 0x200u, 0i64, 0x1FFFFFu, (POBJECT_TYPE)PsProcessType, 0, &ProcessHandle) < 0 )
{
v11 = -535105512;
LABEL_33:
if ( BaseAddress )
{
RegionSize = 0i64;
ZwFreeVirtualMemory(ProcessHandle, &BaseAddress, &RegionSize, 0x8000u);
}
goto LABEL_35;
}
if ( ZwAllocateVirtualMemory(ProcessHandle, &BaseAddress, 0i64, &RegionSize, 0x3000u, 0x40u) < 0 )
{
v11 = -535105513;
goto LABEL_33;
}
if ( BaseAddress )
{
v12 = *(char **)(a1 + 48);
if ( v12 )
{
len = *(_DWORD *)(a1 + 56);
R0Buf = CopyR3BufToR0(v12, len);
R0Buf_1 = R0Buf;
if ( R0Buf )
{
len_1 = len;
R0Buf_2 = R0Buf;
v7 = *(_DWORD *)(a1 + 64);
v22 = v7;
}
else
{
v7 = 8976;
}
}
if ( (int)AssembleShellCode((struct _KPROCESS *)processObj, BaseAddress, (_QWORD *)a1, (__int64)R0Buf_2, len_1) < 0 )// 可能是组装ShellCode
{
v11 = 0xE01AF039;
goto LABEL_31;
}
v23 = 0i64;
v28 = 0i64;
if ( RtlCreateUserThread )
{
if ( RtlCreateUserThread(
ProcessHandle,
0i64,
0i64,
0i64,
0i64,
0i64,
(char *)BaseAddress + v7,
BaseAddress,
&v23,
&v28) < 0 )
{
v11 = -535104991;
goto LABEL_31;
}
}
else
{
if ( !qword_140018158 )
{
LABEL_30:
v11 = -535104743;
goto LABEL_31;
}
v25 = 0i64;
v26 = 0i64;
v27 = 0i64;
KeStackAttachProcess_0((PRKPROCESS)processObj, &ApcState);
if ( v15 >= 0 )
{
v16 = (_BYTE *)(*(__int64 (__fastcall **)(struct _KTHREAD *))(qword_140018180 + 128))(KeGetCurrentThread());
v17 = v22;
v18 = *v16;
v19 = v16;
*v16 = 0;
LODWORD(v25) = 48;
*((_QWORD *)&v25 + 1) = 0i64;
DWORD2(v26) = 512;
*(_QWORD *)&v26 = 0i64;
v27 = 0i64;
v11 = qword_140018158(
&v23,
0x1FFFFFi64,
&v25,
-1i64,
(char *)BaseAddress + v17,
BaseAddress,
4,
0i64,
4096i64,
0x100000i64,
0i64);
KeUnstackDetachProcess_0(&ApcState);
*v19 = v18;
if ( v11 < 0 )
{
LABEL_31:
if ( R0Buf_1 )
ExFreePoolWithTag(R0Buf_1, 0x78687A31u);
goto LABEL_33;
}
}
}
if ( v23 )
{
ZwWaitForSingleObject(v23, 0, 0i64);
ZwClose(v23);
v11 = sub_1400078FC((struct _KPROCESS *)processObj, ProcessHandle, BaseAddress, (__int64)a2);
if ( v11 >= 0 )
{
if ( (int)R0BufToR3_FreeR0(a2) >= 0 )
{
v11 = 0;
}
else
{
ExFreePoolWithTag(*a2, 0x78687A31u);
v11 = 0xE01AF31A;
}
}
goto LABEL_31;
}
goto LABEL_30;
}
v11 = 0xE01AF018;
LABEL_35:
if ( ProcessHandle )
ZwClose(ProcessHandle);
return (unsigned int)v11;
}
4.具体组装ShellCode的逻辑。
__int64 __fastcall AssembleShellCode(struct _KPROCESS *a1, void *buf, _QWORD *a3, __int64 R0Buf, unsigned __int64 len)
{
int v7; // eax
ULONG64 r0buf; // rax
const void *v10; // rdx
void *r0buf_1; // rbx
PMDL mdl; // [rsp+20h] [rbp-58h] BYREF
struct _KAPC_STATE ApcState; // [rsp+28h] [rbp-50h] BYREF
mdl = 0i64;
KeStackAttachProcess_0(a1, &ApcState);
if ( v7 < 0 )
return 0xE01AF031i64;
r0buf = (ULONG64)LockMemR0(buf, 0x4184u, &mdl);
r0buf_1 = (void *)r0buf;
if ( r0buf )
{
*(_DWORD *)(r0buf + 16532) = 0xE01AF119;
strcpy((char *)(r0buf + 16652), "dwmcore.dll");
strcpy((char *)(r0buf + 16612), "gdi32.dll");
strcpy((char *)(r0buf + 16632), "user32.dll");
*(_QWORD *)(r0buf + 16712) = a3[3];
*(_QWORD *)(r0buf + 16720) = a3[4];
*(_QWORD *)(r0buf + 16728) = a3[5];
memcpy((void *)r0buf, v10, len);
unLockMemR0(mdl, r0buf_1);
KeUnstackDetachProcess_0(&ApcState);
return 0i64;
}
else
{
KeUnstackDetachProcess_0(&ApcState);
return 0xE01AF037i64;
}
}
总结:R3传递参数通过调用驱动接口,驱动接口内部解析参数获的注入的进程、组装来自R3的ShellCode,并在目标进程内部运行ShellCode,由于都是静态分析,未见具体ShellCode逻辑,分析到此为止。
绕过:已知xhunter1.sys驱动会注入DWM进程,在未知ShellCode逻辑的情况下可以监控这条线程,当线程启动时关闭绘制,线程结束时启动绘制即可,仅针对上文逻辑。