网页资讯视频图片知道文库贴吧地图采购
进入贴吧全吧搜索

 
 
 
日一二三四五六
       
       
       
       
       
       

签到排名:今日本吧第个签到,

本吧因你更精彩,明天继续来努力!

本吧签到人数:0

一键签到
成为超级会员,使用一键签到
一键签到
本月漏签0次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行补签。
连续签到:天  累计签到:天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
05月16日漏签0天
c语言吧 关注:801,906贴子:4,377,746
  • 看贴

  • 图片

  • 吧主推荐

  • 视频

  • 游戏

  • 1 2 3 下一页 尾页
  • 42回复贴,共3页
  • ,跳到 页  
<<返回c语言吧
>0< 加载中...

让tcc用上SEH

  • 取消只看楼主
  • 收藏

  • 回复
  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
本文将简要地介绍SEH最基础的内容以及tcc自带的SEH,并用宏为tcc实现一个类VC的try-except扩展(基于帧的异常处理程序模型)。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
## 前言
1.本文不建议初学者阅读。
2.本文将涉及少量汇编,请确保你已经了解x86汇编的基础知识。
3.确保你已经了解VC的try-except扩展。
tcc(Tiny C Compiler)是Fabrice Bellard大佬用C和汇编实现的一个的C语言编译器,可自举并支持部分GCC扩展。并不建议在学习或生产中使用tcc,因为它有着较多缺陷,譬如switch的作用域处理有问题,asm的"=q"未正常弹栈,vm类型大小分析错误,等等。同时,它对C99的支持也不完善,它并不支持C99的复数类型。比起一个工具,它更像是一个玩具。
本文使用的tcc版本:tcc version 0.9.27 (i386 Windows)。


2026-05-16 09:16:10
广告
不感兴趣
开通SVIP免广告
  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
## SEH简介
在开始之前,我们先简要地介绍一下SEH。SEH,顾名思义,就是结构化异常处理(Structured Exception Handling)。
当线程出现错误时,操作系统调用用户定义的回调函数来处理这个错误。回调函数长这样:

record包含了异常的一些重要信息,包括异常代码、异常标志、发生异常时的地址,等等。
frame非常重要,我们稍后提及,并围绕它逐步深入。
context包含了异常发生时寄存器的值。
dispatcher会涉及比较深入的内容,由于本文仅介绍SEH最基础的内容,所以我们忽略它,把它当做保留参数即可。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
当线程发生错误时,操作系统如何知道去哪调用异常处理程序呢?答案是线程信息块(TIB, Thread Information Block)。TIB的第一个成员指向了一个EXCEPTION_REGISTRATION结构,它的定义如下:

注意,这里是有语法错误的。但为了简洁起见,我们忽略这个错误。后同不述。
prev事实上还有写成next的,但是我更倾向于写成prev。它指向了前一个EXCEPTION_REGISTRATION。事实上,这是一个链表,每一个结点都给出了一个异常处理程序,而TIB的第一个成员便是这个链表的头结点。
handler是异常处理程序,每个函数可以根据异常代码选择是否处理该异常,并通过返回值来指示接下来应当进行何种操作。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
在winnt.h中,这个结构被称为EXCEPTION_REGISTRATION_RECORD。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
那么我们又应当在哪里去找TIB呢?答案是FS段寄存器,fs段的首地址即存放着该线程的TIB,因此fs:[0]便是EXCEPTION_REGISTARTION的地址。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
虽说我们不怎么涉及展开(Unwinding),但是若不介绍似乎又有些缺憾,这里非常简要地介绍一下:
我们知道,异常发生时,操作系统遍历EXCEPTION_REGISTARTION结构链表,直到有一个函数处理了这个异常。此时,操作系统再次遍历链表,并将ExceptionRecord中的异常标志设置为EH_UNWINDING。它为异常处理程序提供清理的机会。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
好了,说了这么多,相信读者已经差不多头晕了。但事实上,这只是SEH中最基础的内容,本文还有相当多的细节未提及,但我们先放下它,因为这些内容已经足够阅读本文了。


2026-05-16 09:10:10
广告
不感兴趣
开通SVIP免广告
  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
## 使用tcc自带的SEH
众所周知,tcc确实已经为我们提供了简单的SEH支持。tcc提供了一个__TRY__宏,它被定义在_mingw.h。它为我们构造的try-except块长这样:

这个宏被用于tcc的start函数(即在调用main之前的thunk函数),包括_tstart、_twinstart以及对应的run版本。
细心的读者可能就会发现了,是的,它与VC6的start函数的try-except块神似。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
但是有些人就会说了,要是每个try-except都长一样的话那也没啥用啊。是的,tcc事实上还提供了两个宏,见excpt.h。其中,`__try1`宏用于构造异常处理帧,而`__except1`宏用于移除异常处理帧。我们来看一下这两个宏:


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
我们解释一下:


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
比较搞笑的是,当你使用__except1时会报错:error: invalid clobber register '%eax'。这是因为tcc不支持这种写法,所以得把%eax的%给去掉。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
好了,现在我们可以自己写一个函数,用__try1注册异常处理程序,并用__except1卸载,我们写一个简单的demo:

运行结果如下:

在这个demo里,由于scanf中故意没写取址符,因此在尝试向0地址写入内容时会触发一个EXCEPTION_ACCESS_VIOLATION异常,被我们的异常处理程序捕捉,打印提示信息后继续让其他处理程序去处理异常。


  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
我们还可以用这两个宏来做一些更有趣的事情,比如实现一个简单的反调试手段:通过设置TF来让程序产生单步断点,在产生单步异常后,我们用异常处理程序处理异常发生地址的内容来实现代码的动态加解密。
如果诸位吃饱了撑着可以尝试一下我写的一个简单的注册机demo,源代码和解析会放在文章的最后。
网址:网页链接
密码:1234


2026-05-16 09:04:10
广告
不感兴趣
开通SVIP免广告
  • Dangfer
  • 小吧主
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
## 扩展SEH
也许有人会说,SEH的作用实在有限啊,这样怎么实现try-except?事实上这是因为基本的SEH包含的信息太少了,我们只需扩展一下EXCEPTION_REGISTRATION结构,便能做很多事情了。接下来让我们扩展这个结构并实现类VC的try-except扩展。


登录百度账号

扫二维码下载贴吧客户端

下载贴吧APP
看高清直播、视频!
  • 贴吧页面意见反馈
  • 违规贴吧举报反馈通道
  • 贴吧违规信息处理公示
  • 1 2 3 下一页 尾页
  • 42回复贴,共3页
  • ,跳到 页  
<<返回c语言吧
分享到:
©2026 Baidu贴吧协议|隐私政策|吧主制度|意见反馈|网络谣言警示