<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    通過ObRegisterCallbacks學習對象監控與反對象監控

    VSole2021-11-23 16:23:57

    簡介

    實現環境:WIN7 X86。

    要實現的目標:對進程對象和線程對象實現監控來保護目標進程不被任務管理器關掉。

    對象監控

    在Windows中可以通過ObRegisterCallbacks來設置對象監控,該函數的定義如下:

    NTSTATUS   ObRegisterCallbacks(    IN POB_CALLBACK_REGISTRATION  CallBackRegistration,    OUT PVOID  *RegistrationHandle);
    

    OB_CALLBACK_REGISTRATION結構體的定義如下:

    typedef struct _OB_CALLBACK_REGISTRATION {  __in USHORT  Version;  __in USHORT  OperationRegistrationCount;  __in UNICODE_STRING  Altitude;  __in PVOID  RegistrationContext;  __in OB_OPERATION_REGISTRATION  *OperationRegistration;} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
    

    OB_OPERATION_REGISTRATION結構體定義如下:

    typedef struct _OB_OPERATION_REGISTRATION {  __in POBJECT_TYPE  *ObjectType;  __in OB_OPERATION  Operations;  __in POB_PRE_OPERATION_CALLBACK  PreOperation;  __in POB_POST_OPERATION_CALLBACK  PostOperation;} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
    

    ObjectPreCallback和ObjectPostCallback的定義如下,它們的參數是一樣的,只是返回值不同。

    OB_PREOP_CALLBACK_STATUS   ObjectPreCallback(    __in PVOID  RegistrationContext,    __in POB_PRE_OPERATION_INFORMATION  OperationInformation);
    VOID   ObjectPostCallback(    __in PVOID  RegistrationContext,    __in POB_POST_OPERATION_INFORMATION  OperationInformation );
    

    最后在介紹一個函數,它可以根據線程對象獲得進程對象。該函數的定義如下:

    PEPROCESS  IoThreadToProcess(    IN PETHREAD  Thread);
    

    根據以上內容就可以實現對進程的保護,具體代碼如下:

    #include 
    #define PROCESS_NAME "demo.exe"   // 要保護的進程名#define PROCESS_TERMINATE 0x0001
    typedef struct _KLDR_DATA_TABLE_ENTRY{    LIST_ENTRY InLoadOrderModuleList;    LIST_ENTRY InMemoryOrderModuleList;    LIST_ENTRY InInitializationOrderModuleList;    PVOID DllBase;    PVOID EntryPoint;    UINT32 SizeOfImage;    UNICODE_STRING FullDllName;    UNICODE_STRING BaseDllName;    UINT32 Flags;    USHORT LoadCount;    USHORT TlsIndex;    LIST_ENTRY HashLinks;    PVOID SectionPointer;    UINT32 CheckSum;    UINT32 TimeDateStamp;    PVOID LoadedImports;    PVOID EntryPointActivationContext;    PVOID PatchInformation;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
    // 未導出函數聲明PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);VOID DriverUnload(IN PDRIVER_OBJECT driverObject);BOOLEAN IsProtectProcess(PEPROCESS pEProcess);     // 判斷是否是要保護的進程NTSTATUS SetProcessCallback(); // 設置進程回調函數NTSTATUS SetThreadCallback();  // 設置線程回調函數OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo);   // 進程回調函數OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo);   // 線程回調函數
    // 進程回調對象句柄HANDLE g_obProcessHandle;// 線程回調對象句柄HANDLE g_obThreadHandle;
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){    NTSTATUS status = STATUS_SUCCESS;    PKLDR_DATA_TABLE_ENTRY pLdrData = NULL;
        DbgPrint("驅動加載完成\r");    pLdrData = (PKLDR_DATA_TABLE_ENTRY)driverObject->DriverSection;    pLdrData->Flags = pLdrData->Flags | 0x20;
        if (NT_SUCCESS(SetProcessCallback()))    {        DbgPrint("進程回調函數設置完成\r");    }
        if (NT_SUCCESS(SetThreadCallback()))    {        DbgPrint("線程回調函數設置完成\r");    }exit:    driverObject->DriverUnload = DriverUnload;    return STATUS_SUCCESS;}
    NTSTATUS SetProcessCallback(){    NTSTATUS status = STATUS_SUCCESS;    OB_CALLBACK_REGISTRATION obCallbackReg = { 0 };    OB_OPERATION_REGISTRATION obOperationReg = { 0 };
        RtlZeroMemory(&obCallbackReg, sizeof(obCallbackReg));    RtlZeroMemory(&obOperationReg, sizeof(obOperationReg));
        //設置OB_OPERATION_REGISTRATION    obOperationReg.ObjectType = PsProcessType;    obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;    obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ProcessPreCall);
        //設置OB_CALLBACK_REGISTRATION    obCallbackReg.Version = ObGetFilterVersion();    obCallbackReg.OperationRegistrationCount = 1;    obCallbackReg.RegistrationContext = NULL;    RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900");    obCallbackReg.OperationRegistration = &obOperationReg;
        status = ObRegisterCallbacks(&obCallbackReg, &g_obProcessHandle);    if (!NT_SUCCESS(status))    {        DbgPrint("ObRegisterCallbacks Error 0x%X\r", status);    }
        return status;}
    OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){    PEPROCESS pEProcess = NULL;
        // 判斷對象類型    if (*PsProcessType != pObPreOperationInfo->ObjectType)    {        goto exit;    }
        // 獲取進程結構體對象    pEProcess = (PEPROCESS)pObPreOperationInfo->Object;    if (IsProtectProcess(pEProcess))   // 是否是要保護的進程    {        // 判斷操作類型是創建句柄還是復制句柄        if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE)        {            //是否具有關閉進程的權限,有的話刪掉它            if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE)            {                pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;            }        }        else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE)        {            //是否具有關閉進程的權限,有的話刪掉它            if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE)            {                pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;            }        }    }exit:    return OB_PREOP_SUCCESS;}
    NTSTATUS SetThreadCallback(){    NTSTATUS status = STATUS_SUCCESS;    OB_CALLBACK_REGISTRATION obCallbackReg = { 0 };    OB_OPERATION_REGISTRATION obOperationReg = { 0 };
        RtlZeroMemory(&obCallbackReg, sizeof(OB_CALLBACK_REGISTRATION));    RtlZeroMemory(&obOperationReg, sizeof(OB_OPERATION_REGISTRATION));
        // 設置 OB_OPERATION_REGISTRATION    obOperationReg.ObjectType = PsThreadType;                                       obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;    obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ThreadPreCall); 
        // 設置 OB_CALLBACK_REGISTRATION    obCallbackReg.Version = ObGetFilterVersion();    obCallbackReg.OperationRegistrationCount = 1;    obCallbackReg.RegistrationContext = NULL;    RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900");    obCallbackReg.OperationRegistration = &obOperationReg;
        // 注冊回調函數    status = ObRegisterCallbacks(&obCallbackReg, &g_obThreadHandle);    if (!NT_SUCCESS(status))    {        DbgPrint("ObRegisterCallbacks Error[0x%X]", status);        return status;    }
        return status;}
    // 線程回調函數OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){    PEPROCESS pEProcess = NULL;
        // 判斷對象類型    if (*PsThreadType != pObPreOperationInfo->ObjectType)    {        return OB_PREOP_SUCCESS;    }    // 獲取線程對應的進程 PEPROCESS    pEProcess = IoThreadToProcess((PETHREAD)pObPreOperationInfo->Object);    // 判斷是否是要保護的進程, 若是, 則拒絕結束線程    if (IsProtectProcess(pEProcess))    {        // 判斷操作類型是創建句柄還是復制句柄        if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE)        {            //是否具有關閉線程的權限,有的話刪掉它            if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE)            {                pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;            }        }        else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE)        {            //是否具有關閉線程的權限,有的話刪掉它            if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE)            {                pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;            }        }    }
        return OB_PREOP_SUCCESS;}
    BOOLEAN IsProtectProcess(PEPROCESS pEProcess){    BOOLEAN bRet = FALSE;    PUCHAR pProcName = PsGetProcessImageFileName(pEProcess); // 獲取要保護的進程名
        if (pProcName)    {        if (strcmp(pProcName, PROCESS_NAME) == 0)        {            bRet = TRUE;        }    }
        return bRet;}
    VOID DriverUnload(IN PDRIVER_OBJECT driverObject){    // 刪除進程回調    if (g_obProcessHandle)    {        ObUnRegisterCallbacks(g_obProcessHandle);        g_obProcessHandle = NULL;    }
        // 卸載線程回調    if (NULL != g_obThreadHandle)    {        ObUnRegisterCallbacks(g_obThreadHandle);        g_obThreadHandle = NULL;    }
        DbgPrint("驅動卸載完成\r");}
    

    反對象監控

    系統設置的對象回調函數會存儲在一個名頭CallbackList表頭的雙向鏈表里,它存儲著系統上所有ObRegisterCallbacks對象回調地址,包括操作前和操作后的回調函數地址以及對象回調句柄信息。CallbackList雙向鏈表的結構定義如下:

    #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()
    

    如果想要獲取進程回調的雙向鏈表信息,可以從*PsProcessType中獲取。要獲得線程回調的雙向鏈表信息,可以從*PsThreadType中獲取。

    *PsProcessType和*PsThreadType的數據結構類型為POBJECT_TYPE,定義如下:

    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;
    

    最后一個成員CallbackList就是雙向鏈表表頭。

    而倒數第四個成員的類型為OBJECT_TYPE_INITIALIZER,它的定義如下:

    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#if (NTDDI_VERSION >= NTDDI_WINBLUE)    // Win8.1    ULONG WaitObjectFlagMask;          // Uint4B    USHORT WaitObjectFlagOffset;       // Uint2B    USHORT WaitObjectPointerOffset;        // Uint2B#endif}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
    

    所以可以從*PsProcessType和*PsThreadType中獲得鏈表頭,然后遍歷鏈表找到對應的句柄對象在調用ObUnRegisterCallbacks將回調刪除,具體代碼如下:

    #include #include  #pragma pack(1)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#if (NTDDI_VERSION >= NTDDI_WINBLUE)    // Win8.1    ULONG WaitObjectFlagMask;          // Uint4B    USHORT WaitObjectFlagOffset;       // Uint2B    USHORT WaitObjectPointerOffset;        // Uint2B#endif}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;  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(IN PDRIVER_OBJECT driverObject);BOOLEAN RemoveProcessObCallback();BOOLEAN RemoveThreadObCallback(); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){    NTSTATUS status = STATUS_SUCCESS;     if (RemoveProcessObCallback())    {        DbgPrint("刪除進程回調成功\r");    }    else    {        DbgPrint("刪除進程回調失敗\r");    }     if (RemoveThreadObCallback())    {        DbgPrint("刪除線程回調成功\r");    }    else    {        DbgPrint("刪除線程回調失敗\r");    }exit:    driverObject->DriverUnload = DriverUnload;    return STATUS_SUCCESS;} BOOLEAN RemoveThreadObCallback(){    BOOLEAN bRet = TRUE;    LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 獲取線程表頭    POB_CALLBACK pObCallback = NULL;     pObCallback = (POB_CALLBACK)CallbackList.Flink;    do{        if (!MmIsAddressValid(pObCallback))        {            bRet = FALSE;            break;        }         if (pObCallback->ObHandle)        {            ObUnRegisterCallbacks(pObCallback->ObHandle);            DbgPrint("刪除回調函數成功,函數地址:0x%X\r", pObCallback->PreCall);        }    } while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);     return bRet;} BOOLEAN RemoveProcessObCallback(){    BOOLEAN bRet = TRUE;    POB_CALLBACK pObCallback = NULL;    LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 獲取設置進程對象回調函數的雙向鏈表表頭     pObCallback = (POB_CALLBACK)CallbackList.Flink;    do{        if (!MmIsAddressValid(pObCallback))        {            bRet = FALSE;            break;        }         if (pObCallback->ObHandle)        {            ObUnRegisterCallbacks(pObCallback->ObHandle);            DbgPrint("刪除回調成功,函數地址為:0x%X\r", pObCallback->PreCall);        }        pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink;    }while (CallbackList.Flink != (PLIST_ENTRY)pObCallback);     return bRet;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){    DbgPrint("驅動卸載完成\r");}
    

    運行結果

    設置回調以后想要關閉進程就會失敗:

    將回調刪除以后就可以正常關閉進程:

    list_entry回調函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    x32TLS回調函數實驗
    2023-05-31 09:34:55
    TLS回調函數介紹TLS回調函數是在程序運行時由操作系統自動調用的一組函數,用于在進程加載和卸載時執行一些初始化和清理操作。在TLS回調函數中,可以訪問當前線程的TLS數據,并對其進行修改或檢查。值得一提的是TLS回調可以用來反調試,原理實為在實際的入口點代碼執行之前執行檢測調試器代碼。為了棧平衡,我們要把傳進這個回調函數的參數所占用的
    TP-LINK 型號為 TL-WR841N V10 的路由器設備上的漏洞被分配 ID CVE-2020-8423。該漏洞允許經過身份驗證的攻擊者通過向 wifi 網絡配置發送 GET 請求來遠程執行設備上的任意代碼。
    CobaltStrike ShellCode詳解
    2022-08-04 16:51:50
    接下來就是重點了,加載起來的這段shellcode開頭先將DF標志位置0,這里為什么這樣做后面會提到。
    簡介實現環境:WIN7 X86。ObjectPreCallback和ObjectPostCallback的定義如下,它們的參數是一樣的,只是返回值不同。最后在介紹一個函數,它可以根據線程對象獲得進程對象。
    Windows內核-句柄
    2022-04-16 16:06:49
    進程的地址空間分為系統空間和用戶空間,內核對象都保存在系統空間中,用戶空間不能通過地址作為指針來引用它們,Windows使用句柄(handle)來對內核對象進行引用。看起來很小,但是涉及的內容很多。
    簡介實驗環境是Win7 X86系統。曾經在這篇文章中常見的幾種DLL注入技術說過,通過修改注冊表的內容可以實現AppInit_DLLs注入。那么本文的實驗是通過CmRegisterCallback來實現對注冊表修改的監控以此來阻止修改。并通過對CmRegisterCallback的逆向分析來實現對監控函數的刪除。
    shellcode loader的編寫
    2023-04-17 11:15:39
    改變加載方式指針執行#include?參數1:分配的內存的起始地址,如果為NULL則由系統決定。參數2:分配的內存大小,以字節為單位。參數3:分配的內存類型,MEM_COMMIT表示將分配的內存立即提交給物理內存,MEM_RESERVE表示保留內存但不提交。參數4:分配的內存保護屬性,PAGE_READWRITE可讀可寫,PAGE_EXECUTE_READ可執行可讀。結構體的指針,用于指定新線程的安全屬性,NULL表示默認安全屬性
    本系列將以官網資料為基礎主要通過動態跟蹤來解析DynamoRIO的源代碼。因為如果不結合實例只是將各函數的作用寫出來,實在無法很好的說明問題,我們將以代碼覆蓋工具drcov為例,分析DynamoRIO的執行流程。
    linux跟蹤技術之ebpf
    2022-12-30 10:51:15
    eBPF是一項革命性的技術,起源于 Linux 內核,可以在操作系統內核等特權上下文中運行沙盒程序。它可以安全有效地擴展內核的功能,而無需更改內核源代碼或加載內核模塊。比如,使用ebpf可以追蹤任何內核導出函數的參數,返回值,以實現kernel hook 的效果;通過ebpf,還可以在網絡封包到達內核協議棧之前就進行處理,這可以實現流量控制,甚至隱蔽通信。
    BEServer - BattlEye服務器,收集上傳的信息,并判定作弊行為。本次分析的是BEDaisy,也就是BE內核驅動中的各種檢測。上傳的內容主要是一些黑名單特征,這些特征應該是從服務器下發的,因此可以在不重新編譯驅動的情況下,動態調整檢測的特征。沒有給定偏移量的特征,BE在檢測時會按子串匹配的方式嘗試所有位置進行匹配。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类