def _get_return_labels(patch): """ Adds labels to the jump out targets """ ret = [] p1 = AddLabelPatch(patch["dst_active"], patch["dst_active_name"]) ret.append(p1) if type(patch["dst_zero"]) != str: p2 = AddLabelPatch(patch["dst_zero"], patch["dst_zero_name"]) ret.append(p2) return ret
def test_add_label_patch(self): p1 = AddLabelPatch(0x080484f4, "added_label") p2 = InlinePatch(0x08048442, "LEA EDX, [{added_label}]") self.run_test("printf_nopie", [p1, p2], expected_output=b"s", expected_returnCode=0)
def test_add_label_patch(self): p1 = AddLabelPatch(0x400935, "added_label") added_code = ''' li $v0, 4004 li $a0, 1 la $a1, {added_label} li $a2, 1 syscall ''' p2 = InsertCodePatch(0x40076c, added_code) self.run_test("printf_nopie", [p1, p2], expected_output=b"sHi", expected_returnCode=0)
def test_add_label_patch(self): p1 = AddLabelPatch(0x400649, "added_label") added_code = ''' mov x8, 0x40 mov x0, 0x1 ldr x1, ={added_label} mov x2, 1 svc 0 ''' p2 = InsertCodePatch(0x400580, added_code) self.run_test("printf_nopie", [p1, p2], expected_output=b"sHi", expected_returnCode=0)
def test_add_label_patch(self): p1 = AddLabelPatch(0x120000cf9, "added_label") added_code = ''' dli $v0, 5001 dli $a0, 1 dla $a1, {added_label} dli $a2, 1 syscall ''' p2 = InsertCodePatch(0x120000b20, added_code) self.run_test("printf_nopie", [p1, p2], expected_output=b"sHi", expected_returnCode=0)
def test_add_label_patch(self): p1 = AddLabelPatch(0x10451, "added_label") added_code = ''' mov r7, 0x4 mov r0, 0x1 ldr r1, ={added_label} mov r2, 1 svc 0 ''' p2 = InsertCodePatch(0x103ec, added_code) self.run_test("printf_nopie", [p1, p2], expected_output=b"sHi", expected_returnCode=0)
def test_add_label_patch(self): p1 = AddLabelPatch(0x10000759, "added_label") added_code = ''' li r0, 4 li r3, 1 lis r4, {added_label}@h ori r4, r4, {added_label}@l li r5, 1 sc ''' p2 = InsertCodePatch(0x100004f8, added_code) self.run_test("printf_nopie", [p1, p2], expected_output=b"sHi", expected_returnCode=0)
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