在分析DriverEntry時,我確定了兩個函數,它們負責不同類型的回調註冊(fn_InitRegistrationNotifyAndCallbackRoutines和fn_RegisterCreateProcessNotifyRoutine),但我沒有更深入地了解他們的作用。
0x01 概述
·識別互斥鎖和自旋鎖
·了解如何使用Win API註冊通知例程
·了解如何創建PCREATE_PROCESS_NOTIFY_ROUTINE
·了解驅動程序如何管理執行期間可能出現的各種錯誤狀態。
由於目標是分析驅動程序並提供所需的信息,你可以自行學習其餘信息,我不會深入了解什麼是Notify和Callback例程。這裡有一些連結資源:
·PsSetCreateProcessNotifyRoutine
·PsSetCreateProcessNotifyRoutineEx
·PCREATE_PROCESS_NOTIFY_ROUTINE
你需要了解的最重要的是,反作弊控制系統中發生的事情。因此,他們將註冊此通知和回調例程,這將允許他們在觸發事件時執行操作前和操作後的操作,例如,已創建新進程,已加載新DLL等。
有一些函數尚未初始化變量,自旋鎖和數組。所有這些變量都在驅動程序的多個函數中使用,當我逆向尚未見過的其他函數時,將發現那些含義。
由於函數越來越大,越來越複雜,因此我將避免解釋一些有關驅動程序開發的基本知識,例如互斥量初始化,分配等。
函數代碼:
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
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
{
status_PsSetCreateProcessNotifyRoutine = 0;
goto LABEL_13;
}
status_PsSetCreateProcessNotifyRoutine = 1;
}
ntStatus_1 = 0;
LABEL_13:
if (ntStatus_1
{
label_exit:
fn_InitWeirdVariables3_();
nullsub_1();
return ntStatus_1;
}
ntStatus_1 = fn_RegisterCallbackFunction();
if (ntStatus_1
{
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
return result;
fn_InitWeirdVariables_();
fn_InitWeirdVariables2_();
status_PsSetCreateProcessNotifyRoutine = 0;
status_PsSetCreateProcessNotifyRoutineEx = 0;
忽略fn_InitWeirdVariables_和fn_InitWeirdVariables2_,因為這些函數只是初始化一些自旋鎖和驅動程序以後使用的變量,暫時對此不感興趣。
ProcessId >>= 2;
v3 = (ProcessId >> 5) & 0x1FF;
v4 = ~(1
之後,將初始化兩個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
{
status_PsSetCreateProcessNotifyRoutine = 0;
goto LABEL_13;
}
status_PsSetCreateProcessNotifyRoutine = 1;
}
確定了另一個回調例程:fn_CreateProcessNotifyRoutine。
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是我稍後將要分析的大函數。
0x04 fn_InitRegistrationNotifyAndCallbackRoutines
嘗試最後一次回調註冊:
ntStatus_1 = fn_RegisterCallbackFunction();
if ( ntStatus_1
{
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/