
    JjE              	         d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
mZmZmZ ddlmZ  ee      j#                         j$                  d   Zedz  Zd	d
dddddddZh dZi dej1                  d      dej1                  d      dej1                  d      dej1                  d      dej1                  d      dej1                  d      dej1                  d      d ej1                  d      d!ej1                  d"      d#ej1                  d$      d%ej1                  d&      d'ej1                  d(      d)ej1                  d*      d+ej1                  d,      d-ej1                  d,      d.ej1                  d,      d/ej1                  d0      d1ej1                  d2      iZdBd3ZdCd4ZdDd5ZdEd6ZdFd7ZdGd8ZdHd9Z dEd:Z!dId;Z"dJdKd<Z#dLd=Z$dLd>Z%edfdMd?Z&dNd@Z'e(dAk(  r e'        yy)OzHSummarize original EXE save-file path construction and loader API usage.    )annotationsN)Path)c_stringoffset_to_varead_sectionsva_to_offset)parse_imports   outzsavedat wildcard for slot scanz-SaveData fallback directory for wildcard scanzsavedat0 base for current slotz,SaveData fallback directory for current slotzsavedat0 base for explicit slotz-SaveData fallback directory for explicit slotzregistry SavePath value writerzregistry SavePath value reader)iH iH iH i$H iHH ihH ieJ ieJ >   ReadFilelstrcatAlstrcpyA	FindClose	WriteFileCloseHandleCreateFileARegCloseKeyRegOpenKeyExAFindFirstFileARegSetValueExARegQueryValueExAi3B 558bec83ec24535657i73B  6848b148006800b35500ff1500045a00iO3B 
a207b35500if3B 
e8d8320000i3B 
e817050000i4B ff151c045a00i04B i\4B ix4B ff1568045a00i4B 
a0da764500i4B 8a0ddb764500i4B 
a330de5900i8B 558bec83ec0c535657i9B ff15e8035a00i;9B i_9B i0B ff15f8035a00ifB ff1558035a00c                    d| dS )N0x08x )values    @/home/exedev/hwanse/tools/summarize_runtime_save_path_context.pyhex_var,   B   s    c{    c                V    | D ]$  }|d   }||d   z   }||cxk  r|k  sn |d   c S  y )Nrawraw_sizenamer)   )sectionsoffsetsectionstartends        r+   section_for_offsetr7   F   sE     #gj))F S 6?"	#
 r-   c                \    t        ||      }|t        t        |       d      | |||z    S )Nz is not in a loaded raw section)r   
ValueErrorr,   )exer2   vasizer3   s        r+   bytes_atr=   O   s;    (B'F~F2J<'FGHHv&&r-   c           	     B   g }t         j                         D ]  \  }}t        | ||t        |            }||k7  r8t	        t        |       d|j                          d|j                                |j                  t        |      |j                  d      d        |S )Nz: expected z, got  )vaHexbytes)EXPECTED_BYTESitemsr=   lenr9   r,   hexappend)r:   r2   rowsr;   expectedactuals         r+   verify_expected_bytesrJ   V   s    D&,,. EH#xS];Xr
|;x||~6FfVZZ\N[\\fRj6::c?CD	E
 Kr-   c                    t        j                  d|      }g }d}	 | j                  ||      }|dk  r	 |S t        ||      }t	        ||      }|$|"|j                  t        |      |d|dd       |dz   }^)N<Ir   r'   06x)r@   r4   fileOffsetHexr
   )structpackfindr   r7   rF   r,   )	r:   r2   r*   needlerefssearchhitr;   r4   s	            r+   find_dword_refsrV   `   s    [[u%FDF
hhvv&7 K (C($Xs3>g1KK#BZ&')#c^ q r-   c                    i }| j                  d      xs g D ]M  }|j                  dd      }|j                  d      xs g D ]!  }|j                  d      }|si |d|i||<   # O |S )Nimportsdll 	functionsr1   get)rX   rG   rY   dll_namefunctionr1   s         r+   import_lookupr`   v   s~    D{{9%+ ;775"%,2 	;H<<'D::%:T
	;; Kr-   c                   t        d |D              }| |d   |d   |d   z    }t        j                  d|      }g }d}	 |j                  ||      }|dk  r	 |S |d   |z   }	d}
