Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completely fails to decompile functions using RAII #41

Closed
0x0ACB opened this issue Dec 15, 2017 · 9 comments
Closed

Completely fails to decompile functions using RAII #41

0x0ACB opened this issue Dec 15, 2017 · 9 comments

Comments

@0x0ACB
Copy link

0x0ACB commented Dec 15, 2017

I have now tested both the 32bit and the 64bit precompiled versions on Windows 10 and it doesnt seem to work at all for functions using RAII. I have tested simple programs compiled with Visual Studio 12 and 14 in debug and release ,with and without pdbs and with and without the -k switch. It seems to be able to decompile most of the library functions which have been linked into the program. It also decompiles some of the user supplied functions.
But every function using RAII for C++ objects decompiles to basically this:

abort();
// UNREACHABLE

Atleast it seems like RAII is the cause. Since getters and simple calculations not involving any objects are decompiled just fine. Here are some examples from 2 programs i decompiled with pdb information.

Edit:
Might also be related to the security cookie check combined with constant propagation.

Edit 2:
The cookie seems the more likely culprit as all the function that check their stack cookie only call abort in the decompiled output and there is not a single call to the check function even though it has been decompiled.

@s3rvac
Copy link
Member

s3rvac commented Dec 17, 2017

Hi. Could you please provide the input binaries (+ PDBs when applicable) and decompile.sh parameters that you used for decompilation so we can verify this?

@0x0ACB
Copy link
Author

0x0ACB commented Dec 17, 2017

Sure here are both programs with their pdbs. for the Gw2MC.exe the code is also completely in the pastebin if you want to compile it differently. Commandlines used:

decompile.sh Gw2MC.exe
decompile.sh -p Gw2MC.pdb Gw2MC.exe
decompile.sh -p Gw2MC.pdb -k Gw2MC.exe

Same for the update-server. The result was always basically identically aside from the function names ofcourse.

@palant
Copy link
Contributor

palant commented Sep 7, 2018

For reference, I do have security cookie checks in the decompiler output, so it's not only that. So far all functions declared "unreachable" have been using security cookies however.

I tried running the decompiler without optimizations, while keeping unreachable functions and disabling removal of statically linked functions. None of these options solved the issue unfortunately.

@palant
Copy link
Contributor

palant commented Sep 10, 2018

Further investigation: the issue happens during bin2llvmir stage already. Tweaking the parameters revealed that the secure cookie isn't the culprit, it's rather this instruction which appears to cause trouble:

mov eax, dword ptr fs:[0]

This is related to exception handling, so it would appear that any function using try..catch would be affected.

@palant
Copy link
Contributor

palant commented Sep 10, 2018

Further playing with parameters revealed that the issue is triggered by multiple optimizations: -jump-threading, -instcombine, -simplifycfg. Editing retdec-config.py and removing these parameters from BIN2LLVMIR_LLVM_PASSES_ONLY and BIN2LLVMIR_PARAMS (note: some are listed there multiple times) makes sure the produced .ll file still has all the function bodies.

@palant
Copy link
Contributor

palant commented Sep 10, 2018

I could trace the issue back to this check. So LLVM considers fs:[0] to be a null pointer, so reading from it would raise an exception. That's why it marks this code as unreachable. Commenting out this check again results in the correct .ll file being generated, even with unchanged retdec-config.py.

@palant
Copy link
Contributor

palant commented Sep 10, 2018

On a deeper level, the issue appears to be this comment. While Capstone marks this particular instruction with "segment override," RetDec will ignore the flag and translate the operand into a plain pointer. So LLVM treating it like a null pointer is correct - trash in, trash out.

@PeterMatula
Copy link
Collaborator

Comment related to this: #391 (comment).

@PeterMatula
Copy link
Collaborator

Code from #391 was merged to master. This should hopefully fix the issue here. Unfortunately the link to sample you gave us is no longer working, and I probably deleted the file from my hard drive - I can't find it anywhere. If you are willing to send it to me again (sorry :-D) I can add it to our regression tests to make sure this is (and stays) fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants