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
原创粉丝点击