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

    枚举与删除线程回调

        进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了。某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出。而线程回调则通常用来监控远程线程的建立,如果发现有远程线程注入到了游戏进程里,则马上把游戏退出。现在来详细讲解如何绕过这个两个监控。

        我们注册的进程回调,会存储在一个名为 PspCreateProcessNotifyRoutine 的数组里。

    PspCreateProcessNotifyRoutine 可以理解成一个 PVOID 数组,它记录了系统里所有进程回调的地址。这个数组最大长度是 64*sizeof(PVOID)。所以枚举进程回调的思路如下:找到这个数组的地址,然后解密数组的数据,得到所有回调的地址(这个数组记录的数据并不是回调的 地 址 , 而 是 经 过 加 密 地 址 , 需 要 解 密 才 行 )。 枚 举 线 程 回 调 同 理 , 要 找 到PspCreateThreadNotifyRoutine 的地址(这个数组最大长度也是 64*sizeof(PVOID)),然后解密数据,并把解密后的地址打印出来。

        至于怎么处理这些回调就简单了。可以使用标准函数(PsSetCreateProcessNotifyRoutine、PsRemoveCreateThreadNotifyRoutine)将其摘掉,也可以直接在回调函数首地址写入 RET 把回调函数废掉。

        首先要获得 PspCreateProcessNotifyRoutine 的地址。PspCreateProcessNotifyRoutine 在PspSetCreateProcessNotifyRoutine 函数里出现了。而 PspSetCreateProcessNotifyRoutine 则在PsSetCreateProcessNotifyRoutine 中被调用(注意前一个是 PspXXX,后一个是 PsXXX)。找到PspSetCreateProcessNotifyRoutine 之后,再匹配特征码:

     

     

        于是我们根据特征码写出了以下代码(仅在 WIN7X64 上有效,WIN8、8.1 需要自己重新

    定义特征码):

    ULONG64 FindPspCreateProcessNotifyRoutine()
    {
    LONG	OffsetAddr=0;
    ULONG64	i=0,pCheckArea=0;
    UNICODE_STRING	unstrFunc;
    //获得PsSetCreateProcessNotifyRoutine的地址
    RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine");
    pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
    //获得PspSetCreateProcessNotifyRoutine的地址
    memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4);
    pCheckArea=(pCheckArea+3)+5+OffsetAddr;
    DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea);
    //获得PspCreateProcessNotifyRoutine的地址
    for(i=pCheckArea;i<pCheckArea+0xff;i++)
    {
    if(*(PUCHAR)i==0x4c && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x35)	//lea r14,xxxx
    {
    LONG OffsetAddr=0;
    memcpy(&OffsetAddr,(PUCHAR)(i+3),4);
    return OffsetAddr+7+i;
    }
    }
    return 0;
    }

        找到了 PspCreateProcessNotifyRoutine,枚举操作就好办了。需要说明的是,在PspCreateProcessNotifyRoutine 里的数据竟然被加密了,需要把数组的值和 0xfffffffffffffff8进行“与”位运算才行:

    找线程的同理:

    PspCreateThreadNotifyRoutine -> 

    PsSetCreateThreadNotifyRoutine ->

    PspCreateThreadNotifyRoutine

    执行结果如下(干净win7系统没有线程回调,特意注册了两个):

    void EnumCreateProcessNotify()
    {
    int i=0;
    BOOLEAN b;
    ULONG64	NotifyAddr=0,MagicPtr=0;
    ULONG64	PspCreateProcessNotifyRoutine=FindPspCreateProcessNotifyRoutine();
    DbgPrint("PspCreateProcessNotifyRoutine: %llx",PspCreateProcessNotifyRoutine);
    if(!PspCreateProcessNotifyRoutine)
    return;
    for(i=0;i<64;i++)
    {
    MagicPtr=PspCreateProcessNotifyRoutine+i*8;
    NotifyAddr=*(PULONG64)(MagicPtr);
    if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0)
    {
    NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8);
    DbgPrint("[CreateProcess]%llx",NotifyAddr);
    }
    }
    }


    代码整理: 进程

    ULONG64 FindPspCreateProcessNotifyRoutine()
    {
    LONG	OffsetAddr=0;
    ULONG64	i=0,pCheckArea=0;
    UNICODE_STRING	unstrFunc;
    //获得PsSetCreateProcessNotifyRoutine的地址
    RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine");
    pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
    //获得PspSetCreateProcessNotifyRoutine的地址
    memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4);
    pCheckArea=(pCheckArea+3)+5+OffsetAddr;
    DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea);
    //获得PspCreateProcessNotifyRoutine的地址
    for(i=pCheckArea;i<pCheckArea+0xff;i++)
    {
    if(*(PUCHAR)i==0x4c && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x35)	//lea r14,xxxx
    {
    LONG OffsetAddr=0;
    memcpy(&OffsetAddr,(PUCHAR)(i+3),4);
    return OffsetAddr+7+i;
    }
    }
    return 0;
    }
     
    void EnumCreateProcessNotify()
    {
    int i=0;
    BOOLEAN b;
    ULONG64	NotifyAddr=0,MagicPtr=0;
    ULONG64	PspCreateProcessNotifyRoutine=FindPspCreateProcessNotifyRoutine();
    DbgPrint("PspCreateProcessNotifyRoutine: %llx",PspCreateProcessNotifyRoutine);
    if(!PspCreateProcessNotifyRoutine)
    return;
    for(i=0;i<64;i++)
    {
    MagicPtr=PspCreateProcessNotifyRoutine+i*8;
    NotifyAddr=*(PULONG64)(MagicPtr);
    if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0)
    {
    NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8);
    DbgPrint("[CreateProcess]%llx",NotifyAddr);
    }
    }
    }


    线程(包括创建线程回调测试代码):

    void CreateThreadNotify1
    (
        IN HANDLE  ProcessId,
        IN HANDLE  ThreadId,
        IN BOOLEAN  Create
    )
    {
    DbgPrint("CreateThreadNotify1
    ");
    }
     
    void CreateThreadNotify2
    (
        IN HANDLE  ProcessId,
        IN HANDLE  ThreadId,
        IN BOOLEAN  Create
    )
    {
    DbgPrint("CreateThreadNotify2
    ");
    }
     
    void CreateThreadNotifyTest(BOOLEAN Remove)
    {
    if(!Remove)
    {
    PsSetCreateThreadNotifyRoutine(CreateThreadNotify1);
    PsSetCreateThreadNotifyRoutine(CreateThreadNotify2);
    }
    else
    {
    PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify1);
    PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify2);
    }
    }
     
    ULONG64 FindPspCreateThreadNotifyRoutine()
    {
    ULONG64	i=0,pCheckArea=0;
    UNICODE_STRING	unstrFunc;
    RtlInitUnicodeString(&unstrFunc, L"PsSetCreateThreadNotifyRoutine");
    pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
    DbgPrint("PsSetCreateThreadNotifyRoutine: %llx",pCheckArea);
    for(i=pCheckArea;i<pCheckArea+0xff;i++)
    {
    if(*(PUCHAR)i==0x48 && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x0d)	//lea rcx,xxxx
    {
    LONG OffsetAddr=0;
    memcpy(&OffsetAddr,(PUCHAR)(i+3),4);
    return OffsetAddr+7+i;
    }
    }
    return 0;
    }
     
    void EnumCreateThreadNotify()
    {
    int i=0;
    BOOLEAN b;
    ULONG64	NotifyAddr=0,MagicPtr=0;
    ULONG64	PspCreateThreadNotifyRoutine=FindPspCreateThreadNotifyRoutine();
    DbgPrint("PspCreateThreadNotifyRoutine: %llx",PspCreateThreadNotifyRoutine);
    if(!PspCreateThreadNotifyRoutine)
    return;
    for(i=0;i<64;i++)
    {
    MagicPtr=PspCreateThreadNotifyRoutine+i*8;
    NotifyAddr=*(PULONG64)(MagicPtr);
    if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0)
    {
    NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8);
    DbgPrint("[CreateThread]%llx",NotifyAddr);
     
    PsRemoveCreateThreadNotifyRoutine(NotifyAddr);
    }
    }
    }

    宋孖健,13

  • 相关阅读:
    Redis 集群方案
    Redis集群搭建
    Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS
    为什么分布式一定要有Redis?
    如何准备Java初级和高级的技术面试
    SpringBoot自动配置原理
    高德地图-- 云图管理台
    GeoJSON格式规范说明
    webGis概念
    npm压缩js文件
  • 原文地址:https://www.cnblogs.com/csnd/p/12061985.html
Copyright © 2011-2022 走看看