【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 其实还可以用SetContextThread来设置TF位。不过必须在线程运行的时候。
如果线程处于system("pause");之后,设置context会失败。
页:
[1]