Skip to content

Commit 2a27dc6

Browse files
authored
Merge pull request #1869 from acemon33/main
Add ghidra Scripts
2 parents 7fe5d0a + 267283c commit 2a27dc6

File tree

3 files changed

+273
-10
lines changed

3 files changed

+273
-10
lines changed

tools/ghidra_scripts/OverlayReduxSymbols.java

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Exports symbols to PCSX-Redux's symbols map including Overlays filtering
2+
//@author Nicolas "Pixel" Noble
23
//@author acemon33
3-
//@category PSX
44

55
import ghidra.app.script.GhidraScript;
66
import ghidra.program.model.symbol.*;
@@ -15,12 +15,9 @@
1515
public class OverlayReduxSymbols extends GhidraScript {
1616

1717
public void run() throws Exception {
18-
MemoryBlock[] MemoryBlockList = state.getCurrentProgram().getMemory().getBlocks();
19-
List<String> choices = new ArrayList();
20-
for (int i = 0; i < MemoryBlockList.length; i++) { if (MemoryBlockList[i].isOverlay()) choices.add(MemoryBlockList[i].getName()); }
21-
List<String> filterList = askChoices("Title", "Message", choices);
22-
List<String> choiceList = new ArrayList();
23-
for (String e : choices) { choiceList.add(e + "::"); choiceList.add(e + "__"); }
18+
List<String> options = this.getMemoryBlockOptions();
19+
List<String> filterList = askChoices("Title", "Message", options);
20+
List<String> choiceList = this.getOptionList(options);
2421

2522
List<String> symbols = new ArrayList<String>();
2623
SymbolTable st = state.getCurrentProgram().getSymbolTable();
@@ -31,15 +28,28 @@ public void run() throws Exception {
3128
String name = sym.getName(true);
3229

3330
boolean hasFilter = true;
34-
for (String s : filterList) { if (add.toString().contains(s)) { hasFilter = false; break; } }
31+
for (String s : filterList) {
32+
if (add.toString().contains(s)) {
33+
hasFilter = false;
34+
break;
35+
}
36+
}
3537
if (hasFilter)
3638
{
3739
boolean isNext = false;
38-
for (String s : choiceList) { if (add.toString().contains(s)) { isNext = true; break; } }
39-
if (isNext) continue;
40+
for (String s : choiceList) {
41+
if (add.toString().contains(s)) {
42+
isNext = true;
43+
break;
44+
}
45+
}
46+
if (isNext)
47+
continue;
4048
}
4149

4250
symbols.add(String.format("%08x %s", add.getOffset(), name));
51+
// symbols.add(String.format("%s %s", add, name));
52+
// println(String.format("%s %s", add, name));
4353
}
4454

4555
HttpClient client = HttpClient.newHttpClient();
@@ -50,6 +60,26 @@ public void run() throws Exception {
5060

5161
client.send(request, HttpResponse.BodyHandlers.ofString());
5262

63+
// for (String address : symbols) println(address);
5364
println("size: " + symbols.size());
5465
}
66+
67+
private List<String> getMemoryBlockOptions() {
68+
MemoryBlock[] MemoryBlockList = state.getCurrentProgram().getMemory().getBlocks();
69+
List<String> options = new ArrayList();
70+
for (int i = 0; i < MemoryBlockList.length; i++) {
71+
if (MemoryBlockList[i].isOverlay())
72+
options.add(MemoryBlockList[i].getName());
73+
}
74+
return options;
75+
}
76+
77+
private List<String> getOptionList(List<String> options) {
78+
List<String> resultList = new ArrayList();
79+
for (String e : options) {
80+
resultList.add(e + "::");
81+
resultList.add(e + "__");
82+
}
83+
return resultList;
84+
}
5585
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Import selected Overlays from a specified folder
2+
//@author ThirstyWraith
3+
//@author acemon33
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.io.File;
8+
import java.io.ByteArrayInputStream;
9+
import java.io.FileInputStream;
10+
import java.awt.*;
11+
import javax.swing.*;
12+
import javax.swing.event.DocumentEvent;
13+
import javax.swing.event.DocumentListener;
14+
15+
import ghidra.app.script.GhidraScript;
16+
import ghidra.util.Msg;
17+
import ghidra.program.model.address.Address;
18+
import ghidra.program.model.mem.*;
19+
20+
21+
public class OverlaysImporter extends GhidraScript {
22+
23+
@Override
24+
protected void run() throws Exception {
25+
File selectedFolder = askDirectory("Select a Folder", "Choose a folder contained Overlays:");
26+
if (selectedFolder != null && selectedFolder.isDirectory()) {
27+
List<JCheckBox> checkBoxes = createFileCheckBoxes(selectedFolder);
28+
29+
JPanel panel = createPanel(checkBoxes);
30+
31+
JButton okButton = new JButton("OK");
32+
okButton.setEnabled(false);
33+
34+
JTextField addressField = setAddressFieldValidation(panel, okButton);
35+
36+
showDialog(panel, okButton, addressField, selectedFolder, checkBoxes);
37+
38+
println("finish");
39+
}
40+
}
41+
42+
private List<JCheckBox> createFileCheckBoxes(File selectedFolder) {
43+
File[] files = selectedFolder.listFiles();
44+
List<JCheckBox> checkBoxes = new ArrayList<>();
45+
for (File file : files) {
46+
if (file.isFile()) {
47+
JCheckBox checkBox = new JCheckBox(file.getName());
48+
checkBoxes.add(checkBox);
49+
}
50+
}
51+
return checkBoxes;
52+
}
53+
54+
private JPanel createPanel(List<JCheckBox> checkBoxes) {
55+
JPanel panel = new JPanel(new BorderLayout());
56+
57+
JCheckBox selectAllCheckBox = new JCheckBox("Select All");
58+
selectAllCheckBox.addItemListener(e -> {
59+
boolean isSelected = selectAllCheckBox.isSelected();
60+
for (JCheckBox checkBox : checkBoxes) {
61+
checkBox.setSelected(isSelected);
62+
}
63+
});
64+
panel.add(selectAllCheckBox, BorderLayout.NORTH);
65+
66+
JPanel checkBoxPanel = new JPanel(new GridLayout(0, 1));
67+
for (JCheckBox checkBox : checkBoxes) {
68+
checkBoxPanel.add(checkBox);
69+
}
70+
JScrollPane scrollPane = new JScrollPane(checkBoxPanel);
71+
panel.add(scrollPane, BorderLayout.CENTER);
72+
73+
JPanel addressPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
74+
JLabel addressLabel = new JLabel("Enter Address:");
75+
JTextField addressField = new JTextField(20);
76+
addressPanel.add(addressLabel);
77+
addressPanel.add(addressField);
78+
panel.add(addressPanel, BorderLayout.SOUTH);
79+
80+
return panel;
81+
}
82+
83+
private JTextField setAddressFieldValidation(JPanel panel, JButton okButton) {
84+
JTextField addressField = (JTextField) ((JPanel) panel.getComponent(2)).getComponent(1);
85+
addressField.getDocument().addDocumentListener(new DocumentListener() {
86+
@Override
87+
public void insertUpdate(DocumentEvent e) {
88+
validateAddress();
89+
}
90+
91+
@Override
92+
public void removeUpdate(DocumentEvent e) {
93+
validateAddress();
94+
}
95+
96+
@Override
97+
public void changedUpdate(DocumentEvent e) {
98+
validateAddress();
99+
}
100+
101+
private void validateAddress() {
102+
String addressText = addressField.getText().trim();
103+
try {
104+
Address address = currentProgram.getAddressFactory().getAddress(addressText);
105+
okButton.setEnabled(address != null && currentProgram.getMemory().contains(address));
106+
} catch (Exception ex) {
107+
okButton.setEnabled(false);
108+
}
109+
}
110+
});
111+
return addressField;
112+
}
113+
114+
private void showDialog(JPanel panel, JButton okButton, JTextField addressField, File selectedFolder, List<JCheckBox> checkBoxes) {
115+
Object[] options = { okButton, "Cancel" };
116+
JOptionPane optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, options, options[1]);
117+
JDialog dialog = optionPane.createDialog("Select Files and Enter Address");
118+
okButton.addActionListener(e -> {
119+
try {
120+
Address bassAddress = currentProgram.getAddressFactory().getAddress(addressField.getText().trim());
121+
Memory memory = currentProgram.getMemory();
122+
123+
for (JCheckBox checkBox : checkBoxes) {
124+
if (checkBox.isSelected()) {
125+
File file = new File(selectedFolder.getAbsolutePath() + "/" + checkBox.getText());
126+
String blockName = getBlockName(file.getName());
127+
128+
FileInputStream fileInputStream = new FileInputStream(file);
129+
byte[] fileData = new byte[(int) file.length()];
130+
fileInputStream.read(fileData);
131+
fileInputStream.close();
132+
133+
ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
134+
MemoryBlock block = memory.createInitializedBlock(blockName, bassAddress, inputStream, file.length(), monitor, true);
135+
block.setRead(true);
136+
block.setWrite(true);
137+
block.setExecute(true);
138+
println(String.format("Added %s as overlay block at %s", blockName, bassAddress));
139+
}
140+
}
141+
} catch (Exception ex) {
142+
println("Invalid address format: " + ex.getMessage());
143+
}
144+
dialog.dispose();
145+
});
146+
dialog.setVisible(true);
147+
}
148+
149+
private String getBlockName(String fileName) {
150+
int lastDotIndex = fileName.lastIndexOf('.');
151+
return lastDotIndex != -1 ? fileName.substring(0, lastDotIndex) : fileName;
152+
}
153+
154+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"""
2+
# Improved version of "export_to_redux.py" script by Nicolas
3+
# that supports overlays filtering with GUI component
4+
# Usage:
5+
# 1. Run the script.
6+
# 2. Paste the main function address.
7+
# 3. Select PCSX-Redux Folder.
8+
# 4. Select the overlays you need, the only selected overlays symbols will be exported.
9+
"""
10+
#@author Nicolas "Pixel" Noble
11+
#@author acemon33
12+
13+
import os
14+
from ghidra.program.model.data import DataType, Pointer, Structure
15+
16+
17+
selected_overlays = []
18+
memory_block_list = []
19+
filter_list = []
20+
21+
22+
def find_overlays():
23+
for mem in currentProgram.getMemory().getBlocks():
24+
if mem.isOverlay():
25+
memory_block_list.append(mem.getName())
26+
27+
28+
def filter_memory_block():
29+
for memory_block_name in selected_overlays:
30+
filter_list.append(memory_block_name + '::')
31+
32+
33+
def print_overlays():
34+
for i in range(0, len(memory_block_list)):
35+
print(i + 1, memory_block_list[i])
36+
37+
38+
main_address = int(str(askAddress("Enter the main Address", "Address")), 16)
39+
root_dir = askDirectory("Select PCSX-Redux Directory", "Select")
40+
fm = currentProgram.getFunctionManager()
41+
dtm = currentProgram.getDataTypeManager()
42+
43+
find_overlays()
44+
selected_overlays = askChoices("Title", "Message", memory_block_list);
45+
46+
filter_memory_block()
47+
print('main: ', hex(main_address))
48+
print('Selected Modules : ', selected_overlays)
49+
50+
filename = os.path.join(str(root_dir), 'redux_data_types.txt')
51+
with open(filename, 'w') as f:
52+
# @todo: enums, typedefs, etc.
53+
for data_type in dtm.getAllStructures():
54+
dt_info = data_type.getName() + ';'
55+
for component in data_type.getComponents():
56+
type_name = component.getDataType().getName()
57+
field_name = component.getFieldName()
58+
if field_name == None:
59+
field_name = 'None'
60+
field_length = str(component.getLength())
61+
dt_info += type_name + ',' + field_name + ',' + field_length + ';'
62+
f.write(dt_info + '\n')
63+
64+
filename = os.path.join(str(root_dir), 'redux_funcs.txt')
65+
with open(filename, 'w') as f:
66+
for func in fm.getFunctions(toAddr(main_address), True):
67+
entry_point = func.getEntryPoint().toString()
68+
in_overlay = entry_point.find('::')
69+
if (in_overlay == -1) or (entry_point[:in_overlay+2] in filter_list):
70+
num_addr = int(entry_point.split(':')[-1], 16)
71+
func_info = entry_point.split(':')[-1] + ';' + func.getName() + ';'
72+
for param in func.getParameters():
73+
data_type_name = param.getDataType().getName()
74+
if data_type_name.__contains__('undefined'):
75+
data_type_name = 'int'
76+
func_info += data_type_name + ',' + param.getName() + ',' + str(param.getLength()) + ';'
77+
f.write(func_info + '\n')
78+
79+
popup('Finish')

0 commit comments

Comments
 (0)