od里看了下
IsDebuggerPresent的实现代码就三条指令
mov eax,dword ptr fs:[18h]
mov eax,dword ptr [eax+30h]
movzx eax,byte ptr [eax+2h]
也就是BYTE PTR [[fs:[18h]+30h]+2h](未声明均表示DWORD类型)的值就表示是否在调试环境中
问题1:用masm实现时发现,必须先assume fs:nothing
否侧就提示非法使用寄存器,为什么?
问题2:fs在我的机子中的值是03bh,为什么

代码:
fs:[00000018]=[7FFDD018]=7FFDD000
希望有达人解答

  • 标 题:答复
  • 作 者:轩辕小聪
  • 时 间:2009-04-14 14:06

对于Ring3的应用程序,fs:[0]的地址指向的是TEB结构,这个结构的开头是一个NT_TIB结构,NT_TIB结构的0x18偏移处是一个Self指针,指向这个结构自身,也就是指向TEB结构的开头。
TEB结构的0x30偏移是一个指向PEB的指针。PEB又是一个结构,这个结构的0x2偏移处是一个UChar,名叫BeingDebugged,当进程被调试时,此值为1,未被调试时此值为0

因此以下代码逐行执行后的结果:
mov eax,dword ptr fs:[18h];eax=TEB的指针
mov eax,dword ptr [eax+30h];eax=PEB的指针
movzx eax,byte ptr [eax+2h];eax=PEB.BeingDebugged(byte扩展为dword)

TEB和PEB结构的详细内容可以在windbg内核调试状态下使用dt _TEB、dt _PEB命令来察看。

MASM中默认是fs:error,也就是默认不能使用fs段寄存器,因此要在masm中使用它时必须先assume fs:nothing
fs是段寄存器,即保存段选择子,对应的地址通过GDT或LDT中的相应项目来决定其范围和使用权限等。

最后回到IsDebuggerPresent,它就是通过检查PEB中的BeingDebugged字段来确定进程是否处于被调试状态的,因此修改此字段可以直接影响此API的返回值。

以上内容在调试或者说软件加密与解密过程中是基本的常识。

  • 标 题:答复
  • 作 者:烁皓
  • 时 间:2009-04-14 15:11

问题1:MASM中默认是fs:error,也就是默认不能使用fs段寄存器,因此要在masm中使用它时必须先assume fs:nothing
问题2:大致是这样,段寄存器中的16位用来做索引信息,索引64位的段描述符。在GDT或LDT中得到段的起始地址。即你在od里看到03bh后面有一个32位7ffdf000(fff)。所以fs的基址就是7ffdf000,你可以去看看,7ffdf000处是一个指针,和你输入fs:[0]一样。

  • 标 题:答复
  • 作 者:wdsm
  • 时 间:2009-04-14 17:11

说说问题二吧,这里我用实例证明一下。

我这里gdtr=8003f00003ff,某个进程空间中ring 3下的fs=0038h。

08h用二进制表示为00000000 00111000,按照intel文档的说明,最低的2位表示将要访问的段的权限级为0,第3位这里是0,表示将要访问的段的段描述符从全局描述符表(即GDT)里面取得,剩下的高13位是所为索引值用的,这里是7。每个段描述符占8个字节,8003f000处存放有一个NULL描述符。
lkd>dd 8003f000+8*7
8003f038 f0000fff 7f40f3fd 0400ffff 0000f200

每个描述符8个字节,按照intel文档的说明,8003f038处的双字的高16位是段起始地址的低16位,8003f03c处双字的高8位是段起始地址的高8位,8003f03c处双字的低8位是段起始地址的中间的8位,综合起来就是7ffdf000。

验证一下。
lkd> dd 7ffdf000+18 l1
7ffdf018  7ffdf000