0xAA55 发表于 2016-2-1 00:58:43

【C】测试Windows下直接将eflags的tf位设置为1会咋样?

eflags的tf位,就是Trap Flag,陷阱标识,是用于给调试器进行单步调试用的。这个位设置为1以后,CPU每执行一条指令,都会产生单步中断。不同于int3(也就是“烫”)的断点中断,这个是硬断,中断号是int 1。
古代的debug.exe的t命令就是用这种方式进行单步调试的。当然还有p命令,这个p命令就是用“烫”来中断的了。
单步位是第8bit,我们看看intel的文档就知道了。

图1:Intel文档片段(1986)

首先我写下这样的代码。大家可以看到我直接读取了eflags的值,然后将第8个bit设置为1,并将其塞回eflags寄存器里面去,看看它会不会立即生效。#include<stdint.h>
#include<stdio.h>
#include<conio.h>

int main(int argc,char**argv)
{
      uint32_t _eflags;
      _asm
      {
                pushfd;
                pop eax;
                mov _eflags,eax;//取得旧的eflags的值
      };
      printf("EFLAGS = 0x%.8X\n",_eflags);

      _asm
      {
                mov eax,_eflags;
                or eax,0x100;//设置tf位
                push eax;
                popfd;//然后将其装入eflags寄存器

                //跑几个指令
                nop;
                xchg eax,edx;
                xchg edx,eax;

                //取回eflags的值,显示一下。
                pushfd;
                pop eax;
                mov _eflags,eax;
      };
      printf("EFLAGS = 0x%.8X\n",_eflags);

      //暂停
      _getch();
      return 0;
}我直接点了VS的运行按钮,它直接弹出了这样的窗口:

图2:VS捕获中断

喜闻乐见,它中断了,然后被VS捕获了。
那么我们让它不带调试器,自己单独运行,看是什么效果。

图3


图4

看样子不带调试器的话这个中断没人管,它就死了。
那这样,我们自己捕获它的中断试试。#include<stdint.h>
#include<stdio.h>
#include<conio.h>
#include<Windows.h>

LONG WINAPI __int3catch(struct _EXCEPTION_POINTERS*pExceptionInfo)
{
      switch(pExceptionInfo->ExceptionRecord->ExceptionCode)
      {
      case EXCEPTION_SINGLE_STEP:
                printf("单步\n");
                break;
      default:
                return EXCEPTION_CONTINUE_SEARCH;
      }
      
      return EXCEPTION_CONTINUE_EXECUTION;
}

int main(int argc,char**argv)
{
      uint32_t _eflags;

      SetErrorMode(SEM_FAILCRITICALERRORS);
      SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)__int3catch);

      _asm
      {
                pushfd;
                pop eax;
                mov _eflags,eax;//取得旧的eflags的值
      };
      printf("EFLAGS = 0x%.8X\n",_eflags);

      _asm
      {
                mov eax,_eflags;
                or eax,0x100;//设置tf位
                push eax;
                popfd;//然后将其装入eflags寄存器

                //跑几个指令
                nop;
                xchg eax,edx;
                xchg edx,eax;

                //取回eflags的值,显示一下。
                pushfd;
                pop eax;
                mov _eflags,eax;
      };
      printf("EFLAGS = 0x%.8X\n",_eflags);
      
      //暂停
      _getch();
      return 0;
}上面的代码运行了以后,它应该能在触发单步中断的时候,显示一个“单步”。

图5

还是会被VS捕获到。
然后我单独运行它(不附加调试器):

图6

它只显示了一个“单步”,并且事前事后显示的eflags数值没变。。估计是单步后,Windows对其进行了处理。Windows应该是确认没有单线程自己调试自己的情况的吧。。

参考资料:
https://en.wikipedia.org/wiki/Trap_flag

Golden Blonde 发表于 2016-2-1 10:46:40

其实还可以用SetContextThread来设置TF位。不过必须在线程运行的时候。
如果线程处于system("pause");之后,设置context会失败。
页: [1]
查看完整版本: 【C】测试Windows下直接将eflags的tf位设置为1会咋样?