Init
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Offline helper (runs HERE, stdlib-only): cluster vtable candidates.
|
||||
|
||||
A vtable = run of >=3 consecutive LE32 words in rodata, each pointing
|
||||
into the code sect. Output CSV is consumed by the Ghidra-side script.
|
||||
|
||||
Usage:
|
||||
python3 ghidra/gen_vtable_csv.py "Lofi-12XT_v1.5.205/.../Lofi-12 XT.bin" /tmp/vtables-1.5.205.csv
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools'))
|
||||
from lofi_image import parse_image, find_sect_by_role
|
||||
|
||||
|
||||
def main():
|
||||
image, out = sys.argv[1], sys.argv[2]
|
||||
d = open(image, 'rb').read()
|
||||
info = parse_image(d)
|
||||
code = find_sect_by_role(info, 'code')
|
||||
ro = find_sect_by_role(info, 'rodata')
|
||||
print("code sect%d %08X..%08X" % (code['index'], code['addr'], code['end']))
|
||||
print("rodata sect%d %08X..%08X" % (ro['index'], ro['addr'], ro['end']))
|
||||
|
||||
p = ro['payload']
|
||||
words = [struct.unpack('<I', p[i:i + 4])[0]
|
||||
for i in range(0, len(p) - 3, 4)]
|
||||
is_code_ptr = [code['addr'] <= w < code['end'] for w in words]
|
||||
|
||||
runs = []
|
||||
i = 0
|
||||
n = len(words)
|
||||
while i < n:
|
||||
if is_code_ptr[i]:
|
||||
j = i
|
||||
while j < n and is_code_ptr[j]:
|
||||
j += 1
|
||||
if j - i >= 3:
|
||||
runs.append((i * 4, j - i, words[i:j]))
|
||||
i = j
|
||||
else:
|
||||
i += 1
|
||||
|
||||
with open(out, 'w') as f:
|
||||
f.write("rodata_off,load_addr,nentries,entries\n")
|
||||
for off, cnt, ws in runs:
|
||||
f.write("%d,%08X,%d,%s\n"
|
||||
% (off, ro['addr'] + off, cnt,
|
||||
";".join("%08X" % w for w in ws)))
|
||||
to_code = sum(is_code_ptr)
|
||||
print("rodata LE words -> code: %d, vtable runs(>=3): %d -> %s"
|
||||
% (to_code, len(runs), out))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user