Skip to content

Commit 921247f

Browse files
1635321ghidra1
authored andcommitted
GP-2412: Improved support for Rust binaries
1 parent d686733 commit 921247f

33 files changed

+2621
-79
lines changed

Ghidra/Features/Base/certification.manifest

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ data/ExtensionPoint.manifest||GHIDRA||||END|
1818
data/GolangFunctionsThatDoNotReturn||GHIDRA||||END|
1919
data/MachOFunctionsThatDoNotReturn||GHIDRA||||END|
2020
data/PEFunctionsThatDoNotReturn||GHIDRA||||END|
21+
data/RustFunctionsThatDoNotReturn||GHIDRA||||END|
2122
data/base.file.extensions.icons.theme.properties||GHIDRA||||END|
2223
data/base.icons.theme.properties||GHIDRA||||END|
2324
data/base.listing.theme.properties||GHIDRA||||END|
@@ -91,6 +92,7 @@ data/typeinfo/golang/golang_1.18_anybit_any.gdt||GHIDRA||||END|
9192
data/typeinfo/golang/golang_1.19_anybit_any.gdt||GHIDRA||||END|
9293
data/typeinfo/golang/golang_1.20_anybit_any.gdt||GHIDRA||||END|
9394
data/typeinfo/mac_10.9/mac_osx.gdt||GHIDRA||||END|
95+
data/typeinfo/rust/rust-common.gdt||GHIDRA||||END|
9496
data/typeinfo/win32/msvcrt/clsids.txt||GHIDRA||reviewed||END|
9597
data/typeinfo/win32/msvcrt/guids.txt||GHIDRA||reviewed||END|
9698
data/typeinfo/win32/msvcrt/iids.txt||GHIDRA||||END|
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Rust function names which do not return
2+
# (names should not start with '_' since these are stripped during checking)
3+
ZN5alloc5alloc18handle_alloc_error17h*
4+
ZN5alloc5alloc18handle_alloc_error8rt_error17h*
5+
ZN5alloc7raw_vec17capacity_overflow17h*
6+
ZN3std5alloc8rust_oom17h*
7+
ZN3std10sys_common9backtrace26__rust_end_short_backtrace17h*
8+
ZN4core9panicking5panic17h*
9+
ZN4core9panicking18panic_bounds_check17h*
10+
ZN4core9panicking9panic_fmt17h*
11+
ZN5alloc5alloc18handle_alloc_error17h*
12+
ZN3std7process5abort17h*
13+
ZN3std3sys4unix14abort_internal17h*
14+
rust_start_panic
15+
rust_panic_cleanup
16+
rust_foreign_exception
17+
rust_drop_panic
18+
rust_begin_unwind
19+
rg_oom
20+
abort

Ghidra/Features/Base/data/noReturnFunctionConstraints.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<compiler id="golang">
44
<functionNamesFile>GolangFunctionsThatDoNotReturn</functionNamesFile>
55
</compiler>
6+
<compiler name="rustc">
7+
<functionNamesFile>RustFunctionsThatDoNotReturn</functionNamesFile>
8+
</compiler>
69
<functionNamesFile>ElfFunctionsThatDoNotReturn</functionNamesFile>
710
</executable_format>
811
<executable_format name="Mac OS X Mach-O">
@@ -15,6 +18,9 @@
1518
<compiler id="golang">
1619
<functionNamesFile>GolangFunctionsThatDoNotReturn</functionNamesFile>
1720
</compiler>
21+
<compiler name="rustc">
22+
<functionNamesFile>RustFunctionsThatDoNotReturn</functionNamesFile>
23+
</compiler>
1824
<functionNamesFile>PEFunctionsThatDoNotReturn</functionNamesFile>
1925
</executable_format>
2026
</noReturnFunctionConstraints>
Binary file not shown.

Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/NoReturnFunctionAnalyzer.java

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
package ghidra.app.plugin.core.analysis;
1717

1818
import java.io.*;
19-
import java.util.HashSet;
20-
import java.util.List;
21-
import java.util.Set;
19+
import java.util.*;
2220

