【顶】详解HOOK SSDT

hookprocess.rar

我想大家都用过冰刃吧,因该对SSDT记忆犹新,但什么是SSDT,他是做什么的呢?

 

SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表的作用就是把ring3Win32 APIring0的内核API联系起来。

他通过对系统调用进行索引,然后定位函数的内存地址。当应用程序采用子系统调用系统服务时,他会调用到Ntdll.dll中,后者向EAX中加载所请求的系统服务标识符编号或系统函数编号,然后向EDX中加载用户模式中函数的参数地址,系统服务调度程序对参数数目进行验证,将他们从用户堆栈复制入内核堆栈,然后调用在SSDT中储存于EAX中的服务标识符编号的索引地址处的函数。

举个例子当我们要调用OpenProcess 函数时。函数进入内核的过程如下:

当程序的处理流程进入ring0之后,系统会根据服务标识符编号eaxSSDT这个系统服务描述符表中查找对应的表项,这个找到的表项就是系统服务函数NtOpenProcess的真正地址。之后,系统会根据这个地址调用相应的系统服务函数,并把结果返回给ntdll.dll中的NtOpenProcess图中的“SSDT”所示即为系统服务描述符表的各个表项;右侧的ntoskrnl.exe”则为Windows系统内核服务进程ntoskrnl即为NT OS KerneL的缩写),它提供了相对应的各个系统服务函数。ntoskrnl.exe这个文件位于Windowssystem32目录下

这里说明一点,SSDT中的各个表项不会全部指向ntoskrnl.exe中的服务函数,因为你机器上的杀毒监控或其它驱动程序可能会改写SSDT

中的某些表项。已到达他们的目的。

 

我们还要明确一个概念,就是KeServiceDescriptorTable它是内核导出的表,该表拥有一个指针,指向SSDT中包含由ntoskrnl.exe实现核心系统服务的相应部分,我们可以把它理解成SSDT在内核中的数据实体。

SSDT的数据结构定义如下:


typedef struct _tagSSDT {
    PVOID pvSSDTBase;
    PVOID pvServiceCounterTable;
    ULONG ulNumberOfServices;
    PVOID pvParamTableBase;
} SSDT, *PSSDT; 

 

有了以上知识后我们就可以钩住SSDT来完成我们希望实现的功能,这里介绍一种隐藏进程的方法。但有一个问题出现了,我们要修改SSDT表,首先这个表必须是可写的,但在xp以后的系统中他都是只读的,我总结了三个办法来修改内存保护机制。这对以后的编程是很有用处的

   

1,更改注册表(要从起)

HKLM/SYSTEM/CurrentControlset/Control/Session Manger/

Memory Management/EnforceWriteProtection=0

HKLM/SYSTEM/CurrentControlset/Control/Session Manger/

Memory Management/DisablePagingExecutive=1

 

(这个方法我没有试验成功)这里只是列出作为一种方法

2,修改控制寄存器CR0 

wp位设置为0

__asm

{

push eax

mov eax,CR0

and eax,0FFFEFFFFh

mov CR0,eax

pop eax

}

 

如果恢复可以

__asm

{

push eax

move eax,CR0

or eax, NOT 0FFFEFFFFh

mov CR0,eax

pop eax

}

 

 

 

 

 

 

这个方法希望以后再编程的时候尽量少用点,因为它常常会带来一些问题。

 

3.利用内存描述符表,描述一块可写内存,本人强烈推荐此办法,有什么好处,你会在编程中体会到的。

以下是MDLntddk.h的定义

typedef struct _MDL {

    struct _MDL *Next;

    CSHORT Size;

    CSHORT MdlFlags;

    struct _EPROCESS *Process;

    PVOID MappedSystemVa;

    PVOID StartVa;

    ULONG ByteCount;

    ULONG ByteOffset;

} MDL, *PMDL;

 

#define MDL_MAPPED_TO_SYSTEM_VA     0x0001

#define MDL_PAGES_LOCKED            0x0002

#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004

#define MDL_ALLOCATED_FIXED_SIZE    0x0008

#define MDL_PARTIAL                 0x0010

#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020

#define MDL_IO_PAGE_READ            0x0040

#define MDL_WRITE_OPERATION         0x0080

#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100

#define MDL_FREE_EXTRA_PTES         0x0200

#define MDL_IO_SPACE                0x0800

#define MDL_NETWORK_HEADER          0x1000

#define MDL_MAPPING_CAN_FAIL        0x2000

#define MDL_ALLOCATED_MUST_SUCCEED  0x4000

