def test_conflicting_symbols(self): filepath = os.path.join(self.bin_location, "printf_nopie") patches = [] backend = DetourBackend(filepath) patches.append(AddRODataPatch(b"0123456789abcdef", "aaa")) patches.append(AddRODataPatch(b"\n", "aaa")) exc = False try: backend.apply_patches(patches) except ValueError: exc = True self.assertTrue(exc) patches = [] backend = DetourBackend(filepath) patches.append(AddRODataPatch(b"0123456789abcdef", "aaa")) added_code = ''' nop ''' patches.append(AddCodePatch(added_code, "aaa")) exc = False try: backend.apply_patches(patches) except ValueError: exc = True self.assertTrue(exc)
def test_complex1(self): patches = [] added_code = ''' mov eax, 4 mov ebx, 1 mov ecx, 0x080484f3 mov edx, 2 int 0x80 call {added_function} ''' patches.append(AddEntryPointPatch(added_code)) added_code = ''' mov eax, 1 mov ebx, 0x34 int 0x80 ''' patches.append(AddEntryPointPatch(added_code)) test_str = b"testtesttest\n\x00" added_code = ''' mov eax, 4 mov ebx, 1 mov ecx, {added_data} mov edx, %d int 0x80 ret ''' % (len(test_str)) patches.append(AddCodePatch(added_code, "added_function")) patches.append(AddRODataPatch(test_str, "added_data")) self.run_test("printf_nopie", patches, expected_output=b'%s' + test_str, expected_returnCode=0x34)
def test_complex1(self): patches = [] added_code = ''' dli $v0, 5001 dli $a0, 1 dla $a1, 0x120000cf8 dli $a2, 2 syscall jal {added_function} dli $v0, 5058 dli $a0, 0x34 syscall ''' patches.append(AddEntryPointPatch(added_code)) test_str = b"testtesttest\n\x00" added_code = ''' dli $v0, 5001 dli $a0, 1 dla $a1, {added_data} dli $a2, %d syscall jr $ra ''' % (len(test_str)) patches.append(AddCodePatch(added_code, "added_function")) patches.append(AddRODataPatch(test_str, "added_data")) self.run_test("printf_nopie", patches, expected_output=b'%s' + test_str, expected_returnCode=0x34)
def test_complex1(self): patches = [] added_code = ''' li r0, 4 li r3, 1 lis r4, 0x10000758@h ori r4, r4, 0x10000758@l li r5, 2 sc bl {added_function} li r0, 1 li r3, 0x34 sc ''' patches.append(AddEntryPointPatch(added_code)) test_str = b"testtesttest\n\x00" added_code = ''' li r0, 4 li r3, 1 lis r4, {added_data}@h ori r4, r4, {added_data}@l li r5, %d sc blr ''' % (len(test_str)) patches.append(AddCodePatch(added_code, "added_function")) patches.append(AddRODataPatch(test_str, "added_data")) self.run_test("printf_nopie", patches, expected_output=b'%s' + test_str, expected_returnCode=0x34)
def test_complex1(self): patches = [] added_code = ''' mov x8, 0x40 mov x0, 0x1 ldr x1, =0x400648 mov x2, 2 svc 0 bl {added_function} mov x8, 0x5d mov x0, 0x34 svc 0 ''' patches.append(AddEntryPointPatch(added_code)) test_str = b"testtesttest\n\x00" added_code = ''' mov x8, 0x40 mov x0, 0x1 ldr x1, ={added_data} mov x2, %d svc 0 ret ''' % (len(test_str)) patches.append(AddCodePatch(added_code, "added_function")) patches.append(AddRODataPatch(test_str, "added_data")) self.run_test("printf_nopie", patches, expected_output=b'%s' + test_str, expected_returnCode=0x34)
def test_complex1(self): patches = [] added_code = ''' mov r7, 0x4 mov r0, 0x1 ldr r1, =0x10450 mov r2, 2 svc 0 bl {added_function} mov r7, 0x1 mov r0, 0x34 svc 0 ''' patches.append(AddEntryPointPatch(added_code)) test_str = b"testtesttest\n\x00" added_code = ''' mov r7, 0x4 mov r0, 0x1 ldr r1, ={added_data} mov r2, %d svc 0 bx lr ''' % (len(test_str)) patches.append( AddCodePatch(added_code, "added_function", is_thumb=True)) patches.append(AddRODataPatch(test_str, "added_data")) self.run_test("printf_nopie", patches, expected_output=b'%s' + test_str, expected_returnCode=0x34)
def test_add_ro_data_patch(self, tlen=5): p1 = AddRODataPatch(b"A"*tlen, "added_data") added_code = ''' li $v0, 4004 li $a0, 1 la $a1, {added_data} li $a2, %d syscall ''' % tlen p2 = InsertCodePatch(0x40076c, added_code, "added_code") self.run_test("printf_nopie", [p1, p2], expected_output=b"A"*tlen + b"Hi", expected_returnCode=0x0)
def test_add_ro_data_patch(self, tlen=5): p1 = AddRODataPatch(b"A"*tlen, "added_data") added_code = ''' mov x8, 0x40 mov x0, 0x1 ldr x1, ={added_data} mov x2, %d svc 0 ''' % tlen p2 = InsertCodePatch(0x400580, added_code, "added_code") self.run_test("printf_nopie", [p1, p2], expected_output=b"A"*tlen + b"Hi", expected_returnCode=0x0)
def test_insert_code_patch(self): test_str = b"qwertyuiop\n\x00" added_code = ''' li $v0, 4004 li $a0, 1 la $a1, {added_data} li $a2, %d syscall ''' % (len(test_str)) p1 = InsertCodePatch(0x40076c, added_code) p2 = AddRODataPatch(test_str, "added_data") self.run_test("printf_nopie", [p1, p2], expected_output=b"qwertyuiop\n\x00Hi", expected_returnCode=0)
def test_insert_code_patch(self): test_str = b"qwertyuiop\n\x00" added_code = ''' mov x8, 0x40 mov x0, 0x1 ldr x1, ={added_data} mov x2, %d svc 0 ''' % (len(test_str)) p1 = InsertCodePatch(0x400580, added_code) p2 = AddRODataPatch(test_str, "added_data") self.run_test("printf_nopie", [p1, p2], expected_output=b"qwertyuiop\n\x00Hi", expected_returnCode=0)
def test_add_ro_data_patch(self, tlen=5): p1 = AddRODataPatch(b"A" * tlen, "added_data") added_code = ''' mov eax, 4 ;sys_write mov ebx, 1 ;fd = stdout mov ecx, {added_data} ;buf mov edx, %d ;len int 0x80 ''' % tlen p2 = InsertCodePatch(0x8048457, added_code, "added_code") self.run_test("printf_nopie", [p1, p2], expected_output=b"A" * tlen + b"Hi", expected_returnCode=0x0)
def test_insert_code_patch(self): test_str = b"qwertyuiop\n\x00" added_code = ''' mov eax, 4 mov ebx, 1 mov ecx, {added_data} mov edx, %d int 0x80 ''' % (len(test_str)) p1 = InsertCodePatch(0x8048457, added_code) p2 = AddRODataPatch(test_str, "added_data") self.run_test("printf_nopie", [p1, p2], expected_output=b"qwertyuiop\n\x00Hi", expected_returnCode=0)
def test_add_ro_data_patch(self, tlen=5): p1 = AddRODataPatch(b"A" * tlen, "added_data") added_code = ''' li r0, 4 li r3, 1 lis r4, {added_data}@h ori r4, r4, {added_data}@l li r5, %d sc ''' % tlen p2 = InsertCodePatch(0x100004f8, added_code, "added_code") self.run_test("printf_nopie", [p1, p2], expected_output=b"A" * tlen + b"Hi", expected_returnCode=0x0)
def test_insert_code_patch(self): test_str = b"qwertyuiop\n\x00" added_code = ''' li r0, 4 li r3, 1 lis r4, {added_data}@h ori r4, r4, {added_data}@l li r5, %d sc ''' % (len(test_str)) p1 = InsertCodePatch(0x100004f8, added_code) p2 = AddRODataPatch(test_str, "added_data") self.run_test("printf_nopie", [p1, p2], expected_output=b"qwertyuiop\n\x00Hi", expected_returnCode=0)
def test_sample_pie(self): patches = [] transmit_code = ''' pop rsi pop rax push rsi sub rsi, rax sub rsi, 0xa add rsi, {transmitted_string} mov rax, 1 mov rdi, 1 syscall mov rbx, (rsp) add rsp, 8 pop r9 pop r8 pop r10 pop rdx pop rsi pop rdi pop rax mov (rsp), rbx ret ''' injected_code = ''' push rax push rdi push rsi push rdx push r10 push r8 push r9 mov rdx, 10 push $ call {transmit_function} ''' patches.append(AddCodePatch(transmit_code, name="transmit_function")) patches.append( AddRODataPatch(b"---HI---\x00", name="transmitted_string")) patches.append( InsertCodePatch(0x400665, injected_code, name="injected_code_after_receive")) self.run_test("sample_x86-64_pie", patches, expected_output=b'---HI---\x00\x00Purdue')
def test_double_patch_collision(self): test_str1 = b"1111111111\n\x00" test_str2 = b"2222222222\n\x00" added_code1 = ''' li r0, 4 li r3, 1 lis r4, {str1}@h ori r4, r4, {str1}@l li r5, %d sc ''' % (len(test_str1)) added_code2 = ''' li r0, 4 li r3, 1 lis r4, {str2}@h ori r4, r4, {str2}@l li r5, %d sc ''' % (len(test_str2)) p1 = InsertCodePatch(0x100004f8, added_code1, name="p1", priority=100) p2 = InsertCodePatch(0x100004f8, added_code2, name="p2", priority=1) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str1 + b"Hi", try_without_cfg=False) p1 = InsertCodePatch(0x100004f8, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x100004f8, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi", try_without_cfg=False) self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches) p1 = InsertCodePatch(0x100004f8, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x100004f8 + 0x4, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi", try_without_cfg=False) self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches)
def test_double_patch_collision(self): test_str1 = b"1111111111\n\x00" test_str2 = b"2222222222\n\x00" added_code1 = ''' dli $v0, 5001 dli $a0, 1 dla $a1, {str1} dli $a2, %d syscall ''' % (len(test_str1)) added_code2 = ''' dli $v0, 5001 dli $a0, 1 dla $a1, {str2} dli $a2, %d syscall ''' % (len(test_str2)) p1 = InsertCodePatch(0x120000b20, added_code1, name="p1", priority=100) p2 = InsertCodePatch(0x120000b20, added_code2, name="p2", priority=1) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str1 + b"Hi", try_without_cfg=False) p1 = InsertCodePatch(0x120000b20, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x120000b20, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi", try_without_cfg=False) self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches) p1 = InsertCodePatch(0x120000b20, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x120000b20 + 0x4, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi", try_without_cfg=False) self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches)
def test_sample_no_pie(self): patches = [] transmit_code = ''' mov rax, 1 mov rdi, 1 syscall mov rbx, (rsp) add rsp, 8 pop r9 pop r8 pop r10 pop rdx pop rsi pop rdi pop rax mov (rsp), rbx ret ''' patches.append(AddCodePatch(transmit_code, name="transmit_function")) patches.append( AddRODataPatch(b"---HI---\x00", name="transmitted_string")) injected_code = ''' push rax push rdi push rsi push rdx push r10 push r8 push r9 mov rsi, {transmitted_string} mov rdx, 10 call {transmit_function} ''' patches.append( InsertCodePatch(0x400502, injected_code, name="injected_code_after_receive")) self.execute(patches, "sample_x86-64_no_pie", b'---HI---\x00\x00Purdue')
def test_double_patch_collision(self): test_str1 = b"1111111111\n\x00" test_str2 = b"2222222222\n\x00" added_code1 = ''' mov r7, 0x4 mov r0, 0x1 ldr r1, ={str1} mov r2, %d svc 0 ''' % (len(test_str1)) added_code2 = ''' mov r7, 0x4 mov r0, 0x1 ldr r1, ={str2} mov r2, %d svc 0 ''' % (len(test_str2)) p1 = InsertCodePatch(0x103ec, added_code1, name="p1", priority=100) p2 = InsertCodePatch(0x103ec, added_code2, name="p2", priority=1) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str1 + b"Hi") p1 = InsertCodePatch(0x103ec, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x103ec, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi") self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches) p1 = InsertCodePatch(0x103ec, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x103ec + 0x4, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi") self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches)
def compile_function(code, compiler_flags="", bits=32, little_endian=False, entry=0x0, symbols=None, data_only=False, prefix=""): with utils.tempdir() as td: c_fname = os.path.join(td, "code.c") object_fname = os.path.join(td, "code.o") object2_fname = os.path.join(td, "code.2.o") linker_script_fname = os.path.join(td, "code.lds") data_fname = os.path.join(td, "data") rodata_sec_index = rodata_sym_index_old = rodata_sym_index_new = -1 # C -> Object File with open(c_fname, 'w') as fp: fp.write(code) target = ("powerpcle-linux-gnu" if little_endian else "powerpc-linux-gnu") if bits == 32 else ( "powerpc64le-linux-gnu" if little_endian else "powerpc64-linux-gnu") res = utils.exec_cmd("clang -target %s -o %s -c %s %s" \ % (target, object_fname, c_fname, compiler_flags), shell=True) if res[2] != 0: raise CLangException("CLang error: " + str(res[0] + res[1], 'utf-8')) # Setup Linker Script linker_script = "SECTIONS { .text : { *(.text) " if symbols: for i in symbols: if i == ".rodata": linker_script += i + " = " + hex(symbols[i] - ( (entry - 0x10700000) & ~0xFFFF)) + ";" else: linker_script += i + " = " + hex(symbols[i] - entry) + ";" linker_script += "} .rodata : { *(.rodata*) } }" with open(linker_script_fname, 'w') as fp: fp.write(linker_script) # Object File --LinkerScript--> Object File res = utils.exec_cmd( "ld.lld -relocatable %s -T %s -o %s" % (object_fname, linker_script_fname, object2_fname), shell=True) if res[2] != 0: raise Exception("Linking Error: " + str(res[0] + res[1], 'utf-8')) # Load Object File ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}, perform_relocations=False) # Figure Out .text Section Size for section in ld.all_objects[0].sections: if section.name == ".text": text_section_size = section.filesize break # Modify Symbols in Object File to Trick Loader with open(object2_fname, "rb+") as f: elf = ELFFile(f) # Find the Index of .rodata Section for i in range(elf.num_sections()): if elf.get_section(i).name == ".rodata": rodata_sec_index = i break # Find the Index of the src and dest Symbol symtab_section = elf.get_section_by_name(".symtab") for i in range(symtab_section.num_symbols()): if symtab_section.get_symbol( i )['st_shndx'] == rodata_sec_index and symtab_section.get_symbol( i)['st_info']['type'] == 'STT_SECTION': rodata_sym_index_old = i if symtab_section.get_symbol(i).name == ".rodata": rodata_sym_index_new = i # Rewrite the Symbol if rodata_sym_index_new != -1 and rodata_sec_index != -1 and rodata_sym_index_old != -1: for i in range(elf.num_sections()): if elf.get_section(i).header[ 'sh_name'] == symtab_section.header['sh_name']: f.seek(0) content = f.read() f.seek(symtab_section['sh_offset'] + rodata_sym_index_new * symtab_section['sh_entsize']) rodata_sym_new = f.read( symtab_section['sh_entsize']) content = utils.bytes_overwrite( content, rodata_sym_new, symtab_section['sh_offset'] + rodata_sym_index_old * symtab_section['sh_entsize']) f.seek(0) f.write(content) f.truncate() break # Replace all R_PPC_PLTREL24 to R_PPC_REL24 rela_section = elf.get_section_by_name(".rela.text") if rela_section is not None: for i in range(rela_section.num_relocations()): if rela_section.get_relocation(i)['r_info_type'] == 18: reloc = rela_section.get_relocation(i).entry reloc['r_info'] -= 8 for j in range(elf.num_sections()): if elf.get_section(j).header[ 'sh_name'] == rela_section.header[ 'sh_name']: f.seek(0) content = f.read() content = utils.bytes_overwrite( content, elf.structs.Elf_Rela.build(reloc), rela_section['sh_offset'] + i * rela_section['sh_entsize']) f.seek(0) f.write(content) f.truncate() break # Load the Modified Object File and Return compiled Data or Code ld = cle.Loader(object2_fname, main_opts={ "base_addr": 0x0, "entry_point": 0x0 }) if data_only: patches = [] for section in ld.all_objects[0].sections: if section.name == ".rodata": res = utils.exec_cmd( "objcopy -B i386 -O binary -j %s %s %s" % (section.name, object2_fname, data_fname), shell=True) if res[2] != 0: raise ObjcopyException("Objcopy Error: " + str(res[0] + res[1], 'utf-8')) with open(data_fname, "rb") as fp: patches.append( AddRODataPatch(fp.read(), name=prefix + section.name)) break return patches else: compiled = ld.memory.load(ld.all_objects[0].entry, text_section_size) return compiled
def get_patches(self): cfg = self.patcher.cfg patches = [] pnum = 0 used_spec_chars = [] for func, (func_name, func_obj) in self.ident.matches.items(): if func_name not in PRINTF_VARIANTS: continue if func_obj.format_spec_char is None: l.warning("func_obj.format_spec_char is None") continue fmt_arg_pos = PRINTF_VARIANTS[func_name] callers = set.union( set(), *(cfg.get_predecessors(node) for node in cfg.get_all_nodes(func.addr))) handled_addrs = set() func_to_cfg = {} for caller in callers: if caller.addr in handled_addrs: continue try: args, _ = self.ident.get_call_args(func, caller.addr) except KeyError: continue fmt_str = args[fmt_arg_pos] if not claripy.is_true(claripy.Or(*(claripy.And(seg.min_addr <= fmt_str, fmt_str <= seg.max_addr)\ for seg in self.ro_segments))): # we bad break handled_addrs.add(caller.addr) else: # patch not necessary for this function continue pnum += 1 # we need this to ensure always different labels used_spec_chars.append(func_obj.format_spec_char) check = """ ; is the address not in RO memory? cmp dword [esp+{stack_offset}], {{max_ro_addr}} jbe _end_printfcheck_%d ; int 3 ; is the address in the flag page? cmp dword [esp+{stack_offset}], {flag_page} jb _check_for_percent_%d cmp dword [esp+{stack_offset}], {flag_page_almost_end} ja _check_for_percent_%d ; they're trying to read from the flag page! f**k them. jmp 0x41414141 _check_for_percent_%d: push esi ; = pointer to string mov esi, [esp+{stack_offset_2}] push eax xor eax, eax; hash _loop_printfcheck_%d: cmp byte [esi], 0 je _final_check_printfcheck_%d xor al, byte[esi] cmp byte[esi], {format_spec_char} jne _continue_printfcheck_%d mov ah, 0x1 _continue_printfcheck_%d: inc esi jmp _loop_printfcheck_%d _final_check_printfcheck_%d: test ah, ah je _restore_printfcheck_%d test al, al ; avoid al==0 as we do in the hash algorithm jne _do_not_inc_%d inc al _do_not_inc_%d: ; the dynamic hash will always be bigger than 0, the hash list is null terminated mov esi, {{hash_list_{format_spec_char}}} _hash_check_loop_%d: cmp byte[esi], 0 ; the end of the list has been reached je 0x41414141 cmp byte[esi], al ; esi points to the hash list je _restore_printfcheck_%d inc esi jmp _hash_check_loop_%d _restore_printfcheck_%d: pop eax pop esi _end_printfcheck_%d: """.format( stack_offset=(fmt_arg_pos + 1) * 4, stack_offset_2=(fmt_arg_pos + 2) * 4, flag_page=FLAG_PAGE, flag_page_almost_end=FLAG_PAGE + 0xffc, format_spec_char=ord(func_obj.format_spec_char), ) % tuple([pnum] * 18) patches.append( InsertCodePatch(func.addr, check, priority=250, name="noflagprintf_%d" % pnum)) l.info("function at %#08x protected" % func.addr) if patches: max_ro_addr = max(seg.max_addr for seg in self.ro_segments) patches.append(AddLabelPatch(max_ro_addr, name="max_ro_addr")) # print repr(self.hash_dict) for fspec in set(used_spec_chars): hash_list = b"".join(self.hash_dict[fspec]) + b"\x00" patches.append( AddRODataPatch(hash_list, name="hash_list_{format_spec_char}".format( format_spec_char=ord(fspec)))) # print "\n".join(map(str,patches)) return patches
def test_double_patch_collision(self): test_str1 = b"1111111111\n\x00" test_str2 = b"2222222222\n\x00" added_code1 = ''' pusha mov eax, 4 mov ebx, 1 mov ecx, {str1} mov edx, %d int 0x80 popa ''' % (len(test_str1)) added_code2 = ''' pusha mov eax, 4 mov ebx, 1 mov ecx, {str2} mov edx, %d int 0x80 popa ''' % (len(test_str2)) p1 = InsertCodePatch(0x8048457, added_code1, name="p1", priority=100) p2 = InsertCodePatch(0x8048457, added_code2, name="p2", priority=1) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str1 + b"Hi") p1 = InsertCodePatch(0x8048457, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x8048457, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi") self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches) p1 = InsertCodePatch(0x8048457, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x8048457 + 3, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str2 + b"Hi") self.assertNotIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches) p1 = InsertCodePatch(0x8048457, added_code1, name="p1", priority=1) p2 = InsertCodePatch(0x8048457 + 0x11, added_code2, name="p2", priority=100) p3 = AddRODataPatch(test_str1, "str1") p4 = AddRODataPatch(test_str2, "str2") backend = self.run_test("printf_nopie", [p1, p2, p3, p4], expected_output=test_str1 + test_str2 + b"Hi") self.assertIn(p1, backend.added_patches) self.assertIn(p2, backend.added_patches)