Modifying Linux ELF Binaries - Changing Callq Addresses

For awhile, I have wanted to write a simple tutorial of in-line patching of binaries and in particular, changing the assembly instructions and having a binary skip to whatever function we desire manually. This involves tweaking the callq instruction (call can be altered too, but it refers to a static address vs. a relative address).

Okay so lets get started - this tutorial is written to alter one specific thing and assumes that you have some basic knowledge of assembly & know how to compile basic programs. I am also assuming that you could find strings within binaries and know how to convert values in hexadecimal.

The example to be used in this test application contains a main function, and two functions (function1 and function2) which print different messages. The goal of this exercise is to modify the application AFTER it has been compiled so that function2() is executed instead of function1().

Simple enough right? Below is the sample C code:

/**
 * @file test.c
 * @author Ronnie Brash (<a href="mailto:ron.brash@gmail.com">ron.brash@gmail.com</a>)
 * @brief Ghetto application to demonstrate altering Linux ELF binaries
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void function1();
void function2();

void function1()
{
        printf("This is function 1\n");
}

int main(int argc, char **argv)
{
        function1();
        return 0;
}

void function2()
{
        printf("This is function 2\n");
}

Now compile the code using gcc -Wall -o test test.c and assuming you have tools like a hex editor installed such as hexedit AND objdump or any ELF related tools (binutils) - we can now review the binary.

Run the command objdump -D test and watch copious amounts of information be displayed on your screen. In particular, you are looking for these lines:

000000000040052d <function1>:
  40052d:       55                      push   %rbp
  40052e:       48 89 e5                mov    %rsp,%rbp
  400531:       bf f4 05 40 00          mov    $0x4005f4,%edi
  400536:       e8 d5 fe ff ff          callq  400410 <<a href="mailto:puts@plt">puts@plt</a>>
  40053b:       5d                      pop    %rbp
  40053c:       c3                      retq  

000000000040053d <main>:
  40053d:       55                      push   %rbp
  40053e:       48 89 e5                mov    %rsp,%rbp
  400541:       48 83 ec 10             sub    $0x10,%rsp
  400545:       89 7d fc                mov    %edi,-0x4(%rbp)
  400548:       48 89 75 f0             mov    %rsi,-0x10(%rbp)
  40054c:       b8 00 00 00 00          mov    $0x0,%eax
  400551:       e8 d7 ff ff ff          callq  40052d <function1>
  400556:       b8 00 00 00 00          mov    $0x0,%eax
  40055b:       c9                      leaveq
  40055c:       c3                      retq  

000000000040055d <function2>:
  40055d:       55                      push   %rbp
  40055e:       48 89 e5                mov    %rsp,%rbp
  400561:       bf 07 06 40 00          mov    $0x400607,%edi
  400566:       e8 a5 fe ff ff          callq  400410 <<a href="mailto:puts@plt">puts@plt</a>>
  40056b:       5d                      pop    %rbp
  40056c:       c3                      retq  
  40056d:       0f 1f 00                nopl   (%rax)

Take note of these lines:
400551: e8 d7 ff ff ff callq 40052d
400556: b8 00 00 00 00 mov $0x0,%eax

000000000040055d :

Now you are wondering okay so what do these three lines have to do anything; especially the line with the mov instruction. In short 400551 is where we will be making our modifications of the binary in the hex editor, 400556 will be used to start our calculation of where function2() is located RELATIVE to where the callq instruction is located.

Next we calculate the relative difference to be used in our modification of the binary: 0x000000000040055d minus 0x0000000000400556 which equals 7 in hexadecimal. NOTE: This value has to be replaced in LITTLE ENDIAN format.

Open hexedit and locate the callq instruction for function1 inside of the main function. Callq can be identified by E8 and 4 additional bytes.

Now change E8 D7 FF FF FF to E8 07 00 00 00 and save. Run the binary and you should see function2 being executed. Congratulations! You may ask though, what is this address's sign? it is a signed integer so you could call functions which are earlier than your relative position.

In a subsequent tutorial, I will demonstrate how to manipulate the binary to have a new function which was unknown during the original compilation.

Blog tags: 

AttachmentSize
Image icon binary-modification.png14.89 KB
Image icon console_elf_binary_editing.PNG72.2 KB
File test.c410 bytes

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <python> <c>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.