|	}|dk\  r||dz
  | dk(  rd	}
|d   |z   dz
  }n|dk\  r||dz
  | d
k(  rd}
|d   |z   dz
  }t	        ||      }|j                  t        |      |
d       |dz   })Nc              3  2   K   | ]  }|d    dk(  s|  yw)r1   z.textNr)   ).0r4   s     r+   	<genexpr>ziat_uses.<locals>.<genexpr>   s     NG76?g3MN   r/   r0   rL   r   zraw-iat-immediate   s   call-indirects   %zjmp-indirect)r@   kindr
   )nextrO   rP   rQ   r   rF   r,   )r:   r2   iat_vatextr/   rR   rG   rT   rU   opcode_offsetrh   start_offsetstart_vas                r+   iat_usesro      s   NxNND
d5kDK$z*::
;C[[v&FDF
hhvv&7 K Uc)"$!8C!Gc*k9"D;,q0LAX#cAg,;!D;,q0L,7fX.=>q r-   c           
        g }t         j                         D ]r  \  }}t        ||      }|t        dt	        |       d      t        | |      }t        | ||      }|j                  t	        |      d|d||t        |      |d       t |S )Nzsave string z is not mappedr'   rM   )r@   rN   rk   meaningdirectRefCount
directRefs)	TARGET_STRING_VASrC   r   r9   r,   r   rV   rF   rD   )r:   r2   rG   r;   rq   r3   rk   rS   s           r+   save_path_stringsru      s    D(..0 
Gh+>|F2J<~FGGV$sHb1#%fS\!2""%d)"		

  Kr-   c           
     <   t        |      }g }t        t              D ]w  }|j                  |      }|st	        | ||d         }|D cg c]  }|d   dk(  s| }	}|j                  |d   |t        |d         t        |      t        |	      |	d       y |S c c}w )NiatVarh   rg   rY   )rY   r1   iatVaHexuseCount	callCount	callSites)r`   sortedINTERESTING_APISr]   ro   rF   r,   rD   )
r:   r2   rX   lookuprG   r1   itemusesuse
call_sitess
             r+   api_summaryr      s    7#FD'( 
zz$XtG}5%)LcS[O-KcL
LE{"4=1I _'		

  K Ms   BBc                j   t        |       }||nt        t        dz        }t        | |      }t	        | ||      }|D ci c]  }|d   |
 c}ddddddd	dd
ddddddg}ddddddddddddddddg}dddg d |D cg c]  }|d!   	 c}d"d#d$d%d&|d'}d(d)d*d+d,g d-d.}	d/t        d0 |D              t        d1 |D              t        d2 |D              |d3   |d4   t        |      |d5   d6d6d/d6d7}
|
||||	|t        fd8|D              t        fd9|d:   D              d;j                  d<i       j                  d=g       D ch c]  }|d>   	 c}v d?j                  d@i       j                  d=g       D ch c]  }|d>   	 c}v dAt        | |      dBdCdDdEdF	S c c}w c c}w c c}w c c}w )GNHwanse2.exer1   
0x00423404
0x004576d80x00000x0072)	callVaHextargetVaHexsaveOffsetHexsizeHex
0x00423430
0x004577500x0288
0x0042345c
0x0059db600x02fa0x0200zwildcard slot scan path
0x00423041
0x0048b0c0
0x0048b0e0
0x0055b420zFindFirstFileA at 0x004230ebzScheck whether any savedat?.dat exists under registry SavePath or SaveData\ fallback)r1   functionVaHexfilenameStringVaHexdirectoryStringVaHexoutputBufferVaHexapiEvidencepurposezexplicit slot path
0x00423319
0x0048b148
0x0048b168
0x0055b318z>lstrcpyA/lstrcatA build path; open helper called at 0x004233cfzKbuild SaveData\savedatN.dat for the slot argument and feed the loader/saver
0x004238eb
0x004233cf)
0x00423917
0x0042393b
0x0042395fr   
0x00423478
0x004234a3
0x004234b1
0x004234ba
0x0059de30)r   openHelperVaHexopenHelperCallVaHexcreateFileCallSitesreadFileCallSitescloseHandleCallVaHexselectorGroupLoadVaHexselectorSlotLoadVaHexselectedPointerStoreVaHexselectedPointerGlobalVaHex
readBlockszsavedat0.dat
0x00423337
0x0042334f   z"filename[7] = slot_argument + 0x31)zsavedat1.datzsavedat2.datzsavedat3.datz...zsavedat9.dat)
baseStringcopyBaseStringVaHexslotCharPatchVaHexslotCharOffsetformulaexpectedRuntimeNamesTc              3  2   K   | ]  }|d    dk(  sd  yw)rk   z	SaveData\r
   Nr)   rc   rows     r+   rd   z build_summary.<locals>.<genexpr>   s     +`#CKS_D_A+`re   c              3  J   K   | ]  }|d    j                  d      sd  yw)rk   savedatr
   N)
