INT3断点

INT3断点是利用0Xcc指令实现的,cpu在执行0xcc指令时会引发断点异常调试器会捕捉这个异常。

INT3断点引发的异常属于陷阱型异常,在执行完0xcc指令后eip指向下一条指令。但是系统对int3有特殊处理,当异常第一次分发时如果调试器没有处理那么第二次异常分发之前系统会令eip-1。

下面写个调试程序来看一下。

#include <Windows.h>
#include <iostream>using namespace std;
int flag = 0; //标志是第一次断点异常,还是第二次断点异常
int main()
{
char a[256] = {0};
cout<<"请输入需要调试的目标程序的路径:";
cin>>a;
PROCESS_INFORMATION pi; //接受新进程的一些有关信息
STARTUPINFO si; //指定新进程的主窗体如何显示
DEBUG_EVENT devent; //消息事件
CONTEXT stContext; //线程信息块 GetStartupInfo(&si); CreateProcessA(
a,
NULL,
NULL,
NULL,
FALSE, // 不可继承
DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS, // 调试模式启动
NULL,
NULL,
&si,
&pi );
cout<<"创建进程成功"<<endl; while(TRUE)
{
if(WaitForDebugEvent(&devent, INFINITE))
{
switch(devent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch(devent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT: //断点异常 if(devent.u.Exception.dwFirstChance == 1) //第一次异常分发
{
cout<<"第一次异常。 ";
cout<<"eip:";
stContext.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &stContext);
int n1 = GetLastError();
cout<<stContext.Eip<<endl;
flag = 1;
}
if(devent.u.Exception.dwFirstChance == 0) //第二次异常分发
{
cout<<"第二次异常。 ";
cout<<"eip:";
GetThreadContext(pi.hThread, &stContext);
cout<<stContext.Eip<<endl;
flag = 0;
}
break;
}
break;
} }
if(flag == 1) //如果是第一次碰见int3断点异常,我们不处理他,让他直接继续进行第二次异常分发
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
else //如果是第二次碰见int3断点异常或者是其他调试事件我们直接返回让程序继续运行
{
flag = 0;
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);
}
}
return 0;
}

将一个不存在异常处理的程序第一条指令变为int3指令。

用上方程序作为例子进行调试,因为我们在第二次异常分发的时候返回DBG_CONTINUE来让系统认为我们处理了异常所以eip又会指向int3指令处,至此以后一直循环产生异常

OD中对int3的处理

我们把刚才的例子程序在od中运行并设置int3异常不交给程序处理



运行程序发现eip指向int3的下一条指令,这说明OD在int3异常第一次分发时因为eip指向了下一条指令,这时od返回DBG_CONTINUE意思是异常不交给程序处理直接返回。

如果设置忽略int3异常,即int3异常传递给程序处理。

因为程序没有异常处理所以第一次异常传给程序后,异常又会进行二次分发。我们运行程序发现eip依然指向int3指令处,继续运行发现程序依然指向int3处,这说明od默认第二次异常返回DBG_CONTINUE然后一直循环产生int异常(和我们文章开始写的那个调试程序一样)。

如果第二次异常时od没有返回DBG_CONTINUE来向系统说明异常已处理,而返回DBG_EXCEPTION_NOT_HANDLED的话异常将不会继续分发,程序将会被终止运行。(异常传到顶层异常处理处,执行了默认的异常处理函数结束运行)

我们把文章开始的调试器修改一下,把让第二次异常处理时返回DBG_EXCEPTION_NOT_HANDLED。


if(flag == 1) //如果是第一次碰见int3断点异常,我们不处理他,让他直接继续进行第二次异常分发
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
else //如果是第二次碰见int3断点异常或者是其他调试事件我们直接返回让程序继续运行
{
flag = 0;
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
}

再次拿原来的那个程序当例子进行调试,我们发现在第二次异常调试器返回DBG_EXCEPTION_NOT_HANDLED后调试程序结束运行。

开始调试前

开始调试后,异常第二次分发后异常没有继续分发,并且程序结束运行

