x64内核HOOK技术之拦截进程.拦截线程.拦截模块

时间:2022-06-14 03:49:17

            x64内核HOOK技术之拦截进程.拦截线程.拦截模块

一丶为什么讲解HOOK技术.

在32系统下, 例如我们要HOOK SSDT表,那么直接讲CR0的内存保护属性去掉. 直接讲表的地址修改即可.

但是在64位系统下,不可以这样操作了.

第一是因为 SSDT表加密了.

第二是 SSDT表你就算解密了. 那么你的API的地址也会很远. SSDT表放不下4G以外的地址. 所以也不能放.

而现在.试想一下, 杀毒软件也要在内核中做点手脚. 如果不能HOOK了,它们该怎么发展那?

所以到了win7 (64位)系统下, 微软被玩怕了. 直接告诉你. 你想HOOK那个API,我帮你做. 你不用动手做. 而且我的还稳定.不会蓝屏.

所以x64下的HOOK都是很简单的

比如 xxx杀毒软件要监视进程的创建. 那么微软就说.我给你API调用,你提供回调. 当创建的时候我就通知你. 返回值也是你说了算.

这样我们就可以使用它的API了.  线程. 模块都是这样的.

二丶进程监控以及拦截HOOK

API:

  PsSetCreateProcessNotifyRoutineEx

函数原型

  

NTSTATUS
PsSetCreateProcessNotifyRoutineEx(
IN PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,    //你提供的回调函数地址.
IN BOOLEAN Remove                        //是否删除回调. 如果为False则是注册回调,如果为TRUE则是删除回调.
);

这个函数的作用就是 当进程创建的时候会通知你.

参数一回调函数原型

VOID
CreateProcessNotifyEx(
__inout PEPROCESS Process,                //进程的EPROCESS会提供给你.
__in HANDLE ProcessId,                  //进程ID会提供给你.
__in_opt PPS_CREATE_NOTIFY_INFO CreateInfo      //进程信息的额外信息会提供给你. 注意参数是可操作的.也就是说可能为NULL
);

进程额外信息结构体

typedef struct _PS_CREATE_NOTIFY_INFO {
__in SIZE_T Size;                    //大小.
union {
__in ULONG Flags;
struct {
__in ULONG FileOpenNameAvailable : ;
__in ULONG Reserved : ;
};
};
__in HANDLE ParentProcessId;            //父进程ID
__in CLIENT_ID CreatingThreadId;      
__inout struct _FILE_OBJECT *FileObject;     //文件对象
__in PCUNICODE_STRING ImageFileName;       //进程路径
__in_opt PCUNICODE_STRING CommandLine;      //命令行参数
__inout NTSTATUS CreationStatus;          //返回状态.
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;

我们如果对返回状态进行操作. 那么如果你返回值给失败,那么进程就不会创建. 也就实现了我们阻止进程的创建了.

内核 代码实际操作 阻止calc计算器的创建.

initHook函数代码.

void InstallHook()
{  
NTSTATUS status;                                  //定义NT状态                                                    
status = PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx, FALSE);//注册回调
if (NT_SUCCESS(status))                              //判断状态是否成功.
dprintf("[Hello] PsSetCreateProcessNotifyRoutineEx CreateProcessNotifyEx=%pOK\r\n", CreateProcessNotifyEx);
else
dprintf("[Hello] PsSetCreateProcessNotifyRoutineEx status=%d\r\n", status);
}

回调函数代码.

