12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* 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 LICENSE). *)(* *)(**************************************************************************)moduleLog=Tracelog.Make(structletcategory="Analyze"end)moduleLogInstruction=Tracelog.Make(structletcategory="Instruction"end)letin_bits=Units.In_bits.of_intopenCodexmoduleTypedC=Types.TypedCmoduleType_check_tree=Types.Type_check_treemoduleLogger=Codex_loggermoduleCreate()=structmoduleDba2CodexC=Dba2Codex.Create()let()=Log.trace(funp->p"Parsing types")@@fun()->letconf_file=Codex_options.TypeConfigurationFile.get()inifconf_file=""then()elseCodex.Types.Parse_ctypes.parse_file~infer_spec:falseconf_fileletresults_tbl=Hashtbl.create10000;;(*module Arch = Ks_arch.Make(RB)(Dba2Codex.Domain)*)moduleArch=X86_arch.Make(Dba2CodexC.Domain)openDba2CodexCmoduleDba2CState=Dba2CodexC.Make(Arch.Registers)openDba2CStatemoduleRecord_cfg=Record_cfg.Make(State)moduleSettings=Hooks.Make(Dba2CState.State)(Record_cfg)openSettingsmoduleAddr_tbl=Hooks.Addr_tblmoduleCfg=Cfg_analysis.CfgmoduleDhunk_regex=Dhunk_analysis.Dhunk_regexletret_special_address=(Z.of_string"0xfedcba98");;letret_addr=Virtual_address.of_bigintret_special_addressletexploration_result=refNone(** Utility functions. **)letfind_optf=trySome(f())withNot_found->NonemoduleDhunk_regex_hash=structtypet=Dhunk_regex.tletequal=Dhunk_regex.equallethash=Hashtbl.hashendmoduleDhunk_regex_tbl=Hashtbl.Make(Dhunk_regex_hash)letrecdo_regex~lociddhunkstate_tableregex=letopenFixpoint.RegexintrySome(Dhunk_regex_tbl.findstate_tableregex)withNot_found->matchregexwith|Empty|Epsilon->assertfalse|Append(_,r,(src,dst))->letstate=do_regex~lociddhunkstate_tablerinbeginmatchstatewith|None->None|Somestate->(* Codex_log.feedback "Here regexp %a" (State.dump_state ctx) state; *)Logger.result"edge from %d to %d"srcdst;letsrc_i=Dhunk.instdhunksrc|>Option.getinletlocid=Syntax_tree.Location_identifier.(DbaInstruction,Inside{locid;idx=src})inletnext=instrstate(src_i,locid)inifnext=[]thenLogger.result"No successor states.";next|>List.iter(function|(Dba2Codex.Jump_Innernext_id,next_state)->letr'=Dhunk_regex.appendr(src,next_id)inassert(not(Dhunk_regex_tbl.memstate_tabler'));Dhunk_regex_tbl.addstate_tabler'next_state|_->());(* if List.length next >= 1 then *)(* next |> List.iter (function *)(* | (Dba2Codex.Jump_Inner next_id, next_state) -> *)(* Logger.result "state diff at entry of successor %d:@ %a" next_id *)(* (fun fmt s -> State.dump_state_diff ctx fmt state s) next_state *)(* | (Dba2Codex.Jump_Outer addr, next_state) -> *)(* Logger.result "state diff at entry of successor %a:@ %a" *)(* Virtual_address.pp addr *)(* (fun fmt s -> State.dump_state_diff ctx fmt state s) next_state *)(* | (Dba2Codex.Jump_Dynamic, next_state) -> *)(* Logger.result "state diff at entry of dynamic successor:@ %a" *)(* (fun fmt s -> State.dump_state_diff ctx fmt state s) next_state *)(* ); *)begintrynext|>List.find(function|(Dba2Codex.Jump_Innerid,_)->id=dst|(Dba2Codex.Jump_Outer_,_)->false|(Dba2Codex.Jump_Dynamic,_)->false)|>(fun(_,state)->Somestate)withNot_found->Noneendend|AppendStar(_,r,body)->(* The code below only works for max. 32 iterations (including one
* after the star). Since we are not sure this will work for any other
* loop than in CLZ, we will crash anywhere else. *)assert(Virtual_address.to_int!Codex_logger.current_instr_addr=0x120005a8);letinit_state=do_regex~lociddhunkstate_tablerinbeginmatchinit_statewith|None->None|Someinit_state->Logger.warning"Unrolling in-dhunk star with max. 32 iterations...";letmax_iter=31inletrecloopentry_statei=ifi=max_iterthenentry_stateelsebeginLogger.result"Unrolling iteration %i..."i;letinner_table=Dhunk_regex_tbl.create17inDhunk_regex_tbl.addinner_tableDhunk_regex.epsilonentry_state;letexit_state=do_regex~lociddhunkinner_tablebodyinletf()=(* The back edge is no longer taken, meaning that the exit
* condition has been met. We take the last exit state as an {e
* approximation} of the state. *)Logger.result"Unrolling: back edge can no longer be taken. \
Returning entry state at this iteration.";entry_stateinmatchexit_statewith|None->f()|Somexwhenx.State.is_bottom->(* The back edge is no longer taken, meaning that the exit
* condition has been met. We take the last exit state as an {e
* approximation} of the state. *)Logger.result"Unrolling: back edge can no longer be taken. \
Returning entry state at this iteration.";entry_state|Someexit_state->loopexit_state(i+1)endinlets=loopinit_state0inLogger.result"Finished unrolling star.";Dhunk_regex_tbl.addstate_tableregexs;Somes(*
Logger.result "Analyzing star...";
let mu_ctx = Domain.mu_context_open ctx in
let mu_ctx' = Domain.mu_context_upcast mu_ctx in
let rec loop (entry_state : Dba2CState.State.t) i =
Logger.result "In-dhunk mu iteration %d..." i;
let inner_table = Dhunk_regex_tbl.create 17 in
Dhunk_regex_tbl.add inner_table Dhunk_regex.epsilon entry_state;
let exit_state =
match do_regex mu_ctx' dhunk inner_table body with
| None -> State.bottom ctx
| Some x -> x in
Logger.result "@[<v 2>fixpoint between:@,entry@ @[<hov 2>%a@]@,exit@ @[<hov 2>%a@]@]" (State.dump_state mu_ctx') entry_state (State.dump_state mu_ctx') exit_state;
let Domain.Result(included,in_tuple,deserialize) =
State.serialize ~widens:true mu_ctx' entry_state exit_state (true, Domain.empty_tuple) in
Logger.result "After serialize: included = %b" included;
let fp,out =
Domain.typed_fixpoint_step mu_ctx (included,in_tuple) in
Logger.result "After fixpoint_step: fp = %b" fp;
if fp then begin
let out_tuple = out ~close:true in
let out_state,_ = deserialize out_tuple in
Logger.result "fixpoint reached, result: %a" (State.dump_state ctx) out_state;
Some out_state
end
else begin
let out_tuple = out ~close:false in
let out_state,_ = deserialize out_tuple in
Logger.result "fixpoint not reached, result: %a" (State.dump_state mu_ctx') out_state;
loop out_state (i+1)
end
in
let state' = loop init_state 0 in
Logger.result "Finished analyzing star.";
begin match state' with
| Some s -> Dhunk_regex_tbl.add state_table regex s;
| None -> ()
end;
state'
*)end|Join(_,r1,r2)->Logger.result"In-dhunk join. Term 1...";letstate1=do_regex~lociddhunkstate_tabler1inLogger.result"[in-dhunk join] Term 2...";letstate2=do_regex~lociddhunkstate_tabler2inbeginmatchstate1,state2with|None,other->Logger.result"In-dhunk join with left branch (at least) never taken";other|other,None->Logger.result"In-dhunk join with right branch never taken";other|Somestate1,Somestate2->Logger.result"[in-dhunk join] nondet...";letnew_state=State.joinstate1state2inDhunk_regex_tbl.addstate_tableregexnew_state;Somenew_stateendletrecfilter_mapf=function|[]->[]|x::xs->beginmatchfxwith|Somey->y::filter_mapfxs|None->filter_mapfxsendlettransfer_dhunk~lociddhunkstate=letregexes=Dhunk_analysis.exit_regexesdhunkinletstate_table=Dhunk_regex_tbl.create17inDhunk_regex_tbl.addstate_tableDhunk_regex.epsilonstate;regexes|>List.map(fun(id,r,addr)->ifaddr<>None&&Virtual_address.equal(Option.getaddr)(Virtual_address.create0x120005ac)thenLogger.result"dhunk %a"Dhunk_regex.prettyr;matchdo_regex~lociddhunkstate_tablerwith|None->[]|Somestate->letlocid=Syntax_tree.Location_identifier.(DbaInstruction,Inside{locid;idx=id})inDhunk.instdhunkid|>Option.get|>funi->instrstate(i,locid))|>List.map(filter_map(functionDba2Codex.Jump_Outeraddr,state->Some(addr,state)|_->None))|>List.concat(* Cache to avoid the enormous cost of spawning a new process for the decoder
* all the time. *)letinstr_cache=Addr_tbl.create5000letdecode_instraddr=tryAddr_tbl.findinstr_cacheaddrwithNot_found->Logger.result"instruction cache miss";letinstr,_=Disasm_core.decodeaddrinAddr_tbl.addinstr_cacheaddrinstr;instrmoduleAddr_map:siginclude(Map.Swithtypekey=Virtual_address.t)valof_list:(key*'a)list->'atend=structincludeVirtual_address.Mapletof_listl=letfacc(addr,v)=addaddrvaccinList.fold_leftfemptylendletcheck_return_typestatertyp=(* Checks the expected return type against the value of register eax *)leteax=State.get~size:(32|>in_bits)state"eax"inmatchrtypwith|None|SomeTypedC.{descr=Void}->()|Sometypwhennotstate.is_bottom->Log.debug(funp->p"Checking that the return value in eax has the expected type.");letsize=TypedC.sizeoftyp|>Units.In_bytes.in_bitsinDomain.check_type~sizestate.ctxtypeax|>Type_check_tree.save|_->()lettransfer_instruction_nostubaddressstate=letinstr=decode_instraddressinletlocid=Syntax_tree.Location_identifier.(Address,Int64(Virtual_address.to_int64address))inletdhunk=instr.Instruction.dba_blockinLog.debug(funp->p"exploration_only : %b"!exploration_only);Logger.result"address: %a@ instruction: %a@\nblock: %a"Virtual_address.ppaddressMnemonic.ppinstr.Instruction.mnemonicDhunk.ppdhunk;LogInstruction.trace(funp->p"%a: %a"Virtual_address.ppaddressMnemonic.ppinstr.mnemonic)~loc:(Codex_options.Location.Instruction{locid;address=Virtual_address.to_int64address})~bintrace:(Syntax_tree.Location_identifier.(Address,Int64(Virtual_address.to_int64address)))(fun_->transfer_dhunk~lociddhunkstate|>Addr_map.of_list)lettransfer_instructionaddresstracestate=letwarn_skip()=Logger.alarmOperator.Alarm.Manual_stubinmatchSettings.find_hookaddresswith|(SkipTo(_skip_type,dest),msg)->warn_skip();Logger.result"Skipping to %a. Reason: %s"Virtual_address.ppdestmsg;trace,Addr_map.singletondeststate|(EndPath,msg)->warn_skip();Logger.result"@[<hov 2>Ending path. Reason: %s@]"msg;trace,Addr_map.empty|(Hookf,msg)->Logger.alarmOperator.Alarm.Manual_stub;warn_skip();Logger.result"@[<hov 2>Hook function. Reason: %s.@]"msg;lettrace,successors=ftracestateinLogger.result"@[<hov 2>Hook function executed. Successors: %a@]"(Format.pp_print_listVirtual_address.pp)(List.mapfstsuccessors);trace,Addr_map.of_listsuccessors|(Unrollnb_iter,_)->warn_skip();Logger.result"Ignoring unroll(%i) indication during exploration."nb_iter;trace,transfer_instruction_nostubaddressstate|(ChangeStatef,msg)->Logger.alarmOperator.Alarm.Manual_stub;Logger.result"Changing state before instruction. Reason: @[<hov 2>%s@]"msg;trace,transfer_instruction_nostubaddress@@fstate|(Returntyp,msg)->warn_skip();Logger.result"@[<hov 2>Reaching return instruction. Reason: %s@]"msg;check_return_typestatetyp;trace,Addr_map.empty|(EntryCall(name,ftyp),msg)->Logger.alarmOperator.Alarm.Manual_stub;Logger.result"Replacing by a hook for later function calls. Reason: @[<hov 2>%s@]"msg;Settings.add_function_hook~nameaddressftyp;trace,transfer_instruction_nostubaddressstate|exceptionNot_found->trace,transfer_instruction_nostubaddressstatelettransfer_from_to_generic~transfer_instruction~self~stop_predstart_addresstracestate=lettrace,successors=transfer_instructionstart_addresstracestatein(* Invariant: the keys of the mapping returned by [transfer_from_to] are in
* [end_addresses], and the values are the merge-over-all-paths final state
* for all paths from the start address. *)ifAddr_map.cardinalsuccessors=1thenletaddr,state=Addr_map.choosesuccessorsin(self~stop_predaddrtracestate:Record_cfg.t*State.tAddr_map.t)elsebeginLogger.result"forking paths";Record_cfg.start_forktrace;lettrace,final_states=Addr_map.fold(funaddrstate(trace,final)->Logger.result"New fork starting with %a"Virtual_address.ppaddr;Record_cfg.next_forktrace;lettrace,other_finals=self~stop_predaddrtracestateinLogger.result"End of fork starting with %a"Virtual_address.ppaddr;trace,Addr_map.union(fun_s1s2->Some(State.joins1s2))finalother_finals)successors(trace,Addr_map.empty)inRecord_cfg.end_forktrace;trace,final_statesendletrectransfer_from_to~stop_predstart_addresstracestate=let_,ctx_change=Record_cfg.(call_stack_after_jumptrace(current_positiontrace)start_address)inifstop_predstart_addressctx_changethentrace,Addr_map.singletonstart_addressstateelsebeginRecord_cfg.nexttrace~exploration_only:true~record_cfg:falsestart_address;transfer_from_to_generic~transfer_instruction~self:transfer_from_to~stop_predstart_addresstracestateend(* The first time, we avoid checking the hook, so that we do not loop
* indefinitely. We also do not call [Record_cfg.next] nor check the stop
* predicate, we assume this has already been done for this address (since this
* function is intended to be used as a hook). *)lettransfer_from_tostart_address~stop_predtracestate=lettransfaddrtracestate=trace,transfer_instruction_nostubaddrstateintransfer_from_to_generic~transfer_instruction:transf~self:transfer_from_to~stop_predstart_addresstracestate(** Like [analyze_address] but does not call [next] on the first, and thus will
not stop if [address] was already visited. *)letrecanalyze_address_nocheckstatetraceaddress=letwarn_skip()=Logger.error"Manual skip at %a!"Virtual_address.ppaddressinletsuccessors=matchSettings.find_hookaddresswith|(SkipTo(skip_type,dest),msg)->if!exploration_only&&skip_type=NotWhenInterpretingthenbegin(* Ignore skips when in "concrete interpreter" *)Logger.result"ignoring skip in concrete execution mode.";NoneendelsebeginLogger.alarmOperator.Alarm.Manual_stub;warn_skip();Logger.result"Skipping to %a. Reason: %s"Virtual_address.ppdestmsg;Some[(dest,state)]end|(EndPath,msg)->warn_skip();Logger.result"@[<hov 2>Ending path. Reason: %s@]"msg;Some[]|(Hookf,msg)->Logger.alarmOperator.Alarm.Manual_stub;warn_skip();Logger.result"@[<hov 2>Hook function. Reason: %s.@]"msg;let_,successors=ftracestateinLogger.result"@[<hov 2>Hook function executed. Successors: %a@]"(Format.pp_print_listVirtual_address.pp)(List.mapfstsuccessors);Somesuccessors|(Unrollnb_iter,_)->warn_skip();Logger.result"Ignoring unroll(%i) indication during exploration."nb_iter;None|(ChangeState_,_)->Logger.alarmOperator.Alarm.Manual_stub;(* Handled lower in this function *)None|(Returntyp,msg)->warn_skip();check_return_typestatetyp;Logger.result"@[<hov 2>Reaching return instruction. Reason: %s@]"msg;Some[]|(EntryCall(name,ftyp),msg)->Logger.alarmOperator.Alarm.Manual_stub;Settings.add_function_hook~nameaddressftyp;None|exceptionNot_found->Noneinletf(address,new_state)=Logger.result"Changes after block: @[<v>%a@]"(funfmt->State.dump_state_difffmtstatenew_stateaddress)results_tbl;(analyze_address[@tailcall])new_statetraceaddressin(* Optimisation to use tail calls when possible. As forks as rare,
this reduces the amount of stack space used. *)matchsuccessorswith|Some[]->Logger.result"Warning: ending path";if!exploration_only&&Virtual_address.equaladdresskernel_exit_pointthenbeginLogger.result"Setting exploration_result at address %a"Virtual_address.ppaddress;exploration_result:=Somestateend|Some[x]->(f[@tailcall])x(* Uncomment this to keep only the first trace. *)(* | l -> f (List.hd l) *)|Somesuccs->(Logger.result"Warning: forking paths";Record_cfg.start_forktrace;List.iteri(funix->Logger.result"New path %d"i;ifi!=0thenRecord_cfg.next_forktrace;fx;Logger.result"Done path %d"i;)succs;Record_cfg.end_forktrace;)|None->beginletnew_state=matchSettings.find_hookaddresswith|(ChangeStatef,msg)->warn_skip();Logger.result"@[<hov 2>Manual state modification. Reason: %s@]"msg;letnew_state=fstateinLogger.result"@[<hov 2>Modification function executed. Executing \
instruction normally now.@]";new_state|_->state|exceptionNot_found->statein(analyze_address'[@tailcall])new_statetraceaddressendandanalyze_addressstatetraceaddress=letvisited=begintryRecord_cfg.nexttrace~exploration_only:!exploration_only~record_cfg:trueaddress;falsewith|Record_cfg.Visited_vertex->(* stop evaluating this trace *)Logger.result"Visited vertex, ending path.";Logger.result"number of forks on the stack: %d"(Record_cfg.nb_forkstrace);trueendinifnotvisitedthen(analyze_address_nocheck[@tailcall])statetraceaddressandanalyze_address'statetraceaddress=letprevstate=stateinletres=transfer_instruction_nostubaddressstate|>Addr_map.bindingsinletf(address,state)=Codex_log.feedback"Changes after dhunk: @[<v>%a@]"(funfmt->State.dump_state_difffmtprevstatestateaddress)results_tbl;(* Codex_log.feedback "Changes after dhunk: @[<v>%a@]" (fun fmt -> State.dump_state ctx fmt) state; *)analyze_addressstatetraceaddressin(* Optimisation to use tail calls when possible. As forks as rare,
this reduces the amount of stack space used. *)matchreswith|[]->(Logger.result"Warning: ending path")|[x]->(f[@tailcall])x(* Uncomment this to keep only the first trace. *)(* | l -> f (List.hd l) *)|_->(Logger.result"Warning: forking paths";Record_cfg.start_forktrace;List.iteri(funix->Logger.result"New path %d"i;ifi!=0thenRecord_cfg.next_forktrace;fx;Logger.result"Done path %d"i;)res;Record_cfg.end_forktrace;)exceptionRecursive_callletrecdestinationrx=letopenFixpoint.Regexinmatchrxwith|Empty->raise@@Invalid_argument"destination"|Epsilon->raise@@Invalid_argument"destination"(* raise Recursive_call *)|Append(_,_,(_,dst))->dst|Join(_,r1,_)->destinationr1|AppendStar(_,_,body)->destinationbodymoduleRegex_tbl_0=Hashtbl.Make(Cfg_analysis.CfgRegex)moduleRegex_tbl=structincludeRegex_tbl_0letdebug_log=reffalseletfindctxtblkey=if!debug_logthenLogger.result"Regex_tbl.find @[<hov 2>%a@]"Cfg_analysis.CfgRegex.prettykey;letres=tryfindtblkeywithNot_found->Logger.warning"Regex_tbl.find: not found, returning Bottom";State.bottomctxinif!debug_logthenLogger.result"Regex_tbl.find returns @[<hov 2>%a@]%!"State.dump_state(Obj.magicres);resletlatest_state_table=Addr_tbl.create1000letaddtblkeyx=if!debug_logthenLogger.result"Regex_tbl.add @[<hov 2>%a@,%a@]%!"(Cfg_analysis.CfgRegex.pretty)keyState.dump_state(Obj.magicx);begintryAddr_tbl.replacelatest_state_table(fst@@destinationkey)xwithInvalid_argument_(* | Recursive_call *)->()end;addtblkeyxletlatest_stateaddress=Addr_tbl.findlatest_state_tableaddressendlethandle_successorssuccessorsstate_tablestatetracer'src=ignore(successors|>List.fold_left(funi(dst,state')->Logger.result"@[<v>changes at entry of successor %d (%a)@,%a@]"iVirtual_address.ppdst(funfmt->State.dump_state_difffmtstatestate'dst)results_tbl;(* Memoize the state at destination to save future computations. *)letdst_stack,_=Record_cfg.call_stack_after_jumptracesrcdstinletnew_r=Cfg_analysis.CfgRegex.appendr'(src,(dst,dst_stack))inifVirtual_address.to_int!Codex_logger.current_instr_addr=0x12000588thenRegex_tbl.debug_log:=true;Logger.result"debug_log = %b"!Regex_tbl.debug_log;Regex_tbl.addstate_tablenew_rstate';ifVirtual_address.to_int!Codex_logger.current_instr_addr=0x12000588thenRegex_tbl.debug_log:=false;(* If this jump adds a new edge to the graph, then we explore it but
* the exploration does not affect the returned state. *)ifnot(Cfg.mem_edge(Record_cfg.instruction_graphtrace)src(dst,dst_stack))thenbeginLogger.result"unvisited edge to %a !!"Virtual_address.ppdst;Record_cfg.set_positiontrace~keep_forks:falsesrc;analyze_addressstate'tracedst;i+1endelsei+1)0)(** Analyze a set of paths in the CFG (described by a regex) to possibly
discover new edges. When that happens, the new path set is explored
immediately, enriching the instruction graph by a depth-first search
without merge ([analyze_address]). If that happens, it means that the
fixpoint was not reached, and [analyze_regex] returns [false]. Otherwise,
if no new instruction is discovered, a fixpoint was reached and
[analyze_regex] returns [true].
{e Please note:} The instruction at the end of the path is not analyzed by
this function.
@param state_table A table associating a path expression of an instruction
to the {e entry state} of that expression. When analyzing a regex, all
intermediary regexes (i.e. expressions of subpaths) are updated in this
table.
*)letrecanalyze_regexstate_tablectxtracer=letopenFixpoint.RegexinletopenCfg_analysis.CfgRegexin(* We propagate two things along the regex: a boolean that tells whether the
* instruction graph has changed, and the state. Like with dhunk-level
* regexes, the state is memoized in a hash table. *)ifnot(Regex_tbl.memstate_tabler)thenmatchrwith|Empty->(* We cannot return a normal result, because if the input is, e.g.,
[Append (Empty, r)] we don't want [r] to be analysed. *)raise@@Invalid_argument"analyze_regex: empty regex"|Epsilon->(* Epsilon should always be in the state table before calling this
* function, so this is an error *)raise@@Invalid_argument"analyze_regex: epsilon not found in state table"|Append(_,r',(src,_))->analyze_regexstate_tablectxtracer';Codex_logger.current_instr_addr:=fstsrc;Logger.result"analyze_regex, case Append, src = %a"Cfg_analysis.V.prettysrc;letstate=Regex_tbl.findctxstate_tabler'in(*
if Virtual_address.to_int (fst src) = 0x106e70 || Virtual_address.to_int (fst src) == 0x106df0 then begin
let size = 32 in
let Some waiting_heap_s = Loader_utils.address_of_symbol_by_name ~name:"waiting_heap" (Kernel_functions.get_img ()) in
let heap_addr = Domain.Binary_Forward.biconst ~size (Z.of_int waiting_heap_s) ctx in
let heap_size = Domain.Memory_Forward.load ~size ctx state.State.memory heap_addr in
Logger.result "heap size: %a" (Domain.binary_pretty ~size ctx) heap_size;
end
else if Virtual_address.to_int (fst src) = 0x106fd0 || Virtual_address.to_int (fst src) == 0x107050 then begin
let size = 32 in
let Some ready_heap_s = Loader_utils.address_of_symbol_by_name ~name:"ready_heap" (Kernel_functions.get_img ()) in
let heap_addr = Domain.Binary_Forward.biconst ~size (Z.of_int ready_heap_s) ctx in
let heap_size = Domain.Memory_Forward.load ~size ctx state.State.memory heap_addr in
Logger.result "heap size: %a" (Domain.binary_pretty ~size ctx) heap_size;
end;
*)letwarn_skip()=Logger.error"Manual skip during r-analysis at %a!"Virtual_address.pp(fstsrc)inletexceptionDoes_not_applyinletinstr=decode_instr(fstsrc)inletlocid=Syntax_tree.Location_identifier.(Address,Int64(Virtual_address.to_int64(fstsrc)))inLogInstruction.trace(funp->p"%a: %a"Virtual_address.pp(fstsrc)Mnemonic.ppinstr.mnemonic)~loc:(Codex_options.Location.Instruction{locid;address=Virtual_address.to_int64(fstsrc)})~bintrace:(Syntax_tree.Location_identifier.(Address,Int64(Virtual_address.to_int64(fstsrc))))(* ~bintrace:(Binarytrace.Instruction {instr_str=Format.asprintf "%a" Mnemonic.pp instr.mnemonic; address=Virtual_address.to_int64 (fst src)}) *)(fun_->begintrymatchSettings.find_hook(fstsrc)with|(SkipTo(_,new_dst),msg)->Logger.alarmOperator.Alarm.Manual_stub;warn_skip();Logger.result"Skipping to %a. Reason: %s"Virtual_address.ppnew_dstmsg;(* Do not interpret the skipped instruction. Instead, set the entry
* state of the skip destination to the entry state of the skipped
* instruction. *)Regex_tbl.addstate_tablerstate|(Hookf,msg)->Logger.alarmOperator.Alarm.Manual_stub;warn_skip();(* Execute the hook function and record all the successors in the
* state table. We assume that the hook function is sound, and
* therefore that all edges going from {src} in the current CFG will
* appear in its result. If this assumption is false, a {Not_found}
* exception is bound to be raised during some recursive call of
* {analyze_regex}. *)Logger.result"@[<hov 2>Hook function. Reason: %s.@]"msg;Record_cfg.set_positiontrace~keep_forks:falsesrc;let_,successors=ftracestateinLogger.result"Hook function executed.";handle_successorssuccessorsstate_tablestatetracer'src|(EndPath,_)->(* Don't interpret this instruction and don't add it to the regex ->
* state mapping. *)()|(Unroll_,_)->Logger.alarmOperator.Alarm.Manual_stub;(* Do nothing special: unrolling is managed by the {AppendStar}
* case. *)raiseDoes_not_apply|(ChangeState_,_)->(* This is handled elsewhere *)raiseDoes_not_apply|(Return_,_)->(* Don't interpret this instruction and don't add it to the regex ->
* state mapping. *)()|(EntryCall_,_)->(* Don't interpret this instruction and don't add it to the regex ->
* state mapping. *)()|exceptionNot_found->raiseDoes_not_applywithDoes_not_apply->letinstr=decode_instr(fstsrc)inletdhunk=instr.Instruction.dba_blockin(* Codex_log.debug "exploration_only : %b" !exploration_only ; *)Logger.result"@[<v>address: %a@,instruction: %a@,dhunk: @[<hov 2>%a@]@]"Virtual_address.pp(fstsrc)Mnemonic.ppinstr.Instruction.mnemonicDhunk.ppdhunk;letnew_state=matchSettings.find_hook(fstsrc)with|(ChangeStatef,msg)->Logger.alarmOperator.Alarm.Manual_stub;Logger.result"@[<hov 2>Manual state modification. Reason: %s@]"msg;letnew_state=fstateinLogger.result"@[<hov 2>Modification function executed. Executing \
instruction normally now.@]";new_state|_->state|exceptionNot_found->stateinletexits=transfer_dhunk~lociddhunknew_stateinhandle_successorsexitsstate_tablestatetracer'srcend)|AppendStar(_,r',x)->analyze_regexstate_tablectxtracer';letinit_state=Regex_tbl.findctxstate_tabler'inifinit_state.State.is_bottomthenRegex_tbl.addstate_tablerinit_stateelsebegin(* try *)lethead=destinationr'inbeginmatchfind_opt(fun()->Settings.find_hook(fsthead))with|Some(Unrollmax_iter,msg)->Logger.warning"Unrolling star... (reason: %s)"msg;letrecloopentry_statei=ifi=max_iterthenentry_stateelsebeginLogger.result"Unrolling iteration %i..."i;letinner_table=Regex_tbl.create100inRegex_tbl.addinner_tableepsilonentry_state;analyze_regexinner_tableentry_state.ctxtracex;letexit_state=Regex_tbl.findentry_state.ctxinner_tablexinifexit_state.State.is_bottomthenbegin(* The back edge is no longer taken, meaning that the exit
* condition has been met. We take the last exit state as an {e
* approximation} of the state. *)Logger.result"Unrolling %a: back edge can no longer be taken. \
Returning entry state at this iteration."Cfg.V.prettyhead;entry_stateendelseloopexit_state(i+1)endinletstate'=loopinit_state0inLogger.result"Finished unrolling star.";Regex_tbl.addstate_tablerstate'|_when!exploration_only->Logger.warning"Unrolling star... (concrete exec.)";letrecloopentry_statei=Logger.result"Unrolling iteration %i..."i;letinner_table=Regex_tbl.create100inRegex_tbl.addinner_tableepsilonentry_state;analyze_regexinner_tableentry_state.ctxtracex;letexit_state=Regex_tbl.findentry_state.ctxinner_tablexinifexit_state.State.is_bottomthenbegin(* The back edge is no longer taken, meaning that the exit
* condition has been met. We take the last exit state as an {e
* approximation} of the state. *)Logger.result"Unrolling %a: back edge can no longer be taken. \
Returning entry state at this iteration."Cfg.V.prettyhead;entry_stateendelseloopexit_state(i+1)inletstate'=loopinit_state0inLogger.result"Finished unrolling star.";Regex_tbl.addstate_tablerstate'|_->Logger.result"Analyzing star...";letmu_ctx'=Domain.mu_context_openinit_state.ctxin(* Way to go to use mu:
1. keep the initial state
2. in a loop, do:
1. keep the state at loop entry
2. analyze the regex under star
3. call [new_mu_context_fixpoint_step3] with the initial state, the
state before analysis and the state after analysis (actual, arg,
body)
4. if fixpoint was reached, call [close], else call [restart].
*)letrecloop(entry_state:Dba2CState.State.t)i=Logger.result"Mu iteration %d ..."i;letinner_table=Regex_tbl.create100inRegex_tbl.addinner_tableepsilonentry_state;analyze_regexinner_table(Domain.Context.copyentry_state.ctx)tracex;letexit_state=Regex_tbl.findentry_state.ctxinner_tablexinLogger.result"@[<v 2>fixpoint between:@,entry@ @[<hov 2>%a@]@,exit@ @[<hov 2>%a@]@]"State.dump_stateentry_stateState.dump_stateexit_state;letDomain.Context.Result(included,in_tuple,deserialize)=State.serialize~widens:trueentry_stateexit_state(true,Domain.Context.empty_tuple())inLogger.result"After serialize: included = %b%!"included;letfp,out=(*
if !exploration_only then
included, fun ~close:_ -> Domain.typed_nondet2 ctx in_tuple
else
*)Domain.typed_fixpoint_step~iteration:i~init:init_state.ctx~arg:entry_state.ctx~body:exit_state.ctx(included,in_tuple)inLogger.result"After fixpoint: fp = %b%!"fp;iffpthenbeginletout_tuple,outctx=out~close:trueinletout_state,_=deserializeoutctxout_tupleinletout_state={out_statewithctx=outctx}inLogger.result"fixpoint reached, result: %a"State.dump_stateout_state;out_stateendelsebeginletout_tuple,outctx=out~close:falseinletout_state,_=deserializeoutctxout_tupleinletout_state={out_statewithctx=outctx}inLogger.result"fixpoint not reached, result: %a%!"State.dump_stateout_state;loopout_state(i+1)endinletstate'=loop{init_statewithctx=mu_ctx'}0inLogger.result"Finished analyzing star.";Regex_tbl.addstate_tablerstate'end(* with Recursive_call ->
Codex_log.debug "Reaching recursive call" ;
Regex_tbl.add state_table r init_state *)end|Join(_,r1,r2)->Logger.result"JOIN";analyze_regexstate_tablectxtracer1;letstate1=Regex_tbl.findctxstate_tabler1inanalyze_regexstate_tablectxtracer2;letstate2=Regex_tbl.findctxstate_tabler2inletnew_state=State.joinstate1state2inRegex_tbl.addstate_tablernew_state(*********************************)(* [run] and auxiliary functions *)letfind_end_nodescfgentry=letrecauxvisitednode=letsucc=Cfg.succcfgnodeinifList.lengthsucc=0then[node]elseList.concat@@List.map(funn->ifList.memnvisitedthen[]elseaux(node::visited)n)succinaux[]entryletcatch_excoperation_namedefaultf=tryf()withe->Logger.error"%s%!"@@Printexc.get_backtrace();Logger.error"Raised during %s: %s"operation_name(Printexc.to_stringe);default();(*
let catch_exc _ _ f = f ()
*)moduleWto_cfg=Cfg_analysis.WtomoduleReduce_cfg=Cfg_analysis.ReducemoduleG'=structincludeCfgletvertex_namev=Format.asprintf"%a"Cfg.V.prettyvletgraph_attributes_=[]letedge_attributes_=[]letdefault_edge_attributes_=[]letvertex_attributes_=[]letdefault_vertex_attributes_=[]letget_subgraph_=NoneendmoduleOutputCfg=Graph.Graphviz.Dot(G')letsetup_entrypointimgstartinit_state=(* start_from entry_point *)letstart=Virtual_address.createstartinlettrace=Record_cfg.initimgstartinletstate_table=Regex_tbl.create10000inRegex_tbl.addstate_tableCfg_analysis.CfgRegex.epsiloninit_state;(start,trace,state_table)letanalyze_path_expressionstate_tableinit_statetraceinstr_graphnoderegex=letopenStateinanalyze_regexstate_tableinit_state.ctxtraceregex;(* If this instruction has no successors, then it was not analyzed by
* [analyze_regex]. Let's analyze it and its successors in a
* depth-first search. *)ifCfg.out_degreeinstr_graphnode=0thenbeginLogger.result"Analyze end node %a."Cfg.V.prettynode;Record_cfg.set_positiontrace~keep_forks:falsenode;(* The state we just computed *)letstate=Regex_tbl.findinit_state.ctxstate_tableregexinanalyze_address_nocheckstatetrace(fstnode)endletcompute_fixpointgraph_filenamehtml_filenameresultsimginit_statestarttracestate_table=letrecloopitrace=Logger.result"##### Iteration %i #####"i;letentry=start,[]inletinstr_graph=Record_cfg.instruction_graphtraceinletwto=Wto_cfg.partition~pref:(fun__->0)~init:entry~succs:(Cfg.succinstr_graph)inRecord_cfg.wto:=wto;Logger.result"%a\n"Wto_cfg.pretty_partitionwto;letpath_expressions=Reduce_cfg.compute_exprsinstr_graphwtoinLogger.result"%d expressions computed!\n"(Hashtbl.lengthpath_expressions);(* Regex analysis *)lettrace=Record_cfg.reusetraceinletanalyze_path_expression_closure=analyze_path_expressionstate_tableinit_statetraceinstr_graphinletclose_record_cfg=(fun()->Record_cfg.closetrace~ret_addrstart~graph_filename~html_filenameresultsimg)inletlogged_close_record_cfg=(funmsg->Logger.resultmsg;ignore@@close_record_cfg())inleterror_callback=(fun()->logged_close_record_cfg"exception raised, closing and dumping state...";true)inletwrapped_path_expressions_analysis=(fun()->Hashtbl.iteranalyze_path_expression_closurepath_expressions;false)inletexcept_thrown=catch_exc(Format.sprintf"r-analysis %i"i)error_callbackwrapped_path_expressions_analysisinif!exploration_onlythen(logged_close_record_cfg"exploration only: first iteration done";except_thrown)elseifexcept_thrownthen(Logger.result"Fixpoint not reached due to an exception.";true)elseifRecord_cfg.graph_changedtracethenbeginlogged_close_record_cfg"Fixpoint not reached.";Record_cfg.set_graph_changedtracefalse;loop(i+1)traceendelse(Logger.result"Fixpoint reached at iteration %i."i;false)inloop0traceletreport_graph_informationsgraph=(* Count nodes of the graph *)Logger.result"Nodes in the graph (with call stack): %d"(Cfg.nb_vertexgraph)letreport_instruction_informationsgraph=letinstr_tbl=Addr_tbl.create10000inCfg.iter_vertex(fun(addr,_)->Addr_tbl.replaceinstr_tbladdr())graph;Logger.result"Number of instructions (no call stack): %d"(Addr_tbl.lengthinstr_tbl)letreport_resultstrace=letgraph=Record_cfg.instruction_graphtraceinreport_graph_informationsgraph;report_instruction_informationsgraph;Logger.result"End of analyze log"letreturn_final_statetraceexpected_last_instr=letopenRegioninletopenVirtual_address.Setinletret=!written_data_addrs,!read_data_addrsinwritten_data_addrs:=empty;read_data_addrs:=empty;(* Return state at {expected_last_instr} *)matchexpected_last_instrwith|Someinstr->letfinal_state=Regex_tbl.latest_stateinstrinret,Somefinal_state,Record_cfg.visited_instructionstrace|None->ret,None,Record_cfg.visited_instructionstrace(* Do an analysis and returns the set of written data addresses, the set of
* read data addresses, and the state at {expected_last_instr} (or one of them,
* if it is present several times in the CFG). If {expected_last_instr} is not
* in the CFG, {Invalid_argument} is thrown. *)letanalyzeimgstartinit_stategraph_filenameexpected_last_instr(html_filename:stringoption)results=letstart,trace,state_table=setup_entrypointimgstartinit_stateinletexcept_thrown=compute_fixpointgraph_filenamehtml_filenameresultsimginit_statestarttracestate_tableinifnotexcept_thrownthenbeginLogger.result"Over ################################################################";report_resultstrace;return_final_statetraceexpected_last_instrendelseraise@@Failure"cannot return final state: exception occurred"letinterprete_concreteimgstartinit_stategraph_filenamehtml_filenameresults=letstart=Virtual_address.createstartinlettrace=Record_cfg.initimgstartinLogger.result"##### Concrete interpretation #####";letexcept_thrown=catch_exc"concrete analysis"(fun()->Logger.result"exception raised, closing and dumping state...";ignore@@Record_cfg.closetrace~ret_addrstart~graph_filename~html_filenameresultsimg;true)(fun()->analyze_addressinit_statetracestart;false)inifnotexcept_thrownthenbeginLogger.result"Over ################################################################";(* Count nodes of the graph *)letgraph=Record_cfg.instruction_graphtraceinLogger.result"Nodes in the graph (with call stack): %d"(Cfg.nb_vertexgraph);letinstr_tbl=Addr_tbl.create10000inCfg.iter_vertex(fun(addr,_)->Addr_tbl.replaceinstr_tbladdr())graph;Logger.result"Number of instructions (no call stack): %d"(Addr_tbl.lengthinstr_tbl);Logger.result"End of concrete interpretation";ignore@@Record_cfg.closetrace~ret_addrstart~graph_filename~html_filenameresultsimg;(* Return state at 0x12000730 *)letfinal_state=Option.get!exploration_resultinletopenRegioninletret=!written_data_addrs,!read_data_addrsinwritten_data_addrs:=Virtual_address.Set.empty;read_data_addrs:=Virtual_address.Set.empty;ret,Somefinal_state,Record_cfg.visited_instructionstraceendelseraise@@Failure"cannot return final state: exception occurred"letlist_initnf=letrecauxacci=ifi=nthenaccelseaux(fi::acc)(succi)inList.rev@@aux[]0letcpu_sp=list_init4(funi->ref@@Virtual_address.create@@0x1200e000+1024*i)moduleReadMem:Heap_typing.MEMORYwithtypet=Domain.Context.t*Dba2CState.State.t=structtypet=Domain.Context.t*Dba2CState.State.texceptionInvalid_readofstringletreadsize(ctx,state)addr=letb,_mem=Region.set_untyped_loadtrue;Domain.Memory_Forward.loadctx~sizestate.Dba2CState.State.memory@@Domain.Binary_Forward.biconst~size:(32|>in_bits)(Z.of_int@@Virtual_address.to_intaddr)ctxinRegion.set_untyped_loadfalse;matchDomain.Query.binaryctxb~size|>Domain.Query.Binary_Lattice.is_singleton~sizewith|Somex->Z.to_intx|None->raise@@Invalid_read(Format.asprintf"addr@ %a@ size@ %d"Virtual_address.ppaddr(size:>int))letread_u8=read(8|>in_bits)letread_u32=read(32|>in_bits)letread_u64=read(64|>in_bits)endmoduleHeap_typechecker=Heap_typing.Make(ReadMem)letadd_stack_argoffsettype_state=lets32=32|>in_bitsinletesp=State.get~size:s32state"esp"inletvalue=Domain.binary_unknown_typed~size:s32state.ctxtype_in{statewithmemory=Domain.(Memory_Forward.store~size:s32state.ctxstate.memoryBinary_Forward.(biadd~size:s32~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)state.ctxesp(biconst~size:s32(Z.of_intoffset)state.ctx))value)}letadd_stack_arg_valueoffsetvaluestate=lets32=32|>in_bitsinletesp=State.get~size:s32state"esp"in{statewithState.memory=Domain.(Memory_Forward.store~size:s32state.State.ctxstate.State.memoryBinary_Forward.(biadd~size:s32~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)state.ctxesp(biconst~size:s32(Z.of_intoffset)state.ctx))value)}letadd_stack_returnstate=lets32=32|>in_bitsinletesp=State.get~size:s32state"esp"inletconst=Domain.Binary_Forward.biconst~size:s32ret_special_addressstate.ctxin{statewithmemory=Domain.Memory_Forward.store~size:s32state.ctxstate.memoryespconst}letpopulate_stack_with_argstypesstate=(* Populate stack, leftmost argument at lowest offset, starting from offset 4
* (offset 0 is for the return address) *)let_,state=List.fold_left(fun(offset,state)typ->(offset+4,add_stack_argoffsettypstate))(4,state)typesinstateletpopulate_globals_with_typesspecstate=lets32=32|>in_bitsinList.fold_left(funstate(addr,typ)->letsize=TypedC.sizeoftyp|>Units.In_bytes.in_bitsinletvalue=Domain.binary_unknown_typed~sizestate.State.ctxtypinletaddr=(Domain.Binary_Forward.biconst~size:s32addrstate.State.ctx)in{statewithState.memory=Domain.Memory_Forward.store~sizestate.ctxstate.State.memoryaddrvalue})statespecletpopulate_globals_with_symbolsspecctx=Log.debug(funp->p"initiazing %d symbols"(List.lengthspec));List.iter(fun(symb,typ)->letsize=TypedC.sizeoftyp|>Units.In_bytes.in_bitsinletvalue=Domain.binary_unknown_typed~sizectxtypinDomain.add_global_symbol~sizectxsymbvalue)spec;;letpopulate_hookhook_directives=hook_directives|>List.iter(fun(addr,directive)->matchdirectivewith|`stop->Settings.add_stopaddr|`return_unknowntyp->Settings.add_return_unknownaddrtyp|`nop->(* Like a skip, but we compute the next address. *)let_,next=Disasm_core.decodeaddrinbeginmatchnextwith|None->assertfalse|Somenext->Settings.add_skipaddr~dest:nextend|`skip_to(dest)->Settings.add_skipaddr~dest|_->assertfalse);Settings.add_stop@@Virtual_address.of_bigintret_special_address;;letset_mmiommio_rangesstate=List.fold_left(funstate(addr,size)->letsize=size|>in_bitsinletvalue=Domain.binary_unknown~sizestate.State.ctxin{statewithState.memory=Domain.Memory_Forward.store~sizestate.ctxstate.memory(Domain.Binary_Forward.biconst(Z.of_intaddr)state.ctx~size:size)value})statemmio_rangesletfresh_int=letfresh_counter=ref(0:int)infun()->incrfresh_counter;!fresh_counterletfresh_symbol()=Format.sprintf"#f%d"(fresh_int())letrecinitial_function_args_ret_typesfuntypctx=letopenTypes.TypedCinmatch(inlinedfuntyp).descrwith|Function{ret;args}->args,ret|Existential{bound_typ;bound_var;body}->letsz=sizeofbound_typ|>Units.In_bytes.in_bitsinletres=Domain.binary_unknown_typed~size:szctxbound_typinletsymb=fresh_symbol()inDomain.add_global_symbol~size:szctxsymbres;letnewft=substitute_symbolbodybound_varsymbininitial_function_args_ret_typesnewftctx|_->assertfalse;;endletanalyze_non_kernel()=beginBinarytrace.init();ifCodex_options.Output_Html.is_set()thenTracelog.set_log_binary_tracetrue;(* Log.trace (fun p -> p "Analyze") @@ fun () -> *)(* Root of the analysis. *)lettinit=Sys.time()inlet()=Codex.Domains.Term_domain.set_pretty_terms(Codex_options.VariableDisplay.get())inletmoduleAnalyze=Create()inHook.run_hookHook.after_domain_build();letopenAnalyzeinletopenAnalyze.Dba2CodexCinletmoduleState=Dba2CState.Stateinlett_begin=Benchmark.make0Linletimg=Kernel_functions.get_img()inletctx=Domain.root_context()inlet()=(* Odvtk_Trace.log "Real deal"; *)letentry_name=(Kernel_options.Entry_point.get())inletentry=matchLoader_utils.address_of_symbol_by_name~name:entry_nameimgwith|None->Log.fatal(funp->p"Could not load entry symbol with name %s. Please ensure the -entrypoint option is correctly specified"entry_name)|Someentry->entryinlettprep=Sys.time()inletinit_state=Log.trace(funp->p"Initializing entry state")@@fun()->beginletinit_state=State.initial_concreteimgctxin(* let entry = unoption @@ Loader_utils.address_of_symbol_by_name ~name:(Kernel_options.Entry_point.get ()) img in *)(* let global_spec = Codex_options.GlobalSymbols.get () in
let () = populate_globals_with_symbols global_spec ctx in *)(* let arg_spec = Codex_options.FnArgs.get () in *)letinit_state=add_stack_returninit_stateinletinit_state=add_stack_returninit_stateinletfundef=Option.get@@TypedC.function_definition_of_nameentry_nameinletarg_spec,rtyp=initial_function_args_ret_typesfundef.funtypctxinletinit_state=populate_stack_with_argsarg_specinit_stateinletglobals_spec=Codex_options.GlobalsTypes.get()inletinit_state=populate_globals_with_typesglobals_specinit_stateinletmmio_list=Codex_options.MMIOs.get()inletinit_state=set_mmiommio_listinit_stateinlethook_directives=Codex_options.Hooks.get()in(* let () = Settings.add_entrycall ~name:entry_name (Virtual_address.create entry) funtyp in *)let()=populate_hookhook_directivesinlet()=Settings.add_return(Virtual_address.of_bigintret_special_address)(iffundef.inlinethenNoneelseSomertyp)ininit_stateendinlet_=Log.trace(funp->p"Analysing")(fun()->analyzeimgentryinit_state"cfg.dot"None(Codex_options.Output_Html.get_opt())results_tbl)inlettfinal=Sys.time()inFormat.printf"Preprocessing time : %fs\n"(tprep-.tinit);Format.printf"Analysis time : %fs\n"(tfinal-.tprep);()inlett_end=Benchmark.make0Linletmyprintfmt=Format.(eprintf(fmt^^"\n"))inmyprint"### Alarms ###";(* Odvtk_Trace.log "Alarms"; *)letalarms=Logger.alarm_record()inmyprint"%a"Logger.Alarm_record.(pretty~unique:true)alarms;myprint"Analysis time: %s"Benchmark.(to_string(subt_endt_begin));lettotal_alarms=Logger.Alarm_record.total_alarms~ignore:["manual_stub"]~unique:true~ignore_phase:[]alarmsinmyprint"@[<v>Total alarms: %d@.%!@]"total_alarms;Binarytrace.close();(match!Record_cfg.dump_html_funwith|Somef->f()|None->());iftotal_alarms<>0thenexit1end;;letinitialize_codex()=Codex_config.set_ptr_size(32|>in_bits);let()=(* Try to infer data model heuristically. *)letdata_model=matchBinsec.Kernel_options.Machine.bits()with|`x32->`ILP32|`x64->beginletimg=Kernel_functions.get_img()inmatchimgwith|Loader.PE_->`LLP64|Loader.ELFimg->`LP64|_->failwith"Cannot infer data model for this machin"end|_->failwith"Cannot analyze code with this bitwith yet"inTypes.Parse_ctypes.init~data_modelin(* Tracelog.set_verbosity_level `Debug ; *)Codex_log.register(moduleCodex_logger.Codex_logger);ifnot(Codex_options.UseShape.get())thenbeginFramac_ival.Ival.set_small_cardinal@@max8@@Codex_options.NbTasks.get();(* Codex_config.set_widen false; *)end;Codex_config.set_valid_absolute_addresses@@(Z.one,Z.of_int(1lsl30));(* Map binsec debug level verbosity to tracelog. We have two levels: 0, 1 and 2.*)(match(Codex_options.Debug_level.get(),Codex_options.Loglevel.get())with|x,_whenx>=2->Tracelog.set_verbosity_level`Debug|_,"debug"->Tracelog.set_verbosity_level`Debug|1,_->Tracelog.set_verbosity_level`Info|_->());Codex.Hook.(run_hookstartup());;letrun()=initialize_codex();analyze_non_kernel();;letrun_codex()=ifCodex_options.is_enabled()thenrun()