枚举与删除线程回调

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

我们注册的进程回调,会存储在一个名为 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\n");
} void CreateThreadNotify2
(
IN HANDLE ProcessId,
IN HANDLE ThreadId,
IN BOOLEAN Create
)
{
DbgPrint("CreateThreadNotify2\n");
} 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

Win64 驱动内核编程-30.枚举与删除线程回调的更多相关文章

  1. Win64 驱动内核编程-33.枚举与删除对象回调

    转载:http://www.voidcn.com/article/p-wulgeluy-bao.html 枚举与删除对象回调 对象回调存储在对应对象结构体里,简单来说,就是存储在 ObjectType ...

  2. Win64 驱动内核编程-31.枚举与删除映像回调

    枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...

  3. Win64 驱动内核编程-32.枚举与删除注册表回调

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

  4. Win64 驱动内核编程-28.枚举消息钩子

    枚举消息钩子 简单粘贴点百度的解释,科普下消息钩子: 钩子是WINDOWS中消息处理机制的一个要点,通过安装各种钩子,应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之 ...

  5. Win64 驱动内核编程-3.内核里使用内存

    内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...

  6. Win64 驱动内核编程-8.内核里的其他常用

    内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...

  7. Win64 驱动内核编程-7.内核里操作进程

    在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...

  8. Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)

    驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...

  9. Win64 驱动内核编程-11.回调监控进线程句柄操作

    无HOOK监控进线程句柄操作 在 NT5 平台下,要监控进线程句柄的操作. 通常要挂钩三个API:NtOpenProcess.NtOpenThread.NtDuplicateObject.但是在 VI ...

随机推荐

  1. [实战]ASP.NET Padding Oracle信息泄露漏洞

    前言 这个漏洞是很多年前的了,刚好碰到网站有这个漏洞,利用一下也记录一下.具体原理请搜索学习,反正我不会. 推荐看这里,写得很清楚:http://www.91ri.org/6715.html 工具 p ...

  2. python内存管理&垃圾回收

    python内存管理&垃圾回收 引用计数器 环装双向列表refchain 在python程序中创建的任何对象都会放在refchain连表中 name = '张三' age = 18 hobby ...

  3. 2018.8.30 nowcoder oi赛制测试1

    2018.8.30 nowcoder oi赛制测试1 普及组难度,发现了一些问题 A 题目大意:求斐波那契数列\(f(k-1)f(k+1)-f(k)^2\),范围极大 打表可得规律 其实是卡西尼恒等式 ...

  4. 自己挖的坑自己填--Mybatis mapper文件if标签中number类型及String类型的坑

    1.现象描述 (1)使用 Mybatis 在进行数据更新时,大部分时候update语句都需要通过动态SQL进行拼接.在其中,if标签中经常会有 xxx !='' 这种判断,若 number 类型的字段 ...

  5. java 实现快速排序

    package leetcode;public class Singleton { public static void sort(int[] array,int low,int high){ int ...

  6. Sequelize 和 MySQL 对照Sequelize 和 MySQL 对照

    安装 这篇文章主要使用MySQL.Sequelize.co来进行介绍.安装非常简单: $ npm install --save co $ npm install --save sequelize $ ...

  7. get和post的区别主要有以下几方面

    1.url可见性: get,参数url可见: post,url参数不可见 2.数据传输上: get,通过拼接url进行传递参数: post,通过body体传输参数 3.缓存性: get请求是可以缓存的 ...

  8. 循环3n加1问题

    package 第二章; import java.util.Scanner; //int 32位整数 /*  * 猜想:对于任意大于一的自然数n,若n为奇数,则将n变为3n+1,否则变为n的一半 经过 ...

  9. PTA 中序输出度为1的结点

    6-9 中序输出度为1的结点 (10 分)   本题要求实现一个函数,按照中序遍历的顺序输出给定二叉树中度为1的结点. 函数接口定义: void InorderPrintNodes( BiTree T ...

  10. 在Ubuntu上安装TensorFlow-GPU开发环境

    深度学习是一个比较复杂的体系,今天记录一下开发环境的搭建步骤. 全新安装Ubuntu 20.10,系统默认安装的是python3,查看python的版本: mango@ubuntu:~$ python ...