逆向XignCode3驱动程序:分析注册通信和回调函数(part4) - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com

逆向XignCode3驱动程序:分析注册通信和回调函数(part4)

h1apwn 技术 2020-12-08 09:52:44
收藏

导语:在分析DriverEntry时,我确定了两个函数,它们负责不同类型的回调注册(**fn_InitRegistrationNotifyAndCallbackRoutines**和**fn_RegisterCreateProcessNotifyRoutine**),但我没有更深入地了解他们的作用。

逆向XignCode3驱动程序:识别驱动程序入口点(part1)

逆向XignCode3驱动程序:分析init初始化函数(part2)

逆向XignCode3驱动程序:分析Dispatcher函数(part3)

在分析DriverEntry时,我确定了两个函数,它们负责不同类型的回调注册(fn_InitRegistrationNotifyAndCallbackRoutines和fn_RegisterCreateProcessNotifyRoutine),但我没有更深入地了解他们的作用。

0x01  概述

· 识别互斥锁和自旋锁

· 了解如何使用Win API注册通知例程

· 了解如何创建PCREATE_PROCESS_NOTIFY_ROUTINE

· 了解驱动程序如何管理执行期间可能出现的各种错误状态。

由于目标是分析驱动程序并提供所需的信息,你可以自行学习其余信息,我不会深入了解什么是Notify和Callback例程。这里有一些链接资源:

· PsSetCreateProcessNotifyRoutine

· PsSetCreateProcessNotifyRoutineEx

· PCREATE_PROCESS_NOTIFY_ROUTINE

你需要了解的最重要的是,反作弊控制系统中发生的事情。因此,他们将注册此通知和回调例程,这将允许他们在触发事件时执行操作前和操作后的操作,例如,已创建新进程,已加载新DLL等。

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。

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 < 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/如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论