Dophi's Technology Blog

享受知识共享带来的愉快

简单的反调试---使用IsDebuggerPresent API

在“汇编,让你更拉风”那片文章中我稍微提到了下fs:[0]这个玩意,这里再重复下,实际上fs:[0]这个地址保存着一个很重要的结构体,TEB ( Thread Evirment Block ) 线程块,SEH异常处理,线程的一些相关信息都和这个结构体紧紧相关,而我要说的IsDebuggerPresent实际上也是从这个结构体中获取信息来判断当前线程所在进程是否处于被调试状态,这实际上和TEB中的一个子结构PEB有关,这个api的效率很高,因为它的实现就像这样:

mov eax, fs:[30h]
mov eax, [eax+0Ch]  // 取fs段偏移0x30的值村放进eax,实际上偏移0x30就是PEB子结构的开始地址
mov eax, [eax+10h]  // 取到标示进程是否被调试的标志
变量

只是几句简单的语句,所以你可以在你要反调试的程序中每个一段时间调用一次这个函数来检测进程是否被调试了,但是调用这个api实在是不安全,因为很可能这个函数已经被hook了,你的调用结果将完全被hook这个函数的人控制了,然后我们可以进一步想,我们可以不通过调用这个函数来获取进程是否被调试的信息吗?当然可以,上面那段汇编代码实际上就能做到,但是别以为这样就安全了,调试者一样有办法,既然你都可以直接通过汇编代码来做,调试者当然也就可以,他可能会写出下面这样的代码来设置这个标志标量:

mov eax, fs:[30h]
mov eax, [eax+0Ch] 
mov [eax+10h], 0x0

这样即使你不调用他hook掉的IsDebuggerPresent,他一样可以让你获取到的东西无效。那么想想吧,我们的程序在开发期被调试器调试是很正常的,真正发布出去了如果被调试了,说明就有问题了,所以我们可以在发布版中这么做:那么调试者们上面的手段都会失效,我们可以每隔一段时间就判断一下那个标志变量的状态,如果是被调试,就直接退出程序。当然这样也不是就安全了,调试者可能会根据代码的特征找到你相关的代码,然后直接修改,为了防止调试者找到你的代码,你可以使用VMProtect技术,作用就是把你的代码弄的很乱,让人根本看不明白,这样一来,调试者可能得花上很长一段时间来跟踪你的代码了。

完毕!其实在IsDebuggerPresent这种ring3级别的函数上花多心思效果是不大的,真正要做到反调试得考虑在驱动层做手脚,这个就以后再说了。

PS:早上起来就写了这篇日志,早饭都没吃,大家不顶简直对不起我的肚子哈!

posted on 2009-01-10 11:09 dophi 阅读(3803) 评论(6)  编辑 收藏 引用

Feedback

# re: 简单的反调试---使用IsDebuggerPresent API 2009-01-10 13:18 小笨象

那我就顶一下吧  回复  更多评论   

# re: 简单的反调试---使用IsDebuggerPresent API 2009-01-10 14:37 Kevin Lynx

PEB结构是TEB结构的成员?
struct TEB
{
...
struct PEB
{
....
??

MSDN:
typedef struct _TEB{
BYTE Reserved1[1952];
PVOID TlsSlots[64];
...

typedef struct _PEB{
BYTE Reserved1[2];
BYTE BeingDebugger; //是有个标志标示进程是否被调试
...
从你的文章来看,PEB应该在TEB偏移0x30H字节的地方,但是从MSDN的TEB结构定义来看,PEB位于Reserved1[1952]中的某个位置?
  回复  更多评论   

# re: 简单的反调试---使用IsDebuggerPresent API 2009-01-10 17:53 dophi

@Kevin Lynx
由于我是凭记忆写的那段代码,现在看起来,的却写错了,实际上IsDebuggerPresent的汇编代码是这样的:
mov eax, dword ptr fs:[0x18]
mov eax, dword ptr [eax+0x30]
movzx eax, byte ptr [eax+0x02]

eax中保存的就是那个是否被调试的标志

实际上msdn中那样定义是一种兼容的做法,为了兼容不同系统版本的定义方式,如果没有记错的话,好像win98和win2000的偏移就不一样。而且你也能看出来msdn中给的结构体中的成员是一个很大的数组而已,根本看不出来有什么有意义的东西, 本来这个结构体就是没有公布出来的,不过微软的某位工程师把这个结构体公布出来过的,具体是怎么样的,我也不清楚了,反正是一个很长的结构体。

现在能确定的是,上面这段代码是正确的了,感谢kevin的纠错。
  回复  更多评论   

# re: 简单的反调试---使用IsDebuggerPresent API 2009-01-10 18:12 dophi

找到PEB的定义了,比较长,我直接转帖:
http://blog.donews.com/zwell/archive/2004/10/16/134681.aspx  回复  更多评论   

# re: 简单的反调试---使用IsDebuggerPresent API[未登录] 2009-01-13 21:27 cc


学习了,,,学习了,,,  回复  更多评论   

# re: 简单的反调试---使用IsDebuggerPresent API 2010-04-18 17:29 evilknight

7C8130A3 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
7C8130A9 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30]
7C8130AC 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]
7C8130B0 C3 RETN


自己用windbg看下结构体,教坏人!  回复  更多评论   



只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理