欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

QQ电脑管家逆向系列之PsSetCreateProcessNotifyRoutine(1)

程序员文章站 2022-07-04 11:19:35
作 者: 星逝     下午一时兴起,打算研究下QQ电脑管家的一系列功能,于是先从PsSetCreateProcessNofityRoutine下手了,打算逆成一个系...
作 者: 星逝
 
 
下午一时兴起,打算研究下QQ电脑管家的一系列功能,于是先从PsSetCreateProcessNofityRoutine下手了,打算逆成一个系列,希望大家多多支持。不喜勿喷。
 
由于下午时间仓促,NofityRoutine仅逆了一部分,当作(1)先分享给大家,总体流程还是比较清楚了的。
 
用XT查看内核--->系统回调,发现有两个CreateProcess回调,分别在TCSafeBox.sys和TCKsp.sys中,这里分析的是TCSafeBox.sys。
 
DriverEntry里调用PsSetCreateProcessNotifyRoutine注册NotifyRoutine,下面是NotifyRoutine的总体流程。
 
 
代码:
void __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
  if(KeGetCurrentIrql() > 0)
  {
    return;
  }
  if(FALSE == Create)
  {
    sub_144DE(ProcessId, ParentId);
  }
  else
  {
    if(0 == dword_15300)
    {
      return;
    }
    else
    {
      sub_143C2(ProcessId, ParentId);
    }
  }
}
这部分代码比较简单,Create标识这次回调是因为进程创建还是销毁,这里先关注创建的过程,毕竟防御为主。在创建过程的处理中QQ电脑管家设置了一个功能开关,也就是这里的dword_15300。
 
sub_143C2的流程如下
 
代码:
void sub_143C2(HANDLE ProcessId, HANDLE ParentId)
{
  char buf[0x314];
  memset(buf, 0, 0x314);
  int a, b;
  a = b = 0;
  *(HANDLE *)buf = ProcessId;
  if(!sub_12326(ProcessId, buf + 8,0x103))
  {
    return;
  }
}
这里就是NotifyRoutine的主要功能了,防御需要两个步骤,一是获得创建进程的相关信息,二是根据这些信息对其进行处理。由于时间关系,这里还只是分析了第一个步骤,也就是这里的sub_12326。第二个步骤放在下一篇讲叙吧。
 
 
代码:
BOOL __stdcall sub_12326(HANDLE ProcessId, PVOID Buffer, int arg2)
{
  PVOID MbString = Buffer;
  if(NULL == Buffer)
  {
    return 0;
  }
  wchar_t SourceString[0x208] = {0};
  wchar_t UnicodeString[0x208] = {0};
  if(!sub_11B6E(ProcessId, SourceString, 0x100))
  {
    return FALSE;
  }
  if(!sub_11D0A(SourceString, UnicodeString, 0x100))
  {
    return FALSE;
  }
  DWORD ReturnSize = 0;
  RtlUnicodeToMultiByteN();
  return TRUE;
}
sub_12326就是获取进程相关信息了,其主要功能就是将得到的进程信息拷贝至sub_143C2所给的缓冲区,让sub_143C2做进一步防御的处理。sub_12326里调用了两个子过程sub_11B6E和sub11D0A。它们一个是获取ProcessImageFileName,另一个根据获得的进程镜像路径将其转换为FileDosDeviceName。
 
 
代码:
BOOL __stdcall sub_11B6E(HANDLE ProcessId, wchar_t *pStr, DWORD dwLength)
{
  if(NULL == ProcessId)
  {
    return FALSE;
  }
  if(NULL == puniStr)
  {
    return FALSE;
  }
  BOOL ret = FALSE;
  PEPROCESS peprocess = NULL;
  HANDLE handle = NULL;
  if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &peprocess)))
  {
    if(NT_SUCCESS(ObOpenObjectByPointer(peprocess, 0x200, 0, 0, 0, 0, &handle))
    {
      PVOID pv = ExAllocatePoolWithTag(NonPagedPool, 0x800, 0x5A5A4D4D);
      if(pv != NULL)
      {
        memset(pv, 0, 0x800);
        if(NT_SUCCESS(ZwQueryInformationProcess(handle, ProcessImageFileName, pv, 0x800, &ProcessId))
        {
          PUNICODE_STRING puniImageFileName = pv;
          if(puniImageFileName->Buffer[0] != 0)
          {
            if(puniImageFileName->Length > 0)
            {
              wcsncpy(pStr, puniImageFileName->Buffer, dwLength);
              ret = TRUE;
            }
          }
        }
        ExFreePoolWithTag(pv, NonPagedPool);
      }
    }
  }
  if(handle != NULL)
  {
    ZwClose(handle);
  }
  if(peprocess != NULL)
  {
    ObfDereferenceObject(peprocess)
  }
  return ret;
}
sub_11B6E获取ProcessImageFileName。
 
 
代码:
BOOL __stdcall sub_11D0A(wchar_t *pStr1, wchar_t *pStr2, DWORD dwLength)
{
  PFILE_OBJECT Object = NULL;
  PVOID pv = NULL;
  BOOL ret = FALSE;
  HANDLE hFile = sub_11C56(pStr1, FALSE);
  if(hFile != NULL)
  {
    if(NT_SUCCESS(ObReferenceObjectByHandle(hFile, 0, *IoFileObjectType, 0, &Object, 0))
    {
      if(NT_SUCCESS(IoQueryFileDosDeviceName(Object, &pv))
      {
        POBJECT_NAME_INFORMATION pInfo = pv;
        if(pv->Name.Length < dwLength * 2)
        {
          memcpy(pStr2, pv->Name.Buffer, pv->Name.Length);
          ret = TRUE;
        }
      }
    }
  }
  if(Object != NULL)
  {
    ObfDereferenceObject(Object);
  }
  if(hFile != NULL)
  {
    ZwClose(hFile);
  }
  if(pv != NULL)
  {
    ExFreePoolWithTag(pv, 0);
  }
  return ret;
}
 
HANDLE __stdcall sub_11C56(wchar_t *pStr, BOOL flag)
{
  if(NULL == pStr)
  {
    return NULL;
  }
  ObjectAttributes ObjAttr = {0};
  UNICODE_STRING DestString = {0};
  IoStatusBlock block = {0};
  HANDLE handle = NULL;
  RtlInitUnicodeString(&DestString, pStr1);
  ULONG CreateOptions = 0;
  if(!flag)
  {
    CreateOptions = 0x21;
  }
  else
  {
    CreateOptions = 0x60;
  }
  ObjAttr.ObjectName = &DestString;
  ObjAttr.Length = sizeof(ObjectAttributes);
  ObjAttr.RootDirectory = NULL;
  ObjAttr.Attributes = 0x240;
  ObjAttr.SecurityDescriptor = NULL;
  ObjAttr.SecurityQualityOfService = NULL;
  if(NT_SUCCESS(IoCreateFile(&handle, 0x80000000, &ObjAttr, &block, 0, 0x80, 1, 1, CreateOptions, 0, 0, 0, 0, 0x100))
  {
    return handle;
  }
  return NULL;
}
sub_11D0A转换FileDosDeviceName,其子过程sub_11C56主要是IoCreateFile获取进程镜像文件的句柄。
 
逆出来的代码都很简单,所以只是简单介绍了下它的流程,相信大家也能看得懂