VOID CreateProcessNotifyEx( __inout PEPROCESS  Process,
__in HANDLE ProcessId,
__in_opt PPS_CREATE_NOTIFY_INFO CreateInfo)
{ UNICODE_STRING ustrCalc;                              //定义内核函数字符串
RtlInitUnicodeString(&ustrCalc, L"\\??\\C:\\Windows\\system32\\calc.exe");//初始化计算器名字. 注意,这个要带上符号连接.  
if (CreateInfo != NULL)                               //参数有可能为NULL
{
dprintf("[Hello] Create Porcess pid=%d ImageFileName=%wZ\r\n",
ProcessId,
CreateInfo->ImageFileName); if (RtlCompareUnicodeString(CreateInfo->ImageFileName, &ustrCalc, TRUE) == ) //比较字符串.如果成功
{
//阻止创建
CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; //标志给失败,则计算器不能运行.
}
}
else
dprintf("[Hello] Exit Porcess pid=%d\r\n", ProcessId);
}

回调卸载函数.

PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx, TRUE);        //卸载回调

代码图片:

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

其中UnInstallHook则是调用卸载回调的函数.

驱动入口点调用initHook即可.

拦截图片:

编译好我们的驱动.去x64加载. 打开计算机则会被拦截.

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

原理:

  如果想知道原理,那么就要看Wrk源码.而在Wrk中,并没有这个API,这个API是64位才有的.但是在32下有一个,有一个不带EX版本的.我们可以参考一下.

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

通过源码可以发现.是操作数组.且这个数组里面是我们填写的回调.操作系统会依次调用回调.

跟随数组查看.

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

跟随查看,发现是个定长数组.里面只有八项.但是在32位,没人会使用这个API.所以8项正好,但是在64位系统下,数组变为了64

也就是说.我们可以通过找到数组首地址,进行HOOK里面的回调.那么我们的就会执行.当然我们也可以自己注册.

三丶线程监控以及拦截HOOK

线程拦截和进程拦截相似.但是在64位下,微软提供的HOOK函数没有这么强大.

并没有带有EX的.

所以我们只能用原来的.

线程监控API

  监控:    PsSetCreateThreadNotifyRoutine

  取消监控:  PsRemoveCreateThreadNotifyRoutine

监控原型:

  

NTSTATUS
PsSetCreateThreadNotifyRoutine(
IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine  //回调函数地址.当线程创建完毕,但还没运行的时候会调用你的回调.
);

卸载函数原型:

  

NTSTATUS
PsRemoveCreateThreadNotifyRoutine(
IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine //回调地址,你刚才注册的回调会取消.
);

本质也是在数组里面注册函数地址.

这两个函数只能看.但是不能进行操作. 但是很多时候看看就已经可以了.

线程回调原型:

  

VOID
(*PCREATE_THREAD_NOTIFY_ROUTINE) (
IN HANDLE ProcessId,          //进程ID
IN HANDLE ThreadId,           //线程ID
IN BOOLEAN Create            
);

可以看到,线程HOOK后,信息很少,就一个进程ID,一个线程ID. 还有一个创建标志.没有什么了.现在我们要进行HOOK

HOOK思路:

  1.通过进程ID,找到EPROCESS 对象

  2.通过线程ID,找到ETHREAD   对象

  3.通过EPROCESS对象.获得进程路径.

  4.通过进程路径.找到对应进程名.

  5..判断进程名是否相同.

    相同: 通过ETHREAD + 偏移,找到线程回调函数的地址. 并修改回调地址的内容为ret.

    不相同:  不相同退出.

在上面HOOK思路中,第五不很重要.ETHREAD + 偏移. 那么找到是那个成员?

那么我们要熟悉ETHREAD中那个成员重要.

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

通过分析ETHREAD,可以得出,在偏移410的位置,存放这ring3下线程回调函数的地址. 那么我们可以操作这个偏移,使其里面变为ret,变相了拦截了线程的创建.

实战代码:

  initHook函数

void InstallHook()
{
NTSTATUS status;
status = PsSetCreateThreadNotifyRoutine(CreateThreadNotify);      //注册线程回调
if (NT_SUCCESS(status))
dprintf("[Hello] PsSetCreateThreadNotifyRoutine CreateThreadNotify=%p\r\n", CreateProcessNotifyEx);
else
dprintf("[Hello] PsSetCreateThreadNotifyRoutine status=%d\r\n", status);
}

  回调函数中的代码