startswithr   s     r+   rd   z build_summary.<locals>.<genexpr>   s"     &aSs6{?U?UV_?`q&as   ##c              3  2   K   | ]  }|d    dk(  sd  yw)rk   SavePathr
   Nr)   r   s     r+   rd   z build_summary.<locals>.<genexpr>   s     *]3v;R\C\1*]re   r   r   r   F)staticSavePathKnownsaveDataDirectoryStringCountslotFilenameStringCountregistrySavePathStringCountloadRoutineVaHexr   readFileCallCountInLoaderselectorStoreVaHex"runtimeInputMenuReachabilityProvencapturedSelector20SavePresent'syntheticSelectorProbeRemainsDiagnosticpromotionAllowedc              3     K   | ]<  }|d    j                  di       j                  dg       D ch c]  }|d   	 c}v  > yc c}w w)r   r   r{   r@   Nr\   )rc   r   siteapi_by_names      r+   rd   z build_summary.<locals>.<genexpr>  sP      * K {z[]?^?b?bcnpr?s$ttT']$tt*$ts   -A
AA
c              3     K   | ]9  }|j                  d i       j                  dg       D ch c]  }|d   	 c}v  ; yc c}w w)r   r{   r@   Nr\   )rc   r;   r   r   s      r+   rd   z build_summary.<locals>.<genexpr>  sK      0 PR1S1W1WXceg1hitG}ii0is   *AAAr   
0x004230ebr   r{   r@   
0x004266fdr   )readFileHasLoaderCallscreateFileHasOpenHelperCallsfindFirstFileHasWildcardCallregistrySavePathReadPresentz2static-save-path-known-runtime-route-proof-missingzThe EXE has a concrete SaveData\savedatN.dat path builder and the selector loader reads three blocks before storing 0x0059de30, but no captured gameplay save or runtime input path currently proves selector 2:0 for map1_01a -> map2_02d.zA controlled diagnostic can place a backup-restored synthetic or captured savedatN.dat under SaveData and try to drive the original load menu, but a synthetic file must remain excluded from route promotion.)statusdetail	nextProbe)	summarystringsapispathBuildersslotFilenamePatchloader	apiChecksverifiedInstructionBytes
conclusion)
r   r	   ROOTru   r   sumrD   allr]   rJ   )r:   rX   r2   r   r   r   
read_callspath_buildersr   
slot_patchr   r   r   s               @r+   build_summaryr      sv   S!H ,g-}@T2UGX.GsHg.D/343v;#4K"<RZgop"<RZgop"<RZgopJ .)#/$0!-9m	
 ))#/$0!-[e	
M* &'+I:DE3c+.E ,".!-%1&2 F %+*7 gJ  $(++`+`(`#&&aG&a#a'**]*]']"?3!"34%(_$%@A.3).37!G %'&) *%* ' -0 0 !670 - -9*5//:JB*O*S*ST_ac*de$We-f+7*5//:Lb*Q*U*UVace*fg$Wg,h
 %:#x$HJJ
