首页
论坛
课程
招聘
[原创]使用CloseHandle欺骗和对抗调试器
2010-12-30 14:54 6957

[原创]使用CloseHandle欺骗和对抗调试器

2010-12-30 14:54
6957
我最近调试程序才发觉,CloseHandle这个函数的一个怪异的行为。我突然想到可以利用这个行为来欺骗或者对抗调试器。
    这个怪异的行为是这样的,调用CloseHandle释放一个无效句柄,如果进程在调试器之外,那么函数返回FALSE,而GetLastError得到ERROR_INVALID_HANDLE;但是如果进程在调试器内,那么系统将抛出异常C0000008H。

一、首先说如何得到一个无效句柄呢?

方法一:一个句柄释放多次次
    这个方法看似没问题,但实际有很大的隐患。因为新创建的内核对象是总是寻找句柄表的空白记录,因此有可能存在已经释放过的句柄又被利用,而这时再次释放会很不安全。

方法二:硬编码一个足够大的句柄值
    用procexp.exe看一下就会发现进程里的句柄值很少大于1000h,因此赌一下也是可以的

方法三:释放一个不可关闭的句柄
   这个我认为是最安全的一种方法,首先自己随便调用一个CreateXXX得到一个句柄h1,再调用SetHandleInformation将句柄h1设为不可关闭的,最后调用CloseHandle释放它就行了

二、再说如何利用这个行为

方法一:利用SEH欺骗
     这样利用CloseHandle根据调试器抛出异常,就可以通过SEH使得程序内外有不同的行为

方法二:隐式调用CloseHandle引发调试异常
    关于方法范围比较广泛,大家八仙过海各显神通吧

偶然发现而已,文章发的比较匆忙,现在只是发现FindClose有相同的现象,我估计很多带Close字段都有这种现象,也不知道其它API是否有相似的现象,希望大家不吝指教。

[培训]12月3日2020京麒网络安全大会《物联网安全攻防实战》训练营,正在火热报名中!地点:北京 · 新云南皇冠假日酒店

收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 1891
活跃值: 活跃值 (25)
能力值: ( LV13,RANK:420 )
在线值:
发帖
回帖
粉丝
demoscene 活跃值 7 2010-12-30 15:16
2
0
我以前也试过,将一个句添加 HANDLE_FLAG_PROTECT_FROM_CLOSE 属性再关闭。不过有SOD在,这些小伎俩都没什么作用了
雪    币: 424
活跃值: 活跃值 (132)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
starrysky 活跃值 2010-12-30 15:26
3
0
from ob\Obclose.c
if (PreviousMode != KernelMode) {

                if ((NtGlobalFlag & ***_ENABLE_CLOSE_EXCEPTIONS) ||
                    (CurrentProcess->DebugPort != NULL) ||
                    (ObjectTable->DebugInfo != NULL)) {

                    if (!KeIsAttachedProcess()) {
                        return KeRaiseUserException (STATUS_INVALID_HANDLE);
                    } else {
                        return STATUS_INVALID_HANDLE;
                    }

                }
雪    币: 356
活跃值: 活跃值 (18)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
yangbostar 活跃值 4 2010-12-30 15:31
4
0
非常好,受教了
雪    币: 8658
活跃值: 活跃值 (322)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2010-12-30 17:35
5
0
忽略一切异常之后,还有什么能对抗?
雪    币: 78
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whypro 活跃值 2010-12-30 17:40
6
0
看不懂,过来膜拜!
雪    币: 356
活跃值: 活跃值 (18)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
yangbostar 活跃值 4 2010-12-30 17:41
7
0
有些壳就是靠SEH解密的,都忽略了,看你怎么解
雪    币: 1891
活跃值: 活跃值 (25)
能力值: ( LV13,RANK:420 )
在线值:
发帖
回帖
粉丝
demoscene 活跃值 7 2010-12-30 18:51
8
0
想靠CloseHandle异常来解密那应该是不可能的,因为在没有调试器的情况下,根本不会抛出异常。
你所说的靠SEH来解密的壳是指那些利用读写非法内存或者除零之类的异常吧,这些异常即使在OD里选择忽略了,handler依然会执行,只是没有通知你而已。所以不会有无法解密的情况。
雪    币: 356
活跃值: 活跃值 (18)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
yangbostar 活跃值 4 2010-12-30 18:54
9
0
壳利用这个跑飞了,这怎么办?是不是这样我也不太清楚。

偶,对不起,那里的“解”,我是说脱壳的意思
雪    币: 356
活跃值: 活跃值 (18)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
yangbostar 活跃值 4 2010-12-30 18:59
10
0
这个我知道,文章里开头不是写了嘛,我是说的是那些加密壳壳
雪    币: 8091
活跃值: 活跃值 (414)
能力值: ( LV15,RANK:1844 )
在线值:
发帖
回帖
粉丝
ccfer 活跃值 15 2010-12-30 20:00
11
0
放bin出来看看谁的调试器跑不了
雪    币: 765
活跃值: 活跃值 (90)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 17 2010-12-30 21:38
12
0
code from fengyue.sys

NTSTATUS 
Hooked_NtClose(	IN HANDLE Handle)
{
	NTSTATUS status;
	PVOID  pObject = NULL;

	if(!bInBlackListByEProcess(PsGetCurrentProcess()))	//不是黑名单
		return ((pfnNtClose)fiNtClose.uRealAddr)(Handle);

	if(NT_SUCCESS(ObReferenceObjectByHandle(Handle, GENERIC_READ, 0, KernelMode, &pObject, NULL)))
	{
		ObDereferenceObject(pObject);
		status = ((pfnNtClose)fiNtClose.uRealAddr)(Handle);
	}
	else
	{
		status = STATUS_INVALID_HANDLE;
	}
	return status;
}
雪    币: 695
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tokiii 活跃值 2010-12-30 22:12
13
0
求楼上代码。。
雪    币: 356
活跃值: 活跃值 (18)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
yangbostar 活跃值 4 2010-12-30 22:17
14
0
这个真是釜底抽薪
游客
登录 | 注册 方可回帖
返回