Search code examples
c++assemblygdbcracking

How to ignore execution of some line of binary file?


I want to make my program more strong in front of hackers, so i have a program::validator class which validate my environment by some parameters. I :

  • Compile program::validator shared library.
  • Compile program using -O2 and --ffast-math and link to libprogramvalidator.so.
  • Run the program with the GDB.
  • Find the line which actually call program::validator::is_valid_system().

and i want know that i can ignore execution of those line ?


Solution

  • i just want avoid call to is_valid_system function in my ELF executable binary file.

    There are several easy ways. You can use GDB jump $address, or return commands to achieve this. Example:

    #include <stdio.h>
    
    int is_valid_system()
    {
      return 0;
    }
    
    int main()
    {
      if (is_valid_system()) {
        printf("Life is good\n");
        return 0;
      }
      printf("Invalid system detected\n");
      return 1;
    }
    

    As you can see, running above program will always print Invalid system and exit with error code 1. Let's confirm that:

    gcc t.c && gdb -q ./a.out
    (gdb) run
    Starting program: /tmp/a.out 
    Invalid system detected
    [Inferior 1 (process 180727) exited with code 01]
    

    Ok, now let's make the program print Life is good. Let's do that via return. To achieve that, set a breakpoint on the desired function, set return register ($rax on x86_64) to desired value, and return to force the function to immediately return:

    (gdb) b is_valid_system
    Breakpoint 1 at 0x1139
    (gdb) run
    Starting program: /tmp/a.out 
    
    Breakpoint 1, 0x0000555555555139 in is_valid_system ()
    (gdb) set $rax = 1
    (gdb) return
    #0  0x000055555555514e in main ()
    (gdb) c
    Continuing.
    Life is good
    [Inferior 1 (process 196141) exited normally]
    

    Alternatively, you can "jump over" the function. Disasemble the caller, break on the CALL instruction, set return register to desired value, and jump to next instruction:

    (gdb) disas main
    Dump of assembler code for function main:
       0x0000555555555140 <+0>:     push   %rbp
       0x0000555555555141 <+1>:     mov    %rsp,%rbp
       0x0000555555555144 <+4>:     mov    $0x0,%eax
       0x0000555555555149 <+9>:     callq  0x555555555135 <is_valid_system>
       0x000055555555514e <+14>:    test   %eax,%eax
       0x0000555555555150 <+16>:    je     0x555555555165 <main+37>
       0x0000555555555152 <+18>:    lea    0xeab(%rip),%rdi        # 0x555555556004
       0x0000555555555159 <+25>:    callq  0x555555555030 <puts@plt>
       0x000055555555515e <+30>:    mov    $0x0,%eax
       0x0000555555555163 <+35>:    jmp    0x555555555176 <main+54>
       0x0000555555555165 <+37>:    lea    0xea5(%rip),%rdi        # 0x555555556011
       0x000055555555516c <+44>:    callq  0x555555555030 <puts@plt>
       0x0000555555555171 <+49>:    mov    $0x1,%eax
       0x0000555555555176 <+54>:    pop    %rbp
       0x0000555555555177 <+55>:    retq   
    End of assembler dump.
    (gdb) b *0x0000555555555149
    Breakpoint 2 at 0x555555555149
    (gdb) run
    Starting program: /tmp/a.out 
    
    Breakpoint 2, 0x0000555555555149 in main ()
    (gdb) set $rax = 1
    (gdb) jump *0x000055555555514e
    Continuing at 0x55555555514e.
    Life is good
    [Inferior 1 (process 205378) exited normally]
    

    You could also use GDB to temporarily or permanently patch the is_valid_system out. Details in this answer.