SSDTHook
SSDT Hook底层原理介绍以及如何实现进程保护 - 知乎 本文为转载文章,点击标题跳转至原文。如转载有侵权行为,请告知删除。
SSDT Hook效果图加载驱动并成功Hook NtTerminateProcess函数:
当对 指定的进程进行保护后,尝试使用“任务管理器”结束进程的时候,会弹出“拒绝访问”的窗口,说明,我们的目的已经达到:
SSDT简介SSDT 的全称是 System Services Descriptor Table,系统服务描述符表。
这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来。
SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
通过修改此表的函数地址可以对常用 Windows 函数及 API 进行 Hook,从而实现对一些关心的系统动作进行过滤、监控的目的。
一些 HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块。
SSDT结构SSDT即系统服务描述符表,它的结构如下(参考《Undocument Windows ...
使用IO控制码进行通信
使用IO控制码进行驱动间通信
驱动对象用DRIVER_OBJECT数据结构表示,它作为驱动的一个实例被内核加载,并且内核对一个驱动只加 载一个实例。确切地说,是由内核中的I/O管理器负责加载的。
每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构表示。每个设备对象都会有一个指 针指向下一个设备对象,因此就形成一个设备链。设备链的第一个设备是由上一节介绍的DRIVER_OBJECT 结构体中指明的。设备对象保存设备特征和状态的信息。
DriverA(Server)定义IO控制码1234567#define IOCTRL_BASE 0x800 // 定义了IO控制码的基础值,确保IO控制码唯一#define IOCTRL_CODE1(i)\ CTL_CODE(FILE_DEVICE_UNKNOWN,IOCTRL_BASE+i,METHOD_IN_DIRECT,FILE_ANY_ACCESS)#define IOCTRL_CODE2(i)\ CTL_CODE(FILE_DEVICE_UNKNOWN,IOCTRL_BASE+i,METHOD_O ...
为什么在ASLR机制下DLL文件在不同进程中的加载基址相同?
为什么在ASLR机制下DLL文件在不同进程中的加载基址相同?本篇文章为转载内容,单击标题进入原作者地址。若转载行为有侵权,请联系删除。
1. DLL 注入实现以下是实现 DLL注入的简要步骤:
1.1 打开 Visual Studio,并创建一个新的 DLL 项目。
1.2 在”dllmain.cpp” 添加以下的代码
12345678910111213141516171819202122232425 1 // dllmain.cpp : 定义 DLL 应用程序的入口点。 2 #include "pch.h" 3 4 BOOL APIENTRY DllMain( HMODULE hModule, 5 DWORD ul_reason_for_call, 6 LPVOID lpReserved 7 ) 8 { 9 switch (ul_reason_for_call)10 {11 case ...
线程池
线程池处理大量的数据
线程池是可用于执行任务的线程的集合。这是一种管理和重用线程的方法,可以减少创建和销毁线程的开销。
在线程池中,会创建和维护固定数量的线程。当任务提交到线程池时,将分配一个可用线程来执行该任务。一旦任务完成,线程就会返回到池中,并可用于执行另一个任务。
线程池通常用于需要同时执行多个任务的应用程序。它们可以通过减少创建和销毁线程的开销,以及允许并行执行任务来提高性能。ThreadPoolExecutor类用于创建和管理线程池,submit方法用于将任务提交到池中执行。以下是如何使用ThreadPoolExecutor类创建线程池的示例:
12345678from concurrent.futures import ThreadPoolExecutor# Create a thread pool with 4 threadswith ThreadPoolExecutor(max_workers=4) as executor: # Submit a task to the pool future = executor.submit(my_function, ...
VT-x
虚拟化目录(点击跳转)
[TOC]
检查硬件虚拟化12345678BOOLEAN HvmIsHVSupported(){ CPU_VENDOR vendor = UtilCPUVendor();// CPU供应商 if (vendor == CPU_Intel) return VmxHardSupported(); return TRUE;}
UtilCPUVendor获取CPU制造商信息1234567891011121314151617181920/// <summary>/// Get CPU vendor/// </summary>/// <returns>Intel or AMD. If failed - Other</returns>CPU_VENDOR UtilCPUVendor(){ CPUID data = { 0 }; char vendor[0x20] = { 0 }; __cpuid( ( ...
TLS
TLS线程局部存储,TLS
如何使用TLS
有静态方法和动态方法
静态方法 把全局变量数据类型前添加 __declspec(thread) 关键字,同一变量在不同的线程中各自使用自己的那一份,不同的线程间不会互相影响
使用这种方法,生成的PE文件在节头中会有.tls头
动态方法 存放索引 使用一个普通的全局变量,在创建线程前创建一个独立的索引 __ v2=TlsAlloc(),根据索引设置数组的值 TlsSetValue( __ v2, 0) ,使用时使用a = TlsGetValue(__ v2)获取
理论上没有.tls头出现,但是测试失败
TLS回调
调用约定为NTAPI,即_stdcall
只要有线程启动或销毁会自动调用线程回调,比EP进程初始化还要早(比主函数启动还早),许多逆向分析人员把这个特性用于反调试
TLS目录使用内存映射的方法进行分析 相当于系统自动申请内存,不用自己手动申请内存。获取内存映射句柄,使用MapViewOfFile获取虚拟地址位置
都是文件粒度对齐
对大文件操作效率更高
将内存粒度转换为文件粒度
DumpTlsDir ...
Hook计算器以显示中文数字
计算器显示中文数字HookLet注入DLL.dll到计算器程序
找到导入表描述,在FirstThunk中把user32.dll文件中导出函数地址改为自己的DLL.dll导出函数的地址
计算器点击数字调用的函数为SetWindowText
注入方式有两种,CreateRemoteThread远程线程,SetWindowHookEx全局钩子
提权,开启UAC 管理员身份运行
可以在项目右键属性,链接器,清单文件,打开UAC运行级别即可
这里使用远程线程注入,填写动态库的完整路径申请内存,在对方进程中开启新的线程,得到LoadLibrary地址,执行LoadLibrary加载自己的动态库
得到自己动态库的完整路径
得到PID
申请虚拟内存
将路径写入虚拟内存
启动线程
从目标进程中的user32模块导出表中获取SetWindowText函数地址
获得进程中第一个模块Taskmgr.exe地址
定位到导入表描述
该模块是加载状态的,因此定位到FirstThunk,里面已经变为真正的函数地址,判断是否为空
定位到模块名
比较得到与我们要感染的模块相同,此时ImageImportDescript ...
PE文件格式
PE此文章为自查文章,部分内容没有详细解释。具体概念出自李承远《逆向工程核心原理》。
.exe .dll .sys
PE或PE+,注意没有PE64
C:\Windows\system32\notepad.exe //32位
C:\Windows\syswow64\notepad.exe //64位
PE文件的标志
PE格式文件加载到内存中的情形
DOS头 windows.h中有定义 _IMAGE_DOS_HEADE
NULL区域是未使用的区域用0填充的,补齐文件或内存粒度对齐
重点关注0x00 word e_magic=0x5a4d 对应MZ, 和dword(long)0x3c e_ifanew, (PIMAGE_NT_HEADERS)(BYTE)ImageDosHeader+(ImagerDosHeader->e_ifanew)就是NT_Headers的地址*
64位下的地址为8字节,32位为4字节,如果文件是64位,则4字节定位的地址必为RVA
32、64位的最大区别是NT_HEADERS后面是否跟数字64
NtHea ...
四种获取目标进程导入DLL模块地址的方法
四种获取目标进程导入DLL模块地址的方法本人在校大学生一枚,技术不太行,各位师傅将就看看。
1. 获取进程快照tlhelp32.h头文件中,提供了CreateToolhelp32SnapshotAPI,可以获取获取指定进程以及这些进程使用的堆、模块和线程的快照。
1234HANDLE CreateToolhelp32Snapshot( [in] DWORD dwFlags, [in] DWORD th32ProcessID);
在进程快照信息中,包含着进程导入模块的信息。因此,我们可以有如下实现思路:
调用CreateToolhelp32Snapshot指定TH32CS_SNAPPROCESS属性,获取进程快照句柄。
使用Process32Next遍历进程信息,对比进程名查找到目标进程。
使用OpenProcess验证目标进程状态。
调用CreateToolhelp32Snapshot指定TH32CS_SNAPMODULE属性,获取目标进程的模块快照。
使用Module32Next遍历模块,直到获取到目标模块信息,返回目标模块的句柄。
后续干什么都可以了,例如使用GetPro ...
目标进程用户模式句柄转换为内核句柄
目标进程用户模式句柄转换为内核句柄网上很多方法都是Ring0内核进程和句柄互相转换的方法,查了一下没怎么看到说怎么将用户模式句柄转换为内核句柄的。如果内核获取到的是目标进程的句柄,拷贝到内核模式是不能直接使用的,会引发异常。
目前想到的实现思路是:
如果是伪句柄,直接返回后面再来处理。
调用ObReferenceObjectByHandle指定用户模式句柄获取任意对象的体指针 (EProcess、EThread )
调用ObOpenObjectByPointer打开指针所引用的对象,并返回对象的句柄,此时设置为内核句柄。就获取到啦。
本人是菜鸟,各位师傅如果知道其他的方法跪求指点!!!
实现代码:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758NTSTATUS ConvertKernelHandle( IN HANDLE UserHandle, OUT PHANDLE KernelHandle, ...