[筆記]inline hook 深層call ObOpenObjectByPointe的實現及用SSDT反HOOK

很久以前看到的...一直存著...今天剛好看到就借轉過來了...


inline hook 深層call ObOpenObjectByPointe的實現及用SSDT反HOOK
作者:rryr  來源:博客園  發佈時間:2010-01-05 19:00  閱讀:1066 次  原文鏈接   [收藏]  

最近研究TESSAFE.SYS的驅動,GOOGLE搜索到微點也是一樣的手法HOOK call ObOpenObjectByPointe,把不完整的代碼給編寫實現了下。未實現檢測,應該是有修改我的代碼或恢復HOOK call即重啟或藍屏,我為了方便沒實現,下載我改動後驅動文件,用來保護記事本不被OPENprocess。。
然後unhook call ObOpenObjectByPointe 的代碼從網上摘來,在搞虛擬機裡可以過掉,但主機確是老藍屏8e代碼。原來是代碼根本不對,看雪上發的貼,有指出不對的代碼拷貝函數,我做下修改為指令長度拷貝,終於可以了。反inline hook 深層call驅動文件,可以下載,源碼都在下面了,文件裡就沒放。注意順序,必須先開這個驅動才有用,因為是從內存拷貝來的,先讓inline hook 深層call驅動加載了,在拷貝內存也是錯誤的。關閉時倒序來,否則藍了別怪我,模擬就只是模擬罷了。
//unhok call 這是SSDT hook,在深層call ObOpenObjectByPointe驅動加載前複製NtOpenThread NtOpenProcess 兩個代碼到別處SSDT。原來主機藍屏,但虛擬機也實現不藍,反彙編下看到代碼烤過來的不對,果然是拷貝函數沒處理細節,做下修改BufferCode函 數加了反彙編引擎判斷指令長度,按長度來拷貝,再根據指令做重定位。

#include "ntddk.h"
#include <ntdef.h>
#include "LDasm.h"
#define ThreadLength 0x4f4 //要保存的 NtOpenThread 原代碼的長度
#define ProcessLength 0x28a //要保存的 NtOpenProcess 原代碼的長度

#define DeviceLink L"\\Device\\DNFCracker"
#define SymbolicLink L"\\DosDevices\\DNFCracker"
#define IOCTL_RESTORE (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN, 0x886, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef NTSTATUS (* NTOPENTHREAD)(
 OUT PHANDLE ThreadHandle,
 IN ACCESS_MASK DesiredAccess,
 IN POBJECT_ATTRIBUTES ObjectAttributes,
 IN OPTIONAL PCLIENT_ID ClientId
 );

typedef NTSTATUS (* NTOPENPROCESS)(
  OUT PHANDLE ProcessHandle,
  IN ACCESS_MASK DesiredAccess,
  IN POBJECT_ATTRIBUTES ObjectAttributes,
  IN PCLIENT_ID ClientId
  );

typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PVOID    ServiceTableBase;
PULONG   ServiceCounterTableBase;
ULONG    NumberOfService;
ULONG    ParamTableBase;
}
SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;

VOID Hook();
VOID Unhook();
VOID BufferCode(PUCHAR pCode, ULONG TrgAddr, ULONG BufferLength);
NTOPENTHREAD OldThread;
NTOPENPROCESS OldProcess;
ULONG AddrRead, AddrWrite;
//原 NtReadVirtualMemory/NtWriteVirtualMemory 的前 16 字節代碼
ULONG OrgRead[2], OrgWrite[2];
//保存 NtOpenThread/NtOpenProcess 代碼
UCHAR MyThread[ThreadLength], MyProcess[ProcessLength];

NTSTATUS MyNtOpenThread(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
ACCESS_MASK oDA;
OBJECT_ATTRIBUTES oOA;
CLIENT_ID oCID;
NTSTATUS statusF, statusT;

oDA = DesiredAccess;
oOA = *ObjectAttributes;
oCID = *ClientId;

statusF = OldThread(ThreadHandle, oDA, &oOA, &oCID);
statusT = ((NTOPENTHREAD)MyThread)(ThreadHandle, DesiredAccess, ObjectAttributes, ClientId);
return statusT;
}

NTSTATUS MyNtOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
ACCESS_MASK oDA;
OBJECT_ATTRIBUTES oOA;
CLIENT_ID oCID;
NTSTATUS statusF, statusT;

