//------------------------------[IDA] => TesSafe.sys --------------------------------------//
// File MD5: E780032179272AFD93BCF4A9A67C7706
// Version: 0.0.6.5
//-----------------------------------------------------------------------------------------//
// 定义
extern "C"
{
#include <ntddk.h>
}
DWORD dword_14288 = 0xBB40E64E; // 这个变量有初值
DWORD dword_142C4 = 0;
DWORD dword_14050 = 5;
DWORD dword_1431C = 0; // 这个四字节变量保存一个指向PsGetProcessImageFileName的指针
DWORD dword_14338 = 0;
PKEVENT unk_143C0 = NULL;
KSPIN_LOCK SpinLock = 0; // 实际上是DWORD
PVOID unk_14328 = NULL;
PVOID unk_142B4 = NULL;
PVOID unk_143E0 = NULL;
PVOID BaseAddress = NULL;
// 其实内核函数默认调用方法就是stdcall,下面的_stdcall都是不用加的。
// 不过为了说明,还是都加上了。
VOID _stdcall proc_1121F(); // 防止动态调试
VOID _stdcall sub_11000(PVOID, DWORD, DWORD);
VOID _stdcall sub_118D0();
VOID _stdcall sub_1230C(); // 实现挂钩
// 下面的函数就是int __stdcall sub_112DA(HANDLE ProcessHandle, int, int, int, int)
NTSTATUS _stdcall Hook_ObOpenObjectByPointer(PVOID Object,ULONG HandleAttributes, PACCESS_STATE PassedAccessState, ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, PHANDLE Handle);
VOID __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create);
NTSTATUS _stdcall sub_11E48(DWORD, PVOID, PVOID);
NTSTATUS _stdcall DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
VOID _stdcall DriverUnload(PDRIVER_OBJECT pDrvObj);
// 实现
extern "C" NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING puRegistryString)
{
// 实际上这个为入口点,不过为了方便就写在了一起
if(dword_14288 != 0 && dword_14288 == 0xBB40E64E) // 十进制3141592654,晕倒。如果下面的异或操作已经执行过奇数次,那么这两个值不等
{
// 不过实际上由于 dword_14288 != 0的判断,不可以执行奇数次
dword_14288 = *(DWORD*)KeTickCount ^ dword_14288; // 与那个大PI异或
}
// 这里有一个长跳转,可能做过手脚
// jmp to text.12996,开始进入正事
// 定义变量
// sub esp,14H
// 由后面的反汇编我们可以知道定义了些什么
UNICODE_STRING SymbolicLinkName;
UNICODE_STRING DestinationString;
PDEVICE_OBJECT DeviceObject = NULL;
// 这个是我自己定义的,实际上在堆栈中没有分配
NTSTATUS st = STATUS_SUCCESS;
NTSTATUS stPre = STATUS_SUCCESS;
// 初始化
DestinationString.Length = 0;
DestinationString.MaximunLength = 0;
SymbolicLinkName.Length = 0;
SymbolicLinkName.MaximnumLength = 0;
_asm call loc_129C5; // 这个花指令思路比较新
_asm emit 0fH;
_asm emit 88H;
_asm jmp loc_129D3; // IDA认错指令了,它认为是:db eb; pop cs
loc_129C5:
_asm pop ecx; // 第一次执行,ecx == loc_129C5 - 3,就是那个0fH 第二次执行为cs
_asm jmp loc_129CA; // 这个作者用了这么多嵌入汇编?要知道jmp和call是不能过IDA的
// 花指令
_asm emit 50H;
_asm emit 33H;
loc_129CA:
_asm add ecx,2; // 第一次执行 ecx == loc_129C5 - 1,就是loc_129C5上面那条指令,IDA将它认出来了。
&nbs
// File MD5: E780032179272AFD93BCF4A9A67C7706
// Version: 0.0.6.5
//-----------------------------------------------------------------------------------------//
// 定义
extern "C"
{
#include <ntddk.h>
}
DWORD dword_14288 = 0xBB40E64E; // 这个变量有初值
DWORD dword_142C4 = 0;
DWORD dword_14050 = 5;
DWORD dword_1431C = 0; // 这个四字节变量保存一个指向PsGetProcessImageFileName的指针
DWORD dword_14338 = 0;
PKEVENT unk_143C0 = NULL;
KSPIN_LOCK SpinLock = 0; // 实际上是DWORD
PVOID unk_14328 = NULL;
PVOID unk_142B4 = NULL;
PVOID unk_143E0 = NULL;
PVOID BaseAddress = NULL;
// 其实内核函数默认调用方法就是stdcall,下面的_stdcall都是不用加的。
// 不过为了说明,还是都加上了。
VOID _stdcall proc_1121F(); // 防止动态调试
VOID _stdcall sub_11000(PVOID, DWORD, DWORD);
VOID _stdcall sub_118D0();
VOID _stdcall sub_1230C(); // 实现挂钩
// 下面的函数就是int __stdcall sub_112DA(HANDLE ProcessHandle, int, int, int, int)
NTSTATUS _stdcall Hook_ObOpenObjectByPointer(PVOID Object,ULONG HandleAttributes, PACCESS_STATE PassedAccessState, ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, PHANDLE Handle);
VOID __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create);
NTSTATUS _stdcall sub_11E48(DWORD, PVOID, PVOID);
NTSTATUS _stdcall DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
VOID _stdcall DriverUnload(PDRIVER_OBJECT pDrvObj);
// 实现
extern "C" NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING puRegistryString)
{
// 实际上这个为入口点,不过为了方便就写在了一起
if(dword_14288 != 0 && dword_14288 == 0xBB40E64E) // 十进制3141592654,晕倒。如果下面的异或操作已经执行过奇数次,那么这两个值不等
{
// 不过实际上由于 dword_14288 != 0的判断,不可以执行奇数次
dword_14288 = *(DWORD*)KeTickCount ^ dword_14288; // 与那个大PI异或
}
// 这里有一个长跳转,可能做过手脚
// jmp to text.12996,开始进入正事
// 定义变量
// sub esp,14H
// 由后面的反汇编我们可以知道定义了些什么
UNICODE_STRING SymbolicLinkName;
UNICODE_STRING DestinationString;
PDEVICE_OBJECT DeviceObject = NULL;
// 这个是我自己定义的,实际上在堆栈中没有分配
NTSTATUS st = STATUS_SUCCESS;
NTSTATUS stPre = STATUS_SUCCESS;
// 初始化
DestinationString.Length = 0;
DestinationString.MaximunLength = 0;
SymbolicLinkName.Length = 0;
SymbolicLinkName.MaximnumLength = 0;
_asm call loc_129C5; // 这个花指令思路比较新
_asm emit 0fH;
_asm emit 88H;
_asm jmp loc_129D3; // IDA认错指令了,它认为是:db eb; pop cs
loc_129C5:
_asm pop ecx; // 第一次执行,ecx == loc_129C5 - 3,就是那个0fH 第二次执行为cs
_asm jmp loc_129CA; // 这个作者用了这么多嵌入汇编?要知道jmp和call是不能过IDA的
// 花指令
_asm emit 50H;
_asm emit 33H;
loc_129CA:
_asm add ecx,2; // 第一次执行 ecx == loc_129C5 - 1,就是loc_129C5上面那条指令,IDA将它认出来了。
&nbs

本文详细介绍了如何逆向分析 TesSafe.sys 驱动程序,包括其关键函数、数据结构和防调试技巧。通过IDA查看,发现驱动中存在一些花指令和异或操作,用于防止动态调试。驱动主要功能包括设备创建、符号链接建立、I/O控制处理以及进程创建通知。此外,还揭示了如何挂钩系统函数并进行权限检查。
最低0.47元/天 解锁文章
2192





