3

I'm wondering if there's a way to compare source code to the disassembled assembly in IDA Pro? (e.g. I compile hello.c in Linux then open the binary in IDA Pro in OS X, and would like to compare the assembly with the source so make it easier to find out what's going on). Does such a feature exist?

ADDED From Comment: By the way, I forgot to mention, I am in OS-X and the binary was compiled by Lunux

5 Answers 5

3

You can compile your file with DWARF information in it, since IDA supports it:

DWARF in IDA

2

Not really. But Visual Studio for example has a debugger, that can directly point to the source (from where the problem occurs) if you start the debugger in the same instance where you loaded your solution. Also Visual Studio supports to output PDB files (and a MAP file, if needed) which would give you all function names, variables names, parameters, etc. This is helpful too when debugging in IDA.

You should find out if your compiler can also output a kind of 'debug' file which you can import in IDA Pro. If not, then it's not possible in this case.

1
  • I forgot to mention I'm in OS X and the binary was compiled in Linux.
    – trusktr
    May 17, 2014 at 11:09
2

I've done this while looking for IP theft before and while it's very unlikely that you will be able to recover a perfect 1 to 1 match there's still certain structures and flows that creep into functions that have been copied from elsewhere. It's very hard to read a piece of code and then copy it and not have the original ideas influence your design. You have a similar situation only that you're looking for matching functions in order to ease your reverse engineering.

This is what I would do:

  • Find the binaries I suspect contains the code I'm interested in identifying.
  • If I have reference source that I'm interested in looking for in the binaries:
    • Find out what compiler was used in order to build the suspect binaries.
    • Use the same compiler to compile the reference source. Now we have reference binaries and suspect binaries.
  • Once I have two binaries, reference and suspect I would run them through something that analyzes flow graphs and call graphis, such as BinDiff.
  • You then get a set of candidates that you have to go in and analyze more thoroughly.

I've successfully used this strategy to successfully identify and analyze similarities between software written in a native language and software written in a managed language. It's quite a powerful technique. If you're on a constrained budget and both reference and suspect binaries are targeting the same platform using the same compiler, you can build a FLIRT database from your reference binaries. This will likely miss a large number of good candidates though.

If you're not analyzing any binaries produced by someone else, just build your target with debug information and you'll get all the information you need, see DWARF if you're using GCC or PDB if you're using MSVC. Alternatively just tell the compiler to produce assembly output: GCC, MSVC.

2

if this is for learning puprose and you want to understand how is assembly generated for your source lines create an assembly listing every major compiler should have the option

for example with visual studio you can issue /FAcs switch to generate an assembly listing file with an extension .cod
the listing file will show how each line in your source has been transformed into assembly

comparesrc:\>dir /b
comparesrc.cpp

comparesrc:\>type comparesrc.cpp
#include <stdio.h>  // standard include file
int main (void)
{ // this line will become prolog
    printf("hello my dear source compare\n");  // see str in .data section
    puts("c");  // will put a char* with line break to console
    puts("om");
    puts("pare");
    int a,b,c,d;
    a = 2; b =3 ; c = 4;
    d = a+b-c;    // 2+3 -4 = 1
    printf("%d\n",d);  // should print 1
    d = (a*b)/c;  // 2*3 /4 = 6 /4  numerator = 1
    printf("%d\n",d);  // should printf 1
    d = (a*b)%c;   // 2 * 3 % 4 denominator = 2
    printf("%d\n",d);  // should print 2
    return 0;   // lets generate a cod file and see the assembly
}   // this line will get converted to epilog



comparesrc:\>cl /FAcs /nologo /Zi  comparesrc.cpp /link /RELEASE
comparesrc.cpp

comparesrc:\>type comparesrc.cod
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01


        TITLE   XXXX\comparesrc.cpp
        .686P
        .XMM
        include listing.inc
        .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

CONST   SEGMENT
$SG3850 DB      'hello my dear source compare', 0aH, 00H
        ORG $+2
$SG3851 DB      'c', 00H
        ORG $+2
$SG3852 DB      'om', 00H
        ORG $+1
$SG3853 DB      'pare', 00H
        ORG $+3
$SG3858 DB      '%d', 0aH, 00H
$SG3859 DB      '%d', 0aH, 00H
$SG3860 DB      '%d', 0aH, 00H
CONST   ENDS
PUBLIC  _main
EXTRN   _puts:PROC
EXTRN   _printf:PROC
; Function compile flags: /Odtp
; File xxx\comparesrc.cpp

_TEXT   SEGMENT
_c$ = -16                                               ; size = 4
_d$ = -12                                               ; size = 4
_b$ = -8                                                ; size = 4
_a$ = -4                                                ; size = 4
_main   PROC

; 3    : { // this line will become prolog

  00000 55               push    ebp
  00001 8b ec            mov     ebp, esp
  00003 83 ec 10         sub     esp, 16                        ; 00000010H

; 4    :     printf("hello my dear source compare\n");  // see str in .data sect
ion

  00006 68 00 00 00 00   push    OFFSET $SG3850
  0000b e8 00 00 00 00   call    _printf
  00010 83 c4 04         add     esp, 4

; 5    :     puts("c");  // will put a char* with line break to console

  00013 68 00 00 00 00   push    OFFSET $SG3851
  00018 e8 00 00 00 00   call    _puts
  0001d 83 c4 04         add     esp, 4

; 6    :     puts("om");

  00020 68 00 00 00 00   push    OFFSET $SG3852
  00025 e8 00 00 00 00   call    _puts
  0002a 83 c4 04         add     esp, 4

; 7    :     puts("pare");

  0002d 68 00 00 00 00   push    OFFSET $SG3853
  00032 e8 00 00 00 00   call    _puts
  00037 83 c4 04         add     esp, 4

; 8    :     int a,b,c,d;
; 9    :     a = 2; b =3 ; c = 4;

  0003a c7 45 fc 02 00
        00 00            mov     DWORD PTR _a$[ebp], 2
  00041 c7 45 f8 03 00
        00 00            mov     DWORD PTR _b$[ebp], 3
  00048 c7 45 f0 04 00
        00 00            mov     DWORD PTR _c$[ebp], 4

; 10   :     d = a+b-c;    // 2+3 -4 = 1

  0004f 8b 45 fc         mov     eax, DWORD PTR _a$[ebp]
  00052 03 45 f8         add     eax, DWORD PTR _b$[ebp]
  00055 2b 45 f0         sub     eax, DWORD PTR _c$[ebp]
  00058 89 45 f4         mov     DWORD PTR _d$[ebp], eax

; 11   :     printf("%d\n",d);  // should print 1

  0005b 8b 4d f4         mov     ecx, DWORD PTR _d$[ebp]
  0005e 51               push    ecx
  0005f 68 00 00 00 00   push    OFFSET $SG3858
  00064 e8 00 00 00 00   call    _printf
  00069 83 c4 08         add     esp, 8

; 12   :     d = (a*b)/c;  // 2*3 /4 = 6 /4  numerator = 1

  0006c 8b 45 fc         mov     eax, DWORD PTR _a$[ebp]
  0006f 0f af 45 f8      imul    eax, DWORD PTR _b$[ebp]
  00073 99               cdq
  00074 f7 7d f0         idiv    DWORD PTR _c$[ebp]
  00077 89 45 f4         mov     DWORD PTR _d$[ebp], eax

; 13   :     printf("%d\n",d);  // should printf 1

  0007a 8b 55 f4         mov     edx, DWORD PTR _d$[ebp]
  0007d 52               push    edx
  0007e 68 00 00 00 00   push    OFFSET $SG3859
  00083 e8 00 00 00 00   call    _printf
  00088 83 c4 08         add     esp, 8

; 14   :     d = (a*b)%c;   // 2 * 3 % 4 denominator = 2

  0008b 8b 45 fc         mov     eax, DWORD PTR _a$[ebp]
  0008e 0f af 45 f8      imul    eax, DWORD PTR _b$[ebp]
  00092 99               cdq
  00093 f7 7d f0         idiv    DWORD PTR _c$[ebp]
  00096 89 55 f4         mov     DWORD PTR _d$[ebp], edx

; 15   :     printf("%d\n",d);  // should print 2

  00099 8b 45 f4         mov     eax, DWORD PTR _d$[ebp]
  0009c 50               push    eax
  0009d 68 00 00 00 00   push    OFFSET $SG3860
  000a2 e8 00 00 00 00   call    _printf
  000a7 83 c4 08         add     esp, 8

; 16   :     return 0;   // lets generate a cod file and see the assembly

  000aa 33 c0            xor     eax, eax

; 17   : }   // this line will get converted to epilog

  000ac 8b e5            mov     esp, ebp
  000ae 5d               pop     ebp
  000af c3               ret     0
_main   ENDP
_TEXT   ENDS
END

comparesrc:\>
0

Basically it isn't possible for the most part.

Since you compile the code to machine codes, compilers add lots of stuff and optimizations to your code. So, recognizing the code with additions would be hard (especially when code is big).

Why are you doing this? Tthere are different strategies to use and I can help more if I know.

  1. Some people do this to make sure compiled binary of open source apps are not backdoored(big example is truecrypt).
  2. Others want to learn about compilers and how they work. they should compile in debug mode and attach some debugger that support source code debugging (for example WinDbg in Windows environment).
1
  • My goal is to learn how it works, and learning reverse engineering.
    – trusktr
    May 17, 2014 at 11:08

Your Answer

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

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