Ruby解析Windows PE文件
来源:互联网 发布:淘宝购物评级突然下降 编辑:程序博客网 时间:2024/06/14 04:37
纯属业余分析一些应用程序的需要,特意去了解了下Windows下的PE文件格式,相比MSDN的其它内容,PE文件规范文件的部分描述算是相当的晦涩了。好记性不如烂笔头,搭好框架后就此记录,以便日后抄袭。代码解决了导入和导出的部分,其余部分日后再作添加和完善,可以继续利用Ruby动态语言的优势、魔幻般的语法糖和强悍的元编程能力构造更便利的代码。
#encoding:gbkrequire "delegate"raise RuntimeError,"This program cannot be run in platform #{RUBY_PLATFORM}" if /mswin|mingw/ !~ RUBY_PLATFORM#Add convenient method to buildin classesclass Fixnum#Bytedef to_sbs = StringIO.news.printf('%02x',self)s.stringend#Worddef to_sws = StringIO.news.printf('%04x',self)s.stringend#Double Worddef to_sds = StringIO.news.printf('%08x',self)s.stringend#Test specified bit fielddef test_b(n)self & 2 ** n != 0end#Masked datadef part_b(a)result = 0if a.class == Array or a.class == Rangea.each do |item|result |= self & 2 ** itemendendresultend#Read little endian datadef Fixnum.read(n,bytes)bytes.slice(0,n).reverse.collect{|item| item.to_sb}.join('').hexend#Read little endian data from fixed locationdef Fixnum.readn(ind_s,nlen,bytes)tmpbytes = bytes.slice(ind_s,nlen)Fixnum.read(nlen,tmpbytes)endendclass Bignum#Bytedef to_sbs = StringIO.news.printf('%02x',self)s.stringend#Worddef to_sws = StringIO.news.printf('%04x',self)s.stringend#Double Worddef to_sds = StringIO.news.printf('%08x',self)s.stringend#Double Long Longdef to_lls = StringIO.news.printf('%016x',self)s.stringend#Test specified bit fielddef test_b(n)self & 2 ** n != 0end#Masked datadef part_b(a)result = 0if a.class == Array or a.class == Rangea.each do |item|result |= self & 2 ** itemendendresultendendclass Arraydef to_hexs = StringIO.newself.each do |item|s.print item.to_sbends.stringenddef to_numto_hex.hexenddef to_lenums = StringIO.newself.reverse.each do |item|s.print item.to_sbends.string.hexenddef to_replself.select{|c| c != 0}.pack('C*')endendmodule PE#Image signatureIMAGE_DOS_SIGNATURE = 0x4D5A #MZIMAGE_NT_SIGNATURE = 0x50450000 #PE00#Machine typesIMAGE_FILE_MACHINE_UNKNOWN= 0IMAGE_FILE_MACHINE_I386= 0x014c # Intel 386.IMAGE_FILE_MACHINE_R3000= 0x0162 # MIPS little-endian, 0x160 big-endianIMAGE_FILE_MACHINE_R4000= 0x0166 # MIPS little-endianIMAGE_FILE_MACHINE_R10000= 0x0168 # MIPS little-endianIMAGE_FILE_MACHINE_WCEMIPSV2= 0x0169 # MIPS little-endian WCE v2IMAGE_FILE_MACHINE_ALPHA= 0x0184 # Alpha_AXPIMAGE_FILE_MACHINE_SH3= 0x01a2 # SH3 little-endianIMAGE_FILE_MACHINE_SH3DSP= 0x01a3IMAGE_FILE_MACHINE_SH3E= 0x01a4 # SH3E little-endianIMAGE_FILE_MACHINE_SH4= 0x01a6 # SH4 little-endianIMAGE_FILE_MACHINE_SH5= 0x01a8 # SH5IMAGE_FILE_MACHINE_ARM= 0x01c0 # ARM Little-EndianIMAGE_FILE_MACHINE_THUMB= 0x01c2 # ARM Thumb/Thumb-2 Little-EndianIMAGE_FILE_MACHINE_ARMNT= 0x01c4 # ARM Thumb-2 Little-EndianIMAGE_FILE_MACHINE_AM33= 0x01d3IMAGE_FILE_MACHINE_POWERPC= 0x01F0 # IBM PowerPC Little-EndianIMAGE_FILE_MACHINE_POWERPCFP= 0x01f1IMAGE_FILE_MACHINE_IA64= 0x0200 # Intel 64IMAGE_FILE_MACHINE_MIPS16= 0x0266 # MIPSIMAGE_FILE_MACHINE_ALPHA64= 0x0284 # ALPHA64IMAGE_FILE_MACHINE_MIPSFPU= 0x0366 # MIPSIMAGE_FILE_MACHINE_MIPSFPU16= 0x0466 # MIPSIMAGE_FILE_MACHINE_AXP64= IMAGE_FILE_MACHINE_ALPHA64IMAGE_FILE_MACHINE_TRICORE= 0x0520 # InfineonIMAGE_FILE_MACHINE_CEF= 0x0CEFIMAGE_FILE_MACHINE_EBC= 0x0EBC # EFI Byte CodeIMAGE_FILE_MACHINE_AMD64= 0x8664 # AMD64 (K8)IMAGE_FILE_MACHINE_M32R= 0x9041 # M32R little-endianIMAGE_FILE_MACHINE_CEE= 0xC0EE#CharacteristicsIMAGE_FILE_RELOCS_STRIPPED= 0x0001 # Relocation info stripped from file.IMAGE_FILE_EXECUTABLE_IMAGE= 0x0002 # File is executable (i.e. no unresolved external references).IMAGE_FILE_LINE_NUMS_STRIPPED= 0x0004 # Line nunbers stripped from file.IMAGE_FILE_LOCAL_SYMS_STRIPPED= 0x0008 # Local symbols stripped from file.IMAGE_FILE_AGGRESIVE_WS_TRIM= 0x0010 # Aggressively trim working setIMAGE_FILE_LARGE_ADDRESS_AWARE= 0x0020 # App can handle >2gb addressesIMAGE_FILE_BYTES_REVERSED_LO= 0x0080 # Bytes of machine word are reversed.IMAGE_FILE_32BIT_MACHINE= 0x0100 # 32 bit word machine.IMAGE_FILE_DEBUG_STRIPPED= 0x0200 # Debugging info stripped from file in .DBG fileIMAGE_FILE_REMOVABLE_RUN_FROM_SWAP= 0x0400 # If Image is on removable media, copy and run from the swap file.IMAGE_FILE_NET_RUN_FROM_SWAP= 0x0800 # If Image is on Net, copy and run from the swap file.IMAGE_FILE_SYSTEM= 0x1000 # System File.IMAGE_FILE_DLL= 0x2000 # File is a DLL.IMAGE_FILE_UP_SYSTEM_ONLY= 0x4000 # File should only be run on a UP machineIMAGE_FILE_BYTES_REVERSED_HI= 0x8000 # Bytes of machine word are reversed.# Subsystem ValuesIMAGE_SUBSYSTEM_UNKNOWN = 0 # Unknown subsystem.IMAGE_SUBSYSTEM_NATIVE = 1 # Image doesn't require a subsystem.IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem.IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 # Image runs in the Windows character subsystem.IMAGE_SUBSYSTEM_OS2_CUI = 5 # image runs in the OS/2 character subsystem.IMAGE_SUBSYSTEM_POSIX_CUI = 7 # image runs in the Posix character subsystem.IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8 # image is a native Win9x driver.IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem.IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 #IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 #IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 #IMAGE_SUBSYSTEM_EFI_ROM = 13IMAGE_SUBSYSTEM_XBOX = 14IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16# DllCharacteristics Entries#IMAGE_LIBRARY_PROCESS_INIT = 0x0001 # Reserved.#IMAGE_LIBRARY_PROCESS_TERM = 0x0002 # Reserved.#IMAGE_LIBRARY_THREAD_INIT = 0x0004 # Reserved.#IMAGE_LIBRARY_THREAD_TERM = 0x0008 # Reserved.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 # Image can handle a high entropy 64-bit virtual address space.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 # DLL can move.IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080 # Code Integrity ImageIMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 # Image is NX compatibleIMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200 # Image understands isolation and doesn't want itIMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400 # Image does not use SEH. No SE handler may reside in this imageIMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800 # Do not bind this image.IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000 # Image should execute in an AppContainerIMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000 # Driver uses WDM modelIMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000 # Image supports Control Flow Guard.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000# Directory EntriesIMAGE_DIRECTORY_ENTRY_EXPORT=0# Export DirectoryIMAGE_DIRECTORY_ENTRY_IMPORT=1# Import DirectoryIMAGE_DIRECTORY_ENTRY_RESOURCE=2# Resource DirectoryIMAGE_DIRECTORY_ENTRY_EXCEPTION=3# Exception DirectoryIMAGE_DIRECTORY_ENTRY_SECURITY=4# Security DirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC=5# Base Relocation TableIMAGE_DIRECTORY_ENTRY_DEBUG=6# Debug Directory#IMAGE_DIRECTORY_ENTRY_COPYRIGHT=7# (X86 usage)IMAGE_DIRECTORY_ENTRY_ARCHITECTURE=7# Architecture Specific DataIMAGE_DIRECTORY_ENTRY_GLOBALPTR=8# RVA of GPIMAGE_DIRECTORY_ENTRY_TLS=9# TLS DirectoryIMAGE_DIRECTORY_ENTRY_LOAD_CONFIG=10# Load Configuration DirectoryIMAGE_DIRECTORY_ENTRY_BOUND_IMPORT=11# Bound Import Directory in headersIMAGE_DIRECTORY_ENTRY_IAT=12# Import Address TableIMAGE_DIRECTORY_ENTRY_DELAY_IMPORT=13# Delay Load Import DescriptorsIMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR=14# COM Runtime descriptor# Section characteristics.## IMAGE_SCN_TYPE_REG=0x00000000# Reserved.# IMAGE_SCN_TYPE_DSECT=0x00000001# Reserved.# IMAGE_SCN_TYPE_NOLOAD=0x00000002# Reserved.# IMAGE_SCN_TYPE_GROUP=0x00000004# Reserved.IMAGE_SCN_TYPE_NO_PAD=0x00000008# Reserved.# IMAGE_SCN_TYPE_COPY=0x00000010# Reserved.IMAGE_SCN_CNT_CODE=0x00000020# Section contains code.IMAGE_SCN_CNT_INITIALIZED_DATA=0x00000040# Section contains initialized data.IMAGE_SCN_CNT_UNINITIALIZED_DATA=0x00000080# Section contains uninitialized data.IMAGE_SCN_LNK_OTHER=0x00000100# Reserved.IMAGE_SCN_LNK_INFO=0x00000200# Section contains comments or some other type of information.# IMAGE_SCN_TYPE_OVER=0x00000400# Reserved.IMAGE_SCN_LNK_REMOVE=0x00000800# Section contents will not become part of image.IMAGE_SCN_LNK_COMDAT=0x00001000# Section contents comdat.#=0x00002000# Reserved.# IMAGE_SCN_MEM_PROTECTED - Obsolete=0x00004000IMAGE_SCN_NO_DEFER_SPEC_EXC=0x00004000# Reset speculative exceptions handling bits in the TLB entries for this section.IMAGE_SCN_GPREL=0x00008000# Section content can be accessed relative to GPIMAGE_SCN_MEM_FARDATA=0x00008000# IMAGE_SCN_MEM_SYSHEAP - Obsolete=0x00010000IMAGE_SCN_MEM_PURGEABLE=0x00020000IMAGE_SCN_MEM_16BIT=0x00020000IMAGE_SCN_MEM_LOCKED=0x00040000IMAGE_SCN_MEM_PRELOAD=0x00080000IMAGE_SCN_ALIGN_1BYTES=0x00100000#IMAGE_SCN_ALIGN_2BYTES=0x00200000#IMAGE_SCN_ALIGN_4BYTES=0x00300000#IMAGE_SCN_ALIGN_8BYTES=0x00400000#IMAGE_SCN_ALIGN_16BYTES=0x00500000# Default alignment if no others are specified.IMAGE_SCN_ALIGN_32BYTES=0x00600000#IMAGE_SCN_ALIGN_64BYTES=0x00700000#IMAGE_SCN_ALIGN_128BYTES=0x00800000#IMAGE_SCN_ALIGN_256BYTES=0x00900000#IMAGE_SCN_ALIGN_512BYTES=0x00A00000#IMAGE_SCN_ALIGN_1024BYTES=0x00B00000#IMAGE_SCN_ALIGN_2048BYTES=0x00C00000#IMAGE_SCN_ALIGN_4096BYTES=0x00D00000#IMAGE_SCN_ALIGN_8192BYTES=0x00E00000## Unused=0x00F00000IMAGE_SCN_ALIGN_MASK=0x00F00000IMAGE_SCN_LNK_NRELOC_OVFL=0x01000000# Section contains extended relocations.IMAGE_SCN_MEM_DISCARDABLE=0x02000000# Section can be discarded.IMAGE_SCN_MEM_NOT_CACHED=0x04000000# Section is not cachable.IMAGE_SCN_MEM_NOT_PAGED=0x08000000# Section is not pageable.IMAGE_SCN_MEM_SHARED=0x10000000# Section is shareable.IMAGE_SCN_MEM_EXECUTE=0x20000000# Section is executable.IMAGE_SCN_MEM_READ=0x40000000# Section is readable.IMAGE_SCN_MEM_WRITE=0x80000000# Section is writeable.## TLS Characteristic Flags#IMAGE_SCN_SCALE_INDEX=0x00000001# Tls index is scaled#Optional magic numberIMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10bIMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20bIMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x107#Max size of directory entriesIMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16#Section header short name max lengthIMAGE_SIZEOF_SHORT_NAME = 8$TYPE_CLASS_INFORMATION = Hash.new$UN_REGISTER_FLAG = trueclass KeyAddress < DelegateClass(Hash)def initialize(init = nil)content = Hash.newfixed = falseif init.class == Hashcontent.merge!(init)fixed = trueendyield content,fixed if block_given?super(content)self.keys.each do |k|add_method(k)endenddef add_item(k,v)self[k] = vadd_method(k)enddef add_method(k)KeyAddress.class_eval <<-EOFdef #{k.downcase}self['#{k}']endEOFendendclass TypeInfoattr_accessor :type,:cls,:nsize,:schemedef initialize(type,cls,scheme = nil,nsize = 0)@type = type@cls = cls@scheme = schemeif scheme.nil?@nsize = nsizeelsensize = 0@scheme.each do |n,v|if v =~ /\[[0-9]+\]/pattern = Regexp.new(/(.*)\[([0-9]+)\]/)m = pattern.match(v)if not $TYPE_CLASS_INFORMATION.has_key?(m[1])raise RuntimeError,"Type [#{m[1]}] not found in list of registered."endnsize += $TYPE_CLASS_INFORMATION[m[1]].nsize * instance_eval(m[2])elseif not $TYPE_CLASS_INFORMATION.has_key?(v)raise RuntimeError,"Type [#{v}] not found in list of registered."endnsize += $TYPE_CLASS_INFORMATION[v].nsizeendend@nsize = nsizeend$TYPE_CLASS_INFORMATION[@type] = selfenddef TypeInfo.fixup(obj,bytes)nseek = 0if obj.class == Stringnsize = $TYPE_CLASS_INFORMATION[obj].nsizeobj = Fixnum.read(nsize,bytes)nseek += nsizeelseobj.scheme.each do |k,v|if v =~ /\[[0-9]+\]/pattern = Regexp.new(/(.*)\[([0-9]+)\]/)m = pattern.match(v)n = obj.instance_eval(m[2])obj[k] = Array.newti = $TYPE_CLASS_INFORMATION[m[1]]n.times doo = nilif ti.cls.respond_to?(:new)o = ti.cls.newelseo = ti.typeendo,new_nseek = TypeInfo.fixup(o,bytes.slice(nseek,ti.nsize))nseek += new_nseekobj[k] << oendelseti = $TYPE_CLASS_INFORMATION[v]o = nilif ti.cls.respond_to?(:new)o = ti.cls.newelseo = ti.typeendo,new_nseek = TypeInfo.fixup(o,bytes.slice(nseek,ti.nsize))nseek += new_nseekobj[k] = oendendendreturn obj,nseekendendclass UglyParserattr_accessor :ntbsdef initialize(code)t = StringIO.new(code)state = falsepattern = Regexp.new(/[ \t]*([A-Za-z0-9_]+)[ \t]+([A-Za-z0-9_\[\]]+);.*/)@ntbs = Hash.newt.readlines.each do |line|next if line.strip.empty? or line.lstrip.start_with?('//')if line.strip == '<<TAG_BEGIN>>'state = trueelsebreak if line.strip == '<<TAG_END>>'endif statem = pattern.match(line)@ntbs[m[2]] = m[1] if m and m.size == 3endendfine_tbs = Hash.new@ntbs.each do |k,v|if k =~ /\[[0-9]+\]/pattern = Regexp.new(/(.*)(\[[0-9]+\])/)m = pattern.match(k)fine_tbs[m[1]] = v + m[2]elsefine_tbs[k] = vendend@ntbs = fine_tbsif block_given?yield selfendendendclass Image< DelegateClass(Array)attr_accessor :name,:bytesdef initialize(input)case input#File pathwhen String@name = :name@bytes = IO.read(input,mode:'rb').bytes#Loaded byteswhen Array@bytes = input.clone#Image file objectwhen File@name = input.to_path@bytes = input.read.bytes#Just promptelseraise RuntimeError,"Could not fetch image bytes from #{input.class}."endsuper(@bytes)#Invoke from blockif block_given?yield selfendendend#Delegate to buildin Hashclass BaseStruct < DelegateClass(Hash)attr_accessor :bytes,:scheme,:nsizedef initialize(defs,input,tn,cls)if $UN_REGISTER_FLAG$TYPE_CLASS_INFORMATION['BYTE'] = TypeInfo.new('BYTE',Fixnum,nil,1)$TYPE_CLASS_INFORMATION['WORD'] = TypeInfo.new('WORD',Fixnum,nil,2)$TYPE_CLASS_INFORMATION['DWORD'] = TypeInfo.new('DWORD',Fixnum,nil,4)$TYPE_CLASS_INFORMATION['LONG'] = TypeInfo.new('LONG',Fixnum,nil,4)$TYPE_CLASS_INFORMATION['ULONGLONG'] = TypeInfo.new('ULONGLONG',Fixnum,nil,8)$UN_REGISTER_FLAG = falseendparser = UglyParser.new(defs)@scheme = parser.ntbsinner = Hash.new@scheme.keys.each do |k|inner[k] = nilendsuper(inner)ti = TypeInfo.new(tn,cls,@scheme)@nsize = ti.nsizeTypeInfo.fixup(self,input) if not input.nil?@scheme.keys.each do |k|cls.class_eval <<-EOFdef #{k.downcase}self['#{k}']endEOFendendendclass DosStub < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_DOS_HEADER { // DOS .EXE header<<TAG_BEGIN>>WORD e_magic; // Magic numberWORD e_cblp; // Bytes on last page of fileWORD e_cp; // Pages in fileWORD e_crlc; // RelocationsWORD e_cparhdr; // Size of header in paragraphsWORD e_minalloc; // Minimum extra paragraphs neededWORD e_maxalloc; // Maximum extra paragraphs neededWORD e_ss; // Initial (relative) SS valueWORD e_sp; // Initial SP valueWORD e_csum; // ChecksumWORD e_ip; // Initial IP valueWORD e_cs; // Initial (relative) CS valueWORD e_lfarlc; // File address of relocation tableWORD e_ovno; // Overlay numberWORD e_res[4]; // Reserved wordsWORD e_oemid; // OEM identifier (for e_oeminfo)WORD e_oeminfo; // OEM information; e_oemid specificWORD e_res2[10]; // Reserved wordsLONG e_lfanew; // File address of new exe header<<TAG_END>> } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;EOFsuper(defs,input,'IMAGE_DOS_HEADER',self.class)endendclass CoffHeader < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_FILE_HEADER {<<TAG_BEGIN>>WORD Machine;WORD NumberOfSections;DWORD TimeDateStamp;DWORD PointerToSymbolTable;DWORD NumberOfSymbols;WORD SizeOfOptionalHeader;WORD Characteristics;<<TAG_END>>} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;EOFsuper(defs,input,'IMAGE_FILE_HEADER',self.class)endendclass ImageDataDirectory < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_DATA_DIRECTORY {<<TAG_BEGIN>>DWORD VirtualAddress;DWORD Size;<<TAG_END>>} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;EOFsuper(defs,input,'IMAGE_DATA_DIRECTORY',self.class)endendclass OptionalHeader32 < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_OPTIONAL_HEADER {//// Standard fields.//<<TAG_BEGIN>>WORD Magic;BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;DWORD SizeOfInitializedData;DWORD SizeOfUninitializedData;DWORD AddressOfEntryPoint;DWORD BaseOfCode;DWORD BaseOfData;//// NT additional fields.//DWORD ImageBase;DWORD SectionAlignment;DWORD FileAlignment;WORD MajorOperatingSystemVersion;WORD MinorOperatingSystemVersion;WORD MajorImageVersion;WORD MinorImageVersion;WORD MajorSubsystemVersion;WORD MinorSubsystemVersion;DWORD Win32VersionValue;DWORD SizeOfImage;DWORD SizeOfHeaders;DWORD CheckSum;WORD Subsystem;WORD DllCharacteristics;DWORD SizeOfStackReserve;DWORD SizeOfStackCommit;DWORD SizeOfHeapReserve;DWORD SizeOfHeapCommit;DWORD LoaderFlags;DWORD NumberOfRvaAndSizes;IMAGE_DATA_DIRECTORY DataDirectory[#{IMAGE_NUMBEROF_DIRECTORY_ENTRIES.to_s}];<<TAG_END>>} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;EOFo = ImageDataDirectory.newsuper(defs,input,'IMAGE_OPTIONAL_HEADER32',self.class)endendclass OptionalHeader64 < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_OPTIONAL_HEADER64 {<<TAG_BEGIN>>WORD Magic;BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;DWORD SizeOfInitializedData;DWORD SizeOfUninitializedData;DWORD AddressOfEntryPoint;DWORD BaseOfCode;ULONGLONG ImageBase;DWORD SectionAlignment;DWORD FileAlignment;WORD MajorOperatingSystemVersion;WORD MinorOperatingSystemVersion;WORD MajorImageVersion;WORD MinorImageVersion;WORD MajorSubsystemVersion;WORD MinorSubsystemVersion;DWORD Win32VersionValue;DWORD SizeOfImage;DWORD SizeOfHeaders;DWORD CheckSum;WORD Subsystem;WORD DllCharacteristics;ULONGLONG SizeOfStackReserve;ULONGLONG SizeOfStackCommit;ULONGLONG SizeOfHeapReserve;ULONGLONG SizeOfHeapCommit;DWORD LoaderFlags;DWORD NumberOfRvaAndSizes;IMAGE_DATA_DIRECTORY DataDirectory[#{IMAGE_NUMBEROF_DIRECTORY_ENTRIES.to_s}];<<TAG_END>>} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;EOFo = ImageDataDirectory.newsuper(defs,input,'IMAGE_OPTIONAL_HEADER64',self.class)endendclass RomOptionalHeader < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_ROM_OPTIONAL_HEADER {<<TAG_BEGIN>>WORD Magic;BYTE MajorLinkerVersion;BYTE MinorLinkerVersion;DWORD SizeOfCode;DWORD SizeOfInitializedData;DWORD SizeOfUninitializedData;DWORD AddressOfEntryPoint;DWORD BaseOfCode;DWORD BaseOfData;DWORD BaseOfBss;DWORD GprMask;DWORD CprMask[4];DWORD GpValue;<<TAG_END>>} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER;EOFsuper(defs,input,'IMAGE_ROM_OPTIONAL_HEADER',self.class)endendclass ImageNTHeaders32 < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_NT_HEADERS {<<TAG_BEGIN>>DWORD Signature;IMAGE_FILE_HEADER FileHeader;IMAGE_OPTIONAL_HEADER32 OptionalHeader;<<TAG_END>>} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;EOFo = CoffHeader.newo = OptionalHeader32.newsuper(defs,input,'IMAGE_NT_HEADERS32',self.class)endendclass ImageNTHeaders64 < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_NT_HEADERS64 {<<TAG_BEGIN>>DWORD Signature;IMAGE_FILE_HEADER FileHeader;IMAGE_OPTIONAL_HEADER64 OptionalHeader;<<TAG_END>>} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;EOFo = CoffHeader.newo = OptionalHeader64.newsuper(defs,input,'IMAGE_NT_HEADERS64',self.class)endendclass SectionHeader < BaseStructdef initialize(input = nil)defs = <<-EOF//winnt.htypedef struct _IMAGE_SECTION_HEADER {<<TAG_BEGIN>>BYTE Name[#{IMAGE_SIZEOF_SHORT_NAME.to_s}];//union {//DWORD PhysicalAddress;DWORD VirtualSize;//} Misc;DWORD VirtualAddress;DWORD SizeOfRawData;DWORD PointerToRawData;DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;<<TAG_END>>} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;EOFsuper(defs,input,'IMAGE_SECTION_HEADER',self.class)endendclass ImportDirectoryTableattr_accessor :import_lookup_table_rva,:time_stamp,:forward_chain,:name_rav,:import_address_table_ravattr_accessor :image,:name,:hintnamesdef initialize(nstart,imagedesc)@image = imagedesc.image@import_lookup_table_rva = Fixnum.readn(nstart + 0,4,@image)@time_stamp = Fixnum.readn(nstart + 4,4,@image)@forward_chain = Fixnum.readn(nstart + 8,4,@image)@name_rav = Fixnum.readn(nstart + 12,4,@image)@import_address_table_rav = Fixnum.readn(nstart + 16,4,@image)if not null?noffset = imagedesc.rav2offset(@name_rav)@name = imagedesc.read_mem_cstr(noffset)end@hintnames = Array.newenddef null?@import_lookup_table_rva == 0 and @time_stamp == 0 and @forward_chain == 0 and @name_rav == 0 and @import_address_table_rav == 0endendclass ImportLookupTableArrayattr_accessor :lookuptabledef initialize(nstart,imagedesc)image = imagedesc.imagearch = imagedesc.image_type@lookuptable = Array.newnsize = 0while truedata = nilif arch == 'PE32'data = Fixnum.readn(nstart + nsize,4,image)nsize += 4elsif arch =='PE32+'data = Fixnum.readn(nstart + nsize,8,image)nsize += 8endbreak if data == 0@lookuptable << dataendendendclass HintNameTableattr_accessor :image,:use_hint,:hint,:namedef initialize(imagedesc,ilt_item)@image = imagedesc.imagearch = imagedesc.image_typeif arch == 'PE32'@use_hint = ilt_item.test_b(31)elsif arch =='PE32+'@use_hint = ilt_item.test_b(63)endif @use_hint@hint = ilt_item.part_b(0..15)@name = nilelsehntab_rva = ilt_item.part_b(0..30)@hint = nilnoffset = imagedesc.rav2offset(hntab_rva)@name = imagedesc.read_mem_cstr(noffset + 2)endendendclass ExportDirectoryTableattr_accessor :image,:name,:ordinal_list,:name_listattr_accessor :exportflags,:timestamp,:majorversion,:minorversion,:namerva,:ordinalbase,:addresstableentries,:numberofnamepointers,:exportaddresstablerva,:namepointerrva,:ordinaltablervaattr_accessor :imagedescdef initialize(nstart,imagedesc)@imagedesc = imagedesc@image = imagedesc.image@exportflags = Fixnum.readn(nstart + 0,4,@image)@timestamp = Fixnum.readn(nstart + 4,4,@image)@majorversion = Fixnum.readn(nstart + 8,2,@image)@minorversion = Fixnum.readn(nstart + 10,2,@image)@namerva = Fixnum.readn(nstart + 12,4,@image)@ordinalbase = Fixnum.readn(nstart + 16,4,@image)@addresstableentries = Fixnum.readn(nstart + 20,4,@image)@numberofnamepointers = Fixnum.readn(nstart + 24,4,@image)@exportaddresstablerva = Fixnum.readn(nstart + 28,4,@image)@namepointerrva = Fixnum.readn(nstart + 32,4,@image)@ordinaltablerva = Fixnum.readn(nstart + 36,4,@image)set_nameset_ordinal_listset_name_listenddef set_namenoffset = @imagedesc.rav2offset(@namerva)@name = @imagedesc.read_mem_cstr(noffset)enddef set_ordinal_list@ordinal_list = Array.newnoffset = @imagedesc.rav2offset(@ordinaltablerva)nsize = 0@numberofnamepointers.times doo = Fixnum.readn(noffset + nsize,2,@image)@ordinal_list << onsize += 2endenddef set_name_list@name_list = Array.newnoffset = @imagedesc.rav2offset(@namepointerrva)nsize = 0@numberofnamepointers.times doo = Fixnum.readn(noffset + nsize,4,@image)offset_o = @imagedesc.rav2offset(o)namestr = @imagedesc.read_mem_cstr(offset_o)@name_list << namestrnsize += 4endendendclass ImageDescattr_accessor :image,:dosheader,:ntheader,:sections,:image_typedef initialize(image,dosheader,ntheader,sections,image_type)@image,@dosheader,@ntheader,@sections,@image_type = image,dosheader,ntheader,sections,image_typeenddef res_idataraise RuntimeError,'No import data directory.' if @ntheader.fileheader.numberofsections < 2imports = Array.newimp_va = @ntheader.optionalheader.datadirectory[1].virtualaddresspage_start = rav2offset(imp_va)nsize = 20while idt = ImportDirectoryTable.new(page_start,self)break if idt.null?noffset = rav2offset(idt.import_lookup_table_rva)lookuptable = ImportLookupTableArray.new(noffset,self).lookuptablelookuptable.each do |lt|hnt = HintNameTable.new(self,lt)idt.hintnames << hntendimports << idtpage_start += nsizeendimportsenddef res_edataraise RuntimeError,'No import data directory.' if @ntheader.fileheader.numberofsections < 1exp_va = @ntheader.optionalheader.datadirectory[0].virtualaddresspage_start = rav2offset(exp_va)edt = ExportDirectoryTable.new(page_start,self)enddef rav2offset(rav)hit_section = nil@sections.each do |section|if rav >= section.virtualaddress and rav <= section.virtualaddress + section.sizeofrawdatahit_section = section#puts "RAV[#{rav.to_sd}] hit #{section.name.to_repl} between [#{section.virtualaddress.to_sd} ~ #{(section.virtualaddress + section.sizeofrawdata).to_sd}],file offset at[#{(section.pointertorawdata + (rav - hit_section.virtualaddress)).to_sd}] between [#{section.pointertorawdata.to_sd} ~ #{(section.virtualaddress + section.sizeofrawdata).to_sd}] "breakendendraise RuntimeError,"RAV[#{rav.to_sd}] out of sections virtual address space." if hit_section.nil?hit_section.pointertorawdata + (rav - hit_section.virtualaddress)enddef read_mem_cstr(nstart)result = StringIO.newwhile @image[nstart] != 0result.putc @image[nstart]nstart += 1endresult.stringendendclass PEParserattr_accessor :image,:keyaddrdef initialize(src)@image = Image.new(src)@keyaddr = KeyAddress.newenddef parseimage_type = nilif @image.slice(0,2).to_num != IMAGE_DOS_SIGNATUREraise RuntimeError,'Not valid image file - test from IMAGE_DOS_SIGNATURE.'end@keyaddr.add_item('dos_start',0)dosstub = DosStub.newdosstub,nsize = TypeInfo.fixup(dosstub,@image.slice(0,dosstub.nsize))@keyaddr.add_item('pe_start',dosstub.e_lfanew)if @image.slice(@keyaddr.pe_start,4).to_num != IMAGE_NT_SIGNATUREraise RuntimeError,'Not valid image file - test from IMAGE_NT_SIGNATURE.'end@keyaddr.add_item('coff_start',@keyaddr.pe_start + 4)@keyaddr.add_item('optional_start',@keyaddr.coff_start + CoffHeader.new.nsize)pe_type = @image.slice(@keyaddr.optional_start,2).to_lenumntheader,nsize = nil,0if pe_type == IMAGE_NT_OPTIONAL_HDR32_MAGICimage_type = 'PE32'ntheader = ImageNTHeaders32.newntheader,nsize = TypeInfo.fixup(ntheader,@image.slice(@keyaddr.pe_start,ntheader.nsize))else if pe_type == IMAGE_NT_OPTIONAL_HDR64_MAGICimage_type = 'PE32+'ntheader = ImageNTHeaders64.newntheader,nsize = TypeInfo.fixup(ntheader,@image.slice(@keyaddr.pe_start,ntheader.nsize))elseputs 'MAGIC:' + pe_type.to_s(16)raise RuntimeError,'Never mind file type - test from IMAGE_NT_OPTIONAL_HDR**_MAGIC.'endend@keyaddr.add_item('nsections',ntheader.fileheader.numberofsections)@keyaddr.add_item('nsizeofoptionalheader',ntheader.fileheader.sizeofoptionalheader)@keyaddr.add_item('sections_start',@keyaddr.optional_start + @keyaddr.nsizeofoptionalheader)sections = Array.new@keyaddr.nsections.times do |i|s = SectionHeader.news,nsize = TypeInfo.fixup(s,@image.slice(@keyaddr.sections_start + s.nsize * i,s.nsize))sections << sendImageDesc.new(@image,dosstub,ntheader,sections,image_type)endendend
这来一个简单的测试用例,输出动态库的import和export的简单信息。
pf = PE::PEParser.new('D:\\Bandicam\\bdcap32.dll')pedec = pf.parseimps = pedec.res_idata$stderr.puts "-----imports-----"imps.each do |imp|$stderr.puts "[#{imp.name}]"imp.hintnames.each do |hn|if hn.use_hint$stderr.puts "\t" + hn.hint.to_selse$stderr.puts "\t" + hn.nameendendendedt = pedec.res_edata$stderr.puts "-----exports-----"$stderr.puts "[#{edt.name}]"edt.name_list.each do |n|$stderr.puts "\t" + nend
0 0
- Ruby解析Windows PE文件
- windows PE结构解析
- windows PE结构解析
- Python解析PE文件
- PE文件解析
- PE文件结构解析
- PE文件结构解析
- PE文件解析代码
- PE文件解析(C#)
- Ruby解析XML文件
- Ruby解析XML文件
- Windows程序调试--PE文件
- windows PE Image 文件分析
- Windows PE文件结构简介
- 【Windows】 PE文件头学习
- pe文件解析:读取pe信息获取文件资源
- PE文件详解1——PE文件头部解析
- PE总结9 --PE文件结构之 解析导出表
- sql server中collate排序关键字的使用
- RISC 和 CISC
- java数组
- 输入字母和数字串,分别输出顺序字母串和逆序数字串
- brk与sbrk
- Ruby解析Windows PE文件
- 消息队列
- Linux命令之"chgrp"
- linux文件系统
- 动态树分治
- Spring之AOP与IOC
- [专题2016-09-26]交易短款排查点
- 工作日记 2016-10-26
- poj 3321 Apple Tree(dfs染色+树状数组)