2

I'm trying to decompile an old binary (about 20 year old).

The program uses exceptions.

I found some FuncInfo but they do not contain any pTryBlockMap and nTryBlocks is 0.

I've tried many options on the VC6 compiler but I could not get this result.

The stack doesn't look like a regular stack:

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

But it looks like:

...
SEH handler
Try level
return address

Do you have any idea how to achieve this and why it would have been like that ?

SEH Handler is :

MOV        EAX,DAT_00412c90
JMP        ___CxxFrameHandler

FuncInfo@00412c90

19930520
00000005
00412cb0
00000000
00000000
00000000
00000000
00000000
2
  • What is the SEH handler called? Do you have a link to the binary?
    – Igor Skochinsky
    Jan 16, 2020 at 21:59
  • @Igor Skochinsky Sorry, I can't provide a link to the binary.
    – picryott
    Jan 16, 2020 at 22:08

2 Answers 2

0

Even when there are no try/catch blocks in a function, the compiler may generate a FunctionInfo structure and register a C++EH handler (such as __CxxFrameHandler). This is necessary, for example, to destruct automatic (stack-allocated) C++ objects going out of scope, or cleaning up a partially constructed object in a constructor. In such functions there will be no try blocks but you should see non-zero pUnwindMap with pointers to unwind funclets containing calls to destructors of stack objects, i.e. something like:

lea ecx, [ebp-2Ch]
jmp std::string::~string
1
  • That's it. Thank you. And the difference in the stack seems to be an optimization option for the compiler (/Ox).
    – picryott
    Jan 18, 2020 at 11:50
1

Actually it was so obvious - I just haven't read the C++ standard and was writing throw() specification thinking it would allow all exceptions - instead it turned out it was the exact opposite.

And yes this throw function specification is what is causing those zero TryBlockMap with more than one Unwind entries. Here is a VC++ 6.0 (and later) compilable example (view dissasembly of 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();
}

With two unwind entries. The tricky part in that scenario is that throw specification is not added to the type of the function so even if you have debug symbols (PDB) - you still will have your head banging against the wall.

EDIT: Actually the above example won't work for newer versions of MSVC - if you want to do it there you would need to add a try - catch block encapsulating the f() call.

Also the class A and all of it's parents were a test case for another question related to the topic of C++ exception if you want to learn more but otherwise I don't think this exact structure is necessary to trigger the generation of FunctionInfo with zero TryBlocks. There just need to be something going on in f I think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.