1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
"""Re-apply reversed symbols, prototypes, comments, segment splits and struct
types to a fresh IDA database of an AMD PSP module.
Usage (inside IDA, or via idat -A -S):
File > Script file... > import_symbols.py (auto-detects the module)
or headless:
idat64 -A -Simport_symbols.py <module>.elf
Auto-detects which symbol JSON to load from the root filename (sos2.elf ->
symbols/sos.json, sys_drv2.elf -> symbols/sys_drv.json, etc.). The JSON files sit
in ./symbols/ next to this script.
What it applies, in order:
1. local struct/enum types (parse C declarations)
2. segment names + permissions (CODE read-only so Hex-Rays folds literal pools)
3. function names + prototypes + function comments
4. data names
5. line comments (regular + repeatable)
Idempotent and safe to re-run. Reports counts and any items it could not apply.
"""
import os, json
import idaapi, idc, idautils, ida_funcs, ida_name, ida_segment, ida_nalt, ida_typeinf, ida_bytes
SN = ida_name.SN_FORCE | ida_name.SN_NOWARN | ida_name.SN_NOCHECK
MODULE_MAP = {
"sos2.elf": "sos.json", "sos.elf": "sos.json",
"sys_drv2.elf": "sys_drv.json", "sys_drv.elf": "sys_drv.json",
"asd2.elf": "asd.json", "asd.elf": "asd.json",
"hdcp2.elf": "hdcp.json", "hdcp.elf": "hdcp.json",
"dtm2.elf": "dtm.json", "dtm.elf": "dtm.json",
"ras2.elf": "ras.json", "ras.elf": "ras.json",
}
def _here():
try:
return os.path.dirname(os.path.abspath(__file__))
except NameError:
return os.path.dirname(idc.get_idb_path())
def set_name_forced(ea, name):
# clear-then-set works around name collisions
idc.set_name(ea, "zzz_%X" % ea, SN)
return idc.set_name(ea, name, SN)
def main():
root = ida_nalt.get_root_filename() or ""
base = MODULE_MAP.get(root)
if base is None:
# fall back: try matching by prefix
for k, v in MODULE_MAP.items():
if root.startswith(k.split(".")[0]):
base = v; break
if base is None:
print("[import] unknown module %r; edit MODULE_MAP" % root); return
path = os.path.join(_here(), "symbols", base)
if not os.path.exists(path):
print("[import] symbol file not found: %s" % path); return
d = json.load(open(path))
print("[import] module=%s <- %s" % (root, base))
# 1. local types
nt = 0
til = ida_typeinf.get_idati()
for decl in d.get("local_types", []):
try:
if idc.parse_decls(decl, 0) == 0:
nt += 1
except Exception:
pass
print("[import] local types applied: %d/%d" % (nt, len(d.get("local_types", []))))
# 2. segments
ns = 0
for name, start, end, perm in d.get("segments", []):
sg = ida_segment.getseg(start)
if sg:
ida_segment.set_segm_name(sg, name)
sg.perm = perm
sg.update()
ns += 1
print("[import] segments set: %d" % ns)
# 3. functions: name + proto + comment
nf = npr = nfc = miss = 0
for hexea, e in d.get("functions", {}).items():
ea = int(hexea, 16)
if not ida_funcs.get_func(ea):
ida_funcs.add_func(ea)
if set_name_forced(ea, e["name"]):
nf += 1
else:
miss += 1
if e.get("proto"):
# get_type() omits the name; SetType needs a full declaration, so
# splice the function name in before the argument list.
p = e["proto"]; i = p.find("(")
decl = (p[:i] + " " + e["name"] + p[i:] + ";") if i >= 0 else p
if idc.SetType(ea, decl):
npr += 1
if e.get("cmt"):
idc.set_func_cmt(ea, e["cmt"], 1)
nfc += 1
print("[import] functions named: %d (proto %d, cmt %d, failed %d)" % (nf, npr, nfc, miss))
# 4. data names
nd = 0
for hexea, name in d.get("names", {}).items():
ea = int(hexea, 16)
if set_name_forced(ea, name):
nd += 1
print("[import] data names: %d" % nd)
# 5. line comments
nc = 0
for hexea, c in d.get("comments", {}).items():
ea = int(hexea, 16)
idc.set_cmt(ea, c, 0)
nc += 1
print("[import] line comments: %d" % nc)
print("[import] done.")
try:
idc.qexit(0) if idaapi.cvar.batch else None
except Exception:
pass
if __name__ == "__main__":
main()
|