首页
论坛
课程
招聘
[原创]Hide your DebugPort in ring0
2009-1-26 11:00 65444

[原创]Hide your DebugPort in ring0

2009-1-26 11:00
65444
一个程序被ring3调试器调试时,有很多的调试特征可以检测,本论坛也有专门的帖子详细论述,但有个非常根本的标志ring3也是可以检测的比较少人提及,那就是_EPROCESS.DebugPort。DebugPort对于ring3调试器来说非常重要,没有它正常的ring3调试是无法进行的。当然要检测这个标志的前提是程序能够读取ring0内存,在XP以上的系统有个非常简单的方法就是使用ZwSystemDebugControl的SysDbgReadVirtualMemory方法,我们也可以map physicalmemory来操作。检测DebugPort之前首先要得到进程的eprocess地址,这可以通过ZwQuerySystemInformation的SystemHandleInformation方法得到,也可以直接搜索ring0内存的eprocess结构。

   对于ring3直接检测DebugPort,我们可以通过禁止该进程访问ring0内存来对付,但是目标一旦使用驱动来检测,那么就非常麻烦了。下面介绍一种隐藏_EPROCESS.DebugPort的方法,这种方法的基本思路是,将一个正常被调试进程的DebugPort置零后,修正所有受影响的函数,使我们的调试器能够正常进行。这些函数如下:
    PspCreateProcess、MmCreatePeb 进程创建,设置DebugPort
          DbgkCreateThread 发送线程或者进程创建的调试信息
          KiDispatchException、DbgkForwardException和DbgkpQueueMessage 发送异常调试信息
          PspExitThread、DbgkExitThread和DbgkExitProcess 发送线程退出、进程退出的调试信息
          DbgkMapViewOfSection和DbgkUnMapViewOfSection 发送映像装载卸载调试信息
          DbgkpSetProcessDebugObject和DbgkpMarkProcessPeb 当调试器附加进程时设置DebugPort   

     这类函数非常多的,如果都HOOK处理的话,那太恐怖了,这里使用一个非常简单的办法:偷龙转凤。我们看系统访问DebugPort的代码都是这样的(XP)
         8b89bc000000    mov     ecx,dword ptr [ecx+0BCh] //0BCh就是DebugPort的偏移

     我们可以把DebugPort转移到_EPROCESS的另外一个地方,比如我使用+0x070 CreateTime,它是纪录进程创建时间的,进程创建之后,在进程退出前系统不会对它进行任何修改,而且我们修改后对系统或进程没有任何影响。这样我们可以把上面的代码改成这样
         8b8970000000    mov     ecx,dword ptr [ecx+070h] //指向CreateTime,实际的DebugPort已经被移到这里
     只需要修改一个字节,非常简单。

     当然这种方法最麻烦的地方就是定位引用到DebugPort的函数(本人仅仅针对不同的XP系统制作特征码都累到吐血),这些函数都是不导出的,如果是特定系统,最简单的方法就是WinDbg->uf *** 直接找地址硬编码,只需要几分钟时间。
   
