parser = ArgumentParser() parser.add_argument("original") parser.add_argument("patched") args = parser.parse_args() try: os.unlink(args.patched) except OSError: pass try: os.unlink(args.patched + ".bin") except OSError: pass backend = DetourBackend(args.original, variant="stm32") patches = [] typedef = ''' typedef unsigned short uint16_t; typedef unsigned char uint8_t; ''' transmit_code = ''' void rx_brake_routine( unsigned char buff[], void *bumper ){ uint16_t speed_value; uint8_t brake_switch; speed_value = (buff[3] << 8) + buff[2]; brake_switch = (buff[4] & 0b00001100) >> 2; ((unsigned char*)bumper)[13] = (brake_switch) ? 1 : 0; if ( ((unsigned char*)bumper)[13] ) {
def test_0b32aa01_01(): print "Testing test_0b32aa01_01..." filepath = os.path.join(bin_location, "0b32aa01_01_2") backend = DetourBackend(filepath) cfg = backend.cfg legitimate_functions = set([ 0x80480a0, 0x8048230, 0x8048400, 0x80484f0, 0x80485fc, 0x8048607, 0x8048615, 0x8048635, 0x80486c3, 0x80486a9L, 0x8048613L, 0x8048655L, 0x804867bL, 0x80486deL, 0x8048695L]) non_syscall_functions = [v for k,v in cfg.functions.iteritems() if not v.is_syscall] #check startpoints, I know that sometimes they could be None, but this should not happen in CADET_00003 function_entrypoints = set([f.startpoint.addr for f in non_syscall_functions]) print "additional:",map(hex,function_entrypoints-legitimate_functions) print "skipped:",map(hex,legitimate_functions-function_entrypoints) nose.tools.assert_equal(function_entrypoints == legitimate_functions, True) sane_functions = [v for k,v in cfg.functions.iteritems() if is_sane_function(v)] function_entrypoints = set([f.startpoint.addr for f in sane_functions]) print "additional:",map(hex,function_entrypoints-legitimate_functions) print "skipped:",map(hex,legitimate_functions-function_entrypoints) nose.tools.assert_equal(function_entrypoints == legitimate_functions, True) #all sane functions ends with ret in CADET_00003 for ff in sane_functions: node = cfg.get_any_node(ff.addr, is_syscall=False) nose.tools.assert_equal(node!=None,True) nose.tools.assert_equal(len(node.instruction_addrs)>0,True) node = cfg.get_any_node(ff.addr+1, is_syscall=False,anyaddr=True) nose.tools.assert_equal(node!=None,True) nose.tools.assert_equal(len(node.instruction_addrs)>0,True) nose.tools.assert_equal(ff.startpoint!=None,True) nose.tools.assert_equal(ff.ret_sites!=None,True) if ff.addr == 0x080485FC or ff.addr==0x8048607: nose.tools.assert_equal(ff.returning==False,True) if ff.returning: nose.tools.assert_equal(len(ff.ret_sites)>0,True) for endpoint in ff.ret_sites: bb = backend.project.factory.block(endpoint.addr) last_instruction = bb.capstone.insns[-1] nose.tools.assert_equal(last_instruction.mnemonic == u"ret", True) syscalls = [v for k,v in cfg.functions.iteritems() if v.is_syscall] for ff in syscalls: bb1 = cfg.get_any_node(ff.addr) nose.tools.assert_equal(len(bb1.predecessors) >= 1, True) bb2 = bb1.predecessors[0] bb = backend.project.factory.block(bb2.addr) ii = bb.capstone.insns[-1] nose.tools.assert_equal(ii.mnemonic == u"int" and ii.op_str == u"0x80", True)
def test_CADET_00003(): print "Testing test_CADET_00003..." filepath = os.path.join(bin_location, "CADET_00003") backend = DetourBackend(filepath) cfg = backend.cfg #how to get the list of functions from the IDA list: #print "["+",\n".join(map(hex,hex,[int(l.split()[2],16) for l in a.split("\n") if l.strip()]))+"]" legitimate_functions = set([ 0x80480a0, 0x8048230, 0x8048400, 0x80484f0, 0x80485fc, 0x804860c, 0x804861a, 0x804863a, 0x8048705, 0x8048735, 0x8048680L, 0x80486e3L, 0x80486c8L, 0x80486aeL, 0x8048618L, 0x804865aL, 0x804869aL]) non_syscall_functions = [v for k,v in cfg.functions.iteritems() if not v.is_syscall] #check startpoints, I know that sometimes they could be None, but this should not happen in CADET_00003 function_entrypoints = set([f.startpoint.addr for f in non_syscall_functions]) print "additional:",map(hex,function_entrypoints-legitimate_functions) print "skipped:",map(hex,legitimate_functions-function_entrypoints) nose.tools.assert_equal(function_entrypoints == legitimate_functions, True) sane_functions = [v for k,v in cfg.functions.iteritems() if is_sane_function(v)] function_entrypoints = set([f.startpoint.addr for f in sane_functions]) print "additional:",map(hex,function_entrypoints-legitimate_functions) print "skipped:",map(hex,legitimate_functions-function_entrypoints) nose.tools.assert_equal(function_entrypoints == legitimate_functions, True) #something which was wrong in the past n = cfg.get_any_node(0x80485EC) nose.tools.assert_true(len(n.instruction_addrs) == 1) nose.tools.assert_true(n.instruction_addrs[0] == 0x80485EC) #all sane functions ends with ret in CADET_00003 for ff in sane_functions: node = cfg.get_any_node(ff.addr, is_syscall=False) nose.tools.assert_equal(node!=None,True) nose.tools.assert_equal(len(node.instruction_addrs)>0,True) node = cfg.get_any_node(ff.addr+1, is_syscall=False,anyaddr=True) nose.tools.assert_equal(node!=None,True) nose.tools.assert_equal(len(node.instruction_addrs)>0,True) nose.tools.assert_equal(ff.startpoint!=None,True) nose.tools.assert_equal(ff.ret_sites!=None,True) if ff.addr == 0x080485FC or ff.addr==0x804860C: nose.tools.assert_equal(ff.returning==False,True) if ff.returning: nose.tools.assert_equal(len(ff.ret_sites)>0,True) for endpoint in ff.ret_sites: bb = backend.project.factory.block(endpoint.addr) last_instruction = bb.capstone.insns[-1] nose.tools.assert_equal(last_instruction.mnemonic == u"ret", True) syscalls = [v for k,v in cfg.functions.iteritems() if v.is_syscall] for ff in syscalls: bb1 = cfg.get_any_node(ff.addr) nose.tools.assert_equal(len(bb1.predecessors) >= 1, True) bb2 = bb1.predecessors[0] bb = backend.project.factory.block(bb2.addr) ii = bb.capstone.insns[-1] nose.tools.assert_equal(ii.mnemonic == u"int" and ii.op_str == u"0x80", True) endpoint_set = set(map(lambda x:(x.addr,x.size),cfg.functions[0x08048230].endpoints)) nose.tools.assert_equal(set([(0x080483F4,12),(0x080483D5,20)]),endpoint_set) ret_set = set(map(lambda x:(x.addr,x.size),cfg.functions[0x08048230].ret_sites)) nose.tools.assert_equal(set([(0x080483F4,12)]),ret_set) # the following is a case of a bb that should be split by normalization # because the bb is split by a "subsequent" jump bb = cfg.get_any_node(0x804824F) nose.tools.assert_equal(bb != None, True) nose.tools.assert_equal(bb.size == 13, True) bb = cfg.get_any_node(0x08048230) nose.tools.assert_equal(bb != None, True) nose.tools.assert_equal(bb.size == 31, True)
# parse command line arguments parser = ArgumentParser() parser.add_argument("original") parser.add_argument("patched") parser.add_argument("patchinfo", nargs="?") args = parser.parse_args() # setup logging options logging.getLogger("angr").propagate = False logging.getLogger("cle").propagate = False logging.getLogger("pyvex").propagate = False logging.getLogger("patcherex").setLevel(logging.DEBUG) # initialize backend backend = DetourBackend(args.original, replace_note_segment=True, try_reuse_unused_space=True) patches = [] # replace the original hash function (using CRC-32) with a modified version of it (using SHA-256) digest_message = ''' #include <stdlib.h> typedef void EVP_MD_CTX; void digest_message(const unsigned char *message, size_t message_len, unsigned char **digest, unsigned int *digest_len) { EVP_MD_CTX *mdctx; if((mdctx = EVP_MD_CTX_new()) == NULL) handleErrors(); if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) handleErrors();