Skip to main content
some fixes
Source Link
nbro
  • 41.4k
  • 12
  • 114
  • 205

First things first  : forget about headers. allAll information about headers and separate C file areis gone.

You're missing some crucial step, imhoIMHO.

  • Compilation create one or multiple object file (.o) then the linker create an executable.

    Compilation creates one or multiple object files (.o), then the linker creates an executable.

  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.

    You should work from disassembled code. The disassembler works pretty well with some exceptions (self-modifying code, self-extracting executable, various obfuscation techniques) and will take care of a lot of work for you: identifying various sections, finding functions, guessing (fairly accurately) the calling convention.

  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").

    Then the compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so I'll just replace them with "xor eax, eax").

  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).

    Sometimes, it's fine, and sometimes it produces unreadable C code (vectorizations that have no C equivalent and will be decompiled into hundreds of lines of intrinsic instead of a fine readable "for" loop).

  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

    I'm not done yet. You also have exceptions and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, etc.

goingGoing down (from human readable-readable to binary) is fairlyrelatively easy compared to going up (decompilation) because so much information is lost during the compilation process.

myMy best bet would be to have a bunch of disassembled function produced by a disassemberdisassembler and produce an LLVM intermediate representation using your IAAI, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.cclang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, iI think it's meaningless to make an AI read C code for the purpose of decompilation  : the information is lost forever.

Commercial and Open/Free decompilerdecompilers do not produce C code either, they produce some kind of pseudo-C full of errorerrors, missing code, or code even less readable than the ASM.

produceproduces this  :

andAnd this is the disassmbleddisassembled version  :

plusPlus a few thousands linelines of assembly that are unrelated to your code but are needed to make the program work.

youYou can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

  1. you can do static analysis (very easy in this case, but absurdly difficult in the real world)

  2. or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

First things first  : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation  : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

produce this  :

and this is the disassmbled version  :

plus a few thousands line of assembly that are unrelated to your code but are needed to make the program work.

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

First things first: forget about headers. All information about headers and separate C file is gone.

You're missing some crucial step, IMHO.

  • Compilation creates one or multiple object files (.o), then the linker creates an executable.

  • You should work from disassembled code. The disassembler works pretty well with some exceptions (self-modifying code, self-extracting executable, various obfuscation techniques) and will take care of a lot of work for you: identifying various sections, finding functions, guessing (fairly accurately) the calling convention.

  • Then the compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so I'll just replace them with "xor eax, eax").

  • Sometimes, it's fine, and sometimes it produces unreadable C code (vectorizations that have no C equivalent and will be decompiled into hundreds of lines of intrinsic instead of a fine readable "for" loop).

  • I'm not done yet. You also have exceptions and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, etc.

Going down (from human-readable to binary) is relatively easy compared to going up (decompilation) because so much information is lost during the compilation process.

My best bet would be to have a bunch of disassembled function produced by a disassembler and produce an LLVM intermediate representation using your AI, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, I think it's meaningless to make an AI read C code for the purpose of decompilation: the information is lost forever.

Commercial and Open/Free decompilers do not produce C code either, they produce some kind of pseudo-C full of errors, missing code, or code even less readable than the ASM.

produces this:

And this is the disassembled version:

Plus a few thousands lines of assembly that are unrelated to your code but are needed to make the program work.

You can't go back and you have no way of knowing this is the exact same code unless

  1. you can do static analysis (very easy in this case, but absurdly difficult in the real world)

  2. or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

added 111 characters in body
Source Link
ker2x
  • 163
  • 7

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, const char **argv, const char **envp)
{
     return -559038737;
}

and this is the disassmbled version :

mov     eax, 0DEADBEEFh
retn

plus a few thousands line of assembly that are unrelated to your code but are needed to make the program work.

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, const char **argv, const char **envp)
{
     return -559038737;
}

and this is the disassmbled version :

mov     eax, 0DEADBEEFh
retn

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, const char **argv, const char **envp)
{
     return -559038737;
}

and this is the disassmbled version :

mov     eax, 0DEADBEEFh
retn

plus a few thousands line of assembly that are unrelated to your code but are needed to make the program work.

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

added 101 characters in body
Source Link
ker2x
  • 163
  • 7

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, char**const argvchar **argv, char**const envp)char **envp)
{ 
     return 0xDEADBEEF-559038737;
}

and this is the disassmbled version :

mov     eax, 0DEADBEEFh
retn

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, char** argv, char** envp) { 
    return 0xDEADBEEF
}

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

Software Reverse Engineering is one of my hobby.

First things first : forget about headers. all information about headers and separate C file are gone.

You're missing some crucial step, imho.

  • Compilation create one or multiple object file (.o) then the linker create an executable.
  • You should work from disassembled code. Disassembler works pretty well with some exception (self modifying code, self extracting executable, various obfuscation techniques) and will take care of a lot of work for you : identifying various sections, finding functions, guessing (fairly accurately) the calling convention.
  • then compiler optimization will mess up your code in a very clever way and some part of your original code will never ever be seen again (hey, look, your 200 lines of bugged code always return 0 anyway so i'll just replace them with "xor eax, eax").
  • sometimes it's fine, and sometimes it produce unreadable C code (vectorization that have no C equivalent and will be decompiled into hundreds of line of intrinsic instead of a fine readable "for" loop).
  • i'm not done yet. you also have exception and interrupts, structures, union, function pointers, function inlining, threading, system call and signals, loop unrolling, ...

going down (from human readable to binary) is fairly easy compared to going up (decompilation) because so much information is lost during the compilation process.

my best bet would be to have a bunch of disassembled function produced by a disassember and produce an LLVM intermediate representation using your IA, then compare it with the LLVM IR produced by Clang (clang -S -emit-llvm foo.c).

An infinite quantity of C code can produce the exact same code. Therefore, i think it's meaningless to make an AI read C code for the purpose of decompilation : the information is lost forever.

Commercial and Open/Free decompiler do not produce C code either, they produce some kind of pseudo-C full of error, missing code, or code even less readable than the ASM.

The following code :

int main() {
    int toto = 0x0000BEEF;
    int titi = 0xDEAD0000;
    toto = toto | titi;
    return toto;
}

produce this :

int __cdecl main(int argc, const char **argv, const char **envp)
{
     return -559038737;
}

and this is the disassmbled version :

mov     eax, 0DEADBEEFh
retn

you can't go back and you have no way of knowing this is the exact same code unless 1) you can do static analysis (very easy in this case but absurdly difficult in the real world) 2) or compare the IR or ASM produced by both code with the same compiler with the same options on the same architecture and operating system.

added 967 characters in body
Source Link
ker2x
  • 163
  • 7
Loading
Source Link
ker2x
  • 163
  • 7
Loading