123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- (*
- * This file is part of ilLib
- * Copyright (c)2004-2013 Haxe Foundation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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
- *)
- open PeData;;
- open IO;;
- open ExtString;;
- open ExtList;;
- exception Error_message of string
- type reader_ctx = {
- ch : Pervasives.in_channel;
- i : IO.input;
- verbose : bool;
- }
- type ctx = {
- r : reader_ctx;
- pe_header : pe_header;
- read_word : IO.input -> pointer;
- }
- let error msg = raise (Error_message msg)
- let seek r pos =
- seek_in r.ch pos
- let pos r =
- Pervasives.pos_in r.ch
- let info r msg =
- if r.verbose then
- print_endline (msg())
- let machine_type_of_int i = match i with
- | 0x0 -> TUnknown (* 0 - unmanaged PE files only *)
- | 0x014c -> Ti386 (* 0x014c - i386 *)
- | 0x0162 -> TR3000 (* 0x0162 - R3000 MIPS Little Endian *)
- | 0x0166 -> TR4000 (* 0x0166 - R4000 MIPS Little Endian *)
- | 0x0168 -> TR10000 (* 0x0168 - R10000 MIPS Little Endian *)
- | 0x0169 -> TWCeMipsV2 (* 0x0169 - MIPS Litlte Endian running MS Windows CE 2 *)
- | 0x0184 -> TAlpha (* 0x0184 - Alpha AXP *)
- | 0x01a2 -> TSh3 (* 0x01a2 - SH3 Little Endian *)
- | 0x01a3 -> TSh3Dsp (* 0x01a3 SH3DSP Little Endian *)
- | 0x01a4 -> TSh3e (* 0x01a4 SH3E Little Endian *)
- | 0x01a6 -> TSh4 (* 0x01a6 SH4 Little Endian *)
- | 0x01a8 -> TSh5
- | 0x01c0 -> TArm (* 0x1c0 ARM Little Endian *)
- | 0x01c2 -> TThumb (* 0x1c2 ARM processor with Thumb decompressor *)
- | 0x01c4 -> TArmN (* 0x1c0 ARM Little Endian *)
- | 0xaa64 -> TArm64
- | 0xebc -> TEbc
- | 0x01d3 -> TAm33 (* 0x1d3 AM33 processor *)
- | 0x01f0 -> TPowerPC (* 0x01f0 IBM PowerPC Little Endian *)
- | 0x01f1 -> TPowerPCFP (* 0x01f1 IBM PowerPC with FPU *)
- | 0x0200 -> TItanium64 (* 0x0200 Intel IA64 (Itanium( *)
- | 0x0266 -> TMips16 (* 0x0266 MIPS *)
- | 0x0284 -> TAlpha64 (* 0x0284 Alpha AXP64 *)
- | 0x0366 -> TMipsFpu (* 0x0366 MIPS with FPU *)
- | 0x0466 -> TMipsFpu16 (* 0x0466 MIPS16 with FPU *)
- | 0x0520 -> TTriCore (* 0x0520 Infineon *)
- | 0x8664 -> TAmd64 (* 0x8664 AMD x64 and Intel E64T *)
- | 0x9041 -> TM32R (* 0x9041 M32R *)
- | _ -> assert false
- let coff_props_of_int iprops = List.fold_left (fun acc i ->
- if (iprops land i) = i then (match i with
- | 0x1 -> RelocsStripped (* 0x1 *)
- | 0x2 -> ExecutableImage (* 0x2 *)
- | 0x4 -> LineNumsStripped (* 0x4 *)
- | 0x8 -> LocalSymsStripped (* 0x8 *)
- | 0x10 -> AgressiveWsTrim (* 0x10 *)
- | 0x20 -> LargeAddressAware (* 0x20 *)
- | 0x80 -> BytesReversedLO (* 0x80 *)
- | 0x100 -> Machine32Bit (* 0x100 *)
- | 0x200 -> DebugStripped (* 0x200 *)
- | 0x400 -> RemovableRunFromSwap (* 0x400 *)
- | 0x800 -> NetRunFromSwap (* 0x800 *)
- | 0x1000 -> FileSystem (* 0x1000 *)
- | 0x2000 -> FileDll (* 0x2000 *)
- | 0x4000 -> UpSystemOnly (* 0x4000 *)
- | 0x8000 -> BytesReversedHI (* 0x8000 *)
- | _ -> assert false) :: acc
- else
- acc) [] [0x1;0x2;0x4;0x8;0x10;0x20;0x80;0x100;0x200;0x400;0x800;0x1000;0x2000;0x4000;0x8000]
- let section_props_of_int32 props = List.fold_left (fun acc i ->
- if (Int32.logand props i) = i then (match i with
- | 0x8l -> SNoPad
- | 0x20l -> SHasCode
- | 0x40l -> SHasIData
- | 0x80l -> SHasData
- | 0x200l -> SHasLinkInfo
- | 0x1000l -> SLinkRemove
- | 0x8000l -> SGlobalRel
- | 0x20000l -> SHas16BitMem
- | 0x100000l -> SAlign1Bytes
- | 0x200000l -> SAlign2Bytes
- | 0x300000l -> SAlign4Bytes
- | 0x400000l -> SAlign8Bytes
- | 0x500000l -> SAlign16Bytes
- | 0x600000l -> SAlign32Bytes
- | 0x700000l -> SAlign64Bytes
- | 0x800000l -> SAlign128Bytes
- | 0x900000l -> SAlign256Bytes
- | 0xA00000l -> SAlign512Bytes
- | 0xB00000l -> SAlign1024Bytes
- | 0xC00000l -> SAlign2048Bytes
- | 0xD00000l -> SAlign4096Bytes
- | 0xE00000l -> SAlign8192Bytes
- | 0x1000000l -> SHasExtRelocs
- | 0x02000000l -> SCanDiscard
- | 0x04000000l -> SNotCached
- | 0x08000000l -> SNotPaged
- | 0x10000000l -> SShared
- | 0x20000000l -> SExec
- | 0x40000000l -> SRead
- | 0x80000000l -> SWrite
- | _ -> assert false) :: acc
- else
- acc) [] [ 0x8l; 0x20l; 0x40l; 0x80l; 0x200l; 0x1000l; 0x8000l; 0x20000l; 0x100000l; 0x200000l; 0x300000l; 0x400000l; 0x500000l; 0x600000l; 0x700000l; 0x800000l; 0x900000l; 0xA00000l; 0xB00000l; 0xC00000l; 0xD00000l; 0xE00000l; 0x1000000l; 0x02000000l; 0x04000000l; 0x08000000l; 0x10000000l; 0x20000000l; 0x40000000l; 0x80000000l; ]
- let subsystem_of_int i = match i with
- | 0 -> SUnknown (* 0 *)
- | 1 -> SNative (* 1 *)
- | 2 -> SWGui (* 2 *)
- | 3 -> SWCui (* 3 *)
- | 7 -> SPCui (* 7 *)
- | 9 -> SWCeGui (* 9 *)
- | 10 -> SEfi (* 10 *)
- | 11 -> SEfiBoot (* 11 *)
- | 12 -> SEfiRuntime (* 12 *)
- | 13 -> SEfiRom (* 13 *)
- | 14 -> SXbox (* 14 *)
- | _ -> error ("Unknown subsystem " ^ string_of_int i)
- let dll_props_of_int iprops = List.fold_left (fun acc i ->
- if (iprops land i) = i then (match i with
- | 0x0040 -> DDynamicBase (* 0x0040 *)
- | 0x0080 -> DForceIntegrity (* 0x0080 *)
- | 0x0100 -> DNxCompat (* 0x0100 *)
- | 0x0200 -> DNoIsolation (* 0x0200 *)
- | 0x0400 -> DNoSeh (* 0x0400 *)
- | 0x0800 -> DNoBind (* 0x0800 *)
- | 0x2000 -> DWdmDriver (* 0x2000 *)
- | 0x8000 -> DTerminalServer (* 0x8000 *)
- | _ -> assert false) :: acc
- else
- acc) [] [0x40;0x80;0x100;0x200;0x400;0x800;0x2000;0x8000]
- let pe_magic_of_int i = match i with
- | 0x10b -> P32
- | 0x107 -> PRom
- | 0x20b -> P64
- | _ -> error ("Unknown PE magic number: " ^ string_of_int i)
- let clr_flags_of_int iprops = List.fold_left (fun acc i ->
- if (iprops land i) = i then (match i with
- | 0x1 -> FIlOnly (* 0x1 *)
- | 0x2 -> F32BitRequired (* 0x2 *)
- | 0x4 -> FIlLibrary (* 0x4 *)
- | 0x8 -> FSigned (* 0x8 *)
- | 0x10 -> FNativeEntry (* 0x10 *)
- | 0x10000 -> FTrackDebug (* 0x10000 *)
- | _ -> assert false) :: acc
- else
- acc) [] [0x1;0x2;0x4;0x8;0x10;0x10000]
- let get_dir dir ctx =
- let idx,name = directory_type_info dir in
- try
- ctx.pe_header.pe_data_dirs.(idx)
- with
- | Invalid_argument _ ->
- error (Printf.sprintf "The directory '%s' of index '%i' is required but is missing on this file" name idx)
- let read_rva = read_real_i32
- let read_word is64 i =
- if is64 then read_i64 i else Int64.logand (Int64.of_int32 (read_real_i32 i)) 0xFFFFFFFFL
- let read_coff_header i =
- let machine = machine_type_of_int (read_ui16 i) in
- let nsections = read_ui16 i in
- let stamp = read_real_i32 i in
- let symbol_table_pointer = read_rva i in
- let nsymbols = read_i32 i in
- let optheader_size = read_ui16 i in
- let props = read_ui16 i in
- let props = coff_props_of_int (props) in
- {
- coff_machine = machine;
- coff_nsections = nsections;
- coff_timestamp = stamp;
- coff_symbol_table_pointer = symbol_table_pointer;
- coff_nsymbols = nsymbols;
- coff_optheader_size = optheader_size;
- coff_props = props;
- }
- let read_pe_header r header =
- let i = r.i in
- let sections_offset = (pos r) + header.coff_optheader_size in
- let magic = pe_magic_of_int (read_ui16 i) in
- let major = read_byte i in
- let minor = read_byte i in
- let code_size = read_i32 i in
- let init_size = read_i32 i in
- let uinit_size = read_i32 i in
- let entry_addr = read_rva i in
- let base_code = read_rva i in
- let base_data, read_word = match magic with
- | P32 | PRom ->
- read_rva i, read_word false
- | P64 ->
- Int32.zero, read_word true
- in
- (* COFF Windows extension *)
- let image_base = read_word i in
- let section_alignment = read_i32 i in
- let file_alignment = read_i32 i in
- let major_osver = read_ui16 i in
- let minor_osver = read_ui16 i in
- let major_imgver = read_ui16 i in
- let minor_imgver = read_ui16 i in
- let major_subsysver = read_ui16 i in
- let minor_subsysver = read_ui16 i in
- ignore (read_i32 i); (* reserved *)
- let image_size = read_i32 i in
- let headers_size = read_i32 i in
- let checksum = read_real_i32 i in
- let subsystem = subsystem_of_int (read_ui16 i) in
- let dll_props = dll_props_of_int (read_ui16 i) in
- let stack_reserve = read_word i in
- let stack_commit = read_word i in
- let heap_reserve = read_word i in
- let heap_commit = read_word i in
- ignore (read_i32 i); (* reserved *)
- let ndata_dir = read_i32 i in
- let data_dirs = Array.init ndata_dir (fun n ->
- let addr = read_rva i in
- let size = read_rva i in
- addr,size)
- in
- (* sections *)
- let nsections = header.coff_nsections in
- seek r sections_offset;
- let sections = Array.init nsections (fun n ->
- let name = nread_string i 8 in
- let name = try
- let index = String.index name '\x00' in
- String.sub name 0 index
- with | Not_found ->
- name
- in
- (*TODO check for slash names *)
- let vsize = read_rva i in
- let vaddr = read_rva i in
- let raw_size = read_rva i in
- let raw_pointer = read_i32 i in
- let reloc_pointer = read_i32 i in
- let line_num_pointer = read_i32 i in
- let nrelocs = read_ui16 i in
- let nline_nums = read_ui16 i in
- let props = section_props_of_int32 (read_rva i) in
- {
- s_name = name;
- s_vsize =vsize;
- s_vaddr =vaddr;
- s_raw_size =raw_size;
- s_raw_pointer =raw_pointer;
- s_reloc_pointer =reloc_pointer;
- s_line_num_pointer =line_num_pointer;
- s_nrelocs =nrelocs;
- s_nline_nums =nline_nums;
- s_props =props;
- }
- ) in
- {
- pe_coff_header = header;
- pe_magic = magic;
- pe_major = major;
- pe_minor = minor;
- pe_code_size = code_size;
- pe_init_size = init_size;
- pe_uinit_size = uinit_size;
- pe_entry_addr = entry_addr;
- pe_base_code = base_code;
- pe_base_data = base_data;
- pe_image_base = image_base;
- pe_section_alignment = section_alignment;
- pe_file_alignment = file_alignment;
- pe_major_osver = major_osver;
- pe_minor_osver = minor_osver;
- pe_major_imgver = major_imgver;
- pe_minor_imgver = minor_imgver;
- pe_major_subsysver = major_subsysver;
- pe_minor_subsysver = minor_subsysver;
- pe_image_size = image_size;
- pe_headers_size = headers_size;
- pe_checksum = checksum;
- pe_subsystem = subsystem;
- pe_dll_props = dll_props;
- pe_stack_reserve = stack_reserve;
- pe_stack_commit = stack_commit;
- pe_heap_reserve = heap_reserve;
- pe_heap_commit = heap_commit;
- pe_ndata_dir = ndata_dir;
- pe_data_dirs = data_dirs;
- pe_sections = sections;
- }
- let create_r ch props =
- let verbose = PMap.mem "IL_VERBOSE" props in
- let i = IO.input_channel ch in
- {
- ch = ch;
- i = i;
- verbose = verbose;
- }
- (* converts an RVA into a file offset. *)
- let convert_rva ctx rva =
- let sections = ctx.pe_header.pe_sections in
- let nsections = Array.length sections in
- let sec =
- (* linear search. TODO maybe binary search for many sections? *)
- let rec loop n =
- if n >= nsections then error (Printf.sprintf "The RVA %lx is outside sections bounds!" rva);
- let sec = sections.(n) in
- if rva >= sec.s_vaddr && (rva < (Int32.add sec.s_vaddr sec.s_raw_size)) then
- sec
- else
- loop (n+1)
- in
- loop 0
- in
- let diff = Int32.to_int (Int32.sub rva sec.s_vaddr) in
- sec.s_raw_pointer + diff
- let seek_rva ctx rva = seek ctx.r (convert_rva ctx rva)
- let read_cstring i =
- let ret = Buffer.create 8 in
- let rec loop () =
- let chr = read i in
- if chr = '\x00' then
- Buffer.contents ret
- else begin
- Buffer.add_char ret chr;
- loop()
- end
- in
- loop()
- (* reads import data *)
- let read_idata ctx = match get_dir ImportTable ctx with
- | 0l,_ | _,0l ->
- []
- | rva,size ->
- seek_rva ctx rva;
- let i = ctx.r.i in
- let rec loop acc =
- let lookup_table = read_rva i in
- if lookup_table = Int32.zero then
- acc
- else begin
- let timestamp = read_real_i32 i in
- let fchain = read_real_i32 i in
- let name_rva = read_rva i in
- let addr_table = read_rva i in
- ignore addr_table; ignore fchain; ignore timestamp;
- loop ((lookup_table,name_rva) :: acc)
- end
- in
- let tables = loop [] in
- List.rev_map (function (lookup_table,name_rva) ->
- seek_rva ctx lookup_table;
- let is_64 = ctx.pe_header.pe_magic = P64 in
- let imports_data = if not is_64 then
- let rec loop acc =
- let flags = read_real_i32 i in
- if flags = Int32.zero then
- acc
- else begin
- let is_ordinal = Int32.logand flags 0x80000000l = 0x80000000l in
- loop ( (is_ordinal, if is_ordinal then Int32.logand flags 0xFFFFl else Int32.logand flags 0x7FFFFFFFl) :: acc )
- end
- in
- loop []
- else
- let rec loop acc =
- let flags = read_i64 i in
- if flags = Int64.zero then
- acc
- else begin
- let is_ordinal = Int64.logand flags 0x8000000000000000L = 0x8000000000000000L in
- loop ( (is_ordinal, Int64.to_int32 (if is_ordinal then Int64.logand flags 0xFFFFL else Int64.logand flags 0x7FFFFFFFL)) :: acc )
- end
- in
- loop []
- in
- let imports = List.rev_map (function
- | true, ord ->
- SOrdinal (Int32.to_int ord)
- | false, rva ->
- seek_rva ctx rva;
- let hint = read_ui16 i in
- SName (hint, read_cstring i)
- ) imports_data in
- seek_rva ctx name_rva;
- let name = read_cstring i in
- {
- imp_name = name;
- imp_imports = imports;
- }
- ) tables
- let has_clr_header ctx = match get_dir ClrRuntimeHeader ctx with
- | 0l,_ | _,0l ->
- false
- | _ ->
- true
- let read_clr_header ctx = match get_dir ClrRuntimeHeader ctx with
- | 0l,_ | _,0l ->
- error "This PE file does not have managed content"
- | rva,size ->
- seek_rva ctx rva;
- let i = ctx.r.i in
- let cb = read_i32 i in
- let major = read_ui16 i in
- let minor = read_ui16 i in
- let read_tbl i =
- let rva = read_rva i in
- let size = read_real_i32 i in
- rva,size
- in
- let meta = read_tbl i in
- let corflags = clr_flags_of_int (read_i32 i) in
- let entry_point = read_rva i in
- let res = read_tbl i in
- let clrsig = read_tbl i in
- let codeman = read_tbl i in
- let vtable_fix = read_tbl i in
- let export_addr = read_tbl i in
- {
- clr_cb = cb;
- clr_major = major;
- clr_minor = minor;
- clr_meta = meta;
- clr_flags = corflags;
- clr_entry_point = entry_point;
- clr_res = res;
- clr_sig = clrsig;
- clr_codeman = codeman;
- clr_vtable_fix = vtable_fix;
- clr_export_address = export_addr;
- }
- let read r =
- let i = r.i in
- if read i <> 'M' || read i <> 'Z' then
- error "MZ magic header not found: Is the target file really a PE?";
- seek r 0x3c;
- let pe_sig_offset = read_i32 i in
- seek r pe_sig_offset;
- if really_nread_string i 4 <> "PE\x00\x00" then
- error "Invalid PE header signature: PE expected";
- let header = read_coff_header i in
- let pe_header = read_pe_header r header in
- {
- r = r;
- pe_header = pe_header;
- read_word = read_word (pe_header.pe_magic = P64);
- }
|