windows内核木马

1Image Patches(映像补丁)

修改内核模块比如ntoskrnl.exendis.sysntfs.sys等的代码段

1.1、函数前导Hook

Intel架构下,控制转移指令有三种,分别是2字节的寄存器操作,5字节的相对偏移操作和6字节的内存操作。当然,我们有两种方式来实现这种inline hook

1)用Microsoftdetour

2)用一个长度反汇编引擎,字节构建

我自己实现过一个动态HOOK引擎,在我的即将推出的书<<网游外挂艺术大揭秘>>HOOK一节中有详细介绍。

现在的xp sp2vista为动态HOOK提供了更方便的方式,函数的前导是两个字节的no-op操作指令,比如mov ediedi

这样我们可以用一个两个字节的短相对jmp指令(0xEBXX)

1.2、禁用SeAccessCheck

 Greg Hoglund首次提出禁用ntSecAccessCheck,这样就能绕过对象的访问检测。虽然,不能执行特权指令,但是,能够使非特权用户访问和修改系统进程。

2Descriptor Tables(描述符表)

x86架构下有很多表供处理器访问:内存管理的GDT,中断分发的IDT.

                           OS用的SSDT

2.1 IDT

中断来自硬件或INT软指令。IDT包含256个描述符,这些描述符关联着256中断向量。每个IDT描述符可能是三种gate(任务门、中断门、陷阱门)之一,每种门代表着中断发生的时候,该怎么转,转哪的问题。

IDT的基地址和限长保存在idtr寄存器中,由lidt初始化。当前的idtr值可以由sidt读取。

每个IDT描述符占8字节大小:

dt>dt _KIDTENTRY

+0x000 Offset                  :Uint2B //例程入口点的低16BIT

+0x002 Selector              :Uint2B

+0x004 Access                :Uint2B

+0x006 ExtendedOffset :Uint2B  //例程入口点的高16BIT

 

//IDT HOOK

typedef struct _IDT
{
    USHORT Limit;
    PIDT_DESCRIPTOR Descriptors;

} IDT, *PIDT;

 