VOID CreateThreadNotify(
IN HANDLE ProcessId,
IN HANDLE ThreadId,
IN BOOLEAN Create)
{
PEPROCESS Process = NULL;
PETHREAD Thread = NULL;
UCHAR *pszImageName = NULL;
NTSTATUS status;
UCHAR *pWin32Address = NULL; status = PsLookupProcessByProcessId(ProcessId, &Process);  //1.通过进程ID,获取EPROCESS
if (!NT_SUCCESS(status))
return; status = PsLookupThreadByThreadId(ThreadId, &Thread);    //2.通过线程ID,获取ETHREAD pszImageName = PsGetProcessImageFileName(Process);      //3.通过EPROCESS获取进程名 if (Create)
{
dprintf("[Hello] Create Thread pid=%d tid=%d ImageName=%s\r\n", ProcessId, ThreadId, pszImageName);
if (strstr(pszImageName, "calc") != NULL)          //4.判断进程名是否是计算器
{
//KdBreakPoint(); //修改回调函数代码
pWin32Address = *(UCHAR**)((UCHAR*)Thread + 0x410);   //5.是的话.找到回调函数地址.并改为C3
//KeAttachProcess();
if (MmIsAddressValid(pWin32Address))
{
KdBreakPoint();
//*pWin32Address = 0xC3;                 //修改为C3,但是注意,你修改的是否内存保护属性需要去掉.但是在64位下,不允许使用内联汇编了.不过你可以写二进制进行更改.或者汇编生成obj,驱动来使用
                               //这里直接手动更改为C3.
}
//KeUnstackDetachProcess();
}
}
else
dprintf("[Hello] Exit Thread pid=%d tid=%d\r\n", ProcessId, ThreadId); if( Process )
ObDereferenceObject (Process);              //引用计数--
if( Thread )
ObDereferenceObject (Thread); }

PS:

上面通过进程ID获取EPROCESS等等的API,都是微软未公开的.但是导出了. 我们只需要声明一下即可.但是既然是未公开那么就要看微软怎么使用.
微软使用之后,会对其引用计数--,所以我们也要这样做.

内存中都改为C3,则线程都不能创建了.

四丶模块拦截,以及阻止思路.

模块拦截以及HOOK也是和上面一样,提供回调即可.

但莫模块是给的ImageBae,也就是模块基址. 所以我们只需要解析PE找到OEP,把OEP代码改成ret即可.

API:

监控:

  PsSetLoadImageNotifyRoutine

取消监控:

  PsRemoveLoadImageNotifyRoutine

函数原型:

  

NTSTATUS
PsSetLoadImageNotifyRoutine(
IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
);

回调函数原型:

  

VOID
(*PLOAD_IMAGE_NOTIFY_ROUTINE) (
IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId, // where image is mapped
IN PIMAGE_INFO ImageInfo
);

