找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5656|回复: 1

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

[复制链接]
发表于 2016-2-1 00:58:43 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

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

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

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

  14.         _asm
  15.         {
  16.                 mov eax,_eflags;
  17.                 or eax,0x100;//设置tf位
  18.                 push eax;
  19.                 popfd;//然后将其装入eflags寄存器

  20.                 //跑几个指令
  21.                 nop;
  22.                 xchg eax,edx;
  23.                 xchg edx,eax;

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

  30.         //暂停
  31.         _getch();
  32.         return 0;
  33. }
复制代码
我直接点了VS的运行按钮,它直接弹出了这样的窗口:
vs.png
图2:VS捕获中断

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

20160201014922.png
图4

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

  5. LONG WINAPI __int3catch(struct _EXCEPTION_POINTERS*pExceptionInfo)
  6. {
  7.         switch(pExceptionInfo->ExceptionRecord->ExceptionCode)
  8.         {
  9.         case EXCEPTION_SINGLE_STEP:
  10.                 printf("单步\n");
  11.                 break;
  12.         default:
  13.                 return EXCEPTION_CONTINUE_SEARCH;
  14.         }
  15.         
  16.         return EXCEPTION_CONTINUE_EXECUTION;
  17. }

  18. int main(int argc,char**argv)
  19. {
  20.         uint32_t _eflags;

  21.         SetErrorMode(SEM_FAILCRITICALERRORS);
  22.         SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)__int3catch);

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

  30.         _asm
  31.         {
  32.                 mov eax,_eflags;
  33.                 or eax,0x100;//设置tf位
  34.                 push eax;
  35.                 popfd;//然后将其装入eflags寄存器

  36.                 //跑几个指令
  37.                 nop;
  38.                 xchg eax,edx;
  39.                 xchg edx,eax;

  40.                 //取回eflags的值,显示一下。
  41.                 pushfd;
  42.                 pop eax;
  43.                 mov _eflags,eax;
  44.         };
  45.         printf("EFLAGS = 0x%.8X\n",_eflags);
  46.         
  47.         //暂停
  48.         _getch();
  49.         return 0;
  50. }
复制代码
上面的代码运行了以后,它应该能在触发单步中断的时候,显示一个“单步”。
20160201015249.png
图5

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

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

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

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2016-2-1 10:46:40 | 显示全部楼层
其实还可以用SetContextThread来设置TF位。不过必须在线程运行的时候。
如果线程处于system("pause");之后,设置context会失败。
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-12-22 16:48 , Processed in 0.038784 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表