Skip to content

Commit 3bdbf88

Browse files
authored
Merge pull request #8 from shaymargolis/add-pic-tests
Add pic tests
2 parents e3182cc + 092e0ea commit 3bdbf88

11 files changed

Lines changed: 180 additions & 39 deletions

File tree

.github/workflows/python-app.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
# stop the build if there are Python syntax errors or undefined names
3131
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
3232
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
33-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
33+
flake8 . --count --max-complexity=10 --max-line-length=127 --statistics
3434
- name: Test with pytest
3535
run: |
3636
pytest

shellblocks/primitives/print.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ class ShellcodePrimitivePrint(ShellcodePrimitive):
55
def __init__(self, nickname: str, print_function: int, print_string: str):
66
super().__init__(
77
nickname,
8-
["print.c", "utils.h"],
9-
"print.c",
8+
["print.S", "utils.h"],
9+
"print.S",
1010
"print.h"
1111
)
1212

shellblocks/shellcode_primitive.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def generate_header_file(self, path: Path):
2424
if isinstance(val, int):
2525
contents += [f"#define {key} ({hex(val)})"]
2626
elif isinstance(val, str):
27-
contents += [f"#define {key} (\"{val}\")"]
27+
contents += [f"#define {key} \"{val}\""]
2828
else:
2929
raise Exception(f"Cannot write header! Bad type {type(val)}")
3030

shellblocks/src/jump_hook.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
#include "utils.h"
22
#include "jump_hook.h"
33

4-
const u32 opcodes[] = {
5-
0x3c020000 + (JUMP_HOOK_GOTO_ADDRESS >> 16), // lui $v0, %HI(dst_address)
6-
0x24420000 + (JUMP_HOOK_GOTO_ADDRESS & 0xffff), // addiu $v0, $v0, %LO(dst_address)
7-
0x00400008, // jr $v0
8-
0x00000000, // nop
9-
};
10-
114
void __attribute__((noreturn)) start(void) {
125
u32 *hook_address = (u32 *)JUMP_HOOK_HOOK_ADDRESS;
136

14-
for (int i = 0; i < sizeof(opcodes) / sizeof(opcodes[0]); i++) {
15-
*(hook_address + i) = opcodes[i];
16-
}
7+
*(hook_address + 0) = 0x3c020000 + (JUMP_HOOK_GOTO_ADDRESS >> 16); // lui $v0, %HI(dst_address)
8+
*(hook_address + 1) = 0x24420000 + (JUMP_HOOK_GOTO_ADDRESS & 0xffff); // addiu $v0, $v0, %LO(dst_address)
9+
*(hook_address + 2) = 0x00400008; // jr $v0
10+
*(hook_address + 3) = 0x00000000; // nop
1711

1812
__builtin_unreachable();
1913
}

shellblocks/src/print.S

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "print.h"
2+
3+
.global start
4+
start:
5+
// Save $ra
6+
addiu $sp, -4
7+
sw $ra, 0($sp)
8+
9+
// Get $pc using bal
10+
bal code
11+
nop
12+
code:
13+
// bal somehow compiles to "bal + nop" so 2 opcodes
14+
addiu $a0, $ra, (print_string - code + 4)
15+
nop
16+
17+
lui $v0, %hi(PRINT_FUNCTION_ADDRESS)
18+
addiu $v0, %lo(PRINT_FUNCTION_ADDRESS)
19+
jalr $v0
20+
nop
21+
22+
// Restore $ra
23+
lw $ra, 0($sp)
24+
addiu $sp, 4
25+
nop
26+
27+
// Jump over the printed string, to ensure we can run
28+
// another primitive after this one.
29+
b end_of_code
30+
31+
print_string:
32+
.asciiz PRINT_STRING
33+
.align 2
34+
35+
end_of_code:
36+
nop

shellblocks/src/print.c

Lines changed: 0 additions & 10 deletions
This file was deleted.