MDL包含了该内存区域的起始地址,拥有者进程,字节数量以及标志;

 

这里以修改SSDT为例,以下代码先声明一个结构,该结构用了转换由内核导出的KeServiceDescriptorTable变量的类型。调用MmCreateMdl时要KeServiceDescriptorTable的基地址和他包含的项数,从中我们得到MDL所描述的内存区域与大小。然后从不分页内存中创建MDL.我们将MDL标志与MDL_MAPPED_TO_SYSTEM_VA进行或操作,以便允许写入一块内存区域。然后就可以调用MmMapLockedPage来锁定内存中的MDL页。

 

 

 

 

 

 

 

 

 

好了,有了以上准备工作我们可以钩住SSDT表了,为了方便这里给出了四个宏定义

 

//获得SSDT基址宏

#define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]

 

//获得函数在SSDT中的索引宏

#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)

 

//调换自己的hook函数与原系统函数的地址

#define HOOK_SYSCALL(_Function, _Hook, _Orig )  _Orig = (PVOID) InterlockedExchange( (PLONG)  &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)

 

//卸载hook函数

#define UNHOOK_SYSCALL(_Function, _Hook, _Orig )  InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)

 

有点乱了吧:我来总结一下

如果要隐藏进程我们可以

首先:突破SSDT的内存保护,如上所用的MDL方法

然后:实现自己的NewZwQuerySystemInformation函数,过滤掉以某些字符开头的进程
  
最后:用上面介绍的宏来交换ZwQuerySystemInformation与我们自己的New*函数
      
这里我们要首先声明进程和线程结构:

struct _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientIs;
KPRIORITY Priority;
KPRIORITY BasePriority;
ULONG ContextSwitchCount;
ULONG ThreadState;
KWAIT_REASON WaitReason;
};

struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters; 
 

struct _SYSTEM_THREADS Threads[1];
};

下面给出一个完整的代码,它的出自于rootkit.com,我这里只详细讲解以下链表的操作,完整的代码附在文后:

if(SystemInformationClass == 5)

 

 

转自:  http://bbs.pusc.cn/topic.aspx?topicid=7864&boardid=8

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vt hook ssdt是一种技术,用于在操作系统内核中拦截和修改系统服务调用。通过Vt(Virtualization Technology)技术,可以在操作系统运行时对系统服务进行动态修改,从而实现对系统行为的控制和修改。 以下是一个Vt hook ssdt的示例代码: ```c #include <ntddk.h> ULONG_PTR OriginalServiceAddress = 0; NTSTATUS HookServiceCall(IN PUNICODE_STRING ServiceName, IN ULONG_PTR NewServiceAddress) { NTSTATUS status = STATUS_SUCCESS; ULONG_PTR serviceAddress = 0; // 获取系统服务地址 status = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &serviceAddress); if (status != STATUS_INFO_LENGTH_MISMATCH) { return status; } // 遍历系统服务表 PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, serviceAddress, 'hook'); if (pModuleInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } status = ZwQuerySystemInformation(SystemModuleInformation, pModuleInfo, serviceAddress, NULL); if (!NT_SUCCESS(status)) { ExFreePoolWithTag(pModuleInfo, 'hook'); return status; } for (ULONG i = 0; i < pModuleInfo->NumberOfModules; i++) { PRTL_PROCESS_MODULES pModule = &pModuleInfo->Modules[i]; // 找到ntoskrnl.exe模块 if (wcsstr(pModule->FullPathName, L"ntoskrnl.exe") != NULL) { // 计算SSDT地址 ULONG_PTR ssdtAddress = (ULONG_PTR)pModule->ImageBase + pModule->OffsetToFileName; // 保存原始的系统服务地址 OriginalServiceAddress = *(ULONG_PTR*)ssdtAddress; // 修改系统服务地址为新的地址 *(ULONG_PTR*)ssdtAddress = NewServiceAddress; break; } } ExFreePoolWithTag(pModuleInfo, 'hook'); return status; } NTSTATUS UnhookServiceCall() { if (OriginalServiceAddress != 0) { // 恢复原始的系统服务地址 *(ULONG_PTR*)ssdtAddress = OriginalServiceAddress; OriginalServiceAddress = 0; } return STATUS_SUCCESS; } ``` 以上代码是一个简单的Vt hook ssdt的示例,通过调用`HookServiceCall`函数可以将指定的系统服务地址替换为新的地址,通过调用`UnhookServiceCall`函数可以恢复原始的系统服务地址。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值