oDA = DesiredAccess;
oOA = *ObjectAttributes;
oCID = *ClientId;

statusF = OldProcess(ProcessHandle, oDA, &oOA, &oCID);
statusT = ((NTOPENPROCESS)MyProcess)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
return statusT;
}


VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
//UNICODE_STRING usLink;
/*ULONG i;
for (i = 0; i < ThreadLength; i += 4)
{
DbgPrint("%02x %02x %02x %02x\n", MyThread[i], MyThread[i + 1], MyThread[i + 2], MyThread[i + 3]);
DbgPrint("%02x %02x %02x %02x\n", MyProcess[i], MyProcess[i + 1], MyProcess[i + 2], MyProcess[i + 3]);
}
*/
Unhook();
DbgPrint("DNF Cracker Unloaded!");
}

VOID Hook()
{
ULONG AddrProcess, AddrThread;
KIRQL Irql;
AddrRead = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0xBA * 4;
AddrWrite = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x115 * 4;
AddrThread = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x80 * 4;
AddrProcess = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;

OldThread = (NTOPENTHREAD)(*(PULONG)AddrThread);
OldProcess = (NTOPENPROCESS)(*(PULONG)AddrProcess);
//DbgPrint("MyThread:0x%08X OldThread:0x%08X", MyThread, OldThread);
//DbgPrint("MyProcess:0x%08X OldProcess:0x%08X", MyProcess, OldProcess);

__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
Irql=KeRaiseIrqlToDpcLevel();
//記錄 NtReadVirtualMemory/NtWriteVirtualMemory 前 16 字節
/* OrgRead[0] = *(PULONG)(*(PULONG)AddrRead);
OrgRead[1] = *(PULONG)(*(PULONG)AddrRead + 4);
OrgWrite[0] = *(PULONG)(*(PULONG)AddrWrite);
OrgWrite[1] = *(PULONG)(*(PULONG)AddrWrite + 4);*/

//保存原代碼
BufferCode(MyThread, (ULONG)OldThread, ThreadLength);
BufferCode(MyProcess, (ULONG)OldProcess, ProcessLength);

//SSDT Hook
*(PULONG)AddrThread = (ULONG)MyNtOpenThread;
*(PULONG)AddrProcess = (ULONG)MyNtOpenProcess;
KeLowerIrql(Irql);
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
DbgPrint("OldThread!:%08X\n",(ULONG)OldThread);
DbgPrint("OldProcess!:%08X\n",(ULONG)OldProcess);
DbgPrint("MyThread!:%08X\n",(ULONG)MyThread);
DbgPrint("MyProcess!:%08X\n",(ULONG)MyProcess);
}

VOID Unhook()
{
ULONG AddrProcess, AddrThread;KIRQL Irql;
AddrThread = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x80 * 4;
AddrProcess = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;

__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
Irql=KeRaiseIrqlToDpcLevel();
//恢復 SSDT
*(PULONG)AddrThread = (ULONG)OldThread;
*(PULONG)AddrProcess = (ULONG)OldProcess;
KeLowerIrql(Irql);
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
DbgPrint("DNF Cracker Loaded!");
DriverObject->DriverUnload = OnUnload;

Hook();

return STATUS_SUCCESS;
}

// OrgRel 原相對跳轉地址
// CurAbs 當前代碼絕對地址
// MyAbs 替換代碼絕對地址
// CodeLen 跳轉代碼佔據的長度
// 返回值 到替換代碼的相對地址
LONG GetRelAddr(LONG OrgRel, ULONG CurAbs, ULONG MyAbs) //, ULONG CodeLen)
{
ULONG TrgAbs;
TrgAbs = CurAbs + OrgRel; // + CodeLen; //目的地址
return TrgAbs - MyAbs;
}

