Skip to content

Commit

Permalink
Merge pull request #26 from burhanr13/more-examples
Browse files Browse the repository at this point in the history
more examples
  • Loading branch information
DennyDai authored Apr 8, 2024
2 parents 88f791c + 7073a19 commit 528ad57
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 3 deletions.
64 changes: 64 additions & 0 deletions docs/examples/insert_instruction_patch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# InsertInstructionPath

We have a simple C program:

```c title="examples/insert_instruction_patch/add.c"
--8<-- "examples/insert_instruction_patch/add.c"
```

And here is the disassembly of the compiled binary:

```asm title="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:

```python title="examples/insert_instruction_patch/patch.py"
--8<-- "examples/insert_instruction_patch/patch.py"
```

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

```bash
$ ./add.patched
2 + 3 = 12
```

We have successfully modified the binary at the
instruction level.
98 changes: 98 additions & 0 deletions docs/examples/multiple_patches.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Multiple Patches

Here is a simple example of a vulnerable C program which we will use to show how different patches can be used together:

```c title = "examples/multiple_patches/getline.c"
--8<-- "examples/multiple_patches/getline.c"
```

And here is the disassembly of the relevant functions:

```asm title = "examples/multiple_patches/getline"
0000000000001189 <my_getline>:
1189: f3 0f 1e fa endbr64
118d: 55 push %rbp
118e: 48 89 e5 mov %rsp,%rbp
1191: 48 83 ec 20 sub $0x20,%rsp
1195: 48 89 7d e8 mov %rdi,-0x18(%rbp)
1199: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
11a0: 48 8b 05 69 2e 00 00 mov 0x2e69(%rip),%rax # 4010 <stdin@GLIBC_2.2.5>
11a7: 48 89 c7 mov %rax,%rdi
11aa: e8 e1 fe ff ff call 1090 <getc@plt>
11af: 88 45 fb mov %al,-0x5(%rbp)
11b2: 80 7d fb 0a cmpb $0xa,-0x5(%rbp)
11b6: 74 1b je 11d3 <my_getline+0x4a>
11b8: 8b 45 fc mov -0x4(%rbp),%eax
11bb: 8d 50 01 lea 0x1(%rax),%edx
11be: 89 55 fc mov %edx,-0x4(%rbp)
11c1: 48 63 d0 movslq %eax,%rdx
11c4: 48 8b 45 e8 mov -0x18(%rbp),%rax
11c8: 48 01 c2 add %rax,%rdx
11cb: 0f b6 45 fb movzbl -0x5(%rbp),%eax
11cf: 88 02 mov %al,(%rdx)
11d1: eb cd jmp 11a0 <my_getline+0x17>
11d3: 90 nop
11d4: 8b 45 fc mov -0x4(%rbp),%eax
11d7: 48 63 d0 movslq %eax,%rdx
11da: 48 8b 45 e8 mov -0x18(%rbp),%rax
11de: 48 01 d0 add %rdx,%rax
11e1: c6 00 00 movb $0x0,(%rax)
11e4: 8b 45 fc mov -0x4(%rbp),%eax
11e7: c9 leave
11e8: c3 ret
00000000000011e9 <main>:
11e9: f3 0f 1e fa endbr64
11ed: 55 push %rbp
11ee: 48 89 e5 mov %rsp,%rbp
11f1: 48 83 ec 20 sub $0x20,%rsp
11f5: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
11fc: 00 00
11fe: 48 89 45 f8 mov %rax,-0x8(%rbp)
1202: 31 c0 xor %eax,%eax
1204: 48 8d 45 ee lea -0x12(%rbp),%rax
1208: 48 89 c7 mov %rax,%rdi
120b: e8 79 ff ff ff call 1189 <my_getline>
1210: 48 8d 45 ee lea -0x12(%rbp),%rax
1214: 48 89 c7 mov %rax,%rdi
1217: e8 54 fe ff ff call 1070 <puts@plt>
121c: b8 00 00 00 00 mov $0x0,%eax
1221: 48 8b 55 f8 mov -0x8(%rbp),%rdx
1225: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
122c: 00 00
122e: 74 05 je 1235 <main+0x4c>
1230: e8 4b fe ff ff call 1080 <__stack_chk_fail@plt>
1235: c9 leave
1236: c3 ret
```

The program currently reads a string from standard input and echos it back. We can run it with short strings:
```bash
$ ./getline
aaaaa
aaaaa
```
And it works fine. Using a longer string, however will cause it to crash:
```bash
$ ./getline
aaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaa
*** stack smashing detected ***: terminated
[1] 194473 IOT instruction (core dumped) ./getline
```

We will patch this program to fix the vulnerability, by adding a second argument to the `my_getline` function, and printing a message when the buffer would have overflowed. Here is the script:

```python title = "examples/multiple_patches/patch.py"
--8<-- "examples/multiple_patches/patch.py"
```

This patch adds the buffer size as a second argument to `my_getline`. To do this we insert instructions at the beginning to save the argument, and in the loop body we insert a check to see if the index is out of bounds. When it is, we print a message, which was inserted using the `InsertDataPatch`. We can use the `SAVE_CONTEXT` and `RESTORE_CONTEXT` macros (expanded by Patcherex2) to do operations that could modify data we have in registers, like calling a function. We also insert instructions in `main` to put the buffer size in `esi` before calling the function. Now we can run the script to patch the binary and run the new fixed program:
```bash
$ ./getline.patched
aaaaaaaaaaaaaaaaaaaaaaa
Ran out of space
aaaaaaaaa
```

We have successfully fixed the bug with Patcherex2.
Binary file added examples/insert_instruction_patch/add
Binary file not shown.
10 changes: 10 additions & 0 deletions examples/insert_instruction_patch/add.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <stdio.h>

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

int main() {
printf("2 + 3 = %d\n", add(2, 3));
return 0;
}
14 changes: 14 additions & 0 deletions examples/insert_instruction_patch/patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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()
Binary file added examples/multiple_patches/getline
Binary file not shown.
21 changes: 21 additions & 0 deletions examples/multiple_patches/getline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>

int my_getline(char* buf) {
int i = 0;
while (1) {
char c = getc(stdin);
if (c == '\n') break;
buf[i++] = c;
}
buf[i] = '\0';
return i;
}

int main() {

char buf[10];
my_getline(buf);
puts(buf);

return 0;
}
29 changes: 29 additions & 0 deletions examples/multiple_patches/patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from patcherex2 import *

p = Patcherex("getline")

p.patches.append(InsertInstructionPatch(0x120b,"mov esi, 0xa\n"))
p.patches.append(InsertDataPatch("my_str",b"Ran out of space\0"))

p.patches.append(InsertInstructionPatch(0x1199,"mov [rbp-0xc],esi"))

asm_string = """
cmp edx, [rbp-0xc]
jl less
SAVE_CONTEXT
lea rdi, [{my_str}]
call {puts}
RESTORE_CONTEXT
mov rsi, [rbp-0x18]
mov byte ptr [rsi+rax], 0
mov eax, edx
leave
ret
less:
"""

p.patches.append(InsertInstructionPatch(0x11c1,asm_string))

p.apply_patches()

p.binfmt_tool.save_binary()
2 changes: 1 addition & 1 deletion src/patcherex2/components/archinfo/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ArmInfo:
is_variable_length_isa = False
instr_size = 4 # TODO: thumb 2
call_asm = "bl {dst}"
pc_reg_names = ["pc", "r15", "ip"]
pc_reg_names = ["pc", "r15"]
save_context_asm = """
push {r0-r11}
"""
Expand Down
4 changes: 2 additions & 2 deletions src/patcherex2/patches/instruction_patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(
Constructor.
:param addr: Memory address of instruction(s) to overwrite.
:param instr: Assembly instruction(s) to place in binary.
:param instr: Assembly instruction(s) to place in binary. If you want to use any symbols from the program or from previous patches, you must surround them with curly braces.
:param symbols: Symbols to include when assembling, in format {symbol name: memory address}, defaults to None
"""
self.addr = addr
Expand Down Expand Up @@ -94,7 +94,7 @@ def __init__(
:param addr_or_name: If an integer, the new instructions are placed in a free spot in the binary and the jump to them is inserted at that memory address.
If a string, the new instructions are placed in a free spot in the binary and added as a symbol (with this as its name).
:param instr: Instructions to insert. You can use "SAVE_CONTEXT" and "RESTORE_CONTEXT" wherever you want to save and restore program context.
:param instr: Instructions to insert. You can use "SAVE_CONTEXT" and "RESTORE_CONTEXT" wherever you want to save and restore program context. If you want to use any symbols from the program or from previous patches, you must surround them with curly braces.
:param force_insert: If Patcherex should ignore whether instructions can be moved when inserting, defaults to False
:param detour_pos: If given a name, specifies the file address to place the new instructions, defaults to -1
:param symbols: Symbols to include when assembling, in format {symbol name: memory address}, defaults to None
Expand Down

0 comments on commit 528ad57

Please sign in to comment.