C++ 的 try throw catch 反汇编方法

C++代码中如果包括了 try - throw - catch ,分析起来很不方便,不容易搞懂.可惜我非要搞懂
一段这种代码,只好分析一下,简单笔记.

为了方便区分各部分,起它们起名叫TAG_1,TAG_2等等.

反汇编代码中,一个包含try throw catch的函数通常是这样的结构:
                push    ebp
                mov     ebp, esp
                push    0FFFFFFFFh
                push    offset TAG_2
                mov     eax, dword ptr fs:__except_list
                push    eax
                mov     dword ptr fs:__except_list, esp
                sub     esp, 20h
                push    ebx
                push    esi
......
                lea     ecx, [ebp+var_18]
                push    offset TAG_A
                push    ecx
                mov     [ebp+var_18], TAG_ThrowValue
                call    _CxxThrowException(x,x)
......


                mov     ecx, [ebp-0Ch]
                pop     edi
                pop     esi
                mov     dword ptr fs:__except_list, ecx
                pop     ebx
                mov     esp, ebp
                pop     ebp
                retn

上面的TAG_ThrowValue是throw的值,类型要看TAG_A
TAG_2是这么个东东:
TAG_2:
                mov     eax, offset TAG_3
                jmp     ___CxxFrameHandler
TAG_3是这么个东东:
TAG_3           dd 19930520h            ; 这叫 magic
                dd 4                    ; 这是 TAG_4 的数目
                dd offset TAG_4         
                dd 2                    ; 这是 TAG_5 的数目
                dd offset TAG_5
                dd 0
                dd 0
TAG_4是:
TAG_4           dd 0FFFFFFFFh
                dd 0
                dd 0FFFFFFFFh
                dd 0
                dd 0FFFFFFFFh
                dd 0
                dd 0FFFFFFFFh
                dd 0
TAG_5是:
TAG_5           dd 0
                dd 0
                dd 1
                dd 4
                dd offset TAG_6_first
                dd 2
                dd 2
                dd 3
                dd 4
                dd offset TAG_6_second
这里有两个 TAG_6 表示本函数中有两份 try-throw-catch
TAG_6是:
TAG_6_first     dd 0
                dd offset TAG_8_char    ;char `RTTI Type Descriptor'
                dd -13h
                dd offset TAG_7_catch_char
                dd 0
                dd offset TAG_8_int     ;int `RTTI Type Descriptor'
                dd -28h
                dd offset TAG_7_catch_int
                dd 1
                dd offset TAG_8_pchar   ;char * `RTTI Type Descriptor'
                dd -2Ch
                dd offset TAG_7_catch_pchar
                dd 0
                dd 0
                dd 0
                dd offset TAG_7_catch_all

TAG_7就是catch处理程序 label 了.
上面 TAG_7_catch_all 前面是3个 dd 0 表示它是 catch(...)

TAG_8是这样的:
TAG_8_char      dd offset const type_info::`vftable'
                dd 0
                db '.D',0
上面的".D"表示它的类型是 char,还有其它的类型:
        ".D"    char
        ".H"    int
        ".PAD"  char *
        ".PAX"  void *
        ".?AVmyexception@@"     class myexception
        ".PAVCException@@"      class CException *


TAG_A 是:
TAG_A           dd 0
                dd 0
                dd 0
                dd offset TAG_B
TAG_B 是:
TAG_B           dd    1
                dd offset TAG_C
TAG_C 是
TAG_C           dd 1                    
                dd offset TAG_8_char    ;char `RTTI Type Descriptor'
                dd 0
                dd 0FFFFFFFFh
                dd 0
                dd 1
                dd 0
以上是简单的分析.对于一般简单的try-throw-catch知道这些足够了.
下面进一步分析复杂一些的.如果对代码:
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
public:
  virtual const char* what() const
  {
    return "My exception happened";
  }
} ;

int kkmain () {
  try
  {
      myexception myex;
    throw myex;
  }
  catch (myexception& e)
  {
    cout << e.what() << endl;
  }
  return 0;
}
则它的 TAG_4 会变成
TAG_4           dd 0FFFFFFFFh   
                dd 0
                dd 0
                dd offset TAG_42
                dd 0FFFFFFFFh
                dd 0
上面的 TAG_42 是一个 label:
TAG_42:         lea     ecx, [ebp-20h]
                jmp     myexception::~myexception(void)
因为上面 throw 了一个class,这个class是需要析构的.这就是它的析构.
TAG_A 变成了;
TAG_A           dd 0
                dd offset myexception::~myexception(void)       ; 看来这里是throw对象的析构函数
                dd 0
                dd offset TAG_B
而TAG_B 变成了以下,看来不管有多少层父class都会在这里展开:
TAG_B           dd 2             
                dd offset TAG_C_me      ;__CT??_R0?AVmyexception@@@8??0myexception@@QAE@ABV0@@Z12
                dd offset TAG_C_parent  ;__CT??_R0?AVexception@@@8??0exception@@QAE@ABV0@@Z12
而 TAG_C 也复杂了:
TAG_C_me        dd 0
                dd offset TAG_8_myexcepton      ;myexception `RTTI Type Descriptor'
                dd 0
                dd 0FFFFFFFFh
                dd 0
                dd 0Ch
                dd offset myexception::myexception(myexception const &) ; 看来这里是我的构造函数

