Skip to content

InsertInstructionPatch

We have a simple C program:

examples/insert_instruction_patch/add.c
#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int main() {
    printf("2 + 3 = %d\n", add(2, 3));
    return 0;
}

And here is the disassembly of the compiled binary:

examples/insert_instruction_patch/add
0000000000001149 <add>:
    1149:   f3 0f 1e fa             endbr64
    114d:   55                      push   %rbp
    114e:   48 89 e5                mov    %rsp,%rbp
    1151:   89 7d fc                mov    %edi,-0x4(%rbp)
    1154:   89 75 f8                mov    %esi,-0x8(%rbp)
    1157:   8b 55 fc                mov    -0x4(%rbp),%edx
    115a:   8b 45 f8                mov    -0x8(%rbp),%eax
    115d:   01 d0                   add    %edx,%eax
    115f:   5d                      pop    %rbp
    1160:   c3                      ret

0000000000001161 <main>:
    1161:   f3 0f 1e fa             endbr64
    1165:   55                      push   %rbp
    1166:   48 89 e5                mov    %rsp,%rbp
    1169:   be 03 00 00 00          mov    $0x3,%esi
    116e:   bf 02 00 00 00          mov    $0x2,%edi
    1173:   e8 d1 ff ff ff          call   1149 <add>
    1178:   89 c6                   mov    %eax,%esi
    117a:   48 8d 05 83 0e 00 00    lea    0xe83(%rip),%rax        # 2004 <_IO_stdin_used+0x4>
    1181:   48 89 c7                mov    %rax,%rdi
    1184:   b8 00 00 00 00          mov    $0x0,%eax
    1189:   e8 c2 fe ff ff          call   1050 <printf@plt>
    118e:   b8 00 00 00 00          mov    $0x0,%eax
    1193:   5d                      pop    %rbp
    1194:   c3                      ret

Suppose we want to modify the add function to do some extra calculations on the first argument, for example doubling it and adding 5, without changing the rest of the function. We can use Patcherex2's InsertInstructionPatch to insert these instructions at the address 114d which is at the beginning of the function. To insert instructions, we need at least enough space to fit a jump instruction before the function ends, so we cannot insert them later on in the function. Here is how:

examples/insert_instruction_patch/patch.py
from patcherex2 import *

p = Patcherex("add")


asm_str = """
    add edi, edi
    add edi, 5
"""

p.patches.append(InsertInstructionPatch(0x114d,asm_str))
p.apply_patches()

p.binfmt_tool.save_binary()

Now we can run this script and run the patched binary to see the result:

$ ./add.patched
2 + 3 = 12

We have successfully modified the binary at the instruction level.