(
-# #{ 5> F^ fgs    F!F&	F+=F0c                   | d   }ddddddd| d   d    d	d
|d    d	d|d    d	d|d    d	d| d   d    d| d   d    dddddg}| d   D ],  }|j                  d|d    d|d    d|d    d|d    d 	       . |j                  g d!       | d"   D ]8  }|j                  d#|d$    d%|d&    d|d'    d|d(    d|d)    d|d*    d        : | d+   }|j                  dd,dd-|d.    d	d/|d0    d	d1|d2    d	d3|d4    d	d5d6j                  |d7          d	dd8dd9| d:   d&    d	d;| d:   d<    d=| d:   d>    d	d?| d:   d@    dA| d:   dB    d	ddCdDg       | d:   dE   D ],  }|j                  d|dF    d|dG    d|dH    d|dI    dJ	       . |j                  g dK       | dL   D ]z  }d6j                  dM |dN   d dO D              xs dP}t        |dN         dOkD  r|dQt        |dN         dOz
   dRz  }|j                  d|dS    dT|d$    d|dU    d|dV    d| d        | |j                  g dW       | dX   j	                         D ]  \  }}|j                  dY| dZ| d	        d[j                  |      j                         d[z   S )\Nr   z# Runtime Save Path ContextrZ   z0Original EXE save path and save-loader evidence.z## Conclusionz- status: `r   r   `z- static save path known: `r   z+- runtime input menu reachability proven: `r   z- promotion allowed: `r   z
- detail: r   z- next probe: r   z## Save Path Stringsz,| string VA | text | direct refs | meaning || --- | --- | ---: | --- |r   z| `r@   z` | `rk   z` | rr   z | rq   z |)rZ   z## Path BuildersrZ   zE| name | function | filename | directory | output buffer | evidence |z%| --- | --- | --- | --- | --- | --- |r   | r1   z | `r   r   r   r   r   r   z## Slot Filename Patchz- base string: `r   z	- copy: `r   z
- patch: `r   z- formula: `r   z- expected names: `z, r   z	## Loaderz- function: `r   z- open helper: `r   z` via `r   z- selected pointer store: `r   z` -> `r   z/| ReadFile call | target | save offset | size |z| --- | --- | --- | --- |r   r   r   r   r   z` |)rZ   z## API Call SitesrZ   z(| API | IAT | calls | first call sites |r   r   c              3  .   K   | ]  }d |d    d   yw)r   r@   Nr)   )rc   r   s     r+   rd   zmarkdown.<locals>.<genexpr>{  s     Q4Ad7m_A.Qs   r{      -z, ... (+)rY   !rx   rz   )rZ   z## API ChecksrZ   r   - z: `
)rF   extendjoinrD   rC   rstrip)r   slinesr   patchsiteskeyr*   s           r+   markdownr  -  sR   	A%
:


gl+H56a8
%a(=&>%?qA
5a8\6]5^^_`
 #5!6 7q9
W\*8456
.{;<=

6$#E& y! 
#g,uS[Mc:J6K5LCPST]P^O__ab	


 
LL	
 ~& 
VT#o"6!7uSAV=W<X Y*+,E#6I2J1K4PSTaPbOcceg	

 '(E	LL$u\2315345Q7345Q75+,A.!$))E2H,I"J!K1MGH-o>?qAwx01BCDGGT\L]^sLtKuuvw)'(*;<W*X)YY_`ghp`q  sO  aP  `Q  QR  S='#	
* x . 
#k"#5]);(<E#oBVAWW\]`aj]k\llop	


 
LL	
 v o		Q3{;KCR;PQQXUXs; 2%xC$4 5 :;1==Es3u:,aF}E#j/9J$sS^O_N``cdicjjlmn	o 
LL	
 k*002 ,
