Search code examples
reverse-engineeringollydbg

Reverse engineering on my simple C program


I would like to start learning reverse engineering. So I decided to start simple. I created this simple program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf ("Hello World!\n");
  system("PAUSE");  
  return 0;
}

And I dissembled it in Ollydbg. So I wanted to try and change the printf to "World Hello". But I don't know what to do now. Can you guide me, or at least tell me what I should theoretically do?


Solution

  • In this case you'd need to edit the character string that is passed to printf, but first we need to get its address. looking ad the code fro the call to printf, we will see something along the lines of this:

    PUSH mymodule.1234567
    CALL printf
    ADD ESP,4
    

    so if we go to the address 0x1234567, via ctrl + g, we would see:

    01234567   48 65 6C 6C 6F 20 57 6F 72 6C 64 0A 00 00 00 00  Hello World.....
    

    so now you can edit that string to whatever you want, so long as you don't overflow the space available and you keep the null terminator.

    Saving the changes depends on how you loaded the binary (either by attaching or just cold viewing), the easiest way is via cold viewing (using olly purely as a disassembler/assembler). Its access via view -> file then right-clicking and choosing disassemble from the context menu. In this mode saving is done by right clicking and selecting save file from the context menu .

    In debugger mode (aka when you attach), saving is done using right-click, and selecting one of the options from the copy to executable context menu option.


    Update

    If you are debugging GCC generated code, it generally avoids generating PUSH's and favours putting the variables directly into the stack, using MOV [ESP+c],c/r/m. Compiling your example with GCC, you'd see code similar to (for main):

    00401AFC     /$  PUSH EBP
    00401AFD     |.  MOV EBP,ESP
    00401AFF     |.  AND ESP,FFFFFFF0
    00401B02     |.  SUB ESP,10
    00401B05     |.  CALL GCCOllyT.0040182C
    00401B0A     |.  MOV DWORD PTR SS:[ESP],GCCOllyT.00403024   ; ||ASCII "Hello World!"
    00401B11     |.  CALL <JMP.&msvcrt.puts>                    ; |\puts
    00401B16     |.  MOV DWORD PTR SS:[ESP],GCCOllyT.00403031   ; |ASCII "PAUSE"
    00401B1D     |.  CALL <JMP.&msvcrt.system>                  ; \system
    00401B22     |.  XOR EAX,EAX
    00401B24     |.  LEAVE
    00401B25     \.  RETN
    

    Its important here to notice that GCC optimized the call to printf into a call to puts. In a case like this where you know the string you are looking for, you can use olly in debugger mode, right-click and select search for -> all referenced text strings, then simple select your desired string from the list to find the code using it, or follow its address to find its .data section entry so you can alter it. A longer way to find it is to use the binary search available from the right-click context menu, but this generally is a waste for text strings.

    And to cover all bases, lets assume we needed to get to the code from the entry point. If we where to navigate to the code from the module entry point, we would follow the chain like so:

    GCCOllyT.<ModuleEntryPoint> 0> $ >PUSH EBP
    0040126D                       . >MOV EBP,ESP
    0040126F                       . >SUB ESP,18
    00401272                       . >MOV DWORD PTR SS:[ESP],1
    00401279                       . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>;  msvcrt.__set_app_type
    0040127F                       . >CALL GCCOllyT.00401000
    00401284                       . >PUSH EBP
    00401285                       . >MOV EBP,ESP
    00401287                       . >SUB ESP,18
    0040128A                       . >MOV DWORD PTR SS:[ESP],2
    00401291                       . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>;  msvcrt.__set_app_type
    00401297                       . >CALL GCCOllyT.00401000
    0040129C                       $ >PUSH EBP
    0040129D                       . >MOV EBP,ESP
    0040129F                       . >SUB ESP,8
    004012A2                       . >MOV EAX,DWORD PTR DS:[<&msvcrt.atexit>]
    004012A7                       . >LEAVE
    004012A8                       . >JMP EAX
    

    from here we see the only viable call as GCCOllyT.00401000, following that, we end up here (this is the GCC mainCRTstartup):

    00401000   /$ >PUSH EBP
    00401001   |. >MOV EBP,ESP
    00401003   |. >PUSH EBX
    00401004   |. >SUB ESP,34
    00401007   |. >MOV EAX,DWORD PTR DS:[403038]
    0040100C   |. >TEST EAX,EAX
    0040100E   |. >JE SHORT GCCOllyT.0040102C
    00401010   |. >MOV DWORD PTR SS:[ESP+8],0
    00401018   |. >MOV DWORD PTR SS:[ESP+4],2
    00401020   |. >MOV DWORD PTR SS:[ESP],0
    00401027   |. >CALL EAX
    00401029   |. >SUB ESP,0C
    0040102C   |> >MOV DWORD PTR SS:[ESP],GCCOllyT.00401110           ; |
    00401033   |. >CALL <JMP.&KERNEL32.SetUnhandledExceptionFilter>   ; \SetUnhandledExceptionFilter
    00401038   |. >PUSH EAX
    00401039   |. >CALL GCCOllyT.004013CC
    0040103E   |. >CALL GCCOllyT.004014AC
    00401043   |. >MOV DWORD PTR SS:[EBP-10],0
    0040104A   |. >LEA EAX,DWORD PTR SS:[EBP-10]
    0040104D   |. >MOV DWORD PTR SS:[ESP+10],EAX
    00401051   |. >MOV EAX,DWORD PTR DS:[402000]
    00401056   |. >MOV DWORD PTR SS:[ESP+C],EAX
    0040105A   |. >LEA EAX,DWORD PTR SS:[EBP-C]
    0040105D   |. >MOV DWORD PTR SS:[ESP+8],EAX
    00401061   |. >MOV DWORD PTR SS:[ESP+4],GCCOllyT.00404004
    00401069   |. >MOV DWORD PTR SS:[ESP],GCCOllyT.00404000
    00401070   |. >CALL <JMP.&msvcrt.__getmainargs>
    00401075   |. >MOV EAX,DWORD PTR DS:[404018]
    0040107A   |. >TEST EAX,EAX
    0040107C   |. >JNZ SHORT GCCOllyT.004010C8
    0040107E   |> >CALL <JMP.&msvcrt.__p__fmode>
    00401083   |. >MOV EDX,DWORD PTR DS:[402004]
    00401089   |. >MOV DWORD PTR DS:[EAX],EDX
    0040108B   |. >CALL GCCOllyT.004015E4
    00401090   |. >AND ESP,FFFFFFF0
    00401093   |. >CALL GCCOllyT.0040182C
    00401098   |. >CALL <JMP.&msvcrt.__p__environ>
    0040109D   |. >MOV EAX,DWORD PTR DS:[EAX]
    0040109F   |. >MOV DWORD PTR SS:[ESP+8],EAX
    004010A3   |. >MOV EAX,DWORD PTR DS:[404004]
    004010A8   |. >MOV DWORD PTR SS:[ESP+4],EAX
    004010AC   |. >MOV EAX,DWORD PTR DS:[404000]
    004010B1   |. >MOV DWORD PTR SS:[ESP],EAX
    004010B4   |. >CALL GCCOllyT.00401AFC
    004010B9   |. >MOV EBX,EAX                                        ; |
    004010BB   |. >CALL <JMP.&msvcrt._cexit>                          ; |[msvcrt._cexit
    004010C0   |. >MOV DWORD PTR SS:[ESP],EBX                         ; |
    004010C3   |. >CALL <JMP.&KERNEL32.ExitProcess>                   ; \ExitProcess
    004010C8   |> >MOV DWORD PTR DS:[402004],EAX                      ; |||
    004010CD   |. >MOV DWORD PTR SS:[ESP+4],EAX                       ; |||
    004010D1   |. >MOV EBX,DWORD PTR DS:[<&msvcrt._iob>]              ; |||msvcrt._iob
    004010D7   |. >MOV EAX,DWORD PTR DS:[EBX+10]                      ; |||
    004010DA   |. >MOV DWORD PTR SS:[ESP],EAX                         ; |||
    004010DD   |. >CALL <JMP.&msvcrt._setmode>                        ; ||\_setmode
    004010E2   |. >MOV EAX,DWORD PTR DS:[404018]                      ; ||
    004010E7   |. >MOV DWORD PTR SS:[ESP+4],EAX                       ; ||
    004010EB   |. >MOV EAX,DWORD PTR DS:[EBX+30]                      ; ||
    004010EE   |. >MOV DWORD PTR SS:[ESP],EAX                         ; ||
    004010F1   |. >CALL <JMP.&msvcrt._setmode>                        ; |\_setmode
    004010F6   |. >MOV EAX,DWORD PTR DS:[404018]                      ; |
    004010FB   |. >MOV DWORD PTR SS:[ESP+4],EAX                       ; |
    004010FF   |. >MOV EAX,DWORD PTR DS:[EBX+50]                      ; |
    00401102   |. >MOV DWORD PTR SS:[ESP],EAX                         ; |
    00401105   |. >CALL <JMP.&msvcrt._setmode>                        ; \_setmode
    0040110A   \.^>JMP GCCOllyT.0040107E
    

    Now we know the signature for the call to main takes 3 args, we also know it will be called before app cleanup and exit, thus we get GCCOllyT.00401AFC. As you can see, it pays heavily to have symbols enabled, this can be done from the disassembly section of the debugging options menu.