shellblocks/src/shellcode_ldscript.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ SECTIONS
22
{
33
.text :
44
{
5-
*(.text)
5+
*(.text*)
66
}
77

88
.rodata :

tests/test_goto.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
from shellblocks.primitives.goto import ShellcodePrimitiveGoto
88

99

10+
SECTOR_SIZE = 0x2000
11+
12+
1013
@pytest.mark.parametrize('goto_page_and_address', [
1114
(0x81000000, 0x81000010),
1215
(0xbc000000, 0xbc000010),
@@ -36,11 +39,50 @@ def test_goto_sanity(temp_dir_path, goto_page_and_address):
3639

3740
mu = Uc(UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_BIG_ENDIAN)
3841
mu.mem_map(shellcode_address, 0x2000)
39-
mu.mem_map(0x81000000, 0x2000)
4042

4143
# write machine code to be emulated to memory
4244
mu.mem_write(shellcode_address, shellcode)
4345

4446
mu.emu_start(shellcode_address, goto_address)
4547

4648
assert goto_address == mu.reg_read(UC_MIPS_REG_PC)
49+
50+
51+
@pytest.mark.parametrize('shellcode_run_addr', [
52+
(0x81000010),
53+
(0xbc000010),
54+
(0xbcf00010),
55+
(0x91000118),
56+
])
57+
def test_goto_is_pic(temp_dir_path, shellcode_run_addr):
58+
# Generate shellcode
59+
# ------------------
60+
shellcode_address = 0xbfc00000
61+
_, goto_address = (0xbc000000, 0xbc000010)
62+
63+
shellcode_run_sector = int(shellcode_run_addr/SECTOR_SIZE) * SECTOR_SIZE
64+
65+
step = ShellcodeStep(
66+
"first_step",
67+
shellcode_address,
68+
[
69+
ShellcodePrimitiveGoto("copy_next_stage", goto_address),
70+
],
71+
0x1000
72+
)
73+
74+
out_file = step.generate(temp_dir_path / step.nickname)
75+
shellcode = out_file.read_bytes()
76+
77+
# Try to run shellcode
78+
# --------------------
79+
80+
mu = Uc(UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_BIG_ENDIAN)
81+
mu.mem_map(shellcode_run_sector, 0x2000)
82+
83+
# write machine code to be emulated to memory
84+
mu.mem_write(shellcode_run_addr, shellcode)
85+
86+
mu.emu_start(shellcode_run_addr, goto_address)
87+
88+
assert goto_address == mu.reg_read(UC_MIPS_REG_PC)

tests/test_jump_hook.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
0x91000118,
1717
])
1818
@pytest.mark.parametrize('jump_hook_goto', [
19-
0x81000020,
19+
0x81002020,
2020
0xbc002020,
2121
0xbcf00070,
2222
0x910f0218,
@@ -53,8 +53,6 @@ def test_jump_hook_sanity(temp_dir_path, jump_hook_location, jump_hook_goto):
5353
]
5454
))
5555

56-
end_of_code = shellcode.find(EXPECTED_HOOK)
57-
5856
# Try to run shellcode
5957
# --------------------
6058

@@ -67,7 +65,7 @@ def test_jump_hook_sanity(temp_dir_path, jump_hook_location, jump_hook_goto):
6765
mu.mem_write(jump_hook_sector, b"\x00" * 0x1000)
6866

6967
# emulate code in infinite time & unlimited instructions
70-
mu.emu_start(shellcode_address, shellcode_address + end_of_code)
68+
mu.emu_start(shellcode_address, shellcode_address + len(shellcode))
7169

7270
assert mu.mem_read(jump_hook_location, len(EXPECTED_HOOK)) == EXPECTED_HOOK
7371
assert mu.mem_read(jump_hook_location+len(EXPECTED_HOOK), 1) == (b"\x00")

tests/test_memcpy.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,35 @@ def test_memcpy_sanity(temp_dir_path, default_memcpy_helper, copy_len):
9090
assert helper.mu.mem_read(helper.second_copy_addr + copy_len, 1) == b"\x00"
9191

9292

93+
@pytest.mark.parametrize('shellcode_run_addr', [
94+
(0x83000010),
95+
(0xbc000010),
96+
(0xbcf00010),
97+
(0x91000118),
98+
])
99+
def test_memcpy_is_pic(temp_dir_path, shellcode_run_addr, default_memcpy_helper):
100+
copy_len = 0x1000
101+
helper = default_memcpy_helper
102+
shellcode = memcpy_get_shellcode(temp_dir_path, helper, copy_len)
103+
104+
shellcode_run_sector = int(shellcode_run_addr/SECTOR_SIZE) * SECTOR_SIZE
105+
helper.mu.mem_map(shellcode_run_sector, SECTOR_SIZE)
106+
107+
# Try to run shellcode
108+
# --------------------
109+
110+
# write machine code to be emulated to memory
111+
helper.mu.mem_write(shellcode_run_addr, shellcode)
112+
helper.mu.mem_write(helper.first_copy_addr, b"\xAA" * copy_len)
113+
helper.mu.mem_write(helper.second_copy_addr, b"\x00" * copy_len)
114+
115+
helper.mu.emu_start(shellcode_run_addr, shellcode_run_addr + len(shellcode))
116+
117+
assert helper.mu.mem_read(helper.second_copy_addr - 1, 1) == b"\x00"
118+
assert helper.mu.mem_read(helper.second_copy_addr, copy_len) == (b"\xAA" * copy_len)
119+
assert helper.mu.mem_read(helper.second_copy_addr + copy_len, 1) == b"\x00"
120+
121+
93122
@pytest.mark.parametrize('copy_len', [
94123
100,
95124
200,

0 commit comments

Comments
 (0)