驅動開發:核心列舉程序與執行緒ObCall回撥

2022-10-22 12:01:03

在筆者上一篇文章《驅動開發:核心列舉Registry登入檔回撥》中我們通過特徵碼定位實現了對登入檔回撥的列舉,本篇文章LyShark將教大家如何列舉系統中的ProcessObCall程序回撥以及ThreadObCall執行緒回撥,之所以放在一起來講解是因為這兩中回撥在列舉是都需要使用通用結構體_OB_CALLBACK以及_OBJECT_TYPE所以放在一起來講解最好不過。

我們來看一款閉源ARK工具是如何實現的:

首先我們需要定義好結構體,結構體是微軟公開的,如果有其它需要請自行去微軟官方去查。

typedef struct _OBJECT_TYPE_INITIALIZER
{
	USHORT Length;                // Uint2B
	UCHAR ObjectTypeFlags;            // UChar
	ULONG ObjectTypeCode;             // Uint4B
	ULONG InvalidAttributes;          // Uint4B
	GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
	ULONG ValidAccessMask;       // Uint4B
	ULONG RetainAccess;         // Uint4B
	POOL_TYPE PoolType;        // _POOL_TYPE
	ULONG DefaultPagedPoolCharge;  // Uint4B
	ULONG DefaultNonPagedPoolCharge; // Uint4B
	PVOID DumpProcedure;       // Ptr64     void
	PVOID OpenProcedure;      // Ptr64     long
	PVOID CloseProcedure;     // Ptr64     void
	PVOID DeleteProcedure;        // Ptr64     void
	PVOID ParseProcedure;     // Ptr64     long
	PVOID SecurityProcedure;      // Ptr64     long
	PVOID QueryNameProcedure;     // Ptr64     long
	PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
	ULONG WaitObjectFlagMask;     // Uint4B
	USHORT WaitObjectFlagOffset;    // Uint2B
	USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
	LIST_ENTRY TypeList;           // _LIST_ENTRY
	UNICODE_STRING Name;         // _UNICODE_STRING
	PVOID DefaultObject;         // Ptr64 Void
	UCHAR Index;             // UChar
	ULONG TotalNumberOfObjects;      // Uint4B
	ULONG TotalNumberOfHandles;      // Uint4B
	ULONG HighWaterNumberOfObjects;    // Uint4B
	ULONG HighWaterNumberOfHandles;    // Uint4B
	OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
	EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
	ULONG Key;                 // Uint4B
	LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
	LIST_ENTRY ListEntry;
	ULONGLONG Unknown;
	HANDLE ObHandle;
	PVOID ObTypeAddr;
	PVOID PreCall;
	PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

程式碼部分的實現很容易,由於程序與執行緒控制程式碼的列舉很容易,直接通過(POBJECT_TYPE)(*PsProcessType))->CallbackList就可以拿到連結串列頭結構,得到後將其解析為POB_CALLBACK並回圈輸出即可。

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>
#include <wdm.h>
#include <ntddk.h>

typedef struct _OBJECT_TYPE_INITIALIZER
{
	USHORT Length;                // Uint2B
	UCHAR ObjectTypeFlags;            // UChar
	ULONG ObjectTypeCode;             // Uint4B
	ULONG InvalidAttributes;          // Uint4B
	GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
	ULONG ValidAccessMask;       // Uint4B
	ULONG RetainAccess;         // Uint4B
	POOL_TYPE PoolType;        // _POOL_TYPE
	ULONG DefaultPagedPoolCharge;  // Uint4B
	ULONG DefaultNonPagedPoolCharge; // Uint4B
	PVOID DumpProcedure;       // Ptr64     void
	PVOID OpenProcedure;      // Ptr64     long
	PVOID CloseProcedure;     // Ptr64     void
	PVOID DeleteProcedure;        // Ptr64     void
	PVOID ParseProcedure;     // Ptr64     long
	PVOID SecurityProcedure;      // Ptr64     long
	PVOID QueryNameProcedure;     // Ptr64     long
	PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
	ULONG WaitObjectFlagMask;     // Uint4B
	USHORT WaitObjectFlagOffset;    // Uint2B
	USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
	LIST_ENTRY TypeList;           // _LIST_ENTRY
	UNICODE_STRING Name;         // _UNICODE_STRING
	PVOID DefaultObject;         // Ptr64 Void
	UCHAR Index;             // UChar
	ULONG TotalNumberOfObjects;      // Uint4B
	ULONG TotalNumberOfHandles;      // Uint4B
	ULONG HighWaterNumberOfObjects;    // Uint4B
	ULONG HighWaterNumberOfHandles;    // Uint4B
	OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
	EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
	ULONG Key;                 // Uint4B
	LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
	LIST_ENTRY ListEntry;
	ULONGLONG Unknown;
	HANDLE ObHandle;
	PVOID ObTypeAddr;
	PVOID PreCall;
	PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
	NTSTATUS status = STATUS_SUCCESS;

	DbgPrint("hello lyshark.com \n");

	POB_CALLBACK pObCallback = NULL;

	// 直接獲取 CallbackList 連結串列
	LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList;

	// 開始遍歷
	pObCallback = (POB_CALLBACK)CallbackList.Flink;
	do
	{
		if (FALSE == MmIsAddressValid(pObCallback))
		{
			break;
		}
		if (NULL != pObCallback->ObHandle)
		{
			// 顯示
			DbgPrint("[LyShark.com] ObHandle = %p | PreCall = %p | PostCall = %p \n", pObCallback->ObHandle, pObCallback->PreCall, pObCallback->PostCall);

		}
		// 獲取下一連結串列資訊
		pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink;

	} while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);
	return status;
}

