逆向TesSafe.sys
来源:互联网 发布:今古传奇故事月末 知乎 编辑:程序博客网 时间:2024/06/06 08:59
//------------------------------[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将它认出来了。
// 第二次执行时 ecx = loc_129D3
_asm jmp loc_129D0;
_asm emit 76H;
loc_129D0:
goto ecx; // 原来这里的指令是 push ecx, retn,相当于jmp
// 第二次执行时跳到了loc_129D3处
loc_129D3:
// 花指令段结束。开始!
// 这里最好把前面那些花指令Undefine掉,使得IDA认为这是一个函数。
// 这样就可以显示函数的参数名了。
proc_11218(); // 里面有jmp 1121F,进去
RtlInitUnicodeString(&DestinationString, L"//Device//TesSafe");
st = IoCreateDevice(DriverObject, 0, &DestinationString, 0x22,
0, FALSE, &DeviceObject);
// 反汇编里有一句 mov [ebp+DriverObject],eax 可能是因为参数DriverObject已经不再使用
// 可以用来放st ,这是编译器优化的结果
if(!NT_SUCCESS(st))
{
return st;
}
RtlInitUnicodeString(&SourceString, L"//DosDevices//TesSafe");
st = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
stPre = st;
if(!NT_SUCCESS(st))
{
return st;
}
// 这里有个小花
_asm call loc_12A34;
_asm emit 83H;
_asm emit 0F8H;
_asm emit 2H;
_asm emit 74H;
loc_12A34:
_asm add esp,4; // 保持堆栈平衡
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
st = sub_11E48(&dword_142B0, &unk_142B4, &unk_143E0);
if(!NT_SUCCESS(st))
{
IoDeleteSymolicLink(&SymbolicLinkName);
// 这里还有一个判断,用于判断上次的st是否为TRUE
if(!NT_SUCCESS(stPre))
{
IoDeleteDevice(DeviceObject);
}
return st;
}
// 这里来了个小花(call loc_12A8A),将它去掉
_asm call loc_12A8A;
_asm emit 74H;
loc_12A8A:
_asm add esp,4; // 平衡堆栈
BaseAddess = MmAllocateNonCachedMemory(0x2000);
return st;
}
// 防止动态调试
VOID proc_1121F()
{
while(::KdDebuggerEnabled())
{
::KdDisableDebugger();
}
}
// 下面的东西先反成C,等有时间看看头文件,再把结构补上
NTSTATUS _stdcall sub_11E48(DWORD* arg_0 /* ntoskrnl.exe 大小 */, PVOID arg_4 /* 标志 */, PVOID arg_8)
{
DWORD dwCount = 0x10000;
PVOID pMem;
NTSTATUS st = 0xC0000004;
for(; st == 0xC0000004; dwCount *= 2)
{
pMem = ExAllocatePoolWithTag(0, dwCount, 0x4E746547);
if(pMem == NULL)
return 0xC000009A;
st = ZwQuerySystemInformation(SystemModuleInformation, pMem, 0x10000, 0);
if(st == 0xC0000004) // 缓冲太小?
{
ExFreePoolWithTag(pMem, 0);
}
else if(NT_SUCCESS(st)) // 怎么看着这么别扭?
{
// 空间大小合适
break;
}
else
{
ExFreePoolWithTag(pMem, 0);
return st;
}
}
PSYSTEM_MODULE_INFORMATION pInfo = (PSYSTEM_MODULE_INFORMATION)pMem;
// pInfo是第一个成员
*arg_0 = pInfo->Size; // 一些信息
*arg_4 = pInfo->Flags;
if(arg_8 != 0)
{
sub_11000(arg_8, 0x10, (DWORD)(pInfo->ModuleNameOffset + (DWORD)pInfo + 0x20));
if(pMem != NULL) // 这个判断好像没用吧,如果内存分配不成功早就return 0xC000009A了。
ExFreePoolWithTag(pMem, 0);
}
return st;
}
VOID _stdcall sub_11000(PBYTE arg_0, int arg_4, PBYTE arg_8)
{
if(arg_4 == 0)
return 0xC000000D;
// 字符串拷贝?
// 直接反C:
for(char c = *arg_8; c != 0; c = *(arg_8++))
{
*arg_0 = c;
arg_0++;
arg_4--;
}
if(arg_4 == 0) // 长度?
{
arg_0--;
}
*(BYTE*)arg_0 = 0;
}
VOID _stdcall DriverUnload(PDRIVER_OBJECT pDrvObj)
{
// 应用了与DriverEntry几乎一样的加花手法,这里不再重复。
// 我已经去除了花指令
UNICODE_STRING DestinationString;
LARGE_INTEGER TimeOut;
NTSTATUS st = STATUS_SUCCESS;
TimeOut.HighPart = 0xFFFFFFFF;
TimeOut.LowPart = 0xFFE17B80;
if(dword_142C4 == 0)
return;
sub_118D0();
PsSetCreateProcessNotifyRoutine(NotifyRoutine, 1);
do
{
KeWaitForSingleObject(unk_143C0, 0, 0, 0, &TimeOut); // 应该对unk_143C0检测一下合理性吧。。我没逆完,先不下结论。
// ....
}while(InterlockedExchange(&unk_14328, 0); // 工作还没有完成,不要执行清理工作。
KeWaitForSingleObject(unk_143C0, 0, 0, 0, &TimeOut);
ObDereferenceObject(unk_143C0);
if(BaseAddress != 0)
{
MmFreeNonCachedMemory(BaseAddress, 0x2000);
}
RtlInitUnicodeString(&DestinationString, L"//DosDevices//TesSafe");
IoDeleteSymbolicLink(&destinationString);
IoDeleteDevice(pDrvObj->DeviceObject);
}
NTSTATUS __stdcall DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus = STATUS_SUCCESS;
pIrp->Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID _stdcall sub_118D0()
{
// 待续
}
VOID _stdcall sub_1230C()
{
// 待续
}
// 这个函数的反C可能错误多些
// 逻辑判断不少,再加上花指令,容易搞错
VOID __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
NTSTATUS st = STATUS_SUCCESS;
PEPROCESS Object = NULL;
BOOLEAN NewIrql = FALSE;
char* pImageName = NULL;
if(Create)
{
if(dword_14050 == 6)
{
if(dword_1431C == 0) // 这个四字节变量保存一个指向PsGetProcessImageFileName的指针
return;
st = PsLookupProcessByProcessId(ProcessId, &Object);
if(!NT_SUCCESS(st))
return;
pImageName = PsGetProcessImageFileName(Object); // 返回名字
// 多媒体保护进程?
if(strnicmp(pImageName, "mfpmp.exe") == 0) // 这是一个_cdecl约定的函数,所以调用后使用add esp,0ch平衡堆栈
{
// 这个函数是_fastcall,需要通过EDX和ECX传递参数,这个函数仅仅使用了ECX
KfAcquireSpinLock(&SpinLock);
if(dword_14338 != *(DWORD*)dword_14338)
{
// 下面是伪C代码,要想编译得自己定义结构
// 这个结构中有SINGLE_LIST_ENTRY
for(DWORD pEsi = dword_14338; pEsi != NULL; pEsi = *(DWORD*)pEsi /* Offset 0 , Equal to pEsi = *pEsi*/)
{
if(*(DWORD*)(pEsi - 4) == ParentId) // 应该是个链表吧。。。。
{
*(DWORD*)pEsi = Object; // 加入?
break;
}
}
}
KfReleaseSpinLock(&SpinLock, FALSE);
}
ObDereferenceObject(Object);
}
}
else
{
// 还是老的加花方法,略
PsLookupProcessByProcessId(ProcessId, &Object);
// 没有对st 验值。如果我HOOK掉PsLookupProcessByProcessId怎么办?
NewIrql = KfAcquireSpinLock(&SpinLock);
if(dword_14338 != *(DWORD*)dword_14338) // 链表
{
for(DWORD pEax = dword_14338; pEax != NULL; pEax = *(DWORD*)pEax /* Offset 0 , Equal to pEsi = *pEsi*/)
{
DWORD dwContain = pEax - 8;
if(*(DWORD*)dwContain == (DWORD)Object || *(DWORD)(dwContain + 4) == 0) // 这个CONTAIN的偏移为8
{
// 从其中删除元素?
DWORD temp = *(DWORD*)pEax;
*(DWORD*)(pEax + 4) = *(DWORD*)pEax; // 设置链表
*(DWORD*)(temp + 4) = pEax + 4; // A* q = p; q->pNext = p->pNext;
ExFreePoolWithTag((DWORD)(pEax - 8), 0);
break;
}
}
}
KfReleaseSpinLock(&SpinLock, NewIrql);
}
}
// 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将它认出来了。
// 第二次执行时 ecx = loc_129D3
_asm jmp loc_129D0;
_asm emit 76H;
loc_129D0:
goto ecx; // 原来这里的指令是 push ecx, retn,相当于jmp
// 第二次执行时跳到了loc_129D3处
loc_129D3:
// 花指令段结束。开始!
// 这里最好把前面那些花指令Undefine掉,使得IDA认为这是一个函数。
// 这样就可以显示函数的参数名了。
proc_11218(); // 里面有jmp 1121F,进去
RtlInitUnicodeString(&DestinationString, L"//Device//TesSafe");
st = IoCreateDevice(DriverObject, 0, &DestinationString, 0x22,
0, FALSE, &DeviceObject);
// 反汇编里有一句 mov [ebp+DriverObject],eax 可能是因为参数DriverObject已经不再使用
// 可以用来放st ,这是编译器优化的结果
if(!NT_SUCCESS(st))
{
return st;
}
RtlInitUnicodeString(&SourceString, L"//DosDevices//TesSafe");
st = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
stPre = st;
if(!NT_SUCCESS(st))
{
return st;
}
// 这里有个小花
_asm call loc_12A34;
_asm emit 83H;
_asm emit 0F8H;
_asm emit 2H;
_asm emit 74H;
loc_12A34:
_asm add esp,4; // 保持堆栈平衡
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
st = sub_11E48(&dword_142B0, &unk_142B4, &unk_143E0);
if(!NT_SUCCESS(st))
{
IoDeleteSymolicLink(&SymbolicLinkName);
// 这里还有一个判断,用于判断上次的st是否为TRUE
if(!NT_SUCCESS(stPre))
{
IoDeleteDevice(DeviceObject);
}
return st;
}
// 这里来了个小花(call loc_12A8A),将它去掉
_asm call loc_12A8A;
_asm emit 74H;
loc_12A8A:
_asm add esp,4; // 平衡堆栈
BaseAddess = MmAllocateNonCachedMemory(0x2000);
return st;
}
// 防止动态调试
VOID proc_1121F()
{
while(::KdDebuggerEnabled())
{
::KdDisableDebugger();
}
}
// 下面的东西先反成C,等有时间看看头文件,再把结构补上
NTSTATUS _stdcall sub_11E48(DWORD* arg_0 /* ntoskrnl.exe 大小 */, PVOID arg_4 /* 标志 */, PVOID arg_8)
{
DWORD dwCount = 0x10000;
PVOID pMem;
NTSTATUS st = 0xC0000004;
for(; st == 0xC0000004; dwCount *= 2)
{
pMem = ExAllocatePoolWithTag(0, dwCount, 0x4E746547);
if(pMem == NULL)
return 0xC000009A;
st = ZwQuerySystemInformation(SystemModuleInformation, pMem, 0x10000, 0);
if(st == 0xC0000004) // 缓冲太小?
{
ExFreePoolWithTag(pMem, 0);
}
else if(NT_SUCCESS(st)) // 怎么看着这么别扭?
{
// 空间大小合适
break;
}
else
{
ExFreePoolWithTag(pMem, 0);
return st;
}
}
PSYSTEM_MODULE_INFORMATION pInfo = (PSYSTEM_MODULE_INFORMATION)pMem;
// pInfo是第一个成员
*arg_0 = pInfo->Size; // 一些信息
*arg_4 = pInfo->Flags;
if(arg_8 != 0)
{
sub_11000(arg_8, 0x10, (DWORD)(pInfo->ModuleNameOffset + (DWORD)pInfo + 0x20));
if(pMem != NULL) // 这个判断好像没用吧,如果内存分配不成功早就return 0xC000009A了。
ExFreePoolWithTag(pMem, 0);
}
return st;
}
VOID _stdcall sub_11000(PBYTE arg_0, int arg_4, PBYTE arg_8)
{
if(arg_4 == 0)
return 0xC000000D;
// 字符串拷贝?
// 直接反C:
for(char c = *arg_8; c != 0; c = *(arg_8++))
{
*arg_0 = c;
arg_0++;
arg_4--;
}
if(arg_4 == 0) // 长度?
{
arg_0--;
}
*(BYTE*)arg_0 = 0;
}
VOID _stdcall DriverUnload(PDRIVER_OBJECT pDrvObj)
{
// 应用了与DriverEntry几乎一样的加花手法,这里不再重复。
// 我已经去除了花指令
UNICODE_STRING DestinationString;
LARGE_INTEGER TimeOut;
NTSTATUS st = STATUS_SUCCESS;
TimeOut.HighPart = 0xFFFFFFFF;
TimeOut.LowPart = 0xFFE17B80;
if(dword_142C4 == 0)
return;
sub_118D0();
PsSetCreateProcessNotifyRoutine(NotifyRoutine, 1);
do
{
KeWaitForSingleObject(unk_143C0, 0, 0, 0, &TimeOut); // 应该对unk_143C0检测一下合理性吧。。我没逆完,先不下结论。
// ....
}while(InterlockedExchange(&unk_14328, 0); // 工作还没有完成,不要执行清理工作。
KeWaitForSingleObject(unk_143C0, 0, 0, 0, &TimeOut);
ObDereferenceObject(unk_143C0);
if(BaseAddress != 0)
{
MmFreeNonCachedMemory(BaseAddress, 0x2000);
}
RtlInitUnicodeString(&DestinationString, L"//DosDevices//TesSafe");
IoDeleteSymbolicLink(&destinationString);
IoDeleteDevice(pDrvObj->DeviceObject);
}
NTSTATUS __stdcall DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus = STATUS_SUCCESS;
pIrp->Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID _stdcall sub_118D0()
{
// 待续
}
VOID _stdcall sub_1230C()
{
// 待续
}
// 这个函数的反C可能错误多些
// 逻辑判断不少,再加上花指令,容易搞错
VOID __stdcall NotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
NTSTATUS st = STATUS_SUCCESS;
PEPROCESS Object = NULL;
BOOLEAN NewIrql = FALSE;
char* pImageName = NULL;
if(Create)
{
if(dword_14050 == 6)
{
if(dword_1431C == 0) // 这个四字节变量保存一个指向PsGetProcessImageFileName的指针
return;
st = PsLookupProcessByProcessId(ProcessId, &Object);
if(!NT_SUCCESS(st))
return;
pImageName = PsGetProcessImageFileName(Object); // 返回名字
// 多媒体保护进程?
if(strnicmp(pImageName, "mfpmp.exe") == 0) // 这是一个_cdecl约定的函数,所以调用后使用add esp,0ch平衡堆栈
{
// 这个函数是_fastcall,需要通过EDX和ECX传递参数,这个函数仅仅使用了ECX
KfAcquireSpinLock(&SpinLock);
if(dword_14338 != *(DWORD*)dword_14338)
{
// 下面是伪C代码,要想编译得自己定义结构
// 这个结构中有SINGLE_LIST_ENTRY
for(DWORD pEsi = dword_14338; pEsi != NULL; pEsi = *(DWORD*)pEsi /* Offset 0 , Equal to pEsi = *pEsi*/)
{
if(*(DWORD*)(pEsi - 4) == ParentId) // 应该是个链表吧。。。。
{
*(DWORD*)pEsi = Object; // 加入?
break;
}
}
}
KfReleaseSpinLock(&SpinLock, FALSE);
}
ObDereferenceObject(Object);
}
}
else
{
// 还是老的加花方法,略
PsLookupProcessByProcessId(ProcessId, &Object);
// 没有对st 验值。如果我HOOK掉PsLookupProcessByProcessId怎么办?
NewIrql = KfAcquireSpinLock(&SpinLock);
if(dword_14338 != *(DWORD*)dword_14338) // 链表
{
for(DWORD pEax = dword_14338; pEax != NULL; pEax = *(DWORD*)pEax /* Offset 0 , Equal to pEsi = *pEsi*/)
{
DWORD dwContain = pEax - 8;
if(*(DWORD*)dwContain == (DWORD)Object || *(DWORD)(dwContain + 4) == 0) // 这个CONTAIN的偏移为8
{
// 从其中删除元素?
DWORD temp = *(DWORD*)pEax;
*(DWORD*)(pEax + 4) = *(DWORD*)pEax; // 设置链表
*(DWORD*)(temp + 4) = pEax + 4; // A* q = p; q->pNext = p->pNext;
ExFreePoolWithTag((DWORD)(pEax - 8), 0);
break;
}
}
}
KfReleaseSpinLock(&SpinLock, NewIrql);
}
}
- 逆向TesSafe.sys
- Pass all use tessafe.sys protect game
- 绕TX驱动保护TesSafe.sys方法
- 搞定QQ游戏系列驱动保护TesSafe.sys
- 最新绕过TX驱动保护TesSafe.sys方法
- 搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys
- 过游戏保护之 过TX驱动保护TesSafe.sys方法(现在可以用)3
- QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys
- 过NP 系列之一---搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys
- Rtvcan.sys的不完全逆向
- 逆向:Ucoresys.sys (一)
- 逆向:Ucoresys.sys (二)
- 逆向未知dhook.sys驱动源代码
- NMFilter.sys(4.3.2.2485)逆向源代码
- NMFilter.sys(4.3.2.2485)逆向源代码
- NMFilter.sys(4.3.2.2485) 逆向源代码
- 逆向病毒nvmini.sys--编译通过-
- 逆向fuck.sys--编译通过--源码
- TJU2988解题报告
- 开始。。
- 生日52
- vc Format()
- 串口通信 同步传送与异步传送
- 逆向TesSafe.sys
- 手机探索者开发实录—数据解包
- Java仿雷电及其源代码
- 将笔记本打造成遥控器――远程桌面控制台式机
- http://www.codeproject.com/KB/IP/persistentevents.aspx
- Ajax学习笔记(2)----Ajax访问XML实例代码(全)
- 越是深入学习越是对那些很高级的东西不感兴趣
- 消息与消息队列二(译自MSDN的About Message and Message Queue)
- 伊始