def disassemble(code, offset=0x0): # pylint: disable=arguments-differ with utils.tempdir() as td: bin_fname = os.path.join(td, "code.bin") fp = open(bin_fname, 'wb') fp.write(code) fp.close() res = utils.exec_cmd( "avr-objdump -D -b binary -m avr5 %s | tail +8" % (bin_fname), shell=True) if res[2] != 0: raise Exception("avr-objdump error: " + str(res[0] + res[1], 'utf-8')) str_result = res[0].decode("utf-8") result = [] for line in str_result.splitlines(): m = re.match( r"\s+(?P<address>[0-9a-f]+):\s+(?P<bytes>([0-9a-f]{2}\s)+)\s+(?P<mnemonic>.+?)\s+(?P<op_str>.+?)$", line) if m: instr = AttrDict(m.groupdict()) instr['address'] = int(instr['address'], 16) + offset instr['bytes'] = bytes.fromhex(instr['bytes']) instr['mnemonic'] = re.sub(r'\s+', '', instr['mnemonic']) instr['op_str'] = re.sub( r'\s+', '', instr['op_str'].split(";")[0]).replace(",", ", ") result.append(instr) return result
def compile_function(code, compiler_flags="-fPIE", bits=32, little_endian=False, entry=0x0, symbols=None): 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") with open(c_fname, 'w') as fp: fp.write(code) linker_script = "SECTIONS { .text : { *(.text) " if symbols: for i in symbols: linker_script += i + " = " + hex(symbols[i] - entry) + ";" linker_script += "}}" with open(linker_script_fname, 'w') as fp: fp.write(linker_script) target = ("mipsel-linux-gnu" if little_endian else "mips-linux-gnu") if bits == 32 else ( "mips64el-linux-gnuabi64" if little_endian else "mips64-linux-gnuabi64") 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')) 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')) ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}) compiled = ld.memory.load(ld.all_objects[0].entry, 0xFFFFFFFFFFFFFFFF) return compiled
def compile_function(code, compiler_flags="", entry=0x0, symbols=None): 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") # C -> Object File with open(c_fname, 'w') as fp: fp.write(code) # clang -target avr -mmcu=atmega328p res = utils.exec_cmd("avr-gcc -mmcu=atmega328p -o %s -c %s %s" % (object_fname, c_fname, compiler_flags), shell=True) if res[2] != 0: raise Exception("avr-gcc error: " + str(res[0] + res[1], 'utf-8')) # Setup Linker Script linker_script = "SECTIONS { .text : { *(.text) " if symbols: for i in symbols: linker_script += i + " = " + hex(symbols[i] - entry) + ";" linker_script += "}}" with open(linker_script_fname, 'w') as fp: fp.write(linker_script) # Object File --LinkerScript--> Object File res = utils.exec_cmd( "avr-ld -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')) ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}) compiled = ld.memory.load(ld.all_objects[0].entry, 0xFFFFFFFFFFFFFFFF) return compiled
def compile_function(code, compiler_flags="", is_thumb=False, entry=0x0, symbols=None): 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") with open(c_fname, 'w') as fp: fp.write(code) linker_script = "SECTIONS { .text : { *(.text) " if symbols: for i in symbols: linker_script += i + " = " + hex(symbols[i] - entry) + ";" linker_script += "}}" with open(linker_script_fname, 'w') as fp: fp.write(linker_script) res = utils.exec_cmd("clang -target arm-none-eabi -Os -mcpu=cortex-m0 -o %s -c %s %s %s" \ % (object_fname, c_fname, compiler_flags, "-mthumb" if is_thumb else "-mno-thumb"), shell=True) if res[2] != 0: raise CLangException("CLang error: " + str(res[0] + res[1], 'utf-8')) 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')) ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}) compiled = ld.memory.load(ld.all_objects[0].entry, 0xFFFFFFFFFFFFFFFF) return compiled
def compile_asm(code, name_map=None): # pylint: disable=arguments-differ if not code.endswith("\n"): # prevent avr-as warning code += "\n" try: if name_map is not None: code = code.format(**name_map) # compile_asm else: code = re.subn(r'{.*?}', "0x41414141", code)[0] # solve symbols # TODO except KeyError as e: raise UndefinedSymbolException(str(e)) from e with utils.tempdir() as td: asm_fname = os.path.join(td, "code.asm") object_fname = os.path.join(td, "code.o") bin_fname = os.path.join(td, "code.bin") fp = open(asm_fname, 'w') fp.write(code) fp.close() res = utils.exec_cmd("avr-as -mmcu=avr5 %s -o %s" % (asm_fname, object_fname), shell=True) if res[2] != 0: raise Exception("avr-as error: " + str(res[0] + res[1], 'utf-8')) res = utils.exec_cmd("objcopy -B i386 -O binary -j .text %s %s" % (object_fname, bin_fname), shell=True) if res[2] != 0: raise Exception("objcopy error: " + str(res[0] + res[1], 'utf-8')) fp = open(bin_fname, "rb") compiled = fp.read() fp.close() return compiled
def compile_c(self, code, optimization='-Oz', compiler_flags=""): # TODO symbol support in c code with utils.tempdir() as td: c_fname = os.path.join(td, "code.c") object_fname = os.path.join(td, "code.o") bin_fname = os.path.join(td, "code.bin") fp = open(c_fname, 'w') fp.write(code) fp.close() print(self.project.arch.triplet) res = utils.exec_cmd("clang -nostdlib -mno-sse -target %s -ffreestanding %s -o %s -c %s %s" \ % (self.project.arch.triplet, optimization, object_fname, c_fname, compiler_flags), shell=True) if res[2] != 0: print("CLang error:") print(res[0]) print(res[1]) fp = open(c_fname, 'r') fcontent = fp.read() fp.close() print("\n".join([ "%02d\t%s" % (i + 1, j) for i, j in enumerate(fcontent.split("\n")) ])) raise CLangException res = utils.exec_cmd("objcopy -B i386 -O binary -j .text %s %s" % (object_fname, bin_fname), shell=True) if res[2] != 0: print("objcopy error:") print(res[0]) print(res[1]) raise ObjcopyException fp = open(bin_fname, "rb") compiled = fp.read() fp.close() return compiled
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 compile_function(self, code, compiler_flags="", is_thumb=False, entry=0x0, symbols=None): 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") with open(c_fname, 'w') as fp: fp.write(code) linker_script = "SECTIONS { .text : SUBALIGN(0) { . = " + hex( entry) + "; *(.text) " if symbols: for i in symbols: linker_script += i + " = " + hex(symbols[i]) + ";" linker_script += "}}" with open(linker_script_fname, 'w') as fp: fp.write(linker_script) res = utils.exec_cmd("clang -target arm-linux-gnueabihf -o %s -c %s %s %s" \ % (object_fname, c_fname, compiler_flags, "-mthumb" if is_thumb else "-mno-thumb"), shell=True) if res[2] != 0: raise CLangException("CLang error: " + str(res[0] + res[1], 'utf-8')) 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')) ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}) compiled = ld.memory.load(ld.all_objects[0].entry + entry, ld.memory.max_addr) disasm = self.disassemble(compiled, entry, is_thumb=is_thumb) disasm_str = "" for instr in disasm: if is_thumb and instr.mnemonic == "bl" and instr.operands[ 0].imm in symbols.values(): disasm_str += self.capstone_to_asm(instr).replace( "bl", "blx") + "\n" elif is_thumb and instr.mnemonic == "blx" and ( instr.operands[0].imm + 1) in symbols.values(): disasm_str += self.capstone_to_asm(instr).replace( "blx", "bl") + "\n" elif not is_thumb and instr.mnemonic == "bl" and ( instr.operands[0].imm + 1) in symbols.values(): disasm_str += self.capstone_to_asm(instr).replace( "bl", "blx") + "\n" elif not is_thumb and instr.mnemonic == "blx" and instr.operands[ 0].imm in symbols.values(): disasm_str += self.capstone_to_asm(instr).replace( "blx", "bl") + "\n" else: disasm_str += self.capstone_to_asm(instr) + "\n" compiled = self.compile_asm(disasm_str, base=entry, name_map={}, is_thumb=is_thumb) return compiled
def compile_function(self, code, compiler_flags="", bits=32, entry=0x0, symbols=None, stacklayout=None): import json with utils.tempdir() as td: c_fname = os.path.join(td, "code.c") ll_fname = os.path.join(td, "code.ll") ll2_fname = os.path.join(td, "code.2.ll") json_fname = os.path.join(td, "code.json") 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") if stacklayout is None: clang = "clang-11" opt = "opt-11" llc = "llc-11" lld = "ld.lld-11" else: clang = "/precompiled_llvm_bins/clang" opt = "/precompiled_llvm_bins/opt" llc = "/precompiled_llvm_bins/llc" lld = "/precompiled_llvm_bins/ld.lld" with open(c_fname, 'w') as fp: fp.write(code) linker_script = "SECTIONS { .text : SUBALIGN(0) { . = " + hex( entry) + "; *(.text) " if symbols is not None: for i in symbols: linker_script += i + " = " + hex(symbols[i]) + ";" linker_script += "}}" print(linker_script) with open(linker_script_fname, 'w') as fp: fp.write(linker_script) # c -> ll res = utils.exec_cmd( "%s -S -emit-llvm -g -o %s %s %s %s" % (clang, ll_fname, "-m32" if bits == 32 else "-m64", c_fname, compiler_flags), shell=True) if res[2] != 0: raise Exception("Clang Error: " + str(res[0] + res[1], 'utf-8')) # ll --force-dso-local-> ll res = utils.exec_cmd( "%s -load /precompiled_llvm_bins/LLVMAMP.so --force-dso-local -S %s -o %s" % (opt, ll_fname, ll_fname), shell=True) if res[2] != 0: raise Exception("opt Error: " + str(res[0] + res[1], 'utf-8')) res = utils.exec_cmd("%s -Os -S %s -o %s" % (opt, ll_fname, ll_fname), shell=True) if res[2] != 0: raise Exception("opt Error: " + str(res[0] + res[1], 'utf-8')) # # ll -> ll + AMPDebug if stacklayout is not None: self.addAMPDebug(ll_fname, ll2_fname, stacklayout) else: ll2_fname = ll_fname # ll + AMPDebug -> obj res = utils.exec_cmd( "%s -o %s %s -relocation-model=pic --x86-asm-syntax=intel --filetype=obj" % (llc, object_fname, ll2_fname), shell=True) if res[2] != 0: raise CLangException("llc error: " + str(res[0] + res[1], 'utf-8')) print(str(res[1], 'utf-8')) # TODO: remove this # relocate res = utils.exec_cmd( "%s -relocatable %s -T %s -o %s" % (lld, object_fname, linker_script_fname, object2_fname), shell=True) if res[2] != 0: raise Exception("Linking Error: " + str(res[0] + res[1], 'utf-8')) print(str(res[1], 'utf-8')) ld = cle.Loader(object2_fname, main_opts={"base_addr": 0x0}) compiled = ld.memory.load(ld.all_objects[0].entry + entry, ld.memory.max_addr) return compiled