執行這段驅動程式,即可得到程序控制程式碼回撥:

當然瞭如上是程序控制程式碼的列舉,如果是想要輸出執行緒控制程式碼,則只需要替換程式碼中的PsProcessType((POBJECT_TYPE)(*PsThreadType))->CallbackList即可,修改後的程式碼如下。

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>
#include <wdm.h>
#include <ntddk.h>

typedef struct _OBJECT_TYPE_INITIALIZER
{
	USHORT Length;                // Uint2B
	UCHAR ObjectTypeFlags;            // UChar
	ULONG ObjectTypeCode;             // Uint4B
	ULONG InvalidAttributes;          // Uint4B
	GENERIC_MAPPING GenericMapping;   // _GENERIC_MAPPING
	ULONG ValidAccessMask;       // Uint4B
	ULONG RetainAccess;         // Uint4B
	POOL_TYPE PoolType;        // _POOL_TYPE
	ULONG DefaultPagedPoolCharge;  // Uint4B
	ULONG DefaultNonPagedPoolCharge; // Uint4B
	PVOID DumpProcedure;       // Ptr64     void
	PVOID OpenProcedure;      // Ptr64     long
	PVOID CloseProcedure;     // Ptr64     void
	PVOID DeleteProcedure;        // Ptr64     void
	PVOID ParseProcedure;     // Ptr64     long
	PVOID SecurityProcedure;      // Ptr64     long
	PVOID QueryNameProcedure;     // Ptr64     long
	PVOID OkayToCloseProcedure;     // Ptr64     unsigned char
	ULONG WaitObjectFlagMask;     // Uint4B
	USHORT WaitObjectFlagOffset;    // Uint2B
	USHORT WaitObjectPointerOffset;   // Uint2B
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE
{
	LIST_ENTRY TypeList;           // _LIST_ENTRY
	UNICODE_STRING Name;         // _UNICODE_STRING
	PVOID DefaultObject;         // Ptr64 Void
	UCHAR Index;             // UChar
	ULONG TotalNumberOfObjects;      // Uint4B
	ULONG TotalNumberOfHandles;      // Uint4B
	ULONG HighWaterNumberOfObjects;    // Uint4B
	ULONG HighWaterNumberOfHandles;    // Uint4B
	OBJECT_TYPE_INITIALIZER TypeInfo;  // _OBJECT_TYPE_INITIALIZER
	EX_PUSH_LOCK TypeLock;         // _EX_PUSH_LOCK
	ULONG Key;                 // Uint4B
	LIST_ENTRY CallbackList;       // _LIST_ENTRY
}OBJECT_TYPE, *POBJECT_TYPE;

#pragma pack(1)
typedef struct _OB_CALLBACK
{
	LIST_ENTRY ListEntry;
	ULONGLONG Unknown;
	HANDLE ObHandle;
	PVOID ObTypeAddr;
	PVOID PreCall;
	PVOID PostCall;
}OB_CALLBACK, *POB_CALLBACK;
#pragma pack()

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
	NTSTATUS status = STATUS_SUCCESS;

	DbgPrint("hello lyshark.com \n");

	POB_CALLBACK pObCallback = NULL;

	// 直接獲取 CallbackList 連結串列
	LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsThreadType))->CallbackList;

	// 開始遍歷
	pObCallback = (POB_CALLBACK)CallbackList.Flink;
	do
	{
		if (FALSE == MmIsAddressValid(pObCallback))
		{
			break;
		}
		if (NULL != pObCallback->ObHandle)
		{
			// 顯示
			DbgPrint("[LyShark] ObHandle = %p | PreCall = %p | PostCall = %p \n", pObCallback->ObHandle, pObCallback->PreCall, pObCallback->PostCall);
		}
		// 獲取下一連結串列資訊
		pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink;

	} while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);

	return status;
}

執行這段驅動程式,即可得到執行緒控制程式碼回撥: