Author: star death
At one o'clock P.M., I plan to study a series of functions of QQ's computer manager. So I started with PsSetCreateProcessNofityRoutine and planned to turn it into a series. I hope you can support it more. Don't like, don't spray.
Due to the rush of time in the afternoon, NofityRoutine is only a part of it. As a result, I will share it with you first. The overall process is clear.
Use XT to view the kernel ---> system callback. Two CreateProcess Callbacks are found in TCSafeBox. sys and TCKsp. sys. TCSafeBox. sys are analyzed here.
In DriverEntry, call pssetcreateprocesspolicyroutine to register policyroutine. The following describes the overall process of policyroutine.
Code:
Void _ stdcall policyroutine (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 );
}
}
}
This part of the code is relatively simple. Create identifies the callback because the process is created or destroyed. Here we first focus on the creation process. After all, the defense is the main one. During the creation process, the QQ computer manager sets a function switch, that is, the dword_15300 here.
The sub_143C2 process is as follows:
Code:
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;
}
}
Here is the main function of policyroutine. Two steps are required for defense. One is to obtain information about the creation process, and the other is to process it based on the information. Due to the time relationship, only the first step is analyzed here, that is, sub_12326. The second step is described in the next article.
Code:
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 is used to obtain process-related information. Its main function is to copy the obtained process information to the buffer zone provided by sub_143C2, so that sub_143C2 can be further defended. Sub_11B6E and sub11D0A are called in sub_12326. One of them is to get ProcessImageFileName, and the other is to convert it to FileDosDeviceName Based on the obtained process image path.
Code:
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 obtain ProcessImageFileName.
Code:
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, 0, 0, 0x100 ))
{
Return handle;
}
Return NULL;
}
Sub_11D0A converts FileDosDeviceName. Its sub_11C56 sub-process mainly refers to IoCreateFile to obtain the handle of the process image file.
The reverse code is very simple, so I just briefly introduced the process. I believe everyone can understand it.