x64内核HOOK技术之拦截进程.拦截线程.拦截模块的更多相关文章

  1. Windows内核基础知识-8-监听进程、线程和模块

    Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...

  2. Hook技术--Activity的启动过程的拦截

    1.寻找Hook点的原则 Android中主要是依靠分析系统源码类来做到的,首先我们得找到被Hook的对象,我称之为Hook点:什么样的对象比较好Hook呢?自然是容易找到的对象.什么样的对象容易找到 ...

  3. pg3 bypass源码阅读 —— 学习x64内核hook跳板技术

    如之前描述的 pg3复杂了许多 先来看看都要hook哪些点 1.hook dpc和定时器分发器,防止seh路线触发pg KiTimerListExpire,KiRetireDpcList 看一下hoo ...

  4. 三种进程和线程数据共享模块方法Queue》Pipe》manager

    >>>>线程中的queue import threading import queue def f(qq): print("in child",qq.qsi ...

  5. 采用个hook技术对writefile函数进行拦截(2)

    http://www.cnblogs.com/zhxfl/archive/2011/11/03/2233846.html 这个是笔者之前写过的WriteFile HOOK代码 必须补充对这几个函数的H ...

  6. 【Hook技术】实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展

    [Hook技术]实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展 公司有个监控程序涉及到进程的保护问题,需要避免用户通过任务管理器结束掉监控进程,这里使用 ...

  7. HOOK技术之SSDT hook(x86/x64)

    x86 SSDT Hook 32位下进行SSDT Hook比较简单,通过修改SSDT表中需要hook的系统服务为自己的函数,在自己的函数中进行过滤判断达到hook的目的. 获取KeServiceDes ...

  8. HOOK技术的一些简单总结

    好久没写博客了, 一个月一篇还是要尽量保证,今天谈下Hook技术. 在Window平台上开发任何稍微底层一点的东西,基本上都是Hook满天飞, 普通应用程序如此,安全软件更是如此, 这里简单记录一些常 ...

  9. 64位下Hook NtOpenProcess的实现进程保护 + 源码 (升级篇 )

    64位下Hook NtOpenProcess的实现进程保护 + 源码 (升级篇 ) [PS: 如果在64位系统下,出现调用测试demo,返回false的情况下,请修改Hook Dll的代码] glhH ...

随机推荐

  1. (五)什么是RDD-Java&Python版Spark

    什么是RDD 视频教程: 1.优酷 2.YouTube RDD是个抽象类,全称为Resilient Distributed Datasets,是一个容错的.并行的数据结构,可以让用户显式地将数据存储到 ...

  2. 02 Hibernate错题分析

    解析:使用final修饰的成员变量是常量 解析:不存在StateMoreSession的对象 解析:一个PreparedStatement 可以执行多次executQuery方法 解析:A   使用H ...

  3. Solved Unable to copy the source file ./installer/services.sh to the destination file /etc/vmware-t

    Sometimes when you intall vmwaretools there will be some problems such as "Unable to copy the s ...

  4. 从零开始学Linux[一]:基本命令:系统信息、目录、文件、文件编辑

    摘要:linux基础学习:系统信息.目录.文件查找.文件操作.查看文件内容及大小.软链接.VIM使用. 现在Linux的使用非常普遍.对于一个小白来说,满屏幕的字母,看起来就是一头雾水~   目前由于 ...

  5. 利用Winscp,Putty实现Windows下编写Linux程序

    本文讲的方案实现以下功能:利用winscp和putty的脚本功能,实现在Window平台上编写代码,上传到Linux进行编译,然后取编译结果.需要用到3个文件,分别如下: (1) synchroniz ...

  6. Servlet的学习之Cookie

    从本篇开始学习Servlet技术中的Cookie专题. 首先来了解什么是“会话”.会话是web技术中的一个术语,可以简单的理解为:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭 ...

  7. HBase篇(3)-架构详解

    [每日五分钟搞定大数据]系列,HBase第三篇 聊完场景和数据模型我们来说下HBase的架构,在网上找了张比较清晰的图,我觉得这张图能说明很多问题,那这一篇我们就重点来解析下这张图 角色与职责 先介绍 ...

  8. http 请求 post get 长度限制

    一.问题起因在某项目释放后Bug统计的附件<释放后问题>里有:   问题  原因  分析  备注  CSV处理时,如果处理的主题数过多,发生URL参数上限的错误:  可变长度的参数通过UR ...

  9. Net Web Api Route

    Asp.Net Web Api Route   在目前的主流架构中,我们越来越多的看到web Api的存在,小巧,灵活,基于Http协议,使它在越来越多的微服务项目或者移动项目充当很好的service ...

  10. Openwrt VLAN Configure(2)

    1      Scope of Document This document describes vlan design on nodewrt2p 2      Requiremen 2.1     ...