技术宅的结界

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

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1694|回复: 1
收起左侧

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

[复制链接]

1041

主题

2316

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
217
威望
288 点
宅币
17974 个
贡献
36246 次
宅之契约
0 份
在线时间
1721 小时
注册时间
2014-1-26
发表于 2016-2-1 00:58:43 | 显示全部楼层 |阅读模式

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

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

x
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寄存器里面去,看看它会不会立即生效。
[C] 纯文本查看 复制代码
#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的运行按钮,它直接弹出了这样的窗口:
vs.png
图2:VS捕获中断

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

20160201014922.png
图4

看样子不带调试器的话这个中断没人管,它就死了。
那这样,我们自己捕获它的中断试试。
[C] 纯文本查看 复制代码
#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;
}
上面的代码运行了以后,它应该能在触发单步中断的时候,显示一个“单步”。
20160201015249.png
图5

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

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

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

本帖被以下淘专辑推荐:

34

主题

140

帖子

7132

积分

用户组: 管理员

UID
77
精华
11
威望
112 点
宅币
6584 个
贡献
129 次
宅之契约
0 份
在线时间
106 小时
注册时间
2014-2-22
发表于 2016-2-1 10:46:40 | 显示全部楼层
其实还可以用SetContextThread来设置TF位。不过必须在线程运行的时候。
如果线程处于system("pause");之后,设置context会失败。

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2019-7-17 03:07 , Processed in 0.101014 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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