2321
import generic.jar.ResourceFile;
2422
import ghidra.app.cmd.function.CreateFunctionCmd;
@@ -47,6 +45,7 @@ public class NoReturnFunctionAnalyzer extends AbstractAnalyzer {
4745
private boolean createBookmarksEnabled = OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED;
4846

4947
private Set<String> functionNames;
48+
private Set<String> wildcardFunctionNames;
5049

5150
public NoReturnFunctionAnalyzer() {
5251
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
@@ -91,67 +90,90 @@ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, M
9190
name = name.substring(startIndex);
9291
}
9392

94-
if (!functionNames.contains(name)) {
93+
// check for exact match
94+
if (functionNames.contains(name)) {
95+
makeNoReturnFunction(program, symbol, monitor, log);
9596
continue;
9697
}
9798

98-
// skip noreturn marking if its namespace is not global, library, or std
99-
// it prevents class methods (e.g. Menu::_exit()) incorrectly marked as noreturn
100-
Namespace parentNamespace = symbol.getParentNamespace();
101-
if (parentNamespace != null && !parentNamespace.isGlobal() && !parentNamespace.isLibrary()) {
102-
List<String> pathList = parentNamespace.getPathList(true);
103-
if (!(pathList.size() == 1 && pathList.get(0) == "std")) {
104-
continue;
99+
// if any wildcarded names, check for prefix match
100+
for (String functionName : wildcardFunctionNames) {
101+
if (name.startsWith(functionName)) {
102+
makeNoReturnFunction(program, symbol, monitor, log);
103+
break;
105104
}
106105
}
106+
}
107107

108-
// if this is an external entry place holder, create the function in the external entry location
109-
symbol = checkForAssociatedExternalSymbol(symbol);
110-
111-
if (symbol.isExternal()) {
112-
ExternalLocation externalLocation =
113-
program.getExternalManager().getExternalLocation(symbol);
114-
if (externalLocation != null) {
115-
Function functionAt = externalLocation.createFunction();
116-
//Msg.debug(this,
117-
// "Setting \"no return\" flag on external function " + symbol.getName(true));
118-
functionAt.setNoReturn(true);
119-
}
120-
continue;
108+
// now that all the functions are set, safe to disassemble
109+
// should not disassemble here, could be just a pointer, disassemble later
110+
return true;
111+
}
112+
113+
/**
114+
* Make the symbol into a non-returning function
115+
*
116+
* @param program program
117+
* @param symbol symbol for a function
118+
* @param monitor monitor
119+
* @param log log for errors
120+
*/
121+
private void makeNoReturnFunction(Program program, Symbol symbol, TaskMonitor monitor,
122+
MessageLog log) {
123+
// skip noreturn marking if its namespace is not global, library, or std
124+
// it prevents class methods (e.g. Menu::_exit()) incorrectly marked as noreturn
125+
Namespace parentNamespace = symbol.getParentNamespace();
126+
if (parentNamespace != null && !parentNamespace.isGlobal() &&
127+
!parentNamespace.isLibrary()) {
128+
List<String> pathList = parentNamespace.getPathList(true);
129+
if (!(pathList.size() == 1 && pathList.get(0) == "std")) {
130+
return;
121131
}
132+
}
122133

123-
Address address = symbol.getAddress();
124-
if (symbol.getSymbolType() == SymbolType.LABEL) {
125-
if (!SymbolType.FUNCTION.isValidParent(program, parentNamespace, address, false)) {
126-
continue; // skip if parent does not permit function creation
127-
}
128-
CreateFunctionCmd fCommand = new CreateFunctionCmd(address);
129-
fCommand.applyTo(program, monitor);
134+
// if this is an external entry place holder, create the function in the external entry location
135+
symbol = checkForAssociatedExternalSymbol(symbol);
136+
137+
if (symbol.isExternal()) {
138+
ExternalLocation externalLocation =
139+
program.getExternalManager().getExternalLocation(symbol);
140+
if (externalLocation != null) {
141+
Function functionAt = externalLocation.createFunction();
142+
//Msg.debug(this,
143+
// "Setting \"no return\" flag on external function " + symbol.getName(true));
144+
functionAt.setNoReturn(true);
130145
}
146+
return;
147+
}
131148

132-
Function functionAt = program.getFunctionManager().getFunctionAt(address);
133-
if (functionAt == null) {
134-
log.appendMsg("Failed to create \"no return\" function " + symbol.getName(true) +
135-
" at " + address);
136-
continue;
149+
Address address = symbol.getAddress();
150+
if (symbol.getSymbolType() == SymbolType.LABEL) {
151+
if (!SymbolType.FUNCTION.isValidParent(program, parentNamespace, address, false)) {
152+
return; // skip if parent does not permit function creation
137153
}
154+
CreateFunctionCmd fCommand = new CreateFunctionCmd(address);
155+
fCommand.applyTo(program, monitor);
156+
}
138157

139-
//Msg.debug(this, "Setting \"no return\" flag on function " + symbol.getName(true) +
140-
// " at " + address);
158+
Function functionAt = program.getFunctionManager().getFunctionAt(address);
159+
if (functionAt == null) {
160+
log.appendMsg("Failed to create \"no return\" function " + symbol.getName(true) +
161+
" at " + address);
162+
return;
163+
}
141164

142-
functionAt.setNoReturn(true);
165+
//Msg.debug(this, "Setting \"no return\" flag on function " + symbol.getName(true) +
166+
// " at " + address);
143167

144-
// disassembled later after all bad functions have been marked
168+
functionAt.setNoReturn(true);
145169

146-
if (createBookmarksEnabled) {
147-
program.getBookmarkManager().setBookmark(address, BookmarkType.ANALYSIS,
148-
"Non-Returning Function", "Non-Returning Function Identified");
149-
}
150-
}
170+
// disassembled later after all bad functions have been marked
151171

152-
// now that all the functions are set, safe to disassemble
153-
// should not disassemble here, could be just a pointer, disassemble later
154-
return true;
172+
if (createBookmarksEnabled) {
173+
program.getBookmarkManager()
174+
.setBookmark(address, BookmarkType.ANALYSIS, "Non-Returning Function",
175+
"Non-Returning Function Identified");
176+
}
155177
}
156178

157179
/**
@@ -192,6 +214,7 @@ private void loadFunctionNamesIfNeeded(Program program)
192214
}
193215

194216
functionNames = new HashSet<>();
217+
wildcardFunctionNames = new HashSet<>();
195218

196219
ResourceFile[] files = NonReturningFunctionNames.findDataFiles(program);
197220
for (ResourceFile file : files) {
@@ -217,7 +240,16 @@ private void loadFunctionNamesIfNeeded(Program program)
217240
"' specified in file: " + file.getAbsolutePath());
218241
line = line.substring(startIndex);
219242
}
220-
functionNames.add(line.trim());
243+
244+
String funcName = line.trim();
245+
if (funcName.endsWith("*")) {
246+
// if funcName has a wildcard at the end, put on wildcard list
247+
funcName = funcName.substring(0, funcName.length() - 1);
248+
wildcardFunctionNames.add(funcName);
249+
}
250+
else {
251+
functionNames.add(funcName);
252+
}
221253
}
222254
}
223255
finally {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* ###
2+
* IP: GHIDRA
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package ghidra.app.plugin.core.analysis.rust;
17+
18+
import ghidra.program.model.data.CategoryPath;
19+
20+
public class RustConstants {
21+
public static final CategoryPath RUST_CATEGORYPATH = new CategoryPath("/rust");
22+
public static final byte[] RUST_SIGNATURE_1 = "RUST_BACKTRACE".getBytes();
23+
public static final byte[] RUST_SIGNATURE_2 = "/rustc/".getBytes();
24+
public static final String RUST_EXTENSIONS_PATH = "/extensions/rust/";
25+
public static final String RUST_EXTENSIONS_UNIX = "unix";
26+
public static final String RUST_EXTENSIONS_WINDOWS = "windows";
27+
}

0 commit comments

Comments
 (0)