diff options
author | bloodstalker <thabogre@gmail.com> | 2018-05-25 23:45:50 +0000 |
---|---|---|
committer | bloodstalker <thabogre@gmail.com> | 2018-05-25 23:45:50 +0000 |
commit | a2afe6ff184bc20993f58388887a2d4f1454c140 (patch) | |
tree | 98c3928c40cd268bfbaeb78abbcce50914ef9ea2 | |
parent | wip:added a wasm backend. i need to setup an interface with the main c++ code... (diff) | |
download | mutator-a2afe6ff184bc20993f58388887a2d4f1454c140.tar.gz mutator-a2afe6ff184bc20993f58388887a2d4f1454c140.zip |
load.py is now imported bt another python module, should cut down on startup time. added the WASM linking structures to dwasm. i can start working on the linker as soon as i get some tests.
-rw-r--r-- | .travis.yml | 1 | ||||
-rwxr-xr-x | bfd/delf.py | 27 | ||||
-rwxr-xr-x | bfd/load.py | 5 | ||||
-rw-r--r-- | bruiser/wasm/OpCodes.py | 14 | ||||
-rwxr-xr-x | bruiser/wasm/dwasm.py | 986 | ||||
-rw-r--r-- | bruiser/wasm/section_structs.py | 97 | ||||
-rwxr-xr-x | extra-tools/pretestprep.sh | 3 |
7 files changed, 118 insertions, 1015 deletions
diff --git a/.travis.yml b/.travis.yml index 13fb9d7..88aabf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ before_script: - travis_retry sudo apt-get install clang-5.0 libclang-5.0-dev libclang-common-5.0-dev libllvm5.0 llvm-5.0-dev llvm-5.0 llvm-5.0-runtime libclang1-5.0-dbg libllvm5.0-dbg lldb-5.0 -y - sudo apt-get install gcc-4.9 g++-4.9 - sudo apt-get install libffi-dev -y + - sudo apt-get install bear -y - sudo apt-get install luarocks -y - luarocks install ansicolors --local - ./extra-tools/capstoneubuntu14.sh diff --git a/bfd/delf.py b/bfd/delf.py new file mode 100755 index 0000000..60b2697 --- /dev/null +++ b/bfd/delf.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 + +import argparse +import code +import readline +import signal +import sys +from load import premain, CLIArgParser, SigHandler_SIGINT + +def main(): + argparser = CLIArgParser() + if argparser.args.dbg: + try: + premain(argparser) + except Exception as e: + print(e.__doc__) + if e.message: print(e.message) + signal.signal(signal.SIGINT, SigHandler_SIGINT) + variables = globals().copy() + variables.update(locals()) + shell = code.InteractiveConsole(variables) + shell.interact(banner="DELF REPL") + else: + premain(argparser) + +if __name__ == "__main__": + main() diff --git a/bfd/load.py b/bfd/load.py index ae0771f..73ff05e 100755 --- a/bfd/load.py +++ b/bfd/load.py @@ -16,6 +16,7 @@ #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/ +#**********************************************************************************************************************/ import argparse import sys import readline @@ -1451,7 +1452,9 @@ def main(): if argparser.args.dbg: try: premain(argparser) - except: + except Exception as e: + print(e.__doc__) + if e.message: print(e.message) signal.signal(signal.SIGINT, SigHandler_SIGINT) variables = globals().copy() variables.update(locals()) diff --git a/bruiser/wasm/OpCodes.py b/bruiser/wasm/OpCodes.py index ce813b0..f7c9a1b 100644 --- a/bruiser/wasm/OpCodes.py +++ b/bruiser/wasm/OpCodes.py @@ -11,6 +11,14 @@ class RelocType(Enum): R_WEBASSEMBLY_MEMORY_ADDR_I32 = 5 R_WEBASSEMBLY_TYPE_INDEX_LEB = 6 R_WEBASSEMBLY_GLOBAL_INDEX_LEB = 7 + R_WEBASSEMPLY_FUNCTION_OFFSET_I32 = 8 + R_WEBASSEMBLY_SECTION_OFFSET_I32 = 9 + +class LinkingSubsection(Enum): + WASM_SEGMENT_INFO = 5 + WASM_INIT_FUNCS = 6 + WASM_COMDAT_INFO = 7 + WASM_SYMBOL_TABLE = 8 class TypeType(Enum): none = 1 @@ -19,6 +27,12 @@ class TypeType(Enum): flot = 4 dobl = 5 +class Syminfo_Kind(): + SYMTAB_FUNCTION = 0 + SYMTAB_DATA = 1 + SYMTAB_GLOBAL = 2 + SYMTAB_SECTION = 3 + TypeKS = [['uint8', 8, TypeType.none], ['uint16', 16, TypeType.none], ['uint32', 32, TypeType.none], ['uint64', 64, TypeType.none], ['varuint1', 1, TypeType.lebu], ['varuint7', 7, TypeType.lebu], diff --git a/bruiser/wasm/dwasm.py b/bruiser/wasm/dwasm.py index bb930f9..93217b4 100755 --- a/bruiser/wasm/dwasm.py +++ b/bruiser/wasm/dwasm.py @@ -1,57 +1,17 @@ -#!/bin/python3 +#!/usr/bin/python3 -from __future__ import print_function import argparse -import sys -import re -from section_structs import * -from utils import * -from OpCodes import * -from copy import deepcopy -from TBInit import * -import readline import code +import readline import signal - -_DBG_ = True +import sys +from parse import premain +from utils import ParseFlags def SigHandler_SIGINT(signum, frame): print() sys.exit(0) -# we first read the object file and put all the sections in this class -class ParsedStruct: - def __init__(self): - self.version_number = int() - self.section_list = [] - - -# like the above. currently unused -class ParsedStructV2: - def __init__(self, version_number, section_list): - self.version_number = version_number - self.section_list = section_list - - -# @DEVI-Deprecated-convert a bytearray to int -def Conver2Int(little_endian, size, bytelist): - modifier = size - 1 - sum = 0 - - if little_endian: - for bit in reversed(bytelist): - if bit != 0x80: - sum += bit*(pow(16, modifier)) - modifier -= 1 - return(sum) - else: - for bit in reversed(bytelist): - if bit != 0x80: - sum += bit*(pow(16, modifier)) - modifier -= 1 - return(sum) - -# the argparser class Argparser(object): def __init__(self): parser = argparse.ArgumentParser() @@ -84,943 +44,15 @@ class Argparser(object): self.args.o, self.args.dbg, self.args.unval, self.args.memdump, self.args.idxspc, self.args.run, self.args.metric, self.args.gas, self.args.entry)) -# reads a wasm-obj file, returns a parsedstruct that holds all the sections' -# bytecode, their section type and their length -def ReadWASM(file_path, endianness, is_extended_isa, dbg): - temp_obj_file = [] - wasm_file = open(file_path, "rb") - parsedstruct = ParsedStruct() - # read the magic cookie - byte = wasm_file.read(WASM_OP_Code.uint32) - if byte != WASM_OP_Code.magic_number.to_bytes(WASM_OP_Code.uint32, byteorder=endianness, signed=False): - raise Exception("bad magic cookie") - - # read the version number - byte = wasm_file.read(WASM_OP_Code.uint32) - if byte != WASM_OP_Code.version_number.to_bytes(WASM_OP_Code.uint32, byteorder=endianness, signed=False): - raise Exception("bad version number") - else: - parsedstruct.version_number = byte - - while True: - byte = wasm_file.read(1) - if byte != b'': - temp_obj_file.append(int.from_bytes(byte, byteorder='big', signed=False)) - else: - break - - offset = 0 - loop = True - while loop: - try: - # section_id, offset, dummy = Read(temp_obj_file, offset, 'varuint7') - section_id, offset, dummy = Read(temp_obj_file, offset, 'varuint32') - except IndexError: - break - - payload_length, offset, dummy = Read(temp_obj_file, offset, 'varuint32') - - if section_id == 0: - is_custom_section = True - name_len, offset, dummy = Read(temp_obj_file, offset, 'varuint32') - name = temp_obj_file[offset : offset + name_len] - offset += name_len - if name.find("reloc", 0, 5) == 0: - is_reloc_section = True - reloc_entry_count = Read(temp_obj_file, offset, 'varuint32') - for i in range(0, reloc_entry_count): - reloc_entry, offset, dummy = Read(tmp_obj, offset, 'varuint32') - reloc_entries.append(reloc_entry) - else: - is_custom_section = False - name_len = 0 - name = '' - dummy = 0 - - payload_data = temp_obj_file[offset:offset + payload_length - name_len - dummy] - offset += payload_length - name_len - dummy - - # @DEVI-the second field is for general use. it is unused right - # now so we are filling it with jojo. - parsedstruct.section_list.append([section_id, 'jojo', - payload_length, - is_custom_section, - name_len, name, - payload_data]) - - # prints out the sections in the wasm object - for section in parsedstruct.section_list: - pass - #print(section) - wasm_file.close() - return(parsedstruct) - -# Receives a parsedstruct returned from ReadWASM, parses all the sections and -# fills up a module class. the parse method, then can return the module. -# the returned class objects are all defined in section_structs.py. -class ObjReader(object): - def __init__(self, parsedstruct): - self.parsedstruct = parsedstruct - - # we use this method to read the operands of instructions. it's only - # called by ReadCodeSection - def Disassemble(self, section_byte, offset): - # @DEVI-FIXME- not sure why i was using instruction. its a string... - matched = False - read_bytes = 0 - read_bytes_temp = 0 - read_bytes_temp_iter = 0 - instruction = str() - operands = [] - temp_wasm_ins = WASM_Ins() - - # @DEVI-FIXME-for v1.0 opcodes. needs to get fixed for extended - # op-codes. ideally the mosule should hold its version number so we can - # check it here. - byte = format(section_byte[6][offset], '02x') - offset += 1 - read_bytes += 1 - - for op_code in WASM_OP_Code.all_ops: - if op_code[1] == byte: - matched = True - - # br_table has special immediates - # @DEVI-FIXME-this is costing us quite dearly for every opcode - # we read(at least two ticks per opcode). I could have the - # br_table opcode done separately but kinda hurts the codes - # uniformity. anyways. - if op_code[1] == '0e': - matched = True - temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][0]) - instruction += repr(temp) + ' ' - operands.append(repr(temp)) - read_bytes_temp += read_bytes_temp_iter - for target_table in range(0, temp): - temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][1]) - read_bytes_temp += read_bytes_temp_iter - instruction += repr(temp) + ' ' - operands.append(repr(temp)) - temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][2]) - instruction += repr(temp) + ' ' - operands.append(repr(temp)) - read_bytes_temp += read_bytes_temp_iter - elif op_code[2]: - if isinstance(op_code[3], tuple): - for i in range(0, len(op_code [3])): - temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][i]) - read_bytes_temp += read_bytes_temp_iter - instruction += repr(temp) + ' ' - operands.append(repr(temp)) - else: - temp, offset, read_bytes_temp = Read(section_byte[6], offset, op_code[3]) - instruction += repr(temp) - operands.append(repr(temp)) - - temp_wasm_ins.opcode = op_code[0] - temp_wasm_ins.opcodeint = int(byte, 16) - #temp_wasm_ins.operands = instruction - temp_wasm_ins.operands = operands - instruction = str() - operands = [] - break - - read_bytes += read_bytes_temp - return offset, matched, read_bytes, temp_wasm_ins - - # parses the code section. returns a Code_Section class - def ReadCodeSection(self): - offset = 0 - CS = Code_Section() - temp_func_bodies = Func_Body() - temp_local_entry = Local_Entry() - section_exists = False - for whatever in self.parsedstruct.section_list: - # 10 is the code section - if whatever[0] == 10: - code_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - fn_cn, offset, dummy = Read(code_section[6], offset, 'varuint32') - function_cnt = fn_cn - CS.count = function_cnt - - while function_cnt > 0: - function_body_length, offset, dummy = Read(code_section[6], offset, 'varuint32') - temp_func_bodies.body_size = function_body_length - - local_count, offset, dummy = Read(code_section[6], offset, 'varuint32') - temp_func_bodies.local_count = local_count - - # local_count_size will eventually hold how many bytes we will read - # in total because of the local section - local_count_size = dummy - if local_count != 0: - for i in range(0, local_count): - partial_local_count, offset, dummy = Read(code_section[6], offset, 'varuint32') - local_count_size += dummy - partial_local_type, offset, dummy = Read(code_section[6], offset, 'uint8') - local_count_size += dummy - temp_local_entry.count = partial_local_count - temp_local_entry.type = partial_local_type - temp_func_bodies.locals.append(deepcopy(temp_local_entry)) - local_count -= partial_local_count - else: - pass - - read_bytes_so_far = local_count_size - for i in range(0, function_body_length - local_count_size): - offset, matched, read_bytes, temp_wasm_ins = self.Disassemble(code_section, offset) - temp_func_bodies.code.append(deepcopy(temp_wasm_ins)) - - if not matched: - print(Colors.red + 'did not match anything' + Colors.ENDC) - print(Colors.red + 'code section offset: ' + repr(offset) + Colors.ENDC) - print(Colors.red + 'read bytes: ' + repr(read_bytes) + Colors.ENDC) - print(Colors.red + 'wasm ins: ' + repr(temp_wasm_ins.opcode) + Colors.ENDC) - - for iter in temp_func_bodies.code: - print(iter.opcode) - print(iter.operands) - sys.exit(1) - else: - pass - matched = False - read_bytes_so_far += read_bytes - if read_bytes_so_far == function_body_length: - break - - CS.func_bodies.append(deepcopy(temp_func_bodies)) - temp_func_bodies.locals = [] - temp_func_bodies.code = [] - function_cnt -= 1 - return(CS) - - # parsed the data section. returns a Data_Section class - def ReadDataSection(self): - loop = True - section_exists = False - offset = 0 - DS = Data_Section() - temp_data_segment = Data_Segment() - init_expr = [] - for whatever in self.parsedstruct.section_list: - if whatever[0] == 11: - data_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - data_entry_count, offset, dummy = Read(data_section[6], offset, 'varuint32') - DS.count = data_entry_count - - while data_entry_count != 0: - linear_memory_index, offset, dummy = Read(data_section[6], offset, 'varuint32') - temp_data_segment.index = linear_memory_index - - # reading in the init-expr - while loop: - # @DEVI-FIXME-this only works for none extended opcodes - if data_section[6][offset] == 0x0b: - loop = False - data_char, offset, dummy = Read(data_section[6], offset, 'uint8') - init_expr.append(data_char) - - temp_data_segment.offset = init_expr - - data_entry_length, offset, dummy = Read(data_section[6], offset, 'varuint32') - temp_data_segment.size = data_entry_length - - data_itself = data_section[6][offset:offset + data_entry_length] - temp_data_segment.data = data_itself - offset += data_entry_length - - DS.data_segments.append(deepcopy(temp_data_segment)) - - data_entry_count -= 1 - init_expr = [] - loop = True - return(DS) - - # parses the import section. returns an Import_Section class - def ReadImportSection(self): - offset = 0 - section_exists = False - module_name = [] - field_name = [] - IS = Import_Section() - temp_import_entry = Import_Entry() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 2: - import_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - import_cnt, offset, dummy = Read(import_section[6], offset, 'varuint32') - IS.count = import_cnt - - while import_cnt != 0: - module_length, offset, dummy = Read(import_section[6], offset, 'varuint32') - temp_import_entry.module_len = module_length - - for i in range(0, module_length): - module_name.append(import_section[6][offset + i]) - temp_import_entry.module_str = module_name - offset += module_length - - field_length, offset, dummy = Read(import_section[6], offset, 'varuint32') - temp_import_entry.field_len = field_length - for i in range(0, field_length): - field_name.append(import_section[6][offset + i]) - temp_import_entry.field_str = field_name - offset += field_length - - kind, offset, dummy = Read(import_section[6], offset, 'uint8') - temp_import_entry.kind = kind - - # function type - if kind == 0: - import_type, offset, dummy = Read(import_section[6], offset, 'varuint32') - temp_import_entry.type = import_type - # table type - elif kind == 1: - table_type = Table_Type() - table_type.elemet_type, offset, dummy = Read(import_section[6], offset, 'varint7') - rsz_limits = Resizable_Limits() - rsz_limits.flags, offset, dummy = Read(import_section[6], offset, 'varuint1') - rsz_limits.initial, offset, dummy = Read(import_section[6], offset, 'varuint32') - if rsz_limits.flags: - rsz_limits.maximum, offset, dummy = Read(import_section[6], offset, 'varuint32') - table_type.limit = rsz_limits - temp_import_entry.type = table_type - elif kind == 2: - memory_type = Memory_Type() - rsz_limits = Resizable_Limits() - rsz_limits.flags, offset, dummy = Read(import_section[6], offset, 'varuint1') - rsz_limits.initial, offset, dummy = Read(import_section[6], offset, 'varuint32') - if rsz_limits.flags: - rsz_limits.maximum, offset, dummy = Read(import_section[6], offset, 'varuint32') - memory_type.limits = rsz_limits - temp_import_entry.type = memory_type - elif kind == 3: - global_type = Global_Type() - global_type.content_type, offset, dummy = Read(import_section[6], offset, 'uint8') - global_type.mutability, offset, dummy = Read(import_section[6], offset, 'varuint1') - temp_import_entry.type = global_type - - IS.import_entry.append(deepcopy(temp_import_entry)) - - import_cnt -= 1 - module_name = [] - field_name = [] - return(IS) - - # parses the export section, returns an Export_Section class - def ReadExportSection(self): - offset = 0 - section_exists = False - field_name = [] - ES = Export_Section() - temp_export_entry = Export_Entry() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 7: - export_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - export_entry_cnt, offset, dummy = Read(export_section[6], offset, 'varuint32') - ES.count = export_entry_cnt - - while export_entry_cnt != 0: - field_length, offset, dummy = Read(export_section[6], offset, 'varuint32') - temp_export_entry.field_len = field_length - - for i in range(0, field_length): - field_name.append(export_section[6][offset + i]) - temp_export_entry.fiels_str = field_name - offset += field_length - - kind, offset, dummy = Read(export_section[6], offset, 'uint8') - temp_export_entry.kind = kind - - index, offset, dummy = Read(export_section[6], offset, 'varuint32') - temp_export_entry.index = index - - ES.export_entries.append(deepcopy(temp_export_entry)) - - export_entry_cnt -= 1 - field_name = [] - return(ES) - - # parses the type section, returns a Type_Section class - def ReadTypeSection(self): - offset = 0 - section_exists = False - param_list = [] - return_list = [] - TS = Type_Section() - temp_func_type = Func_Type() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 1: - type_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - type_entry_count, offset, dummy = Read(type_section[6], offset, 'varuint32') - TS.count = type_entry_count - - while type_entry_count != 0: - form, offset, dummy = Read(type_section[6], offset, 'varint7') - temp_func_type.form = form - - param_count, offset, dummy = Read(type_section[6], offset, 'varuint32') - temp_func_type.param_cnt = param_count - - for i in range(0, param_count): - param_list.append(type_section[6][offset + i]) - temp_func_type.param_types = param_list - offset += param_count - - # @DEVI-FIXME- only works for MVP || single return value - return_count, offset, dummy = Read(type_section[6], offset, 'varuint1') - temp_func_type.return_cnt = return_count - - for i in range(0, return_count): - return_list.append(type_section[6][offset + i]) - temp_func_type.return_type = return_list - offset += return_count - - TS.func_types.append(deepcopy(temp_func_type)) - - type_entry_count -= 1 - param_list = [] - return_list = [] - return(TS) - - # parses the function section, returns a Function_section class - def ReadFunctionSection(self): - offset = 0 - section_exists = False - index_to_type = [] - FS = Function_Section() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 3: - function_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - function_entry_count, offset, dummy = Read(function_section[6], offset, 'varuint32') - FS.count = function_entry_count - - for i in range(0, function_entry_count): - index, offset, dummy = Read(function_section[6], offset, 'varuint32') - index_to_type.append(index) - FS.type_section_index = index_to_type - offset += function_entry_count - return(FS) - - # parses the element secction, returns an Element_Section class - def ReadElementSection(self): - offset = 0 - section_exists = False - init_expr = [] - loop = True - function_indices = [] - ES = Element_Section() - temp_elem_segment = Elem_Segment() - - for whatever in self.parsedstruct.section_list: - if whatever[0] == 9: - element_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - element_entry_count, offset, dummy = Read(element_section[6], offset, 'varuint32') - ES.count = element_entry_count - - while element_entry_count != 0: - table_index, offset, dummy = Read(element_section[6], offset, 'varuint32') - temp_elem_segment.index = table_index - - # @DEVI-FIXME-only works for non-extneded opcodes - while loop: - if element_section[6][offset] == 0x0b: - loop = False - init_expr.append(element_section[6][offset]) - offset += 1 - temp_elem_segment.offset = init_expr - - num_elements, offset, dummy = Read(element_section[6], offset, 'varuint32') - temp_elem_segment.num_elem = num_elements - - for i in range(0, num_elements): - index, offset, dummy = Read(element_section[6], offset, 'varuint32') - function_indices.append(index) - temp_elem_segment.elems = function_indices - offset += num_elements - - ES.elem_segments.append(deepcopy(temp_elem_segment)) - - loop = True - init_expr = [] - function_indices = [] - element_entry_count -= 1 - return(ES) - - # parses the memory section, returns a Memory_Section class - def ReadMemorySection(self): - offset = 0 - section_exists = False - MS = Memory_Section() - temp_rsz_limits = Resizable_Limits() - - for whatever in self.parsedstruct.section_list: - if whatever[0] == 5: - memory_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - num_linear_mems, offset, dummy = Read(memory_section[6], offset, 'varuint32') - MS.count = num_linear_mems - - while num_linear_mems != 0: - flag, offset, dummy = Read(memory_section[6], offset, 'varuint1') - temp_rsz_limits.flags = flag - - initial,offset, dummy = Read(memory_section[6], offset, 'varuint32') - temp_rsz_limits.initial = initial - - if flag: - maximum, offset, dummy = Read(memory_section[6], offset, 'varuint32') - temp_rsz_limits.maximum = maximum - - MS.memory_types.append(deepcopy(temp_rsz_limits)) - num_linear_mems -= 1 - return(MS) - - # parses the table section, returns a Table_Section class - def ReadTableSection(self): - offset = 0 - section_exists = False - TS = Table_Section() - temp_table_type = Table_Type() - temp_rsz_limits = Resizable_Limits() - - for whatever in self.parsedstruct.section_list: - if whatever[0] == 4: - table_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - table_count, offset, dummy = Read(table_section[6], offset, 'varuint32') - TS.count = table_count - - while table_count != 0: - element_type, offset, dummy = Read(table_section[6], offset, 'varint7') - temp_table_type.element_type = element_type - - flag, offset, dummy = Read(table_section[6], offset, 'varuint1') - temp_rsz_limits.flags = flag - - initial, offset, dummy = Read(table_section[6], offset, 'varuint32') - temp_rsz_limits.initial = initial - - if flag: - maximum, offset, dummy = Read(table_section[6], offset, 'varuint32') - temp_rsz_limits.maximum = maximum - - temp_table_type.limit = temp_rsz_limits - TS.table_types.append(deepcopy(temp_table_type)) - - table_count -= 1 - return(TS) - - # parses the global section, returns a Global_Section class - def ReadGlobalSection(self): - offset = 0 - loop = True - section_exists = False - init_expr = [] - GS = Global_Section() - temp_gl_var = Global_Variable() - temp_gl_type = Global_Type() - - for whatever in self.parsedstruct.section_list: - if whatever[0] == 6: - global_section = whatever.copy() - section_exists = True - - if not section_exists: - return None - - count, offset, dummy = Read(global_section[6], offset, 'varuint32') - GS.count = count - - while count != 0: - content_type, offset, dummy = Read(global_section[6], offset, 'uint8') - temp_gl_type.content_type = content_type - - mutability, offset, dummy = Read(global_section[6], offset, 'varuint1') - temp_gl_type.mutability = mutability - - # @DEVI-FIXME-only works for non-extended opcodes - while loop: - if global_section[6][offset] == 0x0b: - loop = False - init_expr.append(global_section[6][offset]) - offset += 1 - temp_gl_var.init_expr = init_expr - - temp_gl_var.global_type = temp_gl_type - GS.global_variables.append(deepcopy(temp_gl_var)) - - - count -= 1 - loop = True - init_expr = [] - return(GS) - - # parses the start section, returns a Start_Section - def ReadStartSection(self): - offset = 0 - section_exists = False - SS = Start_Section() - - for whatever in self.parsedstruct.section_list: - if whatever[0] == 8: - start_section = whatever.copy() - section_exists = True - if not section_exists: - return None - - function_index, offset, dummy = Read(start_section[6], offset, 'varuint32') - SS.function_section_index = function_index - return(SS) - - def ReadRelocationSection(self): - offset = 0 - section_exists = False - RS = Relocation_Section() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 0 and whatever[1] == "reloc": - reloc_section = whatever.copy() - section_exists = True - if not section_exists: - return None - - return(RS) - - def ReadNameSection(self): - offset = 0 - section_exists = False - NS = Name_Section() - for whatever in self.parsedstruct.section_list: - if whatever[0] == 0 and whatever[1] == "name": - name_section = whatever.copy() - section_exists = True - if not section_exists: - return None - - return(NS) - - # unused-returns the cursor location in the object file - def getCursorLocation(self): - return(self.wasm_file.tell()) - - # a convinience method-builds a module class and returns it - def parse(self): - return(Module(self.ReadTypeSection(), self.ReadImportSection(), - self.ReadFunctionSection(), self.ReadTableSection(), - self.ReadMemorySection(), self.ReadGlobalSection(), - self.ReadExportSection(), self.ReadStartSection(), - self.ReadElementSection(), self.ReadCodeSection(), - self.ReadDataSection())) - - -# WIP-basically how the assembler is constructed -class ParserV1(object): - def __init__(self, path): - self.path = path - - def run(self): - wasmtobj = WASMText(self.path) - # wasmtobj.test_print() - wasmtobj.RegExSearch() - wasmtobj.PrintTypeDict() - wasmtobj.PrintImportDict() - wasmtobj.PrintTableDict() - wasmtobj.PrintElemDict() - wasmtobj.PrintMemoryDict() - wasmtobj.PrintDataDict() - wasmtobj.PrintExportDict() - wasmtobj.PrintFuncDict() - wasmtobj.PrintElemDict() - wasmtobj.FuncParser() - wasmtobj.FuncParserTest() - - funcbodyparser = FuncBodyParser(wasmtobj.getFuncBodies()) - headerparser = FuncBodyParser(wasmtobj.getTypeHeader()) - - expr_stack = funcbodyparser.ParseBodyV3(False) - header_stack = headerparser.ParseBodyV3(True) - - wasm_codeemitter = WASM_CodeEmitter(expr_stack) - #wasm_codeemitter.Obj_Header_32() - #wasm_codeemitter.Dump_Obj_STDOUT() - - #wasm_codeemitter.SetNewStack(header_stack) - #wasm_codeemitter.EmitTypeHeader() - #wasm_codeemitter.PrintTypeHeaderObj() - - -# our interpreter class -class PythonInterpreter(object): - def __init__(self): - self.modules = [] - self.sections = [] - - # appends a module to the module list that PythonInterpreter has - def appendmodule(self, module): - self.modules.append(module) - - # returns the list of modules that we have parsed so far - def getmodules(self): - return(self.modules) - - def appendsection(self, section): - self.sections.append(section) - - def getsections(self): - return self.sections - - # convinience method.calls the ObjReader to parse a wasm obj file. - # returns a module class. - def parse(self, file_path): - section = ReadWASM(file_path, 'little', False, True) - self.appendsection(section) - parser = ObjReader(section) - return(parser.parse()) - - # dumps the object sections' info to stdout. pretty print. - def dump_sections(self, module, dbgsection): - all = False - if dbgsection == "": - all = True - print(Colors.blue + Colors.BOLD + - 'BEGENNING OF MODULE' + Colors.ENDC) - - # type_section - if module.type_section is not None and (dbgsection == "type" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Type Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.type_section.count)) - for iter in module.type_section.func_types: - print(Colors.cyan + 'form: ' + repr(iter.form) + Colors.ENDC) - print(Colors.green + 'param count: ' + repr(iter.param_cnt) + Colors.ENDC) - print(Colors.red + 'param types: ' + repr(iter.param_types) + Colors.ENDC) - print(Colors.purple + 'return count: ' + repr(iter.return_cnt) + Colors.ENDC) - print(Colors.yellow + 'return type: ' + repr(iter.return_type) + Colors.ENDC) - - # import_section - if module.import_section is not None and (dbgsection == "import" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Import Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.import_section.count)) - for iter in module.import_section.import_entry: - print(Colors.cyan + 'module length: ' + repr(iter.module_len) + Colors.ENDC) - print(Colors.green + 'module str: ' + repr(iter.module_str) + Colors.ENDC) - print(Colors.red + 'field length: ' + repr(iter.field_len) + Colors.ENDC) - print(Colors.purple + 'field str: ' + repr(iter.field_str) + Colors.ENDC) - print(Colors.yellow + 'kind: ' + repr(iter.kind) + Colors.ENDC) - print(Colors.grey + 'type: ' + repr(iter.type) + Colors.ENDC) - - # function_section - if module.function_section is not None and (dbgsection == "function" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Function Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.function_section.count)) - for iter in module.function_section.type_section_index: - print(Colors.cyan + 'type section index: ' + repr(iter) + Colors.ENDC) - - # table_section - if module.table_section is not None and (dbgsection == "table" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Table Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.table_section.count)) - for iter in module.table_section.table_types: - print(Colors.cyan + 'element type: ' + repr(iter.element_type) + Colors.ENDC) - print(Colors.green + 'Resizable_Limits:flags: ' + repr(iter.limit.flags) + Colors.ENDC) - print(Colors.red + 'Resizable_Limits:initial: ' + repr(iter.limit.initial) + Colors.ENDC) - print(Colors.purple + 'Resizable_Limits:maximum: ' + repr(iter.limit.maximum) + Colors.ENDC) - - # memory_section - if module.memory_section is not None and (dbgsection == "memory" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Memory Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.memory_section.count)) - for iter in module.memory_section.memory_types: - print(Colors.green + 'Resizable_Limits:flags: ' + repr(iter.flags) + Colors.ENDC) - print(Colors.red + 'Resizable_Limits:initial: ' + repr(iter.initial) + Colors.ENDC) - print(Colors.purple + 'Resizable_Limits:maximum: ' + repr(iter.maximum) + Colors.ENDC) - - # global_section - if module.global_section is not None and (dbgsection == "global" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Global Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.global_section.count)) - for iter in module.global_section.global_variables: - print(Colors.green + 'global type: ' + repr(iter.global_type) + Colors.ENDC) - print(Colors.red + 'init expr: ' + repr(iter.init_expr) + Colors.ENDC) - - # export_section - if module.export_section is not None and (dbgsection == "export" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Export Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.export_section.count)) - for iter in module.export_section.export_entries: - print(Colors.green + 'field length: ' + repr(iter.field_len) + Colors.ENDC) - print(Colors.red + 'field str: ' + repr(iter.field_str) + Colors.ENDC) - print(Colors.purple + 'kind: ' + repr(iter.kind) + Colors.ENDC) - print(Colors.cyan + 'index: ' + repr(iter.index) + Colors.ENDC) - - # start_section - if module.start_section is not None and (dbgsection == "start" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Start Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('start function index: ' + repr(module.start_section.function_section_index)) - - # element_section - if module.element_section is not None and (dbgsection == "element" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Element Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.element_section.count)) - for iter in module.element_section.elem_segments: - print(Colors.green + 'index: ' + repr(iter.index) + Colors.ENDC) - print(Colors.red + 'offset: ' + repr(iter.offset) + Colors.ENDC) - print(Colors.purple + 'num_elem: ' + repr(iter.num_elem) + Colors.ENDC) - print(Colors.cyan + 'elemes:' + repr(iter.elems) + Colors.ENDC) - - # code_section - if module.code_section is not None and (dbgsection == "code" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Code Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.code_section.count)) - for iter in module.code_section.func_bodies: - print(Colors.green + 'body size: ' + repr(iter.body_size) + Colors.ENDC) - print(Colors.red + 'local enrty count: ' + repr(iter.local_count) + Colors.ENDC) - for iterer in iter.locals: - print(Colors.blue + 'local count: ' + repr(iterer.count) + Colors.ENDC) - print(Colors.blue + 'local type: ' + repr(iterer.type) + Colors.ENDC) - for iterer in iter.code: - instruction = iterer.opcode + ' ' + repr(iterer.operands) - print(Colors.yellow + instruction + Colors.ENDC, end="") - print("\t", end="") - print(Colors.cyan + 'opcode: ' + repr(iterer.opcode) + Colors.ENDC, end="") - print("\t", end="") - print(Colors.grey + 'immediate: ' + repr(iterer.operands) + Colors.ENDC, end="") - print("\t", end="") - print(Colors.UNDERLINE + "num of operands: " + repr(len(iterer.operands)) + Colors.ENDC) - - # data_section - if module.data_section is not None and (dbgsection == "data" or all): - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print(Colors.blue + Colors.BOLD + 'Data Section:' + Colors.ENDC) - print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) - print('count: ' + repr(module.data_section.count)) - for iter in module.data_section.data_segments: - print(Colors.green + 'index: ' + repr(iter.index) + Colors.ENDC) - print(Colors.red + 'offset: ' + repr(iter.offset) + Colors.ENDC) - print(Colors.purple + 'size: ' + repr(iter.size) + Colors.ENDC) - print(Colors.cyan + 'data:' + repr(iter.data) + Colors.ENDC) - - # palceholder for the validation tests - def runValidations(self): - modulevalidation = ModuleValidation(self.modules[0]) - return(modulevalidation.ValidateAll()) - - - -def premain(argparser): - interpreter = PythonInterpreter() - if argparser.args.wasm: - for file_path in argparser.args.wasm: - module = interpreter.parse(file_path) - interpreter.appendmodule(module) - if argparser.args.dbg or argparser.args.dbgsection: - interpreter.dump_sections(module, argparser.args.dbgsection) - if interpreter.runValidations(): - print(Colors.red + "validations are not implemented yet" + Colors.ENDC) - pass - else: - print(Colors.red + 'failed validation tests' + Colors.ENDC) - vm = VM(interpreter.getmodules()) - vm.setFlags(argparser.getParseFlags()) - ms = vm.getState() - if argparser.args.idxspc: - DumpIndexSpaces(ms) - if argparser.args.memdump: - DumpLinearMems(ms.Linear_Memory, argparser.getMEMDUMP()) - if argparser.args.run: - vm.run() - # merklizer = Merklizer(ms.Linear_Memory[0][0:512], module) - # treelength, hashtree = merklizer.run() - - if argparser.args.interactive: - variables = globals().copy() - variables.update(locals()) - shell = code.InteractiveConsole(variables) - shell.interact(banner="WASM python REPL") - if argparser.args.hexdump: - dumpprettysections(interpreter.getsections(), argparser.args.hexdump, "") - if argparser.args.sectiondump is not None: - dumpprettysections(interpreter.getsections(), 24, argparser.args.sectiondump) - if argparser.args.wast: - #print(argparser.getWASTPath()) - parser = ParserV1(argparser.getWASTPath()) - parser.run() - # WIP-the assmebler - if argparser.args.asb: - print("not implemented yet") - sys.exit(1) - # WIP-the disassmebler - if argparser.args.dis: - print("not implemented yet") - sys.exit(1) - def main(): + signal.signal(signal.SIGINT, SigHandler_SIGINT) argparser = Argparser() if argparser.args.dbg: try: premain(argparser) - except Exception: + except Exception as e: + print(e.__doc__) + if e.message: print(e.message) variables = globals().copy() variables.update(locals()) shell = code.InteractiveConsole(variables) diff --git a/bruiser/wasm/section_structs.py b/bruiser/wasm/section_structs.py index b254ff9..219f7ea 100644 --- a/bruiser/wasm/section_structs.py +++ b/bruiser/wasm/section_structs.py @@ -9,19 +9,75 @@ class WASM_SECTION(object): self.name = str() self.payload_data = bytes() +class WASM_SEGMENT_INFO(): + def __int__(self): + self.count = int() + self.segments = [] -class Reloc_Entry_1(): +class WASM_SEGMENT_INFO_SEGMENT(): def __init__(self): - self.offset = int() + self.name_len = int() + self.name_data = str() + self.alignment = int() + self.flags = int() + +class WASM_COMDAT_INFO_SUB(): + def __init__(self): + self.count = int() + self.comdats = [] + +class COMDAT(): + def __init(self): + self.name_len = int() + self.name_str = str() + self.flags = int() + self.count = int() + self.comdat_syms = [] + +class COMDAT_SYM(): + def __init(self): + self.kind = int() self.index = int() +class WASM_COMDAT_KIND(): + WASM_COMDAT_DATA = 0 + WASM_COMDAT_FUNCTION = 1 + WASM_COMDAT_GLOBAL = 2 + +class WASM_INIT_FUNCS(): + def __init__(self): + self.count = int() + self.functions = [] -class Reloc_Entry_2(): +class WASM_SYMBOL_TABLE(): def __init__(self): + self.count = int() + self.syminfo = [] + +class SYM_INFO(): + def __init__(self): + self.kind = int() + self.flags = int() + +class SYM_INFO_FLAGS(): + WASM_SYM_BINDING_WEAK = 1 + WASM_SYM_BINDING_LOCAL = 2 + WASM_SYM_VISIBILITY_HIDDEN = 4 + WASM_SYM_UNDEFINED = 16 + + +class Rel_Entry(): + def __int__(self): + self.type = int() self.offset = int() self.index = int() - self.addend = int() +class RelA_Entry(): + def __int__(self): + self.type = int() + self.offset = int() + self.index = int() + self.addend = int() class Relocation_Section(): def __int__(self): @@ -31,7 +87,6 @@ class Relocation_Section(): self.count = int() self.entries = int() - class Func_Type(): def __init__(self): self.form = int() @@ -40,26 +95,22 @@ class Func_Type(): self.return_cnt = int() self.return_type = [] - class Global_Type(): def __init__(self): self.content_type = int() self.mutability = int() - class Resizable_Limits(): def __init__(self): self.flags = int() self.initial = int() self.maximum = int() - class Table_Type(): def __init__(self): self.element_type = int() self.limit = Resizable_Limits() - class External_Kind(): def __init__(self): self.Function = 0 @@ -67,23 +118,19 @@ class External_Kind(): self.Memory = 2 self.Global = 3 - class Memory_Type(): def __init__(self): self.limits = [Resizable_Limits()] - # @DEVI-FIXME- class Init_Expr(): pass - class Type_Section(): def __init__(self): self.count = [] self.func_types = [] - class Import_Entry(): def __init__(self): self.module_len = int() @@ -93,45 +140,38 @@ class Import_Entry(): self.kind = int() self.type = int() - class Import_Section(): def __init__(self): self.count = [] self.import_entry = [] - class Function_Section(): def __init__(self): self.count = [] self.type_section_index = [int()] - class Table_Section(): def __init__(self): self.count = [] self.table_types = [] - class Memory_Section(): def __init__(self): self.count = [] # Resizable_Limits self.memory_types = [] - class Global_Variable(): def __init__(self): self.global_type = Global_Type() self.init_expr = [] - class Global_Section(): def __init__(self): self.count = [] # Global_Variable self.global_variables = [] - class Export_Entry(): def __init__(self): self.field_len = int() @@ -139,19 +179,16 @@ class Export_Entry(): self.kind = int() self.index = int() - class Export_Section(): def __init__(self): self.count = [] # Export_Entry self.export_entries = [] - class Start_Section(): def __init__(self): self.function_section_index = [] - class Elem_Segment(): def __init__(self): self.index = int() @@ -159,27 +196,23 @@ class Elem_Segment(): self.num_elem = int() self.elems = [] - class Element_Section(): def __init__(self): self.count = [] # Elem_Segment self.elem_segments = [] - class Local_Entry(): def __init__(self): self.count = int() self.type = int() - class WASM_Ins(): def __init__(self): self.opcode = str() self.opcodeint = int() self.operands = [] - class Func_Body(): def __init__(self): self.body_size = int() @@ -190,14 +223,12 @@ class Func_Body(): self.code = [] self.end = int() - class Code_Section(): def __init__(self): self.count = [] # Func_Body self.func_bodies = [] - class Data_Segment(): def __init__(self): self.index = int() @@ -205,53 +236,45 @@ class Data_Segment(): self.size = int() self.data = [] - class Data_Section(): def __init__(self): self.count = [] # Data_Segment self.data_segments = [] - class Name_Type(): Module = 0 Function = 1 Local = 2 - class Name_Section_Entry(object): def __init__(self, name_type, name_payload_len, name_payload_data): self.name_type = name_type self.name_payload_len = name_payload_len self.name_payload_data = name_payload_data - class Name_Section(object): def __init__(self, name_section_entry): self.name_section_entry = [] self.name_section_entry = name_section_entry - class Module_Name(object): def __init__(self, name_len, name_str): self.name_len = name_len self.name_str = name_str - class Naming(object): def __init__(self, index, name_len, name_str): self.index = index self.name_len = name_len self.name_str = name_str - class Name_Map(object): def __init__(self, count, naming): self.count = count self.naming = [] self.naming = naming - # the module class class Module(): def __init__(self, type_section, import_section, function_section, diff --git a/extra-tools/pretestprep.sh b/extra-tools/pretestprep.sh new file mode 100755 index 0000000..30c564c --- /dev/null +++ b/extra-tools/pretestprep.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash +(cd ../obfuscator/test && make clean && bear make) +(cd ../bfd/test && make) |