以上我尽我所能写了一些复杂的try throw catch,编译为OBJ,用 IDA 打开分析.可以对付一般的情况了.非
常可惜我正在研究的一个软件就不包括在这里,它的 TAG_3 是这样子的:
stru_45C2E0     dd 19930520h            ; Magic
                dd 14                   ; Count
                dd offset stru_45C2E0.Info; InfoPtr
                dd 0                    ; CountDtr
                dd 0                    ; DtrPtr
                dd 3 dup(0)             ; _unk
                dd -1                   ; Info.Id
                dd offset sub_453050    ; Info.Proc
                dd 0                    ; Info.Id
                dd offset sub_45305B    ; Info.Proc
                dd 1                    ; Info.Id
                dd offset sub_453066    ; Info.Proc
                dd 2                    ; Info.Id
                dd offset sub_453071    ; Info.Proc
                dd 3                    ; Info.Id
                dd offset sub_45307C    ; Info.Proc
                dd 4                    ; Info.Id
                dd offset sub_453087    ; Info.Proc
                dd 5                    ; Info.Id
                dd offset sub_453092    ; Info.Proc
                dd 6                    ; Info.Id
                dd offset sub_45309D    ; Info.Proc
                dd 5                    ; Info.Id
                dd offset sub_4530A5    ; Info.Proc
                dd 8                    ; Info.Id
                dd offset sub_4530B0    ; Info.Proc
                dd 5                    ; Info.Id
                dd offset sub_4530B8    ; Info.Proc
                dd 10                   ; Info.Id
                dd offset sub_4530C3    ; Info.Proc
                dd 5                    ; Info.Id
                dd offset sub_4530CB    ; Info.Proc
                dd 12                   ; Info.Id
                dd offset sub_4530D6    ; Info.Proc

不可理解.IDA 认识它,还知道它的结构叫 _msExcept :

00000000 _msExcept       struc ; (sizeof=0x20, variable size)
00000000 Magic           dd ?                    ; base 16
00000004 Count           dd ?                    ; base 10
00000008 InfoPtr         dd ?                    ; offset
0000000C CountDtr        dd ?                    ; base 10
00000010 DtrPtr          dd ?                    ; offset
00000014 _unk            dd 3 dup(?)
00000020 Info            _msExcInfo 0 dup(?)
00000020 _msExcept       ends

但我在网上搜索 _msExcept 没找到.什么样的代码才能产生这样的汇编输出呢?研究中...

我知道了!其实上面的一段应该这么理解
TAG_3:
stru_45C2E0     dd 19930520h            ; Magic
                dd 14                   ; Count
                dd offset stru_45C2E0.Info; InfoPtr 实际上这是指向 TAG_4
                dd 0                    ; CountDtr
                dd 0                    ; DtrPtr 这里是 TAG_5
                dd 3 dup(0)             ; _unk

有两个问题.一是它的 TAG_4 有很多项.这是因为这个函数有很多变量需要析构.TAG_4中
的各项就是它们的析构.一般情况下,TAG_4并不产生 C++ 代码.

第二是它的 TAG_5 怎么为空呢?分析表明,只要有一个 catch 就会有一个 TAG_5 项.没有
TAG_5 项只能有一个解释,就是它没有 catch 项!而try与catch是要配对的,没有 catch 
也就没有 try.就是说,这个函数没有 try 也没有 catch 只有 throw 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先关于 [评价可免费] 的严重声明: 一、评价=评论加评价(评星星); 二、评价必须是下载完了该资源后的评价,没下载就评论无效; 三、如果正确评价了,返还积分可能需要等等,系统需要反应下。呵呵 评论时记得要评分。然后会返回给你花费的分再加1分.理论上有十分就可以下载完所有的资源了。一般人我不告诉他。 MFC 程序逆向 – 消息篇(上) 作者:szdbg Email:szdbg@sina.com 前言: 记得前一段时间,我刚接触软件破解和逆向这一行时,对于一些软件不知从何处跟踪按钮消息,试了好多方法,就是断 不下来,在系统模块中经常转得晕头转向,而一无所获。 MFC 程序是一种常见类型的程序,我静下心来,潜心研究了一下MFC 消息流程。弄清原委之后,一切豁然开朗,发现跟 踪MFC 程序和消息处理原来是如此。。。,跟踪按钮事件处理也由此变得特别简单。 于是,我将这些研究整理成文,以备后忘。并希望大家有所帮助,失误之处,请高手指正。 的确, .Net之类的程序必定是大势所趋,不过,就目前来说,MFC程序在软件市场还是占有重要的一席之地,所以,了解它,对于逆向和破解此类程序还是很有必要的. MFC之所以显的复杂,就在于它隐藏了它的消息的处理机制,可以说, 程序员基本上不需要懂得它的消息处理过程,就可以写出一套满足应用的软件来.这有好有坏,好的是大大简化了程序员写程序的过程,坏的一方面是,给一般程序员留下了一个迷团: 我只知道这样做,而不知道为什么这样做.心里老是觉得不踏实.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值