日記/2010/05/31/PEファイルのインポート情報を表示するPython(作りかけ) の続きというか一区切り。
インポート情報にも、Import Name Table(INT) と Import Address Table (IAT)、バインドされたインポート情報、遅延ロードされるインポート情報がある。
この内、IATとINTについて表示するPythonスクリプトがひとまず動いたので、載せておく。
バインドされたインポート情報や遅延ロードについては見るDataDirectoryが異なる為、まだ取得出来ていない。
日記/2010/05/31/PEファイルのインポート情報を表示するPython(作りかけ) では未対応だった序数インポート情報を表示出来るように解決した。
show_imports.py:
class IMAGE_OPTIONAL_HEADER(ctypes.Structure): _fields_ = [ ('Magic', WORD), ('MajorLinkerVersion', BYTE), ('MinorLinkerVersion', BYTE), ('SizeOfCode', DWORD), ('SizeOfInitializedData', DWORD), ('SizeOfUninitializedData', DWORD), ('AddressOfEntryPoint', DWORD), ('BaseOfCode', DWORD), ('BaseOfData', DWORD), ('ImageBase', DWORD), ('SectionAlignment', DWORD), ('FileAlignment', DWORD), ('MajorOperatingSystemVersion', WORD), ('MinorOperatingSystemVersion', WORD), ('MajorImageVersion', WORD), ('MinorImageVersion', WORD), ('MajorSubsystemVersion', WORD), ('MinorSubsystemVersion', WORD), ('Win32VersionValue', DWORD), ('SizeOfImage', DWORD), ('SizeOfHeaders', DWORD), ('CheckSum', DWORD), ('Subsystem', WORD), ('DllCharacteristics', WORD), ('SizeOfStackReserve', DWORD), ('SizeOfStackCommit', DWORD), ('SizeOfHeapReserve', DWORD), ('SizeOfHeapCommit', DWORD), ('LoaderFlags', DWORD), ('NumberOfRvaAndSizes', DWORD), ('DataDirectory', IMAGE_DATA_DIRECTORY * IMAGE_NUMBEROF_DIRECTORY_ENTRIES ), ] class IMAGE_NT_HEADERS(ctypes.Structure): _fields_ = [ ('Signature', DWORD), ('FileHeader', IMAGE_FILE_HEADER), ('OptionalHeader', IMAGE_OPTIONAL_HEADER), ] IMAGE_SIZEOF_SHORT_NAME = 8 class IMAGE_SECTION_HEADER_MISC(ctypes.Union): _fields_ = [ ('PhysicalAddress', DWORD), ('VirtualSize', DWORD), ] class IMAGE_SECTION_HEADER(ctypes.Structure): _fields_ = [ ('Name', BYTE * IMAGE_SIZEOF_SHORT_NAME), ('Misc', IMAGE_SECTION_HEADER_MISC), ('VirtualAddress', DWORD), ('SizeOfRawData', DWORD), ('PointerToRawData', DWORD), ('PointerToRelocations', DWORD), ('PointerToLinenumbers', DWORD), ('NumberOfRelocations', WORD), ('NumberOfLinenumbers', WORD), ('Characteristics', DWORD), ] class IMAGE_IMPORT_DESCRIPTOR_MISC(ctypes.Union): _fields_ = [ # 0 for terminating null import descriptor ('Characteristics', DWORD), # RVA to original unbound IAT (PIMAGE_THUNK_DATA) ('OriginalFirstThunk', DWORD), ] class IMAGE_IMPORT_DESCRIPTOR(ctypes.Structure): _fields_ = [ ('Misc', IMAGE_IMPORT_DESCRIPTOR_MISC), # 0 if not bound, # -1 if bound, and real date/time stamp # in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) # O.W. date/time stamp of DLL bound to (Old BIND) ('TimeDateStamp', DWORD), ('ForwarderChain', DWORD), # -1 if no forwarders ('Name', DWORD), # RVA to IAT (if bound this IAT has actual addresses) ('FirstThunk', DWORD), ] class IMAGE_IMPORT_BY_NAME(ctypes.Structure): _fields_ = [ ('Hint', WORD), ('Name', BYTE), ] class IMAGE_THUNK_DATA(ctypes.Union): _fields_ = [ ('ForwarderString', DWORD), # PBYTE ('Function', DWORD), # PDWORD ('Ordinal', DWORD), ('AddressOfData', DWORD), # PIMAGE_IMPORT_BY_NAME ] IMAGE_ORDINAL_FLAG64 = 0x8000000000000000 IMAGE_ORDINAL_FLAG32 = 0x80000000 def IMAGE_ORDINAL64(Ordinal): return (Ordinal & 0xffff) def IMAGE_ORDINAL32(Ordinal): return (Ordinal & 0xffff) def IMAGE_SNAP_BY_ORDINAL64(Ordinal): return ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) def IMAGE_SNAP_BY_ORDINAL32(Ordinal): return ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) # }}} if 2 != len(sys.argv): print 'usage: python %s filename' % sys.argv[0] quit() file_name = sys.argv[1] logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s %(message)s', ) log = logging.getLogger('main') try: f = open(file_name, 'rb') except IOError, e: log.error("open(%s) faileed." % file_name) log.error(e) raise e # read IMAGE_DOS_HEADER f.seek(0, 0) sz = ctypes.sizeof(IMAGE_DOS_HEADER) data = f.read(sz) dos_header = IMAGE_DOS_HEADER() fit = min(len(data), sz) ctypes.memmove(ctypes.addressof(dos_header), data, fit) # read IMAGE_NT_HEADERS f.seek(dos_header.e_lfanew, 0) sz = ctypes.sizeof(IMAGE_NT_HEADERS) data = f.read(sz) pe_header = IMAGE_NT_HEADERS() fit = min(len(data), sz) ctypes.memmove(ctypes.addressof(pe_header), data, fit) file_header = pe_header.FileHeader opt_header = pe_header.OptionalHeader # enumerate IMAGE_SECTION_HEADER array section_headers = [] section_header_sz = ctypes.sizeof(IMAGE_SECTION_HEADER) for i in range(file_header.NumberOfSections): data = f.read(section_header_sz) section_header = IMAGE_SECTION_HEADER() fit = min(len(data), sz) ctypes.memmove(ctypes.addressof(section_header), data, fit) section_headers.append(section_header) # load to memory f.seek(0, 0) file_bytes = f.read() # read all file contents image_buf = ctypes.create_string_buffer(opt_header.SizeOfImage) ctypes.memset(image_buf, 0, opt_header.SizeOfImage) image_buf_ptr = ctypes.addressof(image_buf) # copy headers ctypes.memmove( image_buf_ptr, file_bytes, opt_header.SizeOfHeaders ) # copy section datas for h in section_headers: section_virtual_addr = h.VirtualAddress pointer_to_rawdata = h.PointerToRawData size_of_rawdata = h.SizeOfRawData if pointer_to_rawdata : ctypes.memmove( image_buf_ptr + section_virtual_addr, file_bytes[pointer_to_rawdata:pointer_to_rawdata + size_of_rawdata], size_of_rawdata) import_directory_entry = opt_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] import_directory_rva = import_directory_entry.VirtualAddress import_directory_head = image_buf_ptr + import_directory_rva # build IMAGE_IMPORT_DESCRIPTOR array import_descriptors = [] sz = ctypes.sizeof(IMAGE_IMPORT_DESCRIPTOR) offset = 0 while 1: import_descriptor = IMAGE_IMPORT_DESCRIPTOR() ctypes.memmove( ctypes.addressof(import_descriptor), import_directory_head + offset, sz) offset = offset + sz if 0 == import_descriptor.FirstThunk: break import_descriptors.append(import_descriptor) # enumerate IMAGE_IMPORT_DESCRIPTOR array for d in import_descriptors: print "------------" print "OriginalFirstThunk(INT) RVA = %04X" % d.Misc.OriginalFirstThunk print "TimeDateStamp = %04X" % d.TimeDateStamp print "ForwarderChain = %04X" % d.ForwarderChain module_name = ctypes.c_char_p(image_buf_ptr + d.Name) print "Name = %s [RVA=%04X]" % (module_name.value, d.Name) print "FirstThunk(IAT) RVA = %04X" % d.FirstThunk # enumerate FirstThunk records ft_thunk_head = image_buf_ptr + d.FirstThunk ft_thunk_sz = ctypes.sizeof(IMAGE_THUNK_DATA) ft_thunks = [] ft_thunk_offset = 0 while 1: ft_thunk = IMAGE_THUNK_DATA() ctypes.memmove( ctypes.addressof(ft_thunk), ft_thunk_head + ft_thunk_offset, ft_thunk_sz) ft_thunk_offset = ft_thunk_offset + ft_thunk_sz if 0 == ft_thunk.Ordinal : break ft_thunks.append(ft_thunk) for ft_thunk in ft_thunks: print "FirstThunk: %08X" % ft_thunk.Ordinal # enumerate OriginalFirstThunk records if 0 != d.Misc.OriginalFirstThunk : oft_thunk_head = image_buf_ptr + d.Misc.OriginalFirstThunk oft_thunk_sz = ctypes.sizeof(IMAGE_THUNK_DATA) oft_thunks = [] oft_thunk_offset = 0 while 1: oft_thunk = IMAGE_THUNK_DATA() ctypes.memmove( ctypes.addressof(oft_thunk), oft_thunk_head + oft_thunk_offset, oft_thunk_sz) oft_thunk_offset = oft_thunk_offset + oft_thunk_sz if 0 == oft_thunk.Ordinal : break oft_thunks.append(oft_thunk) for oft_thunk in oft_thunks: print "OriginalFirstThunk: %08X" % oft_thunk.Ordinal if IMAGE_SNAP_BY_ORDINAL32(oft_thunk.Ordinal): print "\tOrdinal: %d" % IMAGE_ORDINAL32(oft_thunk.Ordinal) else: hint_data = IMAGE_IMPORT_BY_NAME() hint_data_sz = ctypes.sizeof(IMAGE_IMPORT_BY_NAME) ctypes.memmove( ctypes.addressof(hint_data), image_buf_ptr + oft_thunk.AddressOfData, hint_data_sz) print "\tHint: %04X" % hint_data.Hint hint_data_name_ptr = image_buf_ptr + \ oft_thunk.AddressOfData + \ ctypes.sizeof(WORD) hint_data_name = ctypes.c_char_p(hint_data_name_ptr) print "\tName: %s" % hint_data_name.value
OriginalFirstThunkの32bit目が0なら名前によるインポート、1なら序数によるインポートとして処理するよう作り替えた。
for oft_thunk in oft_thunks: print "OriginalFirstThunk: %08X" % oft_thunk.Ordinal if IMAGE_SNAP_BY_ORDINAL32(oft_thunk.Ordinal): # 序数によるインポート print "\tOrdinal: %d" % IMAGE_ORDINAL32(oft_thunk.Ordinal) else: # 名前によるインポート hint_data = IMAGE_IMPORT_BY_NAME() hint_data_sz = ctypes.sizeof(IMAGE_IMPORT_BY_NAME) ctypes.memmove( ctypes.addressof(hint_data), image_buf_ptr + oft_thunk.AddressOfData, hint_data_sz) print "\tHint: %04X" % hint_data.Hint hint_data_name_ptr = image_buf_ptr + \ oft_thunk.AddressOfData + \ ctypes.sizeof(WORD) hint_data_name = ctypes.c_char_p(hint_data_name_ptr) print "\tName: %s" % hint_data_name.value
ifで使っているIMAGE_SNAP_BY_ORDINAL32は32bit用の判別処理で、WinNT.hからのパクリ。
コメント