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
#include
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