逆向XignCode3驱动程序:识别驱动程序入口点(part1)
逆向XignCode3驱动程序:分析init初始化函数(part2)
逆向XignCode3驱动程序:分析Dispatcher函数(part3)
在分析DriverEntry时,我确定了两个函数,它们负责不同类型的回调注册(fn_InitRegistrationNotifyAndCallbackRoutines和fn_RegisterCreateProcessNotifyRoutine),但我没有更深入地了解他们的作用。
![逆向XignCode3驱动程序:分析注册通信和回调函数(part4) 逆向XignCode3驱动程序:分析注册通信和回调函数(part4)]()
0x01 概述
· 识别互斥锁和自旋锁
· 了解如何使用Win API注册通知例程
· 了解如何创建PCREATE_PROCESS_NOTIFY_ROUTINE
· 了解驱动程序如何管理执行期间可能出现的各种错误状态。
由于目标是分析驱动程序并提供所需的信息,你可以自行学习其余信息,我不会深入了解什么是Notify和Callback例程。这里有一些链接资源:
· PsSetCreateProcessNotifyRoutine
· PsSetCreateProcessNotifyRoutineEx
· PCREATE_PROCESS_NOTIFY_ROUTINE
你需要了解的最重要的是,反作弊控制系统中发生的事情。因此,他们将注册此通知和回调例程,这将允许他们在触发事件时执行操作前和操作后的操作,例如,已创建新进程,已加载新DLL等。
![逆向XignCode3驱动程序:分析注册通信和回调函数(part4) 逆向XignCode3驱动程序:分析注册通信和回调函数(part4)]()
0x02 fn_InitRegistrationNotifyAndCallbackRoutines(0x140003550)
有一些函数尚未初始化变量,自旋锁和数组。所有这些变量都在驱动程序的多个函数中使用,当我逆向尚未见过的其他函数时,将发现那些含义。
由于函数越来越大,越来越复杂,因此我将避免解释一些有关驱动程序开发的基本知识,例如互斥量初始化,分配等。
函数代码:
signed __int64 fn_InitRegistrationNotifyAndCallbackRoutines()
{
_QWORD *v0; // rax
_QWORD *v1; // rbx
wchar_t *v2; // rax
signed __int64 result; // rax
__int64(__fastcall *PsSetCreateProcessNotifyRoutineEx)(PVOID, BOOLEAN); // rax
int ntStatus; // eax
signed int v6; // ecx
signed int ntStatus_1; // ebx
__int64 _RemoveRoutine; // rdx
UNICODE_STRING DestinationString; // [rsp+20h] [rbp-18h]
v0 = ExAllocatePoolWithTag(0, 0x28ui64, 0x78687A31u);
qword_14000CD70 = v0;
v1 = v0;
if (!v0)
return 0xC000009Ai64;
memset(v0, 0, 0x28ui64);
*v1 = 0i64;
task_status_NotifyCallbackRoutine = 0; // Task mutex
bNotifyCallbackRoutines = 0;
KeInitializeMutex(&BlackCipherMutex, 0);
v2 = ExAllocatePoolWithTag(0, 0x2000ui64, 0x78687A31u);
Str1 = v2;
if (!v2)
return 0xC000009Ai64;
*v2 = 0;
qword_14000CD08 = 0i64;
someMaxValue = 0x1000i64;
result = j_fn_ConfigWindowsVersion();
if (result < 0)
return result;
fn_InitWeirdVariables_();
fn_InitWeirdVariables2_();
status_PsSetCreateProcessNotifyRoutine = 0;
status_PsSetCreateProcessNotifyRoutineEx = 0;
RtlInitUnicodeString(&DestinationString, L"PsSetCreateProcessNotifyRoutineEx");
PsSetCreateProcessNotifyRoutineEx = MmGetSystemRoutineAddress(&DestinationString);
fn_pPsSetCreateProcessNotifyRoutineEx = PsSetCreateProcessNotifyRoutineEx;
if (PsSetCreateProcessNotifyRoutineEx)
{
ntStatus = PsSetCreateProcessNotifyRoutineEx(fn_CreateProcessNotifyRoutineExImp, 0i64);
v6 = status_PsSetCreateProcessNotifyRoutineEx;
if (ntStatus >= 0)
v6 = 1;
status_PsSetCreateProcessNotifyRoutineEx = v6;
}
else
{
v6 = status_PsSetCreateProcessNotifyRoutineEx;
}
if (!v6)
{
ntStatus_1 = PsSetCreateProcessNotifyRoutine(fn_CreateProcessNotifyRoutine, 0i64);
if (ntStatus_1 < 0)
{
status_PsSetCreateProcessNotifyRoutine = 0;
goto LABEL_13;
}
status_PsSetCreateProcessNotifyRoutine = 1;
}
ntStatus_1 = 0;
LABEL_13:
if (ntStatus_1 < 0)
{
label_exit:
fn_InitWeirdVariables3_();
nullsub_1();
return ntStatus_1;
}
ntStatus_1 = fn_RegisterCallbackFunction();
if (ntStatus_1 < 0) // In case the registerCallbackFunction failed, we need to remove the Notify routines previously registered.
{
if (status_PsSetCreateProcessNotifyRoutineEx && fn_pPsSetCreateProcessNotifyRoutineEx)
fn_pPsSetCreateProcessNotifyRoutineEx(fn_CreateProcessNotifyRoutineExImp, 1u);// 2nd Parameter equal to 1 == remove
if (status_PsSetCreateProcessNotifyRoutine)
{
LOBYTE(_RemoveRoutine) = 1;
PsSetCreateProcessNotifyRoutine(fn_CreateProcessNotifyRoutine, _RemoveRoutine);
}
goto label_exit;
}
return 0i64;
}
在函数的开头,进行了一些缓冲区和互斥锁初始化,尚不知道这些变量的用途是什么,但是由于这些变量的使用方式,可以识别它们。
例如,作为互斥相关函数(例如KeInitializeMutex)或汇编操作码(例如lock xadd)的参数:
之后,将找到第一个有趣的函数sub_140003C38,我决定将其命名为j_fn_ConfigWindowsVersion。
该函数标识Windows的当前版本,并使用有关某些特定内核结构的信息来初始化一系列偏移变量,继续执行:
result = j_fn_ConfigWindowsVersion();
if ( result < 0 )
return result;
fn_InitWeirdVariables_();
fn_InitWeirdVariables2_();
status_PsSetCreateProcessNotifyRoutine = 0;
status_PsSetCreateProcessNotifyRoutineEx = 0;
忽略fn_InitWeirdVariables_和fn_InitWeirdVariables2_,因为这些函数只是初始化一些自旋锁和驱动程序以后使用的变量,暂时对此不感兴趣。
ProcessId >>= 2;
v3 = (ProcessId >> 5) & 0x1FF;
v4 = ~(1 << (0x1F - (ProcessId & 0x1F)));
之后,将初始化两个NTSTATUS变量:status_PsSetCreateProcessNotifyRoutine和status_PsSetCreateProcessNotifyRoutineEx,如果第一次尝试使用PsSetCreateProcessNotifyRoutineEx注册NotifyRoutine失败,那么他们将使用这些变量来控制执行流程,并再次尝试使用PsSetCreateProcessNotifyRoutineEx进行尝试。
RtlInitUnicodeString(&DestinationString, L"PsSetCreateProcessNotifyRoutineEx");
PsSetCreateProcessNotifyRoutineEx = MmGetSystemRoutineAddress(&DestinationString);
fn_pPsSetCreateProcessNotifyRoutineEx = PsSetCreateProcessNotifyRoutineEx;
检索PsSetCreateProcessNotifyRoutineEx的地址并将其存储到变量中,如果此变量值不为NULL,则进行第一次尝试:
if ( PsSetCreateProcessNotifyRoutineEx )
{
ntStatus = PsSetCreateProcessNotifyRoutineEx(fn_CreateProcessNotifyRoutineExImp, 0i64);
v6 = status_PsSetCreateProcessNotifyRoutineEx;
if ( ntStatus >= 0 )
v6 = 1;
status_PsSetCreateProcessNotifyRoutineEx = v6;
}
else
{
v6 = status_PsSetCreateProcessNotifyRoutineEx;
}
可以看到调用了PsSetCreateProcessNotifyRoutineEx ,在第一个参数中,每当创建或退出新进程时,它将发送要执行的例程(fn_CreateProcessNotifyRoutineExImp);在第二个参数中,它确定需要注册而不是删除“通知例程”。相同的函数用于创建和删除NotifyRoutine。
如果第一次尝试失败,则对该函数再进一步一点,将看到PsSetCreateProcessNotifyRoutine 第二次尝试:
if ( !v6 )
{
ntStatus_1 = PsSetCreateProcessNotifyRoutine(fn_CreateProcessNotifyRoutine, 0i64);
if ( ntStatus_1 < 0 )
{
status_PsSetCreateProcessNotifyRoutine = 0;
goto LABEL_13;
}
status_PsSetCreateProcessNotifyRoutine = 1;
}
确定了另一个回调例程:fn_CreateProcessNotifyRoutine。
![逆向XignCode3驱动程序:分析注册通信和回调函数(part4) 逆向XignCode3驱动程序:分析注册通信和回调函数(part4)]()
0x03 fn_CreateProcessNotifyRoutine和fn_CreateProcessNotifyRoutineExImp
如果检查fn_CreateProcessNotifyRoutineExImp和fn_CreateProcessNotifyRoutine,会注意到它们都是真实例程:
void __fastcall fn_CreateProcessNotifyRoutineExImp(PEPROCESS Process, __int64 ProcessId, PVOID CreateInfo)
{
if ( CreateInfo ) // If CreateInfo parameter is NULL, the specified process is exiting.
fn_Analyze_CreateProcessNotifyRoutine(ProcessId);
else
fn_Analyze_ExitProcessNotifyRoutine(ProcessId);
}
在文档中解释了PCREATE_PROCESS_NOTIFY_ROUTINE接收的参数,基于此,可以确定此函数如何确定是否由于创建或删除进程而调用了回调。
fn_Analyze_CreateProcessNotifyRoutine和fn_Analyze_ExitProcessNotifyRoutine是我稍后将要分析的大函数。
![逆向XignCode3驱动程序:分析注册通信和回调函数(part4) 逆向XignCode3驱动程序:分析注册通信和回调函数(part4)]()
0x04 fn_InitRegistrationNotifyAndCallbackRoutines
尝试最后一次回调注册:
ntStatus_1 = fn_RegisterCallbackFunction();
if ( ntStatus_1 < 0 ) // In case the registerCallbackFunction failed, we need to remove teh Notify routines previously registered.
{
if ( status_PsSetCreateProcessNotifyRoutineEx && fn_pPsSetCreateProcessNotifyRoutineEx )
fn_pPsSetCreateProcessNotifyRoutineEx(fn_CreateProcessNotifyRoutineExImp, 1u);// 2nd Parameter equal to 1 == remove
if ( status_PsSetCreateProcessNotifyRoutine )
{
LOBYTE(_RemoveRoutine) = 1;
PsSetCreateProcessNotifyRoutine(fn_CreateProcessNotifyRoutine, _RemoveRoutine);
}
goto label_exit;
}
但是,如果registerCallbackFunction失败,则需要在离开之前删除先前创建的NotifyRoutine,在这种情况下,他们将_RemoveRoutine设置为1,然后再次调用PsSetCreateProcessNotifyRoutine将其删除,fn_RegisterCallbackFunction将被撤销。
参考及来源:https://niemand.com.ar/2020/01/31/reversing-xigncode3-driver-part-4-1-registering-notify-and-callback-routines/
本文始发于微信公众号(嘶吼专业版):逆向XignCode3驱动程序:分析注册通信和回调函数(part4)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论