def pe_header_to_str(pe_header): return ( 'Image File Header:\n' '%s\n' '\n' 'Image Optional Headers:\n' '%s\n' % (utils.indent_string( image_file_header_to_str(pe_header.image_file_header)), utils.indent_string( image_optional_header_to_str(pe_header.image_optional_header))))
def show_memory_information(process_handle, pointer): print('Memory Information for 0x%08x:' % pointer) memory_basic_info = MEMORY_BASIC_INFORMATION() status = VirtualQueryEx(process_handle, pointer, ctypes.pointer(memory_basic_info), ctypes.sizeof(memory_basic_info)) if status == ctypes.sizeof(memory_basic_info): print(utils.indent_string(memory_basic_info_to_str(memory_basic_info))) print() else: print('VirtualQueryEx failed')
def image_file_header_to_str(image_file_header): return ('Machine: %s (0x%04x)\n' 'Number of sections: %s\n' 'Timestamp: %s (%s)\n' 'Symbol table offset: %s\n' 'Number of symbols: %s\n' 'Size of optional header: %s\n' 'Characteristics (0x%04x):\n' '%s' % (image_file_machine_to_str(image_file_header.Machine), image_file_header.Machine, image_file_header.NumberOfSections, time_stamp_to_str(image_file_header.TimeDateStamp), image_file_header.TimeDateStamp, image_file_header.PointerToSymbolTable, image_file_header.NumberOfSymbols, image_file_header.SizeOfOptionalHeader, image_file_header.Characteristics, utils.indent_string( image_file_characteristics_to_str( image_file_header.Characteristics))))
def import_table_to_str(process_handle, image_base_address, rva): pointer = image_base_address + rva rv = '' while True: # break when we reach the last entry image_import_descriptor = IMAGE_IMPORT_DESCRIPTOR() read_structure_from_remote_process(process_handle, pointer, image_import_descriptor) if image_import_descriptor.DUMMYUNIONNAME.OriginalFirstThunk == 0: # no more structures break name = '<< no name >>' if image_import_descriptor.Name != 0: name = read_string_from_remote_process( process_handle, image_base_address + image_import_descriptor.Name) # The import table (at the original first thunk RVA) tells what functions are # imported from the DLL in question. The import address table (at the first thunk RVA) # originally contains the function names but the loader overwrites these names with the # function addresses. if is_iat_populated(process_handle, image_base_address, image_import_descriptor): # show addresses in the IAT, not names rv += ( 'Name: %s\n' 'TimeDateStamp: %s\n' 'ForwarderChain: %s\n' 'This table appears to be populated.\n' '\n' 'Original First Thunk RVA: 0x%08x\n' '%s\n' # hint name array 'First Thunk RVA: 0x%08x\n' '%s' # import address table % (name, image_import_descriptor.TimeDateStamp, image_import_descriptor.ForwarderChain, image_import_descriptor.DUMMYUNIONNAME.OriginalFirstThunk, utils.indent_string( image_import_by_name_array_to_str( process_handle, image_base_address, image_import_descriptor.DUMMYUNIONNAME. OriginalFirstThunk, True)), image_import_descriptor.FirstThunk, utils.indent_string( image_import_by_name_array_to_str( process_handle, image_base_address, image_import_descriptor.FirstThunk, False)))) else: rv += ( 'Name: %s\n' 'TimeDateStamp: %s\n' 'ForwarderChain: %s\n' 'This table does not appear to be populated.\n' '\n' 'Original First Thunk RVA: 0x%08x\n' '%s\n' # hint name array 'First Thunk RVA: 0x%08x\n' '%s' # import address table % (name, image_import_descriptor.TimeDateStamp, image_import_descriptor.ForwarderChain, image_import_descriptor.DUMMYUNIONNAME.OriginalFirstThunk, utils.indent_string( image_import_by_name_array_to_str( process_handle, image_base_address, image_import_descriptor.DUMMYUNIONNAME. OriginalFirstThunk, True)), image_import_descriptor.FirstThunk, utils.indent_string( image_import_by_name_array_to_str( process_handle, image_base_address, image_import_descriptor.FirstThunk, True)))) pointer += ctypes.sizeof(image_import_descriptor) return rv
def image_optional_header_to_str(image_optional_header): return ('Data Directory:\n' '%s' % (utils.indent_string( data_directory_to_str(image_optional_header.DataDirectory))))
def handle(self, full_command): global current_state, main_ui, loaded_images if not full_command: return # don't do anything on blank commands full_command = full_command.strip() if len(full_command) == 0: return # don't do anything on blank commands main_ui.set_short_message('') command_words = full_command.split() # splits into words command, args = command_words[0], command_words[1:] # substitute a command for any alias command = get_command_from_possible_alias(command) # exit should be allowed for any state if command == COMMAND_EXIT: exit(0) # check that this command is allowed for this state if not command in ALLOWED_COMMANDS[current_state]: help_text = get_help_for_state(current_state) main_ui.push_output(help_text) return # handle command based on state if current_state == STATE_UNLOADED: if command == COMMAND_LOAD: with open(loaded_binary, 'rb') as f: # TODO: this doesn't actually "load" the PE file, it just reads it for now analysis = winutils.analyze_pe_file(f) main_ui.push_output(analysis) main_ui.set_short_message('Loaded %s' % loaded_binary) current_state = STATE_STATIC_ANALYSIS return elif current_state == STATE_STATIC_ANALYSIS: if command == COMMAND_UNLOAD: current_state = STATE_UNLOADED main_ui.set_short_message('Unloaded %s' % loaded_binary) return elif command == COMMAND_RUN: global process_info process_info = winutils.create_process(loaded_binary) current_state = STATE_RUNNING main_ui.set_short_message('Started %s' % loaded_binary) return elif current_state == STATE_RUNNING: if command == COMMAND_KILL: main_ui.set_short_message('Under Construction') return elif command == COMMAND_BREAK: main_ui.set_short_message('Under Construction') return elif current_state == STATE_SUSPENDED: if command == COMMAND_KILL: main_ui.set_short_message('Under Construction') return elif command == COMMAND_RUN: if not winapi.ContinueDebugEvent( self.last_debug_event.dwProcessId, self.last_debug_event.dwThreadId, winapi.DBG_CONTINUE): raise Exception('ContinueDebugEvent failed') current_state = STATE_RUNNING return elif command == COMMAND_IGNORE: global ignore_dll_load ignore_dll_load = not ignore_dll_load if ignore_dll_load: main_ui.set_short_message('LOAD_DLL_DEBUG_EVENT ignored.') else: main_ui.set_short_message( 'LOAD_DLL_DEBUG_EVENT no longer ignored.') return elif command == COMMAND_SHOW_LOADED_IMAGES: outstr = 'Loaded Images:\n\n' for (k, v) in loaded_images.items(): outstr += ' 0x%08x: %s\n' % (k, v) main_ui.push_output(outstr) return elif command == COMMAND_SHOW_IMAGE_INFORMATION: # analyze the DLL in memory if len(args) != 1: main_ui.set_short_message('%s expects an image name.' % COMMAND_SHOW_IMAGE_INFORMATION) return image_name = args[0] for (k, v) in loaded_images.items(): if v == image_name: f = winutils.MemoryMetaFile(process_info.hProcess, k) outstr = winutils.analyze_pe_file(f) main_ui.push_output(outstr) return main_ui.set_short_message( 'Image %s not found in loaded images.' % image_name) return elif command == COMMAND_SHOW_DISASSEMBLY: if len(args) != 1 or len(args[0]) < 3: main_ui.set_short_message( f'{COMMAND_SHOW_DISASSEMBLY} expects a memory address (in hex with 0x)' ) return assert (args[0][:2] == '0x') f = winutils.MemoryMetaFile(process_info.hProcess, int(args[0][2:], 16)) output = utils.indent_string(winutils.disassemble(f), ' ') main_ui.push_output(output) return elif command == COMMAND_SHOW_THREAD_CONTEXT: context = winapi.WOW64_CONTEXT() context.ContextFlags = winapi.WOW64_CONTEXT_ALL if not winapi.Wow64GetThreadContext(process_info.hThread, ctypes.pointer(context)): raise Exception('GetThreadContext failed') main_ui.push_output(winutils.wow64_context_to_str(context)) return raise Exception('unhandled command / state (%s / %s)' % (command, current_state))