static NTSTATUS HookIdtEntry(
                         IN UCHAR DescriptorIndex,
                         IN ULONG_PTR NewHandler,
                        OUT PULONG_PTR OriginalH
{
                        PIDT_DESCRIPTOR Descriptor = NULL;
                        IDT Idt;
                        __asm sidt [Idt];
                        Descriptor = &Idt.Descriptors[DescriptorIndex];
                       *OriginalHandler =
                      (ULONG_PTR)(Descriptor->OffsetLow + Descriptor->OffsetHigh << 16);

                      Descriptor->OffsetLow =

                       (USHORT)(NewHandler & 0xffff);

                       Descriptor->OffsetHigh =

                       (USHORT)((NewHandler  >> 16) & 0xffff);

                       __asm lidt [Idt]

 

              return STATUS_SUCCESS;                 

}

当然,我们一可以构造整个IDT,然后用lidt来重置。

2.2 GDT/LDT

GDT/LDT存放段描述符,描述系统地址空间的一个view。当处理器将逻辑地址(Seg:Offset)转换为线性地址的时候,会用包含了BaseAddresslimitprivilege information etc的描述符。

段寄存器CS,DS,ES存放了段选择子,段选择子通过offset定位到GDT/LDT中对应得段描述符。

GDI/LDT中添加描述符,可以使ring3代码执行和访问ring0空间。

 

2.3 SSDT

SSDT由全局变量ntKeServiceDescriptoTable导出,windows支持动态注册新的系统调用ntKeAddSystemServiceTable

SSDT(Native and GDT),SSDT HOOK比较简单,就不多说了。我也曾用HOOK虚表的方式,替换过整个ssdt,没问题,这样的话,可以全部监控SYSTEM CALL,这个技术我觉得在网络安全行为分析模型中应该用的到。

 

2.4 Model -specific Registers

跟处理器模型相关的特定寄存器,未来的处理器分支不一定支持。

读写用rdmsrwrmsr

2.4.1 IA32_SYSENTER_EIP

Pentium II引入了支持用户态向内核态转换的强化机制,通过sysentersysexit两条指令实现。ring3要进ring0,执行sysenterring0要退回到ring3,执行sysexit

IA32_SYSENTER_CS(0x174)处理器设置内核CS

IA32_SYSENTER_EIP(0x176)切换之后,设置内核态要执行代码的入口

IA32_SYSENTER_ESP(0x175)指向内核态的栈

替换IA32_SYSENTER_EIP可以监控所有通过sysenter进入ring0的调用。

缺点:不是所有处理器支持MSR

kd> rdmsr 176
msr[176] = 00000000‘804de6f0
kd> u 00000000‘804de6f0
nt!KiFastCallEntry:   //KiFastCallEntry
这个符号内核未导出
804de6f0 b923000000 mov ecx,23h

 

2.4 Page Table Entries

保护模式下,线性地址转物理地址。PDE/PTE中的user/supervisor位为0ring0才能访问;否则,ring0/ring3都能访问。修改这个标志位以访问内核代码

 

2.5 函数指针

IRQL提升时候,HOOK函数不能放在分页内存中。

SharedUserData物理页同时映射到user mode(只读0x7ffe0000)kernel mode(读写0xffdf0000)。这里面可以保存少量的代码。

 

native dllntdll.dll,映射到所有进程,包括system进程,通过ntPspMapSystemDll

 

kd> !process 0 0 System

PROCESS 81291660 SessionId: none Cid: 0004

Peb: 00000000 ParentCid: 0000

DirBase: 00039000 ObjectTable: e1000a68

HandleCount: 256.

Image: System

kd> !process 81291660

PROCESS 81291660 SessionId: none Cid: 0004

Peb: 00000000 ParentCid: 0000

DirBase: 00039000 ObjectTable: e1000a68

HandleCount: 256.

Image: System

VadRoot 8128f288 Vads 4

...

kd> !vad 8128f288

VAD level start end commit

...

81207d98 ( 1) 7c900 7c9af 5 Mapped Exe

kd> dS poi(poi(81207d98+0x18)+0x24)+0x30

e13591a8 "/WINDOWS/system32/ntdll.dll"

 

2.5.1 KTHREAD’s SuspendApc

 

kd> dt -r1 _KTHREAD 80558c20

...

+0x16c SuspendApc : _KAPC

+0x000 Type : 18

+0x002 Size : 48

+0x004 Spare0 : 0

+0x008 Thread : 0x80558c20 _KTHREAD

+0x00c ApcListEntry : _LIST_ENTRY [ 0x0 - 0x0 ]

+0x014 KernelRoutine : 0x804fa8a1 nt!KiSuspendNop

+0x018 RundownRoutine : 0x805139ed nt!PopAttribNop

+0x01c NormalRoutine : 0x804fa881 nt!KiSuspendThread

+0x020 NormalContext : (null)

+0x024 SystemArgument1: (null)

+0x028 SystemArgument2: (null)

+0x02c ApcStateIndex : 0 ’’

+0x02d ApcMode : 0 ’’

+0x02e Inserted : 0 ’’

 

public _RkSetSuspendApcNormalRoutine@4

_RkSetSuspendApcNormalRoutine@4 proc

assume fs:nothing

push edi

push esi

; Grab the current thread pointer

xor ecx, ecx

inc ch

mov esi, fs:[ecx+24h]

; Grab KTHREAD.InitialStack

lea esi, [esi+18h]

lodsd

xchg esi, edi

; Find StackBase

repne scasd

; Set KTHREAD->SuspendApc.NormalRoutine

mov eax, [esp+0ch]

xchg eax, [edi+1ch]

pop esi

pop edi

ret

_RkSetSuspendApcNormalRoutine@4 endp

 

2.5.2 Object Type Initializers

OBJECT_TYPEOBJECT TYPE INITIALIZER

kd> dt nt!_OBJECT_TYPE_INITIALIZER

...

+0x02c DumpProcedure : Ptr32 //对应对象打开时候调用

+0x030 OpenProcedure : Ptr32

+0x034 CloseProcedure : Ptr32

+0x038 DeleteProcedure : Ptr32

+0x03c ParseProcedure : Ptr32

+0x040 SecurityProcedure : Ptr32

+0x044 QueryNameProcedure : Ptr32

+0x048 OkayToCloseProcedure : Ptr32

 

还有好多,暂不译了

 

你可能感兴趣的:(windows,object,Microsoft,null,hook,Descriptor)