反汇编时如果遇到C++ SEH,会遇到如何快速还原程序流程的问题?
假设有如下代码,我们用VS 2015将其编译为release版本:crack5.exe
int main()
{
try
{
throw 3;//抛出3整形的异常
}
catch (int)
{
printf("%d\r\n", 3);
}
return 0;
}
一、要解决的问题
IDA静态分析crack5.exe
1)怎样找到SEH异常处理回调?
2)怎样找到正确的catch处理函数?
二、理解原理并实战
IDA打开crack5.exe,可以一眼找到SEH异常处理结构:_main_SEH
双击_main_SEH,可以看到结构体402548,__CxxFrameHandler3根据结构体402548对程序进行处理。
(1)原理介绍,上半部分表
注:图片是从别的地方拷贝的,个别字段名称与下面讲的有所不同,意义相同不影响理解。
下面我们来看看结构体 402548
stru_402548对应的为函数信息表FuncInfo。
struct FuncInfo {
DWORD magicNumber; // 编译器版本
int maxState; // 栈展开描述表中的入口数量
UnwindMapEntry* pUnwindMap; // 栈展开处理方法绑定表
DWORD nTryBlocks; // 函数中的 try 语句块数量
TryBlockMapEntry* pTryBlockMap; // try-catch 映射表
DWORD nIPMapEntries;
void* pIPtoStateMap;
ESTypeList* pESTypeList;
int EHFlags;
}
重要字段就是dwTryCount以及pTryBlockMap,我们说过一个函数可以有多个try,所以函数信息就记录了try的个数.以及每个try的try块结构,关于上面的成员,都是SEH的异常展开的.
pTryBlockMap对应为stru_40257C,点击如下所示
TryBlockMapEntry 的定义如下。一个try可以有多个catch,显然,try块信息表也要记录catch的个数。
如果存在多个catch,如何区分?需要查看 tryLow、tryHight、catchHigh进行比对,就是看作用域最终确定catch函数。
struct TryBlockMapEntry {
int tryLow;
int tryHigh; // this try {} covers states ranging from tryLow to tryHigh
int catchHigh; // highest state inside catch handlers of this try
int nCatches; // number of catch handlers
HandlerType* pHandlerArray; //catch handlers table
};
点击stru_402590,它为HandlerType结构,有时IDA识别为__msRttiDscr,两者相同。 可以看这个try由loc_401047进行处理,对应的数据项为addressOfHandler。
401047指向了sub_401080,做打印处理。
HandlerType的定义如下
struct HandlerType {
DWORD adjectives;
TypeDescriptor* pType;
int dispCatchObj;
void* addressOfHandler;
};
到这里,上半部分就看完了。
总结一下:对于上半部分,主要着重于函数信息表,try块信息表和catch信息表。顺藤摸瓜找到catch函数地址。
(2)原理介绍,下半部分表
下半部分用来快速定位异常由谁接收,哪个catch块处理。
实战演练
记得最开始C代码有一个throe吗?其位置就是抛出异常表的位置
首先,找到被抛异常的信息表
struct ThrowInfo {
DWORD attributes;
void (*pmfnUnwind)();
int (*pForwardCompat)();
CatchableTypeArray* pCatchableTypeArray;
};
接着,找到与之匹配的CatchableTypeArray。从中可以看到由1个匹配的CatchableTypes
struct CatchableTypeArray {
int nCatchableTypes; // number of entries in the following array
CatchableType* arrayOfCatchableTypes[0];
};
接着,找catch 这种异常的类型为int型。IDA显示为??_R0H@8
struct CatchableType {
DWORD properties;
TypeDescriptor* pType;
PMD thisDisplacement;
int sizeOrOffset;
void (*copyFunction)();
};
最后,选择??_R0H@8,按x,看到??_R0H@8类型被stru_402590交叉引用了
最终,异常被 loc_401047处理。