VC 6 C++ 异常处理,nTryBlocks=0,pTryBlockMap=0,如何?为什么?

逆向工程 反编译 C++ 调用栈
2021-07-08 02:38:08

我正在尝试反编译一个旧的二进制文件(大约 20 岁)。

该程序使用异常。

我找到了一些 FuncInfo 但它们不包含任何 pTryBlockMap 并且 nTryBlocks 为 0。

我在 VC6 编译器上尝试了很多选项,但我无法得到这个结果。

堆栈看起来不像常规堆栈:

...
SEH handler
scope table
Try Level
saved EBP
return address

但它看起来像:

...
SEH handler
Try level
return address

您知道如何实现这一目标以及为什么会这样吗?

SEH 处理程序是:

MOV        EAX,DAT_00412c90
JMP        ___CxxFrameHandler

FuncInfo@00412c90

19930520
00000005
00412cb0
00000000
00000000
00000000
00000000
00000000
2个回答

实际上这是很明显的 - 我只是没有阅读 C++ 标准并且正在编写throw()规范,认为它会允许所有异常 - 结果却恰恰相反。

是的,这个throw函数规范是导致那些具有多个 Unwind 条目的零 TryBlockMap 的原因。这是一个 VC++ 6.0(及更高版本)可编译示例(查看 的拆卸f):

#include <stdio.h>

struct B {
    int a, b;
};

struct B1 {
    B1() {};
    B1(const B1& tmp) {
        a1 = tmp.a1;
        printf("B1::B1 copy constr\n");
    }
    ~B1() {
        printf("~B1()\n");
    }
    int a1, b1;
};

struct A : B, B1 {
    int b, c;
};

struct A f() throw(int) {
    struct A tmp;
    return tmp;
}

int main() {
    f();
}

有两个展开条目。在这种情况下,棘手的部分throw是没有将规范添加到函数的类型中,因此即使您有调试符号 (PDB) - 您仍然会碰到墙壁。

编辑:实际上,上面的示例不适用于较新版本的 MSVC - 如果您想在那里执行此操作,则需要添加一个try-catch封装f()调用的

另外,class A和它所有的父母都是一个测试用例的另外一个问题,如果你想了解更多,但否则我不认为这个确切的结构是必要的触发FunctionInfo的产生与零个TryBlocks与C ++异常的话题。f我认为只是需要发生一些事情

即使函数中没有 try/catch 块,编译器也可能生成 FunctionInfo 结构并注册 C++EH 处理程序(例如__CxxFrameHandler)。这是必要的,例如,销毁超出范围的自动(堆栈分配)C++ 对象,或清理构造函数中部分构造的对象。在这样的函数中,将没有 try 块,但您应该看到非零pUnwindMap指针指向包含对堆栈对象的析构函数的调用的展开 funclet,例如:

lea ecx, [ebp-2Ch]
jmp std::string::~string