关于调试器中int3断点引发异常的思考的更多相关文章

  1. ssis package 在调试状态中设置断点,程序 不进入断点 的解决方案

    原文:ssis package 在调试状态中设置断点,程序 不进入断点 的解决方案 针对 SSIS intergation 项目 > 属性 > Debug >Run64bITRunt ...

  2. 在Visual Studio调试器中显示Unreal的数据类型的值

    转自:https://blog.csdn.net/witton/article/details/5977766 在Unreal引擎中大量使用了自定义的数据类型如:FName,FString,TArra ...

  3. 用DebuggerDisplay在Visual Studio的调试器中定制类的显示方式

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:用DebuggerDisplay在Visual Studio的调试器中定制类的显示方式.

  4. 在VisualStudio调试器中使用内存窗口和查看内存分布

    调试模式下内存窗口的使用 在调试期间,"内存"窗口显示应用使用的内存空间.调试器窗口(如"监视"."自动"."局部变量" ...

  5. 在 Visual Studio 调试器中指定符号 (.pdb) 和源文件

    查找并指定符号文件和源文件:指定符号加载行为.使用符号和源服务器上:加载符号自动或在要求.   内容 查找符号 (.pdb) 文件 查找源文件   查找符号 (.pdb) 文件 说明 在之前的 Vis ...

  6. @清晰掉 GDB调试器中的战斗机

    GDB 的命令很多,本文不会全部介绍,仅会介绍一些最常用的.在介绍之前,先介绍GDB中的一个非常有用的功能:补齐功能.它就如同Linux下SHELL中的命令补齐一样.当你输入一个命令的前几个字符,然后 ...

  7. 自定义Visual Studio调试器中的对象显示方式

    你有没有盯着调试器窗口中的对象,并希望你可以通过其他类型的东西来查看这些对象?我当然有!扩展项目以确定每个人的身份可能会非常快速.理想情况下,通过特定的属性值快速定位它们会很棒.对我们来说幸运的是,V ...

  8. 在Chrome调试器中引入jQuery

    在Console中输入以下代码并回车,Console显示"function (a,b){return new m.fn.init(a,b)}"说明导入成功,就可以在Console中 ...

  9. xcode 调试器 LLDB

    本文完全转载,转载地址:点击这里 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThisThing); 或者跳过一个函 ...

随机推荐

  1. Django之cookie 与session组件

    一.会话跟踪技术 1.1 什么是会话跟踪 我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如你给10086打个电话,你就是客户端,而 ...

  2. Elasticsearch 单字符串多字段查询

    前言 有些时候,我们搜索的时候,只会提供一个输入框,但是会查询相关的多个字段,典型的如Google搜索,我们该如何用 Elasticsearch 如何实现呢? 实例 从单字符串查询的实例说起 创建测试 ...

  3. Linux 切换用户提示Permission denied

    在使用 su - hdfs 切换到 hdfs 用户时提示 su: Permission denied,但是密码确认是没错的. 找到文件 /etc/pam.d/su,注释掉 auth required ...

  4. MySQL在线DDL工具 gh-ost

    一.简介 gh-ost基于 golang 语言,是 github 开源的一个 DDL 工具,是 GitHub's Online Schema Transmogrifier/Transfigurator ...

  5. python2文件开头两行

    #!/usr/bin/python  或者  #!/usr/bin/env python 告诉操作系统python位置 # -*- coding:utf-8 -*- 设置文件编码为utf-8  (默认 ...

  6. 【linux】系统编程-4-共享内存

    目录 前言 6. 共享内存 6.1 概念 6.2 操作函数 6.2.1 shmget() 6.2.2 shmat() 6.2.3 shmdt() 6.2.4 shmctl() 6.3 例子 参考: 前 ...

  7. 删除文件--rm

    rm file         删除文件 rm -r dir      删除指定文件夹及文件夹下的所有内容 rm -rf dir     强制删除指定文件夹及文件夹下的所有内容

  8. 生产中常用的du命令

    1. 介绍 du是用来查看文件或目录所占用磁盘空间的大小 du [-abcDhHklmsSx] [-L <符号连接>][-X <文件>][--block-size][--exc ...

  9. Apache Hudi核心概念一网打尽

    1. 场景 https://hudi.apache.org/docs/use_cases.html 近实时写入 减少碎片化工具的使用 CDC 增量导入 RDBMS 数据 限制小文件的大小和数量 近实时 ...

  10. 将Java编译为本地代码

    将Java编译为本地代码 通常Java程序的执行流程为:将Java代码编译为Byte Code(字节码),然后JVM执行引擎执行编译好的Byte Code.这是一种中间语言的特性,它的好处就是可以做到 ...