Source code for ducky.tools.as

import os
import sys

from six import iteritems, PY2

[docs]def translate_buffer(logger, buffer, file_in, options): from ..cpu.assemble import AssemblerError, translate_buffer try: return translate_buffer(logger, buffer, mmapable_sections = options.mmapable_sections, writable_sections = options.writable_sections, filename = file_in, defines = options.defines, includes = options.includes, verify_disassemble = options.verify_disassemble) except AssemblerError as exc: exc.log(logger.error) sys.exit(1)
[docs]def encode_blob(logger, file_in, options): logger.debug('encode_blob: file_in=%s', file_in) from ..cpu.assemble import DataSection, SymbolsSection, IntSlot, Label, sizeof, BytesSlot, RelocSection, SourceLocation from ..mm.binary import SectionFlags section_name = '__' + os.path.split(file_in)[1].replace('.', '_').replace('-', '_') section = DataSection('.%s' % section_name, flags = SectionFlags.from_string(options.blob_flags.upper())) section.base = section.ptr = 0 symtab = SymbolsSection('.symtab') symtab.base = symtab.ptr = 0 reloc = RelocSection('.reloc') reloc.base = reloc.ptr = 0 if options.mmapable_sections is True: section.flags.mmapable = True logger.debug('section: %s', section) with open(file_in, 'rb') as f_in: if PY2: data = bytearray([ord(c) for c in f_in.read()]) else: data = f_in.read() var_size = IntSlot() var_size.name = Label('%s_size' % section_name, section, SourceLocation(filename = file_in, lineno = 0)) var_size.value = len(data) var_size.section = section var_size.section_ptr = 0 var_size.close() section.content += var_size.value symtab.content.append(var_size) var_content = BytesSlot() var_content.name = Label('%s_start' % section_name, section, SourceLocation(filename = file_in, lineno = 0)) var_content.value = data var_content.section = section var_content.section_ptr = sizeof(var_size) var_content.close() section.content += var_content.value symtab.content.append(var_content) logger.debug('section: %s', section) return {section.name: section, '.symtab': symtab, '.reloc': reloc}
[docs]def save_object_file(logger, sections, file_out, options): if os.path.exists(file_out) and not options.force: logger.error('Output file %s already exists, use -f to force overwrite', file_out) sys.exit(1) from ..cpu.assemble import sizeof from ..mm.binary import File, SectionTypes, SymbolEntry, RelocEntry section_name_to_index = {} i = 0 for s_name, section in list(iteritems(sections)): if section.type in (SectionTypes.SYMBOLS, SectionTypes.RELOC): continue if section.flags.bss and section.data_size > 0: continue if section.data_size > 0: continue del sections[s_name] section_name_to_index[s_name] = i i += 1 with File.open(logger, file_out, 'w') as f_out: h_file = f_out.create_header() h_file.flags.mmapable = 1 if options.mmapable_sections else 0 filenames = {} section_name_to_index = {} for i, s_name in enumerate(sections.keys()): section_name_to_index[s_name] = i for s_name, section in iteritems(sections): h_section = f_out.create_section() h_section.type = section.type h_section.items = section.items h_section.data_size = section.data_size h_section.file_size = section.file_size h_section.name = f_out.string_table.put_string(section.name) h_section.base = section.base if section.type == SectionTypes.SYMBOLS: symbol_entries = [] for se in section.content: entry = SymbolEntry() symbol_entries.append(entry) entry.flags = se.flags.to_encoding() entry.name = f_out.string_table.put_string(se.name.name) entry.address = se.section_ptr entry.size = se.size entry.section = section_name_to_index[se.section.name] if se.location is not None: loc = se.location if loc.filename not in filenames: filenames[loc.filename] = f_out.string_table.put_string(loc.filename) entry.filename = filenames[loc.filename] if loc.lineno: entry.lineno = loc.lineno entry.type = se.symbol_type f_out.set_content(h_section, symbol_entries) h_section.data_size = h_section.file_size = sizeof(SymbolEntry()) * len(symbol_entries) elif section.type == SectionTypes.RELOC: reloc_entries = [] for rs in section.content: entry = RelocEntry() reloc_entries.append(entry) entry.name = f_out.string_table.put_string(rs.name) entry.flags = rs.flags.to_encoding() entry.patch_section = section_name_to_index[rs.patch_section.name] entry.patch_address = rs.patch_address entry.patch_offset = rs.patch_offset or 0 entry.patch_size = rs.patch_size entry.patch_add = rs.patch_add or 0 f_out.set_content(h_section, reloc_entries) h_section.data_size = h_section.file_size = sizeof(RelocEntry()) * len(reloc_entries) else: h_section.flags = section.flags.to_encoding() f_out.set_content(h_section, section.content) h_section = f_out.create_section() h_section.type = SectionTypes.STRINGS h_section.name = f_out.string_table.put_string('.strings') f_out.save()
[docs]def main(): import optparse from . import add_common_options, parse_options parser = optparse.OptionParser() add_common_options(parser) group = optparse.OptionGroup(parser, 'File options') parser.add_option_group(group) group.add_option('-i', dest = 'file_in', action = 'append', default = [], help = 'Input file') group.add_option('-o', dest = 'file_out', action = 'append', default = [], help = 'Output file') group.add_option('-f', dest = 'force', default = False, action = 'store_true', help = 'Force overwrite of the output file') group = optparse.OptionGroup(parser, 'Translation options') parser.add_option_group(group) group.add_option('-D', dest = 'defines', action = 'append', default = [], help = 'Define variable', metavar = 'VAR') group.add_option('-I', dest = 'includes', action = 'append', default = [], help = 'Add directory to list of include dirs', metavar = 'DIR') group.add_option('--verify-disassemble', dest = 'verify_disassemble', action = 'store_true', default = False, help = 'Verify that disassebler instructions match input text') group = optparse.OptionGroup(parser, 'Binary options') parser.add_option_group(group) group.add_option('-b', '--blob', dest = 'blob', action = 'store_true', default = False, help = 'Create object file wrapping a binary blob') group.add_option('-B', '--blob-flags', dest = 'blob_flags', action = 'store', default = 'rl', help = 'Flags of blob section') group.add_option('-m', '--mmapable-sections', dest = 'mmapable_sections', action = 'store_true', default = False, help = 'Create mmap\'able sections') group.add_option('-w', '--writable-sections', dest = 'writable_sections', action = 'store_true', default = False, help = '.text and other read-only sections will be marked as writable too') options, logger = parse_options(parser) if not options.file_in: parser.print_help() sys.exit(1) if len(options.file_out) and len(options.file_out) != len(options.file_in): logger.error('If specified, number of output files must be equal to number of input files') sys.exit(1) for file_in in options.file_in: with open(file_in, 'r') as f_in: buffer = f_in.read() if options.file_out: file_out = options.file_out.pop(0) else: file_out = os.path.splitext(file_in)[0] + '.o' if options.blob is True: sections = encode_blob(logger, file_in, options) else: sections = translate_buffer(logger, buffer, file_in, options) save_object_file(logger, sections, file_out, options)