zoukankan      html  css  js  c++  java
  • Win64 驱动内核编程-32.枚举与删除注册表回调

    枚举与删除注册表回调

        注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果。部分游戏保护还会在注册表回调上做功夫,监控 service

    键的子键,实现双层拦截驱动加载(在映像回调那里还有一层)。而在卡巴斯基等 HIPS 类软件里,则用来监控自启动等键值。

        注册表回调在 XP 系统上貌似是一个数组,但是从 WINDOWS 2003 开始,就变成了一个链表。这个链表的头称为 CallbackListHead,可在 CmUnRegisterCallback 中找到:

        搜索的过程跟寻找进程、线程、映像的数组类似,根据 lea REG,XXX 来定位。不过为了更加精准,这次资料中是采用两次 lea REG,XXX 来定位:

    ULONG64 FindCmpCallbackAfterXP()
    {
    ULONG64	uiAddress=0;
    PUCHAR	pCheckArea=NULL, i=0, j=0, StartAddress=0, EndAddress=0;
    ULONG64	dwCheckAddr=0;
    UNICODE_STRING	unstrFunc;
    UCHAR b1=0,b2=0,b3=0;
    ULONG templong=0,QuadPart=0xfffff800;
    RtlInitUnicodeString(&unstrFunc, L"CmUnRegisterCallback");
    pCheckArea = (UCHAR*)MmGetSystemRoutineAddress (&unstrFunc) ;
    if (!pCheckArea)
    {
    KdPrint(("MmGetSystemRoutineAddress failed."));
    return 0;
    }
    StartAddress = (PUCHAR)pCheckArea;
    EndAddress = (PUCHAR)pCheckArea + PAGE_SIZE;
    for(i=StartAddress;i<EndAddress;i++)
    {
    if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) )
    {
    b1=*i;
    b2=*(i+1);
    b3=*(i+2);
    if( b1==0x48 && b2==0x8d && b3==0x0d ) //488d0d(lea rcx,)
    {
    j=i-5;
    b1=*j;
    b2=*(j+1);
    b3=*(j+2);
    if( b1==0x48 && b2==0x8d && b3==0x54 ) //488d54(lea rdx,)
    {
    memcpy(&templong,i+3,4);
    uiAddress = MakeLong64ByLong32(templong) + (ULONGLONG)i + 7;
    return uiAddress;
    }
    }
    }
    }
    return 0;
    }

        定位完毕之后,就是枚举链表了。注册表回调是一个“结构体链表”,类似于 EPROCESS,它的定义如下:

    typedef struct _CM_NOTIFY_ENTRY
    {
    LIST_ENTRY	ListEntryHead;
    ULONG	UnKnown1;
    ULONG	UnKnown2;
    LARGE_INTEGER	Cookie;
    ULONG64	Context; 
    ULONG64	Function;
    }CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;


        我们只关心两个值,一个是 Cookie,一个是 Function。前者可以理解成注册表回调的“句柄”(用 CmUnRegisterCallback 注销回调传入的就是这个 Cookie),后者是回调函数的地址。代码如下:

    ULONG CountCmpCallbackAfterXP(ULONG64* pPspLINotifyRoutine)
    {
    ULONG	sum = 0;
    ULONG64	dwNotifyItemAddr;
    ULONG64*	pNotifyFun;
    ULONG64*	baseNotifyAddr;
    ULONG64	dwNotifyFun;
    LARGE_INTEGER	cmpCookie;
    PLIST_ENTRY	notifyList;
    PCM_NOTIFY_ENTRY	notify;
    dwNotifyItemAddr = *pPspLINotifyRoutine;
    notifyList = (LIST_ENTRY *)dwNotifyItemAddr;
    do
    {
    notify = (CM_NOTIFY_ENTRY *)notifyList;
    if (MmIsAddressValid(notify))
    {
    if (MmIsAddressValid((PVOID)(notify->Function)) && notify->Function > 0x8000000000000000)
    {
    DbgPrint("[CmCallback]Function=%p	Cookie=%p", (PVOID)(notify->Function),(PVOID)(notify->Cookie.QuadPart));
    //notify->Function=(ULONG64)MyRegistryCallback;
    sum ++;
    }
    }
    notifyList = notifyList->Flink;
    }while ( notifyList != ((LIST_ENTRY*)(*pPspLINotifyRoutine)) );
    return sum;
    }


    执行效果(在有360的机器上执行的):

        

    对付注册表回调有三种方法:

    1.直接使用CmUnRegisterCallback 把回调注销;

    2.把链表中记录的回调地址修改为自定义的空函数的回调地址;

    3.直接在目标回调地址上写一个 RET,使其不执行任何代码就返回。 第三种 方法 没有针对性,可以用于对付 任何 回调函数。DisableFunctionWithReturnValue 用来对付有返回值的回调函数,DisableFunctionWithoutReturnValue 用于对付无返回值的回调函数。

    /*
    给函数头写RET废除函数功能,这份代码可以用于对抗任意回调函数,但仅限于WIN64系统。
    DisableFunctionWithReturnValue用于有返回值的回调
    DisableFunctionWithoutReturnValue用于无返回值的回调
    */
    
    KIRQL WPOFFx64()
    {
    KIRQL irql=KeRaiseIrqlToDpcLevel();
    UINT64 cr0=__readcr0();
    cr0 &= 0xfffffffffffeffff;
    __writecr0(cr0);
    _disable();
    return irql;
    }
     
    void WPONx64(KIRQL irql)
    {
    UINT64 cr0=__readcr0();
    cr0 |= 0x10000;
    _enable();
    __writecr0(cr0);
    KeLowerIrql(irql);
    }
     
    VOID DisableFunctionWithReturnValue(PVOID Address)
    {
    KIRQL irql;
    CHAR patchCode[] = "x33xC0xC3";	//xor eax,eax + ret
    if(MmIsAddressValid(Address))
    {
    irql=WPOFFx64();
    memcpy(Address,patchCode,3);
    WPONx64(irql);
    }
    }
     
    VOID DisableFunctionWithoutReturnValue(PVOID Address)
    {
    KIRQL irql;
    if(MmIsAddressValid(Address))
    {
    irql=WPOFFx64();
    RtlFillMemory(Address,1,0xC3);
    WPONx64(irql);
    }
    }

    代码备份:win7 X64

    typedef struct _CM_NOTIFY_ENTRY
    {
    LIST_ENTRY	ListEntryHead;
    ULONG	UnKnown1;
    ULONG	UnKnown2;
    LARGE_INTEGER	Cookie;
    ULONG64	Context; 
    ULONG64	Function;
    }CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;
     
    LARGE_INTEGER Cookie;
    ULONG64 CmCallbackListHead=0;
     
    NTSTATUS MyRegistryCallback(
        IN PVOID CallbackContext,
        IN PVOID Argument1,
        IN PVOID Argument2
        )
    {
    return STATUS_SUCCESS;
    }
     
    ULONG CountCmpCallbackAfterXP(ULONG64* pPspLINotifyRoutine)
    {
    ULONG	sum = 0;
    ULONG64	dwNotifyItemAddr;
    ULONG64*	pNotifyFun;
    ULONG64*	baseNotifyAddr;
    ULONG64	dwNotifyFun;
    LARGE_INTEGER	cmpCookie;
    PLIST_ENTRY	notifyList;
    PCM_NOTIFY_ENTRY	notify;
    dwNotifyItemAddr = *pPspLINotifyRoutine;
    notifyList = (LIST_ENTRY *)dwNotifyItemAddr;
    do
    {
    notify = (CM_NOTIFY_ENTRY *)notifyList;
    if (MmIsAddressValid(notify))
    {
    if (MmIsAddressValid((PVOID)(notify->Function)) && notify->Function > 0x8000000000000000)
    {
    DbgPrint("[CmCallback]Function=%p	Cookie=%p", (PVOID)(notify->Function),(PVOID)(notify->Cookie.QuadPart));
    //notify->Function=(ULONG64)MyRegistryCallback;
    sum ++;
    }
    }
    notifyList = notifyList->Flink;
    }while ( notifyList != ((LIST_ENTRY*)(*pPspLINotifyRoutine)) );
    return sum;
    }
     
    LONG64 MakeLong64ByLong32(LONG lng32)
    {
    LONG64 lng64=0;
    if(lng32>0)
    {
    lng64=(LONG64)lng32;
    }
    else
    {
    lng64=0xffffffffffffffff;
    memcpy(&lng64,&lng32,4);
    }
    return lng64;
    }
     
    ULONG64 FindCmpCallbackAfterXP()
    {
    ULONG64	uiAddress=0;
    PUCHAR	pCheckArea=NULL, i=0, j=0, StartAddress=0, EndAddress=0;
    ULONG64	dwCheckAddr=0;
    UNICODE_STRING	unstrFunc;
    UCHAR b1=0,b2=0,b3=0;
    ULONG templong=0,QuadPart=0xfffff800;
    RtlInitUnicodeString(&unstrFunc, L"CmUnRegisterCallback");
    pCheckArea = (UCHAR*)MmGetSystemRoutineAddress (&unstrFunc) ;
    if (!pCheckArea)
    {
    KdPrint(("MmGetSystemRoutineAddress failed."));
    return 0;
    }
    StartAddress = (PUCHAR)pCheckArea;
    EndAddress = (PUCHAR)pCheckArea + PAGE_SIZE;
    for(i=StartAddress;i<EndAddress;i++)
    {
    if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) )
    {
    b1=*i;
    b2=*(i+1);
    b3=*(i+2);
    if( b1==0x48 && b2==0x8d && b3==0x0d ) //488d0d(lea rcx,)
    {
    j=i-5;
    b1=*j;
    b2=*(j+1);
    b3=*(j+2);
    if( b1==0x48 && b2==0x8d && b3==0x54 ) //488d54(lea rdx,)
    {
    memcpy(&templong,i+3,4);
    uiAddress = MakeLong64ByLong32(templong) + (ULONGLONG)i + 7;
    return uiAddress;
    }
    }
    }
    }
    return 0;
    }
     
    void EnumCmCallback64()
    {
    //test to add my reg callback
    CmRegisterCallback(MyRegistryCallback, NULL, &Cookie);
    DbgPrint("[MY FUNCTION]: %p",(PVOID)MyRegistryCallback);
    DbgPrint("[MY COOKIE]: %p",(PVOID)Cookie.QuadPart);
    //get CmCallbackListHead address
    CmCallbackListHead=FindCmpCallbackAfterXP();
    DbgPrint("CmCallbackListHead: %p",(PVOID)CmCallbackListHead);
    //enum callback address
    CountCmpCallbackAfterXP((ULONG64*)CmCallbackListHead);
    //unregister my callback
    CmUnRegisterCallback(Cookie);
    }
     
    /*
    给函数头写RET废除函数功能,这份代码可以用于对抗任意回调函数,但仅限于WIN64系统。
    DisableFunctionWithReturnValue用于有返回值的回调
    DisableFunctionWithoutReturnValue用于无返回值的回调
    */
     
    KIRQL WPOFFx64()
    {
    KIRQL irql=KeRaiseIrqlToDpcLevel();
    UINT64 cr0=__readcr0();
    cr0 &= 0xfffffffffffeffff;
    __writecr0(cr0);
    _disable();
    return irql;
    }
     
    void WPONx64(KIRQL irql)
    {
    UINT64 cr0=__readcr0();
    cr0 |= 0x10000;
    _enable();
    __writecr0(cr0);
    KeLowerIrql(irql);
    }
     
    VOID DisableFunctionWithReturnValue(PVOID Address)
    {
    KIRQL irql;
    CHAR patchCode[] = "x33xC0xC3";	//xor eax,eax + ret
    if(MmIsAddressValid(Address))
    {
    irql=WPOFFx64();
    memcpy(Address,patchCode,3);
    WPONx64(irql);
    }
    }
     
    VOID DisableFunctionWithoutReturnValue(PVOID Address)
    {
    KIRQL irql;
    if(MmIsAddressValid(Address))
    {
    irql=WPOFFx64();
    RtlFillMemory(Address,1,0xC3);
    WPONx64(irql);
    }
    }
     
     

    宋孖健,13

  • 相关阅读:
    InterLockedIncrement and InterLockedDecrement
    bzoj2763
    bzoj1922
    bzoj1705
    bzoj1040
    bzoj3039
    bzoj1801
    bzoj2565
    bzoj1976
    一类最小割bzoj2127,bzoj2132 bzoj3438
  • 原文地址:https://www.cnblogs.com/csnd/p/12061980.html
Copyright © 2011-2022 走看看