123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587(**************************************************************************)(* This file is part of BINSEC. *)(* *)(* Copyright (C) 2016-2026 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It 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 Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openBasic_types.IntegersopenReaderopenLoader_typesletread_magict=(not(dimt<0x40))&&Uint8.to_char(Read.u8t)='M'&&Uint8.to_char(Read.u8t)='Z'&&(set_post0x3c;set_post(Uint32.to_int(Read.u32t));(not(get_post+4>dimt))&&Uint8.to_char(Read.u8t)='P'&&Uint8.to_char(Read.u8t)='E'&&Uint8.to_char(Read.u8t)='\x00'&&Uint8.to_char(Read.u8t)='\x00')letcheck_magicbuffer=lett=of_bigarraybufferinread_magictletinit_cursorbuffer=lett=of_bigarraybufferinifnot(read_magict)theninvalid_format"No PE magic number";t(* File header *)typefile_header={machine:u16;number_of_sections:int;time_date_stamp:u32;pointer_to_symbol_table:int;number_of_symbols:int;size_of_optional_header:int;characteristics:u16;}letarch=function|0x014c->Machine.x86|0x01c0->Machine.armv7Machine.LittleEndian(* | 0x01c2 -> Machine.armv7 *)(* Thumb *)(* | 0x01c4 -> Machine.armv7 *)(* Thumb-2 *)(* | 0x01f0 -> Machine.PowerPC
* | 0x01f1 -> Machine.PowerPC
* | 0x0200 -> Machine.IA64
* | 0x0166 -> Machine.MIPS
* | 0x0169 -> Machine.MIPS
* | 0x0266 -> Machine.MIPS
* | 0x0366 -> Machine.MIPS
* | 0x0466 -> Machine.MIPS *)|0x8664->Machine.amd64(* | 0xaa64 -> Machine.ARM64 *)|_->Machine.unknownletread_file_headert=ensuret20"File header truncated";letmachine=Read.u16tinletnumber_of_sections=Uint16.to_int(Read.u16t)inlettime_date_stamp=Read.u32tinletpointer_to_symbol_table=Uint32.to_int(Read.u32t)inletnumber_of_symbols=Uint32.to_int(Read.u32t)inletsize_of_optional_header=Uint16.to_int(Read.u16t)inletcharacteristics=Read.u16tin{machine;number_of_sections;time_date_stamp;pointer_to_symbol_table;number_of_symbols;size_of_optional_header;characteristics;}(* Optional header *)typestandard_fields={magic:u16;size_of_code:u32;size_of_initialized_data:u32;size_of_uninitialized_data:u32;address_of_entry_point:Virtual_address.t;base_of_code:u32;base_of_data:u32option;}typewindows_fields={image_base:Virtual_address.t;section_alignement:u32;file_alignement:u32;size_of_image:u32;size_of_headers:u32;checksum:u32;subsystem:u16;dll_characteristics:u16;size_of_stack_reserve:u64;size_of_stack_commit:u64;size_of_heap_reserve:u64;size_of_heap_commit:u64;number_of_rva_and_sizes:u32;}typedata_directory={virtual_address:u32;size:u32}typedata_directories={export_directory:data_directory;import_directory:data_directory;resource_directory:data_directory;exception_directory:data_directory;security_directory:data_directory;basereloc_directory:data_directory;debug_directory:data_directory;globalptr_directory:data_directory;tls_directory:data_directory;load_config_directory:data_directory;bound_import_directory:data_directory;iat_directory:data_directory;delay_import_directory:data_directory;clr_header_directory:data_directory;}typeoptional_header={standard_fields:standard_fields;windows_fields:windows_fields;data_directories:data_directories;}typeprogram=file_header*optional_headerletread_standard_fields32tmagic=ensuret26"Standard fields truncated";let_major_linker_version=Read.u8tinlet_minor_linker_version=Read.u8tinletsize_of_code=Read.u32tinletsize_of_initialized_data=Read.u32tinletsize_of_uninitialized_data=Read.u32tinletaddress_of_entry_point=Virtual_address.of_uint32(Read.u32t)inletbase_of_code=Read.u32tinletbase_of_data=Some(Read.u32t)in{magic;size_of_code;size_of_initialized_data;size_of_uninitialized_data;address_of_entry_point;base_of_code;base_of_data;}letread_standard_fields64tmagic=ensuret22"Standard fields truncated";let_major_linker_version=Read.u8tinlet_minor_linker_version=Read.u8tinletsize_of_code=Read.u32tinletsize_of_initialized_data=Read.u32tinletsize_of_uninitialized_data=Read.u32tinletaddress_of_entry_point=Virtual_address.of_uint32(Read.u32t)inletbase_of_code=Read.u32tinletbase_of_data=Nonein{magic;size_of_code;size_of_initialized_data;size_of_uninitialized_data;address_of_entry_point;base_of_code;base_of_data;}letread_standard_fieldst=ensuret2"PE magic number truncated";letmagic=Read.u16tinmatchUint16.to_intmagicwith|0x10b->read_standard_fields32tmagic|0x20b->read_standard_fields64tmagic|_->invalid_format"Invalid PE image file"letread_windows_fields32t=ensuret68"Windows fields truncated";letimage_base=Virtual_address.of_uint32(Read.u32t)inletsection_alignement=Read.u32tinletfile_alignement=Read.u32tinlet_major_os_version=Read.u16tinlet_minor_os_version=Read.u16tinlet_major_image_version=Read.u16tinlet_minor_image_version=Read.u16tinlet_major_subsystem_version=Read.u16tinlet_minor_subsystem_version=Read.u16tinifnot(Read.i32t=0l)theninvalid_format"Invalid Win32 version value";letsize_of_image=Read.u32tinletsize_of_headers=Read.u32tinletchecksum=Read.u32tinletsubsystem=Read.u16tinletdll_characteristics=Read.u16tinletsize_of_stack_reserve=Uint32.to_uint64(Read.u32t)inletsize_of_stack_commit=Uint32.to_uint64(Read.u32t)inletsize_of_heap_reserve=Uint32.to_uint64(Read.u32t)inletsize_of_heap_commit=Uint32.to_uint64(Read.u32t)inifnot(Read.i32t=0l)theninvalid_format"Invalid loader flags";letnumber_of_rva_and_sizes=Read.u32tin{image_base;section_alignement;file_alignement;size_of_image;size_of_headers;number_of_rva_and_sizes;checksum;subsystem;dll_characteristics;size_of_stack_reserve;size_of_stack_commit;size_of_heap_reserve;size_of_heap_commit;}letread_windows_fields64t=ensuret88"Windows fields truncated";letimage_base=Virtual_address.of_uint64(Read.u64t)inletsection_alignement=Read.u32tinletfile_alignement=Read.u32tinlet_major_os_version=Read.u16tinlet_minor_os_version=Read.u16tinlet_major_image_version=Read.u16tinlet_minor_image_version=Read.u16tinlet_major_subsystem_version=Read.u16tinlet_minor_subsystem_version=Read.u16tinifnot(Read.i32t=0l)theninvalid_format"Invalid Win32 version value";letsize_of_image=Read.u32tinletsize_of_headers=Read.u32tinletchecksum=Read.u32tinletsubsystem=Read.u16tinletdll_characteristics=Read.u16tinletsize_of_stack_reserve=Read.u64tinletsize_of_stack_commit=Read.u64tinletsize_of_heap_reserve=Read.u64tinletsize_of_heap_commit=Read.u64tinifnot(Read.i32t=0l)theninvalid_format"Invalid loader flags";letnumber_of_rva_and_sizes=Read.u32tin{image_base;section_alignement;file_alignement;size_of_image;size_of_headers;number_of_rva_and_sizes;checksum;subsystem;dll_characteristics;size_of_stack_reserve;size_of_stack_commit;size_of_heap_reserve;size_of_heap_commit;}letread_windows_fieldsstandardt=matchUint16.to_intstandard.magicwith|0x10b->read_windows_fields32t|0x20b->read_windows_fields64t|_->invalid_format"Invalid PE image file"letread_data_directoryt=ensuret8"Data directory truncated";letvirtual_address=Read.u32tinletsize=Read.u32tin{virtual_address;size}letread_data_directoriest=ensuret96"Data directories truncated";letexport_directory=read_data_directorytinletimport_directory=read_data_directorytinletresource_directory=read_data_directorytinletexception_directory=read_data_directorytinletsecurity_directory=read_data_directorytinletbasereloc_directory=read_data_directorytinletdebug_directory=read_data_directorytinifnot(Read.i64t=0L)theninvalid_format"Invalid data directories";letglobalptr_directory=read_data_directorytinifnot(Uint32.to_int32globalptr_directory.size=0l)theninvalid_format"Invalid data directories";lettls_directory=read_data_directorytinletload_config_directory=read_data_directorytinletbound_import_directory=read_data_directorytinletiat_directory=read_data_directorytinletdelay_import_directory=read_data_directorytinletclr_header_directory=read_data_directorytinifnot(Read.i64t=0L)theninvalid_format"Invalid data directories";{export_directory;import_directory;resource_directory;exception_directory;security_directory;basereloc_directory;debug_directory;globalptr_directory;tls_directory;load_config_directory;bound_import_directory;iat_directory;delay_import_directory;clr_header_directory;}letread_optional_headert=letstandard_fields=read_standard_fieldstinletwindows_fields=read_windows_fieldsstandard_fieldstinletdata_directories=read_data_directoriestin{standard_fields;windows_fields;data_directories}letrebaseoi=Virtual_address.addo.windows_fields.image_basei(* Section header *)typesection={section_name:string;virtual_size:u32;virtual_address:Virtual_address.t;size_of_raw_data:int;pointer_to_raw_data:int;characteristics:u32;}letread_section_namet=letname=Peek.fixed_stringt8inadvancet8;nameletread_sectiontfileoptionaln=set_post(optional+file.size_of_optional_header+(n*40));(* file header + optional header + nbr * section header *)ensuret40"Section header truncated";letsection_name=read_section_nametinletvirtual_size=Read.u32tinletvirtual_address=Virtual_address.of_uint32(Read.u32t)inletsize_of_raw_data=Uint32.to_int(Read.u32t)inletpointer_to_raw_data=Uint32.to_int(Read.u32t)inlet_pointer_to_relocations=Read.u32tinlet_pointer_to_linenumbers=Read.u32tinlet_number_of_relocations=Read.u16tinlet_number_of_linenumbers=Read.u16tinletcharacteristics=Read.u32tin{section_name;virtual_size;virtual_address;size_of_raw_data;pointer_to_raw_data;characteristics;}letread_sectionstfileoptional=Array.initfile.number_of_sections(read_sectiontfileoptional)exceptionFoundofsectionletfind_sectionsectionsf=tryArray.iter(funsection->iffsectionthenraise(Foundsection))sections;NonewithFoundsection->Somesectionletin_sectionoptional(section:section)addr=addr>=rebaseoptionalsection.virtual_address&&addr<Virtual_address.add_bigint(Uint32.to_bigintsection.virtual_size)(rebaseoptionalsection.virtual_address)letin_section_optoptionalsection_optaddr=matchsection_optwith|None->false|Somesection->in_sectionoptionalsectionaddrletfind_section_by_addroptionalsectionsaddr=find_sectionsections(funs->in_sectionoptionalsaddr)(* Symbol header *)typesymbol={symbol_name:string;value:Virtual_address.t;section_number:u16;storage_class:u8;number_of_aux_symbols:u8;}letread_symbol_nametstrtabstrsize=letposition=get_postinletname=ifRead.i32t=0lthen(letn=Uint32.to_int(Read.u32t)inset_post(strtab+n);Read.zero_string"Unterminated symbol name"t~maxlen:(strsize-n)())else(set_postposition;Read.fixed_stringt8)inset_post(position+8);nameletread_symboltfilestrtabstrsizen=set_post(file.pointer_to_symbol_table+(n*18));ensuret18"Symbol header truncated";letsymbol_name=read_symbol_nametstrtabstrsizeinletvalue=Virtual_address.of_uint32(Read.u32t)inletsection_number=Read.u16tinletstorage_class=Read.u8tinletnumber_of_aux_symbols=Read.u8tin{symbol_name;value;section_number;storage_class;number_of_aux_symbols}letread_symbolstfile=letstrtab=file.pointer_to_symbol_table+(18*file.number_of_symbols)inletstrsize=set_poststrtab;Uint32.to_int(Read.u32t)inset_postfile.pointer_to_symbol_table;Array.initfile.number_of_symbols(read_symboltfilestrtabstrsize)moduleSection=structtypet=optional_header*sectiontypeheader=sectionletname(_,s)=s.section_nameletflag((_,s):t)=Uint32.to_int32s.characteristicsletpos(o,(s:section))={raw=s.pointer_to_raw_data;virt=rebaseos.virtual_address}letsize(_,s)={raw=s.size_of_raw_data;virt=Uint32.to_bigints.virtual_size}letheader(_,s)=slethas_flagfs=letmask=matchfwith|Write->0x80000000l|Read->0x40000000l|Exec->0x20000000linInt32.logand(flags)mask=maskendmoduleSymbol=structtypet=symboltypeheader=symbolletnames=s.symbol_nameletvalues=s.valueletheaders=sendletpp_symbolppfsymbol=Format.fprintfppf"@[<h>%s %s@]"(Z.format"%-8x"(Virtual_address.to_bigint(Symbol.valuesymbol)))(Symbol.namesymbol)letpp_symbolsppfsymbols=letnsymbols=Array.lengthsymbolsinifnsymbols<>0thenFormat.fprintfppf"@[<v 2># Symbols (%d) @ %a@]"nsymbols(funppfa->Array.iter(funsy->Format.fprintfppf"%a@ "pp_symbolsy)a)symbolsletpp_sectionippfsection=letauxfmtsection(f,s)=Format.fprintffmt"%s"(ifSection.has_flagfsectionthenselse"-")inletpp_flagsfmtsection=List.iter(auxfmtsection)Loader_types.[(Read,"r");(Write,"w");(Exec,"x")]inletpp_imapppfm=Format.fprintfppf"@[<h>%8x %s@]"m.Loader_types.raw(Z.format"%8x"m.Loader_types.virt)inletpos=Section.possectioninFormat.fprintfppf"@[<h>%2d %-20s %8lx %8x %s %a %a@]"i(Section.namesection)(Section.flagsection)pos.raw(Z.format"%8x"(Virtual_address.to_bigintpos.virt))pp_imap(Section.sizesection)pp_flagssectionletpp_sectionsppfsections=letnsections=Array.lengthsectionsinifnsections<>0thenFormat.fprintfppf"@[<v 2># Sections (%d)@ %a@]"nsections(funppfa->Array.iteri(funisy->Format.fprintfppf"%a@ "(pp_sectioni)sy)a)sectionsletpp_archppfarch=Format.fprintfppf"@[Machine: %a@]"Machine.pparchletpp_epppfep=Format.fprintfppf"@[Entry point address: %a@]"Virtual_address.ppepmoduleImg=structtypet=program*sectionarray*symbolarray*buffertypeheader=programletarch((f,_),_,_,_)=arch(Uint16.to_intf.machine)letentry((_,o),_,_,_)=rebaseoo.standard_fields.address_of_entry_pointletsections((_,o),s,_,_)=Array.map(funs->(o,s))sletsymbols(_,_,s,_)=Array.copysletheader(h,_,_,_)=hletcursor?at(_,_,_,b)=Reader.of_bigarray?pos:atbletcontent(_,_,_,b)(_,s)=Bigarray.Array1.subbs.pointer_to_raw_datas.size_of_raw_dataletbuffer(_,_,_,b)=bletpp_headerppfimg=Format.fprintfppf"@[<v 2># Header@ %a@ %a@]"pp_arch(archimg)pp_ep(entryimg)letppppfimg=Format.fprintfppf"@[<v 0>%a@ %a@ %a@]"pp_headerimgpp_symbols(symbolsimg)pp_sections(sectionsimg)endletloadbuffer=lett=init_cursorbufferinletfile_header=read_file_headertinletposition=get_postinletoptional_header=read_optional_headertinletsections=read_sectionstfile_headerpositioninletsymbols=read_symbolstfile_headerin((file_header,optional_header),sections,symbols,buffer)letload_file_descrfile_descr=letbuffer=Bigarray.(array1_of_genarray(Unix.map_filefile_descrInt8_unsignedC_layoutfalse[|-1|]))inloadbufferletload_filepath=letfile_descr=Unix.openfilepath[Unix.O_RDONLY]0inletimg=load_file_descrfile_descrinUnix.closefile_descr;imgletread_offset(_,_,_,b)offset=Int.unsafe_to_uint8b.{offset}letcache=refNoneletfind_section_by_addr_with_cacheoptionalsectionsaddr=ifnot(in_section_optoptional!cacheaddr)thencache:=find_section_by_addroptionalsectionsaddr;!cacheletread_address((_,o),s,_,b)addr=matchfind_section_by_addr_with_cacheosaddrwith|None->letmsg=Format.asprintf"Unreachable virtual address %a"Virtual_address.ppaddrininvalid_argmsg|Some(s:section)->letoffset=Virtual_address.diffaddr(rebaseos.virtual_address)inifoffset>=s.size_of_raw_datathenInt.unsafe_to_uint80elseInt.unsafe_to_uint8b.{offset+s.pointer_to_raw_data}