// 保存原來整個函數的代碼(已修改的正確拷貝指令函數)
// pCode 用來保存代碼的數組的地址
// TrgAddr 要保存的函數的地址
// BufferLength 整個函數佔用的大小
VOID BufferCode(PUCHAR pCode, ULONG TrgAddr, ULONG BufferLength)
{
PUCHAR cPtr, pOpcode;
ULONG cAbs, i;
LONG oRel, cRel;
    ULONG Length;
memset(pCode, 0x90, BufferLength);
for (i = 0; i < BufferLength; i+= Length)
{

cAbs = TrgAddr + i;
pCode[i] = *(PUCHAR)cAbs;
Length = SizeOfCode((PUCHAR)cAbs, &pOpcode);//計算當前指令長度
if(Length)
{//不為0則考過來指令, 長度:Length
memcpy(pCode + i, (PVOID)(cAbs), Length);
}//下面對這條指令重新處理,修正定位
//if (!Length) break;
switch (*(PUCHAR)cAbs)
{
case 0x0F: //JXX NEAR X
if ((*(PUCHAR)(cAbs + 1) >= 0x80)&&(*(PUCHAR)(cAbs + 1) <= 0x8F))
{
oRel = *(PLONG)(cAbs + 2);
if ((oRel + cAbs + 6 > TrgAddr + BufferLength)||
(oRel + cAbs + 6 < TrgAddr)) //判斷跳轉是否在過程範圍內
{
pCode[i + 1] = *(PUCHAR)(cAbs + 1);
cRel = GetRelAddr(oRel, cAbs, (ULONG)pCode + i);
memcpy(pCode + i + 2, &cRel, sizeof(LONG));
//DbgPrint("JXX: 0x%08X -> 0x%08X", cAbs, (ULONG)pCode + i);
//i += sizeof(LONG) + 1;
}
}
break;
case 0xE8: //CALL
oRel = *(PLONG)(cAbs + 1);
if ((oRel + cAbs + 5 > TrgAddr + BufferLength)||
(oRel + cAbs + 5 < TrgAddr)) //判斷跳轉是否在過程範圍內
{
cRel = GetRelAddr(oRel, cAbs, (ULONG)pCode + i);
memcpy(pCode + i + 1, &cRel, sizeof(LONG));
//DbgPrint("CALL: 0x%08X -> 0x%08X", cAbs, (ULONG)pCode + i);

}
break;
case 0x80: //CMP BYTE PTR X
if (*(PUCHAR)(cAbs + 1) == 0x7D)
{
memcpy(pCode + i + 1, (PVOID)(cAbs + 1), 3);
//i += 3; 
continue;
}
break;
case 0xC2: //RET X
if (*(PUSHORT)(cAbs +1) == 0x10)
{
memcpy(pCode + i + 1, (PVOID)(cAbs + 1), sizeof(USHORT));
//i += sizeof(USHORT);
}
break;
/*case 0xE9: //JMP
oRel = *(PLONG)(cAbs + 1);
if (oRel + cAbs > TrgAddr + BufferLength)
{
cRel = GetRelAddr(oRel, cAbs, (ULONG)pCode + i);
memcpy(pCode + i + 1, &cRel, sizeof(LONG));
i += 4;
}*/
//default:
}
/*下面的處理都不必用了
if ((*(PUCHAR)cAbs == 0x39)||(*(PUCHAR)cAbs == 0x89)||(*(PUCHAR)cAbs == 0x8D))
{
memcpy(pCode + i + 1, (PVOID)(cAbs + 1), sizeof(USHORT));
i += sizeof(USHORT);
continue;
}*/

//DbgPrint("addr:%08X//n:%02X//Length!%08X\n",(ULONG)cAbs,*(PUCHAR)cAbs,Length);
/*if ((*(PUCHAR)cAbs >= 0x70)&&(*(PUCHAR)cAbs <= 0x7F)&&(*(PUCHAR)(cAbs - 1) != 0xFF))
{
oRel = (LONG)(*(PCHAR)(cAbs + 1));
cRel = GetRelAddr(oRel, cAbs, (ULONG)pCode + i);
memcpy(pCode + i + 1, &cRel, 1);
i++; continue;
}*/
}
}
//可惜這個代碼早已放出來很久,TX更新很快,早沒用了,開啟來遊戲就它提示非法,辛虧沒缺德到藍屏重啟。然後又加個INLINE HOOK NTOPENPROCESS 頭,可惜被檢測到。
//不過學習這些還是有好處的,不經意間注意到一個細節被我過了,哈哈。。

----------------------------------------------------
下面是 原來網上hook 深層call ObOpenObjectByPointe的實現代碼 源自於微點

留言

本月最夯

偷用電腦,怎知?事件檢視器全記錄!(開機時間、啟動項時間...)

[Chrome] 不用任何擴充功能,Chrome 內建開發者工具讓您輕鬆下載任何影片!