Ur#c%*+,99U""$t++r-   c           	     "   t        |       }g }d}|j                         D ]  }|j                  d      r,|j                  dt	        j
                  |dd         d       A|j                  d      rA|r|j                  d       d}|j                  dt	        j
                  |d	d         d
       |j                  d      r|j                  d      j                  d      D cg c]  }|j                          }}t        |d         dhk(  r|s|j                  d       d}|r	|d   dv rdnd|j                  ddj                  fd|D              z   dz          E|r|j                  d       d}|j                  d      r*|j                  dt	        j
                  |       d       |s|j                  dt	        j
                  |       d        |r|j                  d       ddj                  |      z   S c c}w )NFz# z<h1>rf   z</h1>z## z</tbody></table>z<h2>   z</h2>r   |r   r   z<table><tbody>T>   	string VAReadFile callAPIr1   thtdz<tr>rZ   c              3  \   K   | ]#  }d  dt        j                  |       d d % yw)<>z</N)htmlescape)rc   celltags     r+   rd   zhtml_page.<locals>.<genexpr>  s2     .gY]3%qT9J8K2cURS/T.gs   ),z</tr>r   z<p>z</p>a]  <!doctype html><meta charset="utf-8"><title>Runtime Save Path Context</title><style>body{font-family:system-ui,sans-serif;margin:24px;line-height:1.45}table{border-collapse:collapse;margin:12px 0;width:100%;font-size:13px}td,th{border:1px solid #bbb;padding:4px 6px;text-align:left;vertical-align:top}code{background:#f3f3f3;padding:1px 3px}</style>r   )
r  
splitlinesr   rF   r  r  stripsplitsetr   )r   md
body_linesin_tableliner  cellsr  s          @r+   	html_pager    s   	'	BJH =??4 T[[ab%:$;5AB??5!!!"45 T[[ab%:$;5AB??4 .2jjo.C.CC.HIdTZZ\IEI58}%!!"23E!H0]$]$cgCfrww.gaf.g'ggjqqr01H??4 DKK$5#6d;<DKK$5#6d;<5=6 ,-	;
 ))J
	 % Js   'Hc                    |j                  dd       |dz  }|j                  t        j                  | dd      dz   d	       ||j                  t	        |       d	       |S )
NT)parentsexist_okzruntime_save_path_context.jsonFrf   )ensure_asciiindentr   zutf-8)encoding)mkdir
write_textjsondumpsr  )r   out_dirhtml_outjson_outs       r+   write_outputsr*    sm    MM$M.99H

7q9D@   Ig.AOr-   c                    t        j                  t              } | j                  dt        t
        dz         | j                  dt        t               | j                  dt        d d       | j                         }|j                  j                         }t        |j                        }t        ||      }t        ||j                  |j                        }t        d	|        y )
N)descriptionz--exer   )typedefaultz	--out-dirz
--html-outz@Optional HTML mirror. Omit to keep the active surface JSON-only.)r-  r.  helpz#wrote runtime save path context -> )argparseArgumentParser__doc__add_argumentr   r   OUT
parse_argsr:   
read_bytesr	   r   r*  r'  r(  print)parserargsr:   rX   r   r)  s         r+   mainr:    s    $$9F
dD=4HI
$<
O	   D
((


CDHH%GC)GWdllDMMBH	/z
:;r-   __main__)r*   intreturnstr)r2   
list[dict]r3   r<  r=  z
str | None)
r:   rA   r2   r?  r;   r<  r<   r<  r=  rA   )r:   rA   r2   r?  r=  r?  )r:   rA   r2   r?  r*   r<  r=  r?  )rX   dictr=  zdict[str, dict])r:   rA   r2   r?  rj   r<  r=  r?  )r:   rA   r2   r?  rX   r@  r=  r?  )N)r:   rA   rX   zdict | Noner=  r@  )r   r@  r=  r>  )r   r@  r'  r   r(  zPath | Noner=  r   )r=  None))r2  
__future__r   r0  r  r%  rO   pathlibr   probe_exe_scene_tablesr   r   r   r   summarize_exe_importsr	   __file__resolver  r   r4  rt   r}   rA   fromhexrB   r,   r7   r=   rJ   rV   r`   ro   ru   r   r   r  r  r*  r:  __name__r)   r-   r+   <module>rJ     s[   N "      V V / H~''*
Ul 1?0>1?00	  23@A l+ l+	
 l+ n- n- n- n- l+ n- l+ 23 n- n-  n-!" n-#$ n-%,',2*,eP\,~(V 25d 	<$ zF r-   