87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
def u16(data, off):
|
||
|
|
return data[off] | (data[off + 1] << 8)
|
||
|
|
|
||
|
|
|
||
|
|
def u32(data, off):
|
||
|
|
return u16(data, off) | (u16(data, off + 2) << 16)
|
||
|
|
|
||
|
|
|
||
|
|
def selector_to_segment_index(selector):
|
||
|
|
return ((selector - 0x1000) // 8) + 1
|
||
|
|
|
||
|
|
|
||
|
|
def get_segment_info(data, selector):
|
||
|
|
ne_off = u32(data, 0x3C)
|
||
|
|
seg_table_off = ne_off + u16(data, ne_off + 0x22)
|
||
|
|
align_shift = u16(data, ne_off + 0x32)
|
||
|
|
seg_index = selector_to_segment_index(selector)
|
||
|
|
seg_entry_off = seg_table_off + (seg_index - 1) * 8
|
||
|
|
sector = u16(data, seg_entry_off)
|
||
|
|
seg_len = u16(data, seg_entry_off + 2)
|
||
|
|
if seg_len == 0:
|
||
|
|
seg_len = 0x10000
|
||
|
|
flags = u16(data, seg_entry_off + 4)
|
||
|
|
seg_file_off = sector << align_shift
|
||
|
|
reloc_off = seg_file_off + seg_len
|
||
|
|
reloc_count = u16(data, reloc_off)
|
||
|
|
return {
|
||
|
|
'selector': selector,
|
||
|
|
'segment_index': seg_index,
|
||
|
|
'segment_file_off': seg_file_off,
|
||
|
|
'segment_len': seg_len,
|
||
|
|
'flags': flags,
|
||
|
|
'reloc_off': reloc_off,
|
||
|
|
'reloc_count': reloc_count,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def read_relocs(data, seg_info):
|
||
|
|
relocs = []
|
||
|
|
pos = seg_info['reloc_off'] + 2
|
||
|
|
for i in range(seg_info['reloc_count']):
|
||
|
|
relocs.append({
|
||
|
|
'index': i,
|
||
|
|
'record_off': pos,
|
||
|
|
'src_type': data[pos],
|
||
|
|
'flags': data[pos + 1],
|
||
|
|
'src_off': u16(data, pos + 2),
|
||
|
|
'b4': data[pos + 4],
|
||
|
|
'b5': data[pos + 5],
|
||
|
|
'target_off': u16(data, pos + 6),
|
||
|
|
'raw': data[pos:pos + 8],
|
||
|
|
})
|
||
|
|
pos += 8
|
||
|
|
return relocs
|
||
|
|
|
||
|
|
|
||
|
|
def dump_site(data, seg_info, site, size=16):
|
||
|
|
raw = seg_info['segment_file_off'] + site
|
||
|
|
print(f'site {seg_info["selector"]:04X}:{site:04X} -> file 0x{raw:X}: {data[raw:raw+size].hex(" ")}')
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
path = Path(r'd:\Ghidra\Crusader\REGRET.EXE')
|
||
|
|
data = path.read_bytes()
|
||
|
|
|
||
|
|
for selector in (0x1148, 0x13F8):
|
||
|
|
info = get_segment_info(data, selector)
|
||
|
|
print(f'selector 0x{selector:04X} -> segment index {info["segment_index"]}, file 0x{info["segment_file_off"]:X}, len 0x{info["segment_len"]:X}, reloc@0x{info["reloc_off"]:X}, count={info["reloc_count"]}')
|
||
|
|
relocs = read_relocs(data, info)
|
||
|
|
interesting = []
|
||
|
|
if selector == 0x1148:
|
||
|
|
interesting = [0x3678, 0x36C0, 0x3702, 0x3743]
|
||
|
|
else:
|
||
|
|
interesting = [0x10FA, 0x2040, 0x209F, 0x20B9]
|
||
|
|
for site in interesting:
|
||
|
|
dump_site(data, info, site, 24)
|
||
|
|
local_hits = [r for r in relocs if site <= r['src_off'] <= site + 0x80]
|
||
|
|
for r in local_hits[:20]:
|
||
|
|
print(f' reloc idx={r["index"]} rec@0x{r["record_off"]:X} src=0x{r["src_off"]:04X} bytes={r["raw"].hex(" ")}')
|
||
|
|
print('')
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|