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

admin 2021年4月22日23:40:37评论63 views字数 6628阅读22分5秒阅读模式

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

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

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

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

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

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

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

· 识别互斥锁和自旋锁

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

· 了解如何创建PCREATE_PROCESS_NOTIFY_ROUTINE

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

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

· PsSetCreateProcessNotifyRoutine

· PsSetCreateProcessNotifyRoutineEx

· PCREATE_PROCESS_NOTIFY_ROUTINE

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

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

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

有一些函数尚未初始化变量,自旋锁和数组。所有这些变量都在驱动程序的多个函数中使用,当我逆向尚未见过的其他函数时,将发现那些含义。

由于函数越来越大,越来越复杂,因此我将避免解释一些有关驱动程序开发的基本知识,例如互斥量初始化,分配等。

函数代码:

 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)的参数:

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

之后,将找到第一个有趣的函数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)
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)
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)

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

本文始发于微信公众号(嘶吼专业版):逆向XignCode3驱动程序:分析注册通信和回调函数(part4)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年4月22日23:40:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   逆向XignCode3驱动程序:分析注册通信和回调函数(part4)http://cn-sec.com/archives/197352.html

发表评论

匿名网友 填写信息