BOOLEAN InitHackAddress()
{
	_SEH_TRY
	{
		g_KernelBase = GetKernelBaseAndSize( &g_KernelSize );			
		g_HackPspCreateProcess = SearchHackPspCreateProcess( &g_NopPspCreateProcess.Address );
		g_HackKiDispatchException = SearchKiDispatchException( g_KernelBase,g_KernelSize );	
		g_HackDbgkpQueueMessage = SearchDbgkpQueueMessage( g_KernelBase,g_KernelSize );
		g_HackDbgkCreateThread = SearchDbgkCreateThread( g_KernelBase,g_KernelSize );		
		SearchDbgkNotifyRoutine( g_KernelBase,g_KernelSize );
		g_HackPspExitThread = SearchPspExitThread();	
		g_HackMmCreatePeb = SearchMmCreatePeb( g_HackPspCreateProcess );
		SearchDbgkpSetProcessDebugObject( g_KernelBase,g_KernelSize );
		if( g_HackDbgkpSetProcessDebugObject[3] )
			g_HackDbgkpMarkProcessPeb = SearchDbgkpMarkProcessPeb( g_HackDbgkpSetProcessDebugObject[3] ) ;
		
		if( g_NopPspCreateProcess.Address != 0 ){
			RtlFillMemory( g_NopPspCreateProcess.NopCode,sizeof(g_NopPspCreateProcess.NopCode),0x90 ); 
			g_NopPspCreateProcess.Size = 9;
			RtlCopyMemory( g_NopPspCreateProcess.OrigCode,(PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.Size );
		}

		if( g_NopDbgkForwardException.Address != 0 ){			
			RtlFillMemory( g_NopDbgkForwardException.NopCode,sizeof(g_NopDbgkForwardException.NopCode),0x90 );
			RtlCopyMemory( g_NopDbgkForwardException.OrigCode,(PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.Size );
		}

		if( g_NopDbgkExitThread.Address != 0 ){			
			RtlFillMemory( g_NopDbgkExitThread.NopCode,sizeof(g_NopDbgkExitThread.NopCode),0x90 );
			RtlCopyMemory( g_NopDbgkExitThread.OrigCode,(PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.Size );
		}

		if( g_NopDbgkExitProcess.Address != 0 ){
			RtlFillMemory( g_NopDbgkExitProcess.NopCode,sizeof(g_NopDbgkExitProcess.NopCode),0x90 );
			RtlCopyMemory( g_NopDbgkExitProcess.OrigCode,(PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.Size );
		}

		if( g_NopDbgkMapViewOfSection.Address != 0){
			RtlFillMemory( g_NopDbgkMapViewOfSection.NopCode,sizeof(g_NopDbgkMapViewOfSection.NopCode),0x90 );
			RtlCopyMemory( g_NopDbgkMapViewOfSection.OrigCode,(PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.Size );
		}

		if( g_NopDbgkUnMapViewOfSection.Address != 0 ){
			RtlFillMemory( g_NopDbgkUnMapViewOfSection.NopCode,sizeof(g_NopDbgkUnMapViewOfSection.NopCode),0x90 );
			RtlCopyMemory( g_NopDbgkUnMapViewOfSection.OrigCode,(PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.Size );
		}	   
		
		
	}
	_SEH_HANDLER
	{		
		DbgPrint( "InitHackAddress Exception!\n" );
	}

	return ( g_HackPspCreateProcess != 0 &&
		     g_HackKiDispatchException != 0 &&
			 g_HackDbgkForwardException != 0 &&
			 g_HackDbgkpQueueMessage != 0 && 
			 g_NopPspCreateProcess.Address != 0 &&
			 g_NopDbgkForwardException.Address != 0 &&
			 g_HackDbgkCreateThread != 0 &&
			 g_HackDbgkExitThread != 0 &&
			 g_NopDbgkExitThread.Address != 0 &&
			 g_HackDbgkExitProcess != 0 &&
			 g_NopDbgkExitProcess.Address != 0 &&
			 g_HackDbgkMapViewOfSection != 0 &&
			 g_NopDbgkMapViewOfSection.Address != 0 &&
			 g_HackDbgkUnMapViewOfSection != 0 &&
			 g_NopDbgkUnMapViewOfSection.Address != 0 &&
			 g_HackPspExitThread != 0 &&
			 g_HackMmCreatePeb != 0 &&
			 g_HackDbgkpSetProcessDebugObject[0] != 0 &&
			 g_HackDbgkpSetProcessDebugObject[1] != 0 &&
			 g_HackDbgkpSetProcessDebugObject[2] != 0 &&
			 g_HackDbgkpSetProcessDebugObject[3] != 0 &&
			 g_HackDbgkpMarkProcessPeb != 0 );
}

//修改已经运行进程的DebugPort位置
BOOLEAN ChangeProcessDebugPort( BOOLEAN Hide )
{
	ULONG eProcess = (ULONG)PsInitialSystemProcess;
	PLIST_ENTRY pListHead,pListWalk;
	ULONG DebugObject;

	if( !g_bIsAddressStartup ){
		return FALSE;
	}

	pListHead = (PLIST_ENTRY)( eProcess + ACTIVE_LINKS_OFFSET );
	pListWalk = pListHead;

	_SEH_TRY
	{		
		do{
			if( pListWalk == NULL || eProcess == 0 )
				break;

			eProcess = ( (ULONG)pListWalk - ACTIVE_LINKS_OFFSET );		

			if( Hide ){

				DebugObject = *(ULONG*)( eProcess + DEBUG_PORT_OFFSET );
				*(ULONG*)( eProcess + CREATE_TIME_OFFSET ) = DebugObject;
				*(ULONG*)( eProcess + DEBUG_PORT_OFFSET ) = 0;

			}else{

				DebugObject = *(ULONG*)( eProcess + CREATE_TIME_OFFSET );
				*(ULONG*)( eProcess + DEBUG_PORT_OFFSET ) = DebugObject;
			}

			pListWalk = pListWalk->Flink;

		}while( pListWalk != pListHead );

	}
	_SEH_HANDLER
	{
		DbgPrint( "ChangeProcessDebugPort exception!\n" );
	}
	
	return TRUE;
}

BOOLEAN ModifyDebugFunction()
{
	if( !g_bIsAddressStartup ){
		return FALSE;
	}

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

	*(ULONG*)g_HackPspCreateProcess = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackKiDispatchException = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkForwardException = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpQueueMessage = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkCreateThread = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkExitThread = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkExitProcess = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkMapViewOfSection = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkUnMapViewOfSection = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackPspExitThread = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpMarkProcessPeb = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackMmCreatePeb = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = CREATE_TIME_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = CREATE_TIME_OFFSET;
		

	RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.NopCode,g_NopPspCreateProcess.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.NopCode,g_NopDbgkForwardException.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.NopCode,g_NopDbgkExitThread.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.NopCode,g_NopDbgkExitProcess.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.NopCode,g_NopDbgkMapViewOfSection.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.NopCode,g_NopDbgkUnMapViewOfSection.Size );

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

	return TRUE;

}

BOOLEAN WriteBackDebugFunction()
{
	if( !g_bIsAddressStartup ){
		return FALSE;
	}

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

	*(ULONG*)g_HackPspCreateProcess = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackKiDispatchException = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkForwardException = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpQueueMessage = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkCreateThread = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkExitThread = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkExitProcess = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkMapViewOfSection = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkUnMapViewOfSection = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackPspExitThread = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpMarkProcessPeb = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackMmCreatePeb = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = DEBUG_PORT_OFFSET;
	*(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = DEBUG_PORT_OFFSET;

	RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.OrigCode,g_NopPspCreateProcess.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.OrigCode,g_NopDbgkForwardException.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.OrigCode,g_NopDbgkExitThread.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.OrigCode,g_NopDbgkExitProcess.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.OrigCode,g_NopDbgkMapViewOfSection.Size );
	RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.OrigCode,g_NopDbgkUnMapViewOfSection.Size );

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

	return TRUE;
}


     我想再啰嗦一下,上面代码大家看到很多函数有个NOPCode,这个实际上是对付线程PS_CROSS_THREAD_FLAGS_HIDEFROMDBG的,NOP掉相关地方后,就算线程被设置为ThreadHideFromDebugger也无法阻挡调试器接收调试信息。

****************************************************************
祝大家牛年技术越来越牛,愿我等小菜在牛年可以望得见牛人项背!

[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班

收藏
点赞0
打赏
分享
最新回复 (67)
雪    币: 200
活跃值: 活跃值 (18)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
shoooo 活跃值 16 2009-1-26 11:31
2
0
膜拜
123456
雪    币: 250
活跃值: 活跃值 (74)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
cxhcxh 活跃值 3 2009-1-26 11:53
3
0
接着膜拜。。。。。。
雪    币: 212
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
安摧 活跃值 2 2009-1-26 12:30
4
0
吃饭喝酒,膜拜!!!
雪    币: 7137
活跃值: 活跃值 (3461)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 22 2009-1-26 12:31
5
0
新年快乐
膜拜
123456
雪    币: 7137
活跃值: 活跃值 (3461)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 22 2009-1-26 12:32
6
0
LZ还不如用源码重新编译一个内核。。。。
雪    币: 4517
活跃值: 活跃值 (1662)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
小菜鸟一 活跃值 2009-1-26 12:59
7
0
跟着大牛膜拜  
雪    币: 419
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fixfix 活跃值 2009-1-26 13:26
8
0
跟着膜拜。。。。。。。
雪    币: 38
活跃值: 活跃值 (16)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2009-1-26 14:50
9
0


同#6

这样弄还不如hook缺页异常然后把eprocess弄成invalid然后自己处理,krnl读就把debugport弄成真正的port,其他读就弄成NULL
雪    币: 326
活跃值: 活跃值 (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 活跃值 4 2009-1-26 16:04
10
0
高人高语..............高来高去
雪    币: 235
活跃值: 活跃值 (10)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
火影 活跃值 11 2009-1-26 20:51
11
0
tessafe.sys是不是也是这样做的
雪    币: 285
活跃值: 活跃值 (11)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
小娃崽 活跃值 13 2009-1-26 21:28
12
0
太深奥了.......
雪    币: 308
活跃值: 活跃值 (77)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
zhuwg 活跃值 11 2009-1-26 23:22
13
0
新年快乐
膜拜

可以试试nooby修改的内核
或者拿wrk编译1个也行。。毕竟方便。直接改1下offset

炉子的缺页打法也不错
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
NaX 活跃值 2009-1-27 11:09
14
0
楼上说的重新编译内核的搞笑了,兼容性有很大问题,可行性不大。内存欺骗也是可以的,但我想有个更加有效方便的办法,内核中访问EPROCESS是通过ETHREAD->Process,所以我们直接枚举目标进程的ETHREAD修改Process项指向我们的新结构,那么就无声无息实现相应的功能。最大的缺点是,如果目标保护驱动也是这么ETHREAD->Process访问EPROCESS那么功夫就白费了。
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
wanmeicpl 活跃值 2009-1-27 13:06
15
0
好深奥 顶一个
雪    币: 38
活跃值: 活跃值 (16)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2009-1-27 17:40
16
0
我也觉得重编译个内核最好

当然改ethread->process也是很不错的方法
雪    币: 432
活跃值: 活跃值 (1046)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
xss 活跃值 4 2009-1-27 22:22
17
0
真的很深奥啊!
雪    币: 208
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
绣绣 活跃值 2009-1-28 21:01
18
0
强顶,不得不顶啊
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
栋城 活跃值 2009-1-28 23:39
19
0
如果写呢,也会处理吗?
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
栋城 活跃值 2009-1-29 18:52
20
0
试验通过,不过这里(DbgkpQueueMessage )有时候会蓝
雪    币: 419
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fixfix 活跃值 2009-2-1 15:28
21
0
LZ的 发个 BIN 出来 看看

我这怎么不行哦
雪    币: 245
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
心驰神野 活跃值 2009-2-1 21:07
22
0
谢谢分享,努力学习中~
雪    币: 246
活跃值: 活跃值 (11)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
Isaiah 活跃值 10 2009-2-2 10:09
23
0
估计tersafe又要进化了。
雪    币: 1470
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
bithaha 活跃值 5 2009-2-2 10:33
24
0
高人啊 学习了
雪    币: 1470
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
bithaha 活跃值 5 2009-2-2 10:34
25
0
汗12345
游客
登录 | 注册 方可回帖
返回