[目录]
一. 前言
二. PhantOm 在驱动层的保护方式
三. 挂钩的SSDT函数
四. 挂钩的SSDT Shadow函数
五. 结语
[内容]
一. 前言
相信脱壳和破解界的朋友们大部分都用过PhantOm这个隐藏OD的插件,以前可以说是过TMD这
种加密壳的利器,它可以在应用层和驱动层对OD进行保护。貌似应用层的保护方式已经给某
强人分析过了,这里就不再重复了,现在分析一下PhantOm的驱动保护。拿来开刀的是
PhantOm V1.54版本的。
PhantOm插件的驱动文件在PhantOm.dll的资源中,在OD运行时自动从资源中释放驱动到临时
文件夹中,我们可以通过PE_Stud等PE工具进行提取。
二. PhantOm的驱动层保护方式
当一个程序被调试,驱动将会将OD和被调试程序的相关信息存储在一个结构中,并以双链表
的形式存放。其结构如下:
typedef struct _DEBUG_INFO
{
struct _DEBUG_INFO *Prev;
struct _DEBUG_INFO *Next;
PLONG Debugger_Id; // OD的id号
PEPROCESS Debugger_Eprocess; // OD的EPROCESS结构
PEPROCESS Debuggee_Eprocess; // 被调试程序的EPROCESS结构
} DEBUG_INFO, *PDEBUG_INFO;
VOID SetDebugInfo (PVOID DebugIdBuf)
{
NTSTATUS status;
PEPROCESS pEprocess;
PDEBUG_INFO NodeAddr, LastNode;
ULONG Debugger_id, Debuggee_id;
Debugger_id = *(PULONG)DebugIdBuf;
Debuggee_id = *(PULONG)((ULONG)DebugIdBuf+1);
if (DebugIdBuf == NULL)
return;
// 判断相关结构是否已经存在
if ( !GetDebugInfoByPid(*(PULONG)DebugIdBuf)
{
// 建立OD与被调试程序的关联
// 传入被调试程序的id
status = PsLookupProcessByProcessId(Debuggee_id),
EprocessOfDebuggee);
if (status == STATUS_SUCCESS)
{
Debug_Info.Debuggee_Eprocess = EprocessOfDebuggee;
ObDereferenceObject(EprocessOfDebuggee);
}
}
else // 相关结构不存在
{
// 为节点分配空间
NodeAddr = (PDEBUG_INFO)ExAllocatePool(PagedPool, sizeof(DEBUG_INFO));
if (NodeAddr == NULL)
return;
RtlZeroMemory(NodeAddr, 16);
// 查找链表最后一个节点
LastNode = GetLast();
if (LastNode)
{
// 非空链表, 插入到表尾
LastNode->Next = NodeAddr;
NodeAddr->Prev = LastNode;
}
else
// 空链表,插入到表头
DebugInfoHeader = NodeAddr;
// 填充链表结构
NodeAddr->Debugger_Id = Debugger_id;
if (STATUS_SUCCESS == PsLookupProcessByProcessId(Debugger_id, pEprocess))
{
NodeAddr->Debugger_Eprocess = pEprocess;
ObDereferenceObject(pEprocess);
}
if (STATUS_SUCCESS == PsLookupProcessByProcessId(Debuggee_id, pEprocess))
{
NodeAddr->Debuggee_Eprocess = pEprocess;
ObDereferenceObject(pEprocess);
}
}
}
NTSTATUS WINAPI New_NtQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
)
{
NTSTATUS status;
PEPROCESS cur_eprocess;
PSYSTEM_PROCESSES system_process;
PSYSTEM_PROCESSES system_process_prev;
PSYSTEM_HANDLE_INFORMATION_EX handle_info;
ULONG NextEntryDelta;
ULONG handle_count, index, total_size;
status = Org_NtQuerySystemInformation(
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if (status != STATUS_SUCCESS | IS_HOOK != TRUE)
return status;
cur_eprocess = IoGetCurrentProcess();
// 当前进程是OD
if (FindDebugInfoByEprocess(cur_eprocess))
return status;
switch (SystemInformationClass)
{
case SystemProcessesAndThreadsInformation: // 5
{
system_process = (PSYSTEM_PROCESSES)SystemInformation;
system_process_prev = system_process;
NextEntryDelta = 0;
do
{
system_process = (PSYSTEM_PROCESSES)((ULONG)system_process + NextEntryDelta);
if (GetDebugInfoByPid(system_process->ProcessId)) // 下面断链
{
// 非最后一项
if (system_process->NextEntryDelta)
system_process_prev->NextEntryDelta += system_process->NextEntryDelta;
// 最后一项
else
system_process_prev->NextEntryDelta = 0;
// 抹掉进程名字信息
RtlZeroMemory(system_process->ProcessName.Buffer,
system_process->ProcessName.Length*2);
// 然后将整个SYSTEM_PROCESS抹去
total_size = system_process->ThreadCount << 6 + 0xB4;
RtlZeroMemory(&system_process, total_size);
}
system_process_prev = system_process;
NextEntryDelta = system_process->NextEntryDelta;
} while (NextEntryDelta);
system_process = (PSYSTEM_PROCESSES)SystemInformation;
NextEntryDelta = 0;
do
{
system_process = (PSYSTEM_PROCESSES)((ULONG)system_process + NextEntryDelta);
if (GetDebugInfoByPid(system_process->InheritedFromProcessId))
// 如果父进程是OD,则将父进程的ID改为explorer.exe的ID号
system_process->InheritedFromProcessId = EXPLORER_ID;
NextEntryDelta = system_process->NextEntryDelta;
} while (NextEntryDelta);
}
break;
case SystemKernelDebuggerInformation: // 35
RtlZeroMemory(SystemInformation, SystemInformationLength);
break;
case SystemHandleInformation: // 16
{
handle_info = (PSYSTEM_HANDLE_INFORMATION_EX)SystemInformation;
handle_count = handle_info->NumberOfHandles;
index = 0;
while (handle_count)
{
if (GetDebugInfoByPid(handle_info->Information[index].ProcessId))
handle_info->Information[index].ProcessId = EXPLORER_ID;
handle_count--;
index++;
}
}
break;
}
return STATUS_SUCCESS;
}
NTSTATUS New_NtOpenProcess (
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId
)
{
NTSTATUS status;
if (IS_HOOK == TRUE && !FindDebugInfoByEprocess(IoGetCurrentProcess()))
{
status = STATUS_INVALID_PARAMETER;
if (!MmIsAddressValid(ClientId) ||
ClientId.UniqueProcess == CSRSS_ID ||
GetDebugInfoByPid(ClientId->UniqueProcess))
return status;
}
return Org_NtOpenProcess(ProcessHandle,
DesiredAccess,
ObjectAttributes,
ClientId);
}
NTSTATUS
NTAPI
New_NtSetInformationThread(
IN HANDLE ThreadHandle,
IN THREAD_INFORMATION_CLASS ThreadInformationClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength
)
{
NTSTATUS status;
PVOID Object;
if (IS_HOOK == TRUE)
{
status = ObReferenceObjectByHandle(ThreadHandle, 0, 0, KernelMode, Object, 0);
if (status != STATUS_SUCCESS)
return STATUS_INVALID_HANDLE;
ObDereferenceObject(Object);
if (!FindDebugInfoByEprocess(IoGetCurrentProcess()) &&
ThreadInformationClass == ThreadHideFromDebugger)
return STATUS_SUCCESS;
}
return Org_NtSetInformationThread(ThreadHandle,
ThreadInformationClass,
ThreadInformation,
ThreadInformationLength);
}
NTSTATUS
NTAPI
New_NtClose(HANDLE ObjectHandle)
{
PVOID Object;
NTSTATUS status;
if (IS_HOOK == FALSE)
return Org_NtClose(ObjectHandle);
// 防止使用无效句柄来检测调试器
InterlockedIncrement(Lock_Number);
status = ObReferenceObjectByHandle(ObjectHandle, 0, 0, 0, Object, 0);
if (status == STATUS_SUCCESS)
{
ObDereferenceObject(Object);
status = Org_NtClose(ObjectHandle);
}
else
status = STATUS_SUCCESS;
InterlockedDecrement(Lock_Number);
return status;
}
NTSTATUS New_NtYieldExecution()
{
Org_NtYieldExecution();
return STATUS_NO_YIELD_PERFORMED;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课