Skip to content

Commit 065ff30

Browse files
committed
Add script to demangle Microsoft style symbols
1 parent 8ef5bc6 commit 065ff30

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

ghidra_scripts/DemangleMore.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Attempts to more aggressively demangle any Microsoft-style mangled symbols.
2+
# DemanglerCmd is not used as it will filter by program format (e.g. Microsoft
3+
# Demangler will not be used if the executable format is not PE/COFF). Instead,
4+
# this script invokes the MicrosoftDemangler directly on any symbol prefixed by
5+
# `?`. Additionally, this script handles `@name@X` (fastcall) and `_name@X`
6+
# (stdcall) mangles.
7+
# @author: Matt Borgerson
8+
# @category: Symbol
9+
from ghidra.app.util.demangler import DemanglerOptions
10+
from ghidra.app.util.demangler.microsoft import MicrosoftDemangler
11+
from ghidra.program.model.symbol import SourceType
12+
import re
13+
14+
st = currentProgram.getSymbolTable()
15+
n = currentProgram.getNamespaceManager().getGlobalNamespace()
16+
17+
numDemangled = 0
18+
failures = []
19+
20+
for s in st.getSymbols(n):
21+
name = s.getName()
22+
addr = s.getAddress()
23+
24+
if name.startswith('?'):
25+
# Attempt using Microsoft demangler
26+
try:
27+
print('Demangling with Microsoft Demangler: %s' % name)
28+
demangled = MicrosoftDemangler().demangle(name, True)
29+
s.delete()
30+
demangled.applyTo(currentProgram, addr, DemanglerOptions(), monitor)
31+
except:
32+
print('Failed to demangle %s' % name)
33+
failures.append(name)
34+
35+
elif name.startswith('@') or name.startswith('_'):
36+
# Attempt decoding @func@0 (__fastcall) and _func@0 (__stdcall) style mangle
37+
# https://en.wikipedia.org/wiki/Name_mangling#Standardised_name_mangling_in_C++
38+
isFastcall, isStdcall = False, False
39+
realName, bytesInParams = '', 0
40+
41+
m = re.match('^@(\w+)@([0-9]+)$', name)
42+
if m is not None:
43+
isFastcall = True
44+
realName, bytesInParams = m.groups()
45+
else:
46+
m = re.match('^_(\w+)@([0-9]+)$', name)
47+
if m is not None:
48+
isStdcall = True
49+
realName, bytesInParams = m.groups()
50+
51+
if isFastcall or isStdcall:
52+
print('Demangling: %s' % name)
53+
bytesInParams = int(bytesInParams)
54+
55+
# Get or create the function
56+
s.delete()
57+
f = getFunctionAt(addr)
58+
if f is None:
59+
f = createFunction(addr, realName)
60+
61+
if f is None:
62+
print('Couldn\'t create function for %s' % realName)
63+
failures.append(name)
64+
else:
65+
f.setName(realName, SourceType.ANALYSIS)
66+
f.setComment(name)
67+
convention = '__fastcall' if isFastcall else '__stdcall'
68+
f.setCallingConvention(convention)
69+
else:
70+
continue
71+
72+
numDemangled += 1
73+
74+
print('Demangled %d names' % numDemangled)
75+
if len(failures) > 0:
76+
print('Failed to demangle (%d):' % len(failures))
77+
for n in sorted(failures):
78+
print('- %s' % n)

0 commit comments

Comments
 (0)