Candidate release of source code.

This commit is contained in:
Dan
2019-03-26 13:45:32 -04:00
parent db81e6b3b0
commit 79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
@@ -0,0 +1,81 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//Test script to lay down known RTTI structures in a file with applied pdb symbols to test the 32 and 64 bit RTTI structures
//@author
//@category Test
//@keybinding
//@menupath
//@toolbar
import ghidra.app.script.GhidraScript;
import ghidra.app.util.datatype.microsoft.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException;
public class ApplyRTTITestScript extends GhidraScript {
@Override
protected void run() throws Exception {
SymbolTable symbolTable = currentProgram.getSymbolTable();
//Find RTTI0 using symbol names pdb put on - symbol contains text: Type_Descriptor
SymbolIterator symbolIterator = symbolTable.getSymbolIterator("*Type_Descriptor*", true);
RTTI0DataType dt0 = new RTTI0DataType();
createRTTIDataType(symbolIterator, dt0);
//Next find RTTI1 using symbol names pdb put on - symbol contains text: Base_Class_Descriptor
symbolIterator = symbolTable.getSymbolIterator("*Base_Class_Descriptor*", true);
RTTI1DataType dt1 = new RTTI1DataType();
createRTTIDataType(symbolIterator, dt1);
//Next find RTTI2 using symbol names pdb put on - symbol contains text: Base_Class_Array
symbolIterator = symbolTable.getSymbolIterator("*Base_Class_Array*", true);
RTTI2DataType dt2 = new RTTI2DataType();
createRTTIDataType(symbolIterator, dt2);
//Next find RTTI3 using symbol names pdb put on - symbol contains text: Class_Hierarchy_Descriptor
symbolIterator = symbolTable.getSymbolIterator("*Class_Hierarchy_Descriptor*", true);
RTTI3DataType dt3 = new RTTI3DataType();
createRTTIDataType(symbolIterator, dt3);
//Next find RTTI4 using symbol names pdb put on - symbol contains text: Complete_Object_Locator
symbolIterator = symbolTable.getSymbolIterator("*Complete_Object_Locator*", true);
RTTI4DataType dt4 = new RTTI4DataType();
createRTTIDataType(symbolIterator, dt4);
return;
}
private void createRTTIDataType(SymbolIterator symbolIterator, DataType dt)
throws CancelledException, Exception {
while (symbolIterator.hasNext()) {
monitor.checkCanceled();
Symbol sym = symbolIterator.next();
DataUtilities.createData(currentProgram, sym.getAddress(), dt, -1, false,
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
println("Created " + dt.getName() + " at " + sym.getAddress().toString());
}
}
}
@@ -0,0 +1,283 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Build ResultState for current function
// @category Experimental
import java.util.*;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.script.GhidraScript;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.state.*;
import ghidra.util.task.TaskMonitor;
@SuppressWarnings("all") // TODO remove this when we decide to support this script
public class BuildResultState extends GhidraScript {
private final Set<VarnodeOperation> computedStackAccess = new HashSet<>();
private final TreeMap<Address, Integer> stackElementSizes = new TreeMap<>();
private Integer stackStorageSpaceId;
@Override
public void run() throws Exception {
final Function func =
currentProgram.getFunctionManager().getFunctionContaining(currentAddress);
if (func == null) {
Msg.showError(this, null, "BuildResultState Error",
"Current location not contained within a function");
return;
}
final Listing listing = currentProgram.getListing();
final AddressFactory addrFactory = currentProgram.getAddressFactory();
final ReferenceManager refMgr = currentProgram.getReferenceManager();
ResultsState results = new ResultsState(func.getEntryPoint(), new FunctionAnalyzer() {
private AddressSpace stackSpace = currentProgram.getAddressFactory().getStackSpace();
@Override
public void dataReference(PcodeOp op, int instrOpIndex, Varnode storageVarnode,
RefType refType, TaskMonitor monitor) throws CancelledException {
// TODO Auto-generated method stub
Msg.info(this, "Data Ref: " + storageVarnode + " " + refType);
}
@Override
public void indirectDataReference(PcodeOp op, int instrOpIndex, Varnode offsetVarnode,
int size, int storageSpaceID, RefType refType, TaskMonitor monitor)
throws CancelledException {
// TODO Auto-generated method stub
}
@Override
public boolean resolvedFlow(PcodeOp op, int instrOpIndex, Address destAddr,
ContextState currentState, ResultsState results, TaskMonitor monitor)
throws CancelledException {
Address opAddr = op.getSeqnum().getTarget();
Instruction instr = currentProgram.getListing().getInstructionAt(opAddr);
boolean conditional = instr.getFlowType().isConditional();
FlowType refType;
switch (op.getOpcode()) {
case PcodeOp.CALL:
refType =
conditional ? RefType.CONDITIONAL_CALL : RefType.UNCONDITIONAL_CALL;
break;
case PcodeOp.CALLIND:
refType =
conditional ? RefType.CONDITIONAL_COMPUTED_CALL : RefType.COMPUTED_CALL;
break;
case PcodeOp.BRANCH:
refType =
conditional ? RefType.CONDITIONAL_JUMP : RefType.UNCONDITIONAL_JUMP;
break;
case PcodeOp.BRANCHIND:
refType =
conditional ? RefType.CONDITIONAL_COMPUTED_JUMP : RefType.COMPUTED_JUMP;
break;
default:
refType = RefType.FLOW;
}
instr.addOperandReference(instrOpIndex, destAddr, refType, SourceType.ANALYSIS);
Msg.info(this, "Flow Ref: " + destAddr);
return true;
}
@Override
public void stackReference(PcodeOp op, int instrOpIndex, int stackOffset, int size,
int storageSpaceID, RefType refType, TaskMonitor monitor)
throws CancelledException {
if (refType.isWrite()) {
stackElementSizes.put(stackSpace.getAddress(stackOffset), size);
stackStorageSpaceId = storageSpaceID;
}
// TODO: don't add stack variables/references for now
if (true) {
return;
}
if (instrOpIndex < 0) {
return;
}
Address fromAddr = op.getSeqnum().getTarget();
Instruction instr = listing.getInstructionAt(fromAddr);
if (instr == null) {
return;
}
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
RefType rt = refType;
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
if (ref != null) {
RefType existingRefType = ref.getReferenceType();
if (existingRefType == rt) {
return;
}
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
rt = RefType.READ_WRITE;
}
}
StackFrame stackFrame = func.getStackFrame();
if (stackFrame.getVariableContaining(stackOffset) == null) {
//long firstUseOffset = op.getSeqnum().getTarget().subtract(func.getEntryPoint());
try {
stackFrame.createVariable(null, stackOffset,
Undefined.getUndefinedDataType(size), SourceType.ANALYSIS);
// TODO: How can I tell when these stack variables are used as a pointer ?
}
catch (DuplicateNameException e) {
throw new AssertException(); // unexpected
}
catch (InvalidInputException e) {
Msg.error(this, "failed to create stack variable", e);
}
}
refMgr.addStackReference(fromAddr, instrOpIndex, stackOffset, rt,
SourceType.ANALYSIS);
}
@Override
public void stackReference(PcodeOp op, int instrOpIndex,
VarnodeOperation computedStackOffset, int size, int storageSpaceID,
RefType refType, TaskMonitor monitor) throws CancelledException {
if (refType.isWrite()) {
computedStackAccess.add(computedStackOffset);
stackStorageSpaceId = storageSpaceID;
}
}
@Override
public List<Address> unresolvedIndirectFlow(PcodeOp op, int instrOpIndex,
Varnode destination, ContextState currentState, ResultsState results,
TaskMonitor monitor) throws CancelledException {
// TODO Auto-generated method stub
return null;
}
}, currentProgram, true, monitor);
// ResultsState results = MySwitchAnalyzer.analyze(currentProgram, func.getEntryPoint(), monitor);
AddressSetView examinedSet = results.getExaminedSet();
if (examinedSet != null) {
PluginTool tool = state.getTool();
if (tool != null) {
tool.firePluginEvent(new ProgramSelectionPluginEvent("BuildResultState",
new ProgramSelection(examinedSet), currentProgram));
}
}
List<Register> regList = sort(results.getModifiedRegisters());
System.out.println("Modified registers: " + regList);
System.out.println("Preserved registers: " + sort(results.getPreservedRegisters()));
System.out.println("Input registers: " + sort(results.getInputRegisters()));
for (ResultsState.FramePointerCandidate candidate : results.getFramePointerCandidates()) {
System.out.println("Frame-pointer candidate: " + candidate);
}
for (SequenceNumber seq : results.getReturnAddresses()) {
int index = 0;
Iterator<ContextState> contextStates = results.getContextStates(seq);
while (contextStates.hasNext()) {
dumpStackState(seq, ++index, contextStates.next());
}
}
// for (SequenceNumber seq : results.getReturnAddresses()) {
// int index = 0;
// Iterator<ContextState> contextStates = results.getContextStates(seq);
// while (contextStates.hasNext()) {
// dumpReturnState(seq, ++index, contextStates.next(), regList);
// }
// }
//
Register[] regs = currentProgram.getLanguage().getRegisters();
try {
Register reg =
askChoice("Results Query", "Select Register:", Arrays.asList(regs), null);
while (reg != null) {
boolean first = true;
boolean preserved = true;
Varnode v = new Varnode(reg.getAddress(), reg.getMinimumByteSize());
Set<Varnode> returnValues = results.getReturnValues(v);
for (Varnode val : returnValues) {
if (!v.equals(val)) {
preserved = false;
if (first) {
first = false;
System.out.println(reg.getName() + " values: ");
}
System.out.println(" " + val.toString(currentProgram.getLanguage()));
}
}
if (preserved) {
System.out.println(reg.getName() + " value is preserved.");
}
reg = askChoice("Results Query", "Select Register:", regs, null);
}
}
catch (CancelledException e) {
}
}
private void dumpStackState(SequenceNumber seq, int index, ContextState state) {
Language lang = currentProgram.getLanguage();
System.out.println("Return Stack state #" + index + " at " + seq);
for (VarnodeOperation op : computedStackAccess) {
// TODO: where do I get the stack storage space ??
Varnode value = state.get(stackStorageSpaceId, op, op.getSize());
String valueStr = value != null ? value.toString(lang) : "<unknown>";
System.out.println(
"Stack[ " + op.toString(lang) + " ]:" + op.getSize() + " = " + valueStr);
}
for (Address addr : stackElementSizes.keySet()) {
Varnode v = new Varnode(addr, stackElementSizes.get(addr));
Varnode value = state.get(v);
String valueStr = value != null ? value.toString(lang) : "<unknown>";
System.out.println(addr + ":" + v.getSize() + " = " + valueStr);
}
}
// private void dumpReturnState(SequenceNumber seq, int index, ContextState state, List<Register> regList) {
// System.out.println("Return state #" + index + " at " + seq);
// for (Register reg : regList) {
// Varnode v = new Varnode(reg.getAddress(), reg.getMinimumByteSize());
// Varnode value = state.get(v);
// }
// }
private List<Register> sort(List<Register> list) {
Collections.sort(list);
return list;
}
}
@@ -0,0 +1,147 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ghidra.app.script.GhidraScript;
import ghidra.framework.data.ProjectFileManager;
import ghidra.framework.model.Project;
import ghidra.framework.store.FileSystem;
import ghidra.framework.store.local.LocalFileSystem;
import ghidra.framework.store.local.LocalFolderItem;
import java.io.IOException;
import java.lang.reflect.Method;
public class CleanupMergeDatabasesScript extends GhidraScript {
@Override
protected void run() throws Exception {
Project project = state.getProject();
ProjectFileManager fileMgr = (ProjectFileManager) project.getProjectData();
LocalFileSystem fs = (LocalFileSystem) fileMgr.getPrivateFileSystem();
int cnt = cleanupFolder(fs, "/");
if (cnt == 0) {
popup("No merge databases found");
}
else {
popup("Removed " + cnt + " merge databases");
}
}
private String getPath(String folderPath, String name) {
String path = FileSystem.SEPARATOR + name;
if (!FileSystem.SEPARATOR.equals(folderPath)) {
path = folderPath + path;
}
return path;
}
private int cleanupFolder(LocalFileSystem fs, String folderPath) throws IOException {
int cnt = 0;
for (String subfolderName : fs.getFolderNames(folderPath)) {
cnt += cleanupFolder(fs, getPath(folderPath, subfolderName));
}
// fs.getItemNames(folderPath, true)
String[] itemNames =
(String[]) invokeInstanceMethod("getItemNames", fs, new Class[] { String.class,
boolean.class }, new Object[] { folderPath, true });
for (String itemName : itemNames) {
if (!itemName.startsWith(LocalFileSystem.HIDDEN_ITEM_PREFIX)) {
continue;
}
println("Removing temp file: " + getPath(folderPath, itemName));
LocalFolderItem item = fs.getItem(folderPath, itemName);
if (item != null) {
// item.deleteContent();
invokeInstanceMethod("deleteContent", item, null, null);
}
else {
// make sure we get item out of index
//fs.deallocateItemStorage(folderPath, itemName);
invokeInstanceMethod("deallocateItemStorage", fs, new Class[] { String.class,
String.class }, new Object[] { folderPath, itemName });
}
++cnt;
}
return cnt;
}
private static Object invokeInstanceMethod(String methodName, Object ownerInstance,
Class<?>[] parameterTypes, Object[] args) throws RuntimeException {
if (ownerInstance == null) {
throw new NullPointerException("Owner of instance field cannot be null");
}
Class<?> objectClass =
(ownerInstance instanceof Class) ? (Class<?>) ownerInstance : ownerInstance.getClass();
Object result = null;
try {
// get the method object to call
Method method = locateMethodObjectOnClass(methodName, objectClass, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("Unable to find a method by " + "the name \"" +
methodName + "\" on the class " + objectClass + " or any of its parent " +
"implementations.");
}
// make sure we have access
method.setAccessible(true);
// execute the method and get the result
result = method.invoke(ownerInstance, args);
}
catch (Exception e) {
throw new RuntimeException("Unable to use reflection to call " + "method: " +
methodName + " from class: " + objectClass, e);
}
return result;
}
private static Method locateMethodObjectOnClass(String methodName, Class<?> containingClass,
Class<?>[] parameterTypes) {
Method method = null;
try {
// if we get an exception here, then the current class does not
// declare the method, but its parent may
method = containingClass.getDeclaredMethod(methodName, parameterTypes);
}
catch (NoSuchMethodException nsme) {
// O.K., the method may be located on a parent class. So, we
// will call this method on the parent class
Class<?> parentClass = containingClass.getSuperclass();
if (parentClass != null) {
method = locateMethodObjectOnClass(methodName, parentClass, parameterTypes);
}
}
return method;
}
}
@@ -0,0 +1,104 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Performs database consistency check on the current program
import ghidra.app.script.GhidraScript;
import ghidra.app.services.ProgramManager;
import ghidra.framework.model.DomainFile;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.Program;
import db.DBHandle;
public class ConsistencyCheck extends GhidraScript {
@Override
public void run() throws Exception {
if (state.getTool() == null) {
popup("Script requires active tool!");
return;
}
ProgramManager programMgr = state.getTool().getService(ProgramManager.class);
if (programMgr == null) {
popup("Script requires Program Manager service!");
return;
}
if (currentProgram == null) {
popup("Script requires open/active program!");
return;
}
DBHandle dbh = ((ProgramDB) currentProgram).getDBHandle();
if (dbh.isChanged()) {
popup("Current program must be saved prior to running!");
return;
}
DomainFile df = currentProgram.getDomainFile();
if (dbh.isConsistent(monitor)) {
popup("Program database is consistent!");
return;
}
if (!df.canSave() || !currentProgram.hasExclusiveAccess()) {
popup("Program database is NOT consistent!\nRebuild requires exclusive checkout.");
return;
}
if (!askYesNo("Rebuild Database?",
"Program database is NOT consistent!\nWould you like to rebuild?")) {
return;
}
end(false);
programMgr.closeProgram(currentProgram, true);
currentProgram = (Program) df.getDomainObject(this, false, false, monitor);
dbh = ((ProgramDB) currentProgram).getDBHandle();
try {
boolean success = false;
long txId = dbh.startTransaction();
try {
success = dbh.rebuild(monitor);
}
finally {
dbh.endTransaction(txId, success);
}
if (!success) {
popup("Rebuild Failed!");
return;
}
if (!askYesNo("Save Database?",
"Program database rebuilt successfully!\nWould you like to save?")) {
return;
}
currentProgram.save("DB Rebuild", monitor);
}
finally {
currentProgram.release(this);
currentProgram = programMgr.openProgram(df);
start();
}
}
}
@@ -0,0 +1,111 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.*;
import generic.jar.ResourceFile;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.Analyzer;
import ghidra.framework.Application;
import ghidra.framework.plugintool.PluginConfigurationModel;
import ghidra.framework.plugintool.util.PluginDescription;
import ghidra.util.classfinder.ClassSearcher;
public class DumpGhidraCapabilitiesScript extends GhidraScript {
private Map<String, List<PluginDescription>> pluginMap = new HashMap<>();
private Map<String, List<Analyzer>> analyzerMap = new HashMap<>();
@Override
public void run() throws Exception {
PluginConfigurationModel model = new PluginConfigurationModel(state.getTool());
List<PluginDescription> descriptions = model.getAllPluginDescriptions();
for (PluginDescription pluginDescription : descriptions) {
String moduleName = pluginDescription.getModuleName();
if (moduleName == null) {
moduleName = "[ No Module ]";
}
addPlugin(moduleName, pluginDescription);
}
Set<Analyzer> instances = ClassSearcher.getInstances(Analyzer.class);
for (Analyzer analyzer : instances) {
Class<? extends Analyzer> clazz = analyzer.getClass();
ResourceFile module = Application.getModuleContainingClass(clazz.getName());
String moduleName;
if (module == null) {
moduleName = "[ No Module ]";
}
else {
moduleName = module.getName();
}
addAnalyzer(moduleName, analyzer);
}
Set<String> set = new HashSet<>(pluginMap.keySet());
set.addAll(analyzerMap.keySet());
List<String> list = new ArrayList<>(set);
Collections.sort(list);
System.out.println("Modules:");
for (String module : list) {
System.out.println("\t" + module);
List<PluginDescription> plugins = pluginMap.get(module);
if (plugins != null && !plugins.isEmpty()) {
System.out.println("\t\tPlugins: ");
Collections.sort(plugins);
for (PluginDescription pd : plugins) {
System.out.println("\t\t\t" + pd.getName());
System.out.println("\t\t\t\t" + pd.getShortDescription());
System.out.println("\t\t\t\t" + pd.getDescription());
}
}
List<Analyzer> analyzers = analyzerMap.get(module);
if (analyzers != null && !analyzers.isEmpty()) {
System.out.println("\t\tAnalyzers: ");
Collections.sort(analyzers,
(arg0, arg1) -> arg0.getName().compareTo(arg1.getName()));
for (Analyzer analyzer : analyzers) {
System.out.println("\t\t\t" + analyzer.getName());
System.out.println("\t\t\t\t" + analyzer.getDescription());
}
}
}
}
private void addAnalyzer(String moduleName, Analyzer analyzer) {
List<Analyzer> list = analyzerMap.get(moduleName);
if (list == null) {
list = new ArrayList<>();
analyzerMap.put(moduleName, list);
}
list.add(analyzer);
}
private void addPlugin(String moduleName, PluginDescription pluginDescription) {
List<PluginDescription> list = pluginMap.get(moduleName);
if (list == null) {
list = new ArrayList<>();
pluginMap.put(moduleName, list);
}
list.add(pluginDescription);
}
}
@@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.symbol.RefType;
public class FindInvalidFlowType extends GhidraScript {
@Override
protected void run() throws Exception {
if (currentProgram == null) {
return;
}
for (Instruction instr : currentProgram.getListing().getInstructions(currentAddress.add(1),
true)) {
if (instr.getFlowType() == RefType.INVALID) {
goTo(instr.getAddress());
return;
}
}
popup("Invalid FlowType not found below current point");
}
}
@@ -0,0 +1,216 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.SwingUtilities;
import db.*;
import db.buffers.BufferFile;
import ghidra.app.script.GhidraScript;
import ghidra.app.script.ImproperUseException;
import ghidra.framework.data.GhidraFile;
import ghidra.framework.data.GhidraFileData;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.model.DomainFile;
import ghidra.framework.store.FolderItem;
import ghidra.framework.store.local.LocalDatabaseItem;
import ghidra.program.model.lang.LanguageDescription;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.Program;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitorAdapter;
public class FixLangId extends GhidraScript {
private static final String LANGUAGE_ID = "Language ID";
private static final String LANGUAGE_VERSION = "Language Version";
private static final String TABLE_NAME = "Program";
@Override
public void run() throws Exception {
DomainFile df = askProgramFile("Select Program File");
if (df == null) {
return;
}
if (df.isVersioned()) {
Msg.showError(getClass(), null, "Script Error",
"Selected project file must not be under version control!");
return;
}
GhidraFile gf = (GhidraFile) df;
Method method = GhidraFile.class.getDeclaredMethod("getFileData", new Class<?>[0]);
method.setAccessible(true);
GhidraFileData fileData = (GhidraFileData) method.invoke(gf, new Object[0]);
FolderItem item = (FolderItem) getInstanceField("folderItem", fileData);
if (!(item instanceof LocalDatabaseItem)) {
Msg.showError(getClass(), null, "Script Error", "Unsupported file type!");
return;
}
LocalDatabaseItem dbItem = (LocalDatabaseItem) item;
BufferFile bf = dbItem.openForUpdate(-1);
DBHandle dbh = new DBHandle(bf);
if (!modifyLanguage(df, dbh)) {
dbh.close();
return;
}
dbh.save("Set Language", null, TaskMonitorAdapter.DUMMY_MONITOR);
dbh.close();
}
private boolean modifyLanguage(DomainFile df, DBHandle dbh) throws IOException,
ImproperUseException {
// TODO: Check for address map and overlay entries which could break from
// changing the memory model !!
Table table = dbh.getTable(TABLE_NAME);
if (table == null) {
Msg.showError(getClass(), null, "Script Error", "Bad program database!!");
return false;
}
Record record = table.getRecord(new StringField(LANGUAGE_ID));
if (record == null) { // must be in old style combined language/compiler spec format
Msg.showError(getClass(), null, "Script Error",
"Old program file! Language fix is not appropriate.");
return false;
}
String langId = record.getString(0);
LanguageDescription desc = null;
List<LanguageDescription> descriptions =
DefaultLanguageService.getLanguageService().getLanguageDescriptions(true);
String[] choices = new String[descriptions.size()];
for (int i = 0; i < choices.length; i++) {
choices[i] = descriptions.get(i).getLanguageID().getIdAsString();
}
try {
langId = askChoice("Select New Language", "Language ID:", choices, null);
if (langId != null) {
Msg.warn(this, "Changing language ID from '" + record.getString(0) + "' to '" +
langId + "' for program: " + df.getName());
desc =
DefaultLanguageService.getLanguageService().getLanguageDescription(
new LanguageID(langId));
long txId = dbh.startTransaction();
try {
record.setString(0, langId);
table.putRecord(record);
record = table.getSchema().createRecord(new StringField(LANGUAGE_VERSION));
record.setString(0, desc.getVersion() + "." + desc.getMinorVersion());
table.putRecord(record);
}
finally {
dbh.endTransaction(txId, true);
}
return true;
}
}
catch (CancelledException e) {
// just return false
}
return false;
}
public DomainFile askProgramFile(String title) {
final DomainFile[] domainFile = new DomainFile[] { null };
final DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
dtd.addOkActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dtd.close();
domainFile[0] = dtd.getDomainFile();
}
});
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
dtd.showComponent();
}
});
}
catch (Exception e) {
return null;
}
if (domainFile[0] != null &&
!Program.class.isAssignableFrom(domainFile[0].getDomainObjectClass())) {
Msg.showError(getClass(), null, "Script Error",
"Selected project file is not a program file!");
return null;
}
return domainFile[0];
}
public static Object getInstanceField(String fieldName, Object ownerInstance)
throws RuntimeException {
if (ownerInstance == null) {
throw new NullPointerException("Owner of instance field cannot be null");
}
Class<?> objectClass =
(ownerInstance instanceof Class) ? (Class<?>) ownerInstance : ownerInstance.getClass();
Object result = null;
try {
// get the field from the class object
Field field = locateFieldObjectOnClass(fieldName, objectClass);
// open up the field so that we have access
field.setAccessible(true);
// get the field from the object instance that we were provided
result = field.get(ownerInstance);
}
catch (Exception e) {
throw new RuntimeException("Unable to use reflection to obtain " + "field: " +
fieldName + " from class: " + objectClass, e);
}
return result;
}
public static Field locateFieldObjectOnClass(String fieldName, Class<?> containingClass) {
Field field = null;
try {
field = containingClass.getDeclaredField(fieldName);
}
catch (NoSuchFieldException nsfe) {
// O.K., the field may be located on a parent class. So, we
// will call this method on the parent class
Class<?> parentClass = containingClass.getSuperclass();
if (parentClass != null) {
field = locateFieldObjectOnClass(fieldName, parentClass);
}
}
return field;
}
}
@@ -0,0 +1,78 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ghidra.app.script.GhidraScript;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.util.LanguageTranslator;
import ghidra.program.util.LanguageTranslatorAdapter;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class ForceRedisassembly extends GhidraScript {
@Override
public void run() throws Exception {
if (currentProgram == null) {
Msg.showError(this, null, "No Program Error", "No active program found");
return;
}
ProgramDB program = (ProgramDB)currentProgram;
Language lang = program.getLanguage();
LanguageTranslator translator = new MyLanguageTranslator(lang.getLanguageID(), lang.getVersion());
if (!translator.isValid()) {
return;
}
program.setLanguage(translator, program.getCompilerSpec().getCompilerSpecID(), true, monitor);
}
private static class MyLanguageTranslator extends LanguageTranslatorAdapter {
protected MyLanguageTranslator(LanguageID languageId, int version) {
super(languageId, version, languageId, version);
}
@Override
public boolean isValid() {
if (super.isValid()) {
try {
validateDefaultSpaceMap();
} catch (IncompatibleLanguageException e) {
throw new AssertException();
}
Register newContextReg = getNewLanguage().getContextBaseRegister();
if (newContextReg != null) {
Register oldContextReg = getOldLanguage().getContextBaseRegister();
if (oldContextReg == null || !isSameRegisterConstruction(oldContextReg, newContextReg)) {
throw new AssertException();
}
}
return true;
}
return false;
}
@Override
public String toString() {
return "[" + getOldLanguageID() + " (Version " + getOldVersion() + ")] -> [" +
getNewLanguageID() + " (Version " + getNewVersion() + ")] {Forced Re-Disassembly Translator}";
}
}
}
@@ -0,0 +1,142 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import docking.widgets.OptionDialog;
import ghidra.app.script.GhidraScript;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
public class MoveMemoryRangeContents extends GhidraScript {
@Override
public void run() throws Exception {
if (!(currentProgram instanceof ProgramDB)) {
Msg.showError(this, null, "No Program Found", "This script requires an open program");
return;
}
ProgramDB program = (ProgramDB) currentProgram;
try {
program.checkExclusiveAccess();
}
catch (Exception e) {
Msg.showError(this, null, "Program Error",
"This script requires an exclusive checkout on the program");
return;
}
Listing listing = currentProgram.getListing();
if (currentSelection == null || currentSelection.getNumAddressRanges() != 1) {
Msg.showError(this, null, "Invalid Selection",
"Action requires a single selected memory range within a single memory block");
return;
}
AddressRange srcRange = currentSelection.getFirstRange();
Address srcStart = srcRange.getMinAddress();
int length = (int) srcRange.getMaxAddress().subtract(srcStart) + 1;
MemoryBlock block1 = program.getMemory().getBlock(srcStart);
MemoryBlock block2 = program.getMemory().getBlock(srcRange.getMaxAddress());
if (block1 == null || block1 != block2 || !block1.isInitialized()) {
Msg.showError(this, null, "Invalid Selection",
"Action requires a single selected memory range within a single initialized memory block");
return;
}
Address destStart = askAddress("Memory Destination", "Enter destination address:");
MemoryBlock block = program.getMemory().getBlock(destStart);
if (block == null || !block.isInitialized()) {
Msg.showError(this, null, "Invalid Destination",
"Initialized memory block not found at destination address: " + destStart);
return;
}
long availableSpace = block.getEnd().subtract(destStart) + 1;
if (availableSpace < length) {
Msg.showError(this, null, "Memory Move Failed",
"Insufficient space in specified memory block starting at " + destStart + ".\n" +
"Selected range is 0x" + Long.toHexString(length) + " bytes long");
return;
}
Address destEnd = destStart.add(length - 1);
int resp =
OptionDialog.showOptionDialog(null, "Confirm Memory Move",
"Do you wish to overwrite all bytes, code units, symbols and references from\n" +
"the specified destination range: " + destStart + " to " + destEnd, "Continue");
if (resp != OptionDialog.OPTION_ONE) {
return;
}
monitor.setMessage("Clearing old code units...");
listing.clearCodeUnits(destStart, destEnd, true, monitor);
monitor.setMessage("Clearing old code properties...");
listing.clearProperties(destStart, destEnd, monitor);
monitor.setMessage("Clearing old symbols...");
SymbolIterator symIter = program.getSymbolTable().getSymbolIterator(destStart, true);
while (symIter.hasNext()) {
monitor.checkCanceled();
Symbol sym = symIter.next();
if (sym.getAddress().compareTo(destEnd) > 0) {
break;
}
}
monitor.setMessage("Clearing old references...");
ReferenceManager refMgr = program.getReferenceManager();
refMgr.removeAllReferencesFrom(destStart, destEnd);
// Remove range from all tree modules
program.getTreeManager().deleteAddressRange(destStart, destEnd, monitor);
monitor.setMessage("Move memory bytes...");
byte[] bytes = new byte[4096];
int len = length;
Address srcAddr = srcStart;
Address destAddr = destStart;
while (true) {
monitor.checkCanceled();
int cnt = program.getMemory().getBytes(srcAddr, bytes, 0, Math.min(len, bytes.length));
currentProgram.getMemory().setBytes(destAddr, bytes, 0, cnt);
len -= cnt;
if (len <= 0) {
break;
}
srcAddr = srcAddr.add(cnt);
destAddr = destAddr.add(cnt);
}
monitor.setMessage("Moving everything else...");
program.moveAddressRange(srcStart, destStart, length, monitor);
// Add tree module for old range
program.getTreeManager().addMemoryBlock("Obsolete", srcRange);
program.invalidate();
}
}
@@ -0,0 +1,115 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File;
import java.util.ArrayList;
import ghidra.app.script.GhidraScript;
import ghidra.framework.model.*;
import ghidra.program.model.listing.Program;
public class PopulateBigRepoScript extends GhidraScript {
private static final File TEST_BINARY = new File("/tmp/helloWorld");
@Override
protected void run() throws Exception {
Project project = state.getProject();
ProjectData projectData = project.getProjectData();
DomainFile firstFile = getFirstFile(projectData);
for (int i = 1; i < 200000; i++) {
String path = getFolderPath(i);
DomainFolder folder = projectData.getRootFolder();
String[] splitPath = path.split("/");
for (int n = 1; n < splitPath.length; n++) {
DomainFolder subfolder = folder.getFolder(splitPath[n]);
if (subfolder == null) {
subfolder = folder.createFolder(splitPath[n]);
}
folder = subfolder;
}
String name = getName(i);
if (folder.getFile(name) == null) {
DomainFile newFile = firstFile.copyTo(folder, monitor);
newFile = newFile.setName(name);
newFile.addToVersionControl("Initial", false, monitor);
System.out.println("File: " + i + " - " + newFile.getPathname());
}
}
}
private DomainFile getFirstFile(ProjectData projectData) throws Exception {
DomainFolder folder = projectData.getFolder(getFolderPath(0));
String name = getName(0);
DomainFile df = folder.getFile(name);
if (df != null) {
return df;
}
Program p = importFile(TEST_BINARY);
try {
df = folder.createFile(name, p, monitor);
}
finally {
p.release(this);
}
df.addToVersionControl("Initial", false, monitor);
return df;
}
private Integer[] getPath(int counter) {
if (counter == 0) {
return new Integer[] { 0 };
}
ArrayList<Integer> list = new ArrayList<>();
while (counter != 0) {
int n = counter % 10;
counter = counter / 10;
list.add(n);
}
Integer[] a = new Integer[list.size()];
int i = a.length;
for (Integer n : list) { // fip path with file# last instead of first
a[--i] = n;
}
return a;
}
private String getName(int counter) {
Integer[] path = getPath(counter);
StringBuilder buf = new StringBuilder("df");
for (int n : path) {
buf.append(n);
}
return buf.toString();
}
private String getFolderPath(int counter) {
Integer[] path = getPath(counter);
StringBuilder buf = new StringBuilder("/");
for (int i = 0; i < (path.length - 1); i++) {
buf.append(path[i]);
buf.append("/");
}
return buf.toString();
}
}
@@ -0,0 +1,343 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File;
import java.io.PrintWriter;
import java.math.BigInteger;
import ghidra.app.script.GhidraScript;
import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
public class RangeDisassemblerScript extends GhidraScript {
/**
* Required properties:
* min - minimum disassembly address or block name
* max - maximum disassembly address (not used if block name used for min)
* out - disassembly output file path
*
* Optional:
* set.<context-reg-name> - optional starting context value
* set.range.<context-reg-name> - optional context value over range
*
*/
private AddressSetView region;
private File outFile;
@Override
protected void run() throws Exception {
if (!isRunningHeadless()) {
printerr("Script intended for Headless use only");
return;
}
if (currentProgram == null) {
printerr("Requires open program");
return;
}
currentProgram.setTemporary(true);
if (!processParameters()) {
return;
}
Msg.info(this, "Disassmbly Output File: " + outFile.getAbsolutePath());
PrintWriter out = new PrintWriter(outFile);
try {
disassembleRegion(out);
}
finally {
out.close();
}
}
private void disassembleRegion(PrintWriter out) {
int alignment = currentProgram.getLanguage().getInstructionAlignment();
Disassembler disassembler =
Disassembler.getDisassembler(currentProgram, false, false, false, monitor, null);
DumbMemBufferImpl memBuffer =
new DumbMemBufferImpl(currentProgram.getMemory(), region.getMinAddress());
ParallelInstructionLanguageHelper helper =
currentProgram.getLanguage().getParallelInstructionHelper();
int cnt = 0;
for (AddressRange range : region.getAddressRanges(true)) {
Address nextAddr = range.getMinAddress();
InstructionBlock lastPseudoInstructionBlock = null;
while (nextAddr != null && nextAddr.compareTo(range.getMaxAddress()) <= 0) {
if ((nextAddr.getOffset() % alignment) != 0) {
nextAddr = nextAddr.next();
continue;
}
Instruction pseudoInstruction = null;
InstructionError error = null;
if (lastPseudoInstructionBlock != null) {
pseudoInstruction = lastPseudoInstructionBlock.getInstructionAt(nextAddr);
if (pseudoInstruction == null) {
error = lastPseudoInstructionBlock.getInstructionConflict();
if (error != null && !nextAddr.equals(error.getInstructionAddress())) {
error = null;
}
}
}
if (pseudoInstruction == null && error == null) {
memBuffer.setPosition(nextAddr);
lastPseudoInstructionBlock =
disassembler.pseudoDisassembleBlock(memBuffer, null, 1);
if (lastPseudoInstructionBlock != null) {
pseudoInstruction = lastPseudoInstructionBlock.getInstructionAt(nextAddr);
if (pseudoInstruction == null) {
error = lastPseudoInstructionBlock.getInstructionConflict();
if (error != null && !nextAddr.equals(error.getInstructionAddress())) {
error = null;
}
}
}
}
try {
if (pseudoInstruction != null) {
out.print(nextAddr.toString());
out.print(" ");
out.print(formatBytes(pseudoInstruction.getBytes()));
out.print(" ");
String prefix = null;
if (helper != null) {
prefix = helper.getMnemonicPrefix(pseudoInstruction);
}
if (prefix == null) {
prefix = " ";
}
else {
prefix = StringUtilities.pad(prefix, ' ', -4);
}
out.println(prefix);
out.println(pseudoInstruction.toString());
nextAddr = pseudoInstruction.getMaxAddress().next();
}
else {
out.print(nextAddr.toString());
out.print(" ");
out.print(formatBytes(new byte[] { memBuffer.getByte(0) }));
out.print(" ERROR: ");
out.println(error.getConflictMessage());
nextAddr = nextAddr.add(alignment);
}
if ((++cnt % 20000) == 0) {
Msg.info(this, "Disassembled: " + cnt);
}
}
catch (AddressOutOfBoundsException e) {
nextAddr = null; // next range
}
catch (MemoryAccessException e) {
out.print(nextAddr.toString());
out.println(" ERROR: " + e.getMessage());
break;
}
}
}
Msg.info(this, "Disassembled: " + cnt + " instructions to " + outFile);
}
private static final int MAX_BYTES = 4;
private String formatBytes(byte[] bytes) {
int totalWidth = (3 * 4) + 2;
StringBuilder buf = new StringBuilder();
for (int i = 0; i < bytes.length && i < MAX_BYTES; i++) {
if (i != 0) {
buf.append(' ');
}
int v = bytes[i] & 0xff;
if (v < 0x10) {
buf.append('0');
}
buf.append(Integer.toHexString(v));
}
if (bytes.length > MAX_BYTES) {
buf.append('.');
}
return StringUtilities.pad(buf.toString(), ' ', -totalWidth);
}
private boolean processParameters() {
Address minAddr = null;
Address maxAddr = null;
AddressFactory addrFactory = currentProgram.getAddressFactory();
boolean missingParam = false;
String minAddrStr = propertiesFileParams.getValue("min");
if (minAddrStr == null) {
printerr("Missing required minimum address property: min");
missingParam = true;
}
else {
minAddr = addrFactory.getAddress(minAddrStr);
if (minAddr == null) {
// Try as block name
MemoryBlock block = currentProgram.getMemory().getBlock(minAddrStr);
if (block == null) {
printerr("Failed to parse min address/block: " + minAddrStr);
missingParam = true;
}
else {
minAddr = block.getStart();
maxAddr = block.getEnd();
}
}
}
if (maxAddr == null) {
String maxAddrStr = propertiesFileParams.getValue("max");
if (minAddrStr == null) {
printerr("Missing required maximum address property: max");
missingParam = true;
}
else {
maxAddr = addrFactory.getAddress(maxAddrStr);
if (maxAddr == null) {
printerr("Failed to parse max address: " + maxAddrStr);
missingParam = true;
}
}
}
String filepath = propertiesFileParams.getValue("out");
if (minAddrStr == null) {
printerr("Missing required output file path property: out");
missingParam = true;
}
else {
outFile = new File(filepath);
File parentDir = outFile.getParentFile();
if (!parentDir.exists()) {
printerr("Output directory not found: " + parentDir.getAbsolutePath());
missingParam = true;
}
}
if (missingParam) {
return false;
}
if (!minAddr.hasSameAddressSpace(maxAddr) || minAddr.compareTo(maxAddr) > 0) {
printerr("Invalid address range: " + minAddr + " - " + maxAddr);
return false;
}
region =
currentProgram.getMemory().getLoadedAndInitializedAddressSet().intersectRange(minAddr, maxAddr);
if (region.isEmpty()) {
printerr("Address range does not intersect initiailized memory: " + minAddr + " - " +
maxAddr);
return false;
}
ProgramContext programContext = currentProgram.getProgramContext();
boolean badReg;
try {
badReg = false;
for (String key : propertiesFileParams.keySet()) {
boolean setRange = false;
int index;
if (key.startsWith("set.range.")) {
setRange = true;
index = 10;
}
else if (key.startsWith("set.")) {
index = 4;
}
else {
continue;
}
String regName = key.substring(index);
Register reg = currentProgram.getRegister(regName);
if (reg == null || !reg.isProcessorContext()) {
printerr("Processor context register field not found: " + regName);
badReg = true;
continue;
}
BigInteger value;
String valueStr = propertiesFileParams.getValue(key);
try {
value = BigInteger.valueOf(Long.parseLong(valueStr));
}
catch (NumberFormatException e) {
printerr("Invalid register set value: " + valueStr);
badReg = true;
continue;
}
if (setRange) {
programContext.setValue(reg, minAddr, maxAddr, value);
}
else {
programContext.setValue(reg, minAddr, minAddr, value);
}
}
}
catch (ContextChangeException e) {
printerr("Program must be clear of all code units!");
printerr(e.getMessage());
return false;
}
if (badReg) {
return false;
}
return true;
}
}
@@ -0,0 +1,149 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.*;
import ghidra.app.script.GhidraScript;
import ghidra.app.services.Analyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
import ghidra.util.classfinder.ClassSearcher;
public class SummarizeAnalyzers extends GhidraScript {
private List<AnalyzerData> byteTasks;
private List<AnalyzerData> functionTasks;
private List<AnalyzerData> functionModifierTasks;
private List<AnalyzerData> functionSignatureTasks;
private List<AnalyzerData> instructionTasks;
private List<AnalyzerData> dataTasks;
private static class AnalyzerData implements Comparable<AnalyzerData> {
private final Analyzer analyzer;
private final boolean enabled;
AnalyzerData(Analyzer analyzer, boolean enabled) {
this.analyzer = analyzer;
this.enabled = enabled;
}
@Override
public int compareTo(AnalyzerData arg0) {
return arg0.analyzer.getPriority().priority() - analyzer.getPriority().priority();
}
@Override
public String toString() {
return (enabled ? " X " : " ") +
StringUtilities.pad(Integer.toString(analyzer.getPriority().priority()), ' ',
4) + " " + analyzer.getName() + " (" + analyzer.getClass().getSimpleName() +
")";
}
}
private void initializeAnalyzers() {
byteTasks = new ArrayList<AnalyzerData>();
functionTasks = new ArrayList<AnalyzerData>();
functionModifierTasks = new ArrayList<AnalyzerData>();
functionSignatureTasks = new ArrayList<AnalyzerData>();
instructionTasks = new ArrayList<AnalyzerData>();
dataTasks = new ArrayList<AnalyzerData>();
Options options = currentProgram.getOptions(Program.ANALYSIS_PROPERTIES);
Set<Class<? extends Analyzer>> classes = ClassSearcher.getClasses(Analyzer.class);
for (Class<? extends Analyzer> element : classes) {
Analyzer analyzer;
try {
analyzer = element.newInstance();
}
catch (Exception e) {
Msg.showError(this, null, "Analyzer Error", "Cannot instantiate " + element + " " +
e.getMessage(), e);
continue;
}
if (!analyzer.canAnalyze(currentProgram)) {
continue;
}
boolean enabled = options.getBoolean(analyzer.getName(), false);
AnalyzerType type = analyzer.getAnalysisType();
if (type == AnalyzerType.BYTE_ANALYZER) {
byteTasks.add(new AnalyzerData(analyzer, enabled));
}
else if (type == AnalyzerType.DATA_ANALYZER) {
dataTasks.add(new AnalyzerData(analyzer, enabled));
}
else if (type == AnalyzerType.FUNCTION_ANALYZER) {
functionTasks.add(new AnalyzerData(analyzer, enabled));
}
else if (type == AnalyzerType.FUNCTION_MODIFIERS_ANALYZER) {
functionModifierTasks.add(new AnalyzerData(analyzer, enabled));
}
else if (type == AnalyzerType.FUNCTION_SIGNATURES_ANALYZER) {
functionSignatureTasks.add(new AnalyzerData(analyzer, enabled));
}
else if (type == AnalyzerType.INSTRUCTION_ANALYZER) {
instructionTasks.add(new AnalyzerData(analyzer, enabled));
}
else {
Msg.showError(this, null, "Unknown Analysis Type", "Unexpected Analysis type " +
type);
}
}
Collections.sort(byteTasks);
Collections.sort(instructionTasks);
Collections.sort(functionTasks);
Collections.sort(functionModifierTasks);
Collections.sort(functionSignatureTasks);
Collections.sort(dataTasks);
}
@Override
public void run() throws Exception {
if (currentProgram == null) {
return;
}
initializeAnalyzers();
dump("Byte Analyzers", byteTasks);
dump("Instruction Analyzers", instructionTasks);
dump("Function Analyzers", functionTasks);
dump("Function Modifier Analyzers", functionModifierTasks);
dump("Function Signature Analyzers", functionSignatureTasks);
dump("Data Analyzers", dataTasks);
}
private void dump(String type, List<AnalyzerData> list) {
println("*** " + type + " ***");
for (AnalyzerData data : list) {
println(data.toString());
}
}
}
@@ -0,0 +1,133 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ghidra.app.script.GhidraScript;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.lang.LanguageNotFoundException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitorAdapter;
import java.io.File;
import java.io.IOException;
import db.DBConstants;
import db.DBHandle;
public class UpgradeTestProgramScript extends GhidraScript {
@Override
public void run() throws Exception {
// File testResourceDirectory = RunInfo.getCoreSubDirectory("test_resources");
//
// File gzf = this.askFile("Upgrade Program Archive", testResourceDirectory, "Upgrade");
// if (!gzf.getName().endsWith(".gzf")) {
// popup("Only Ghidra Zip files (*.gzf) are supported!");
// return;
// }
//
// if (upgradeProgramArchive(gzf)) {
// popup("Program upgraded");
// }
File gzfDir = this.askDirectory("Upgrade Program Archives", "Upgrade All");
if (!askYesNo("Upgrade Program Archives",
"Do you want to upgrade all Program archives in the directory: " + gzfDir.getName() +
"?")) {
return;
}
upgradeDir(gzfDir);
}
private void upgradeDir(File dir) throws CancelledException, VersionException, IOException {
if ("upgrades".equals(dir.getName())) {
return; // ignore the special upgrade directory
}
for (File f : dir.listFiles()) {
if (f.isFile() && f.getName().endsWith(".gzf")) {
Msg.info(this, "Processing " + f.getName() + " ...");
if (upgradeProgramArchive(f)) {
Msg.info(this, " program upgraded!");
}
}
else if (f.isDirectory()) {
upgradeDir(f);
}
}
}
private boolean upgradeProgramArchive(File gzf) throws IOException, CancelledException,
VersionException {
PackedDatabase db = PackedDatabase.getPackedDatabase(gzf, TaskMonitorAdapter.DUMMY_MONITOR);
DBHandle dbh = null;
ProgramDB p = null;
try {
dbh = db.openForUpdate(monitor);
if (dbh.getTable("Program") == null) {
return false;
}
try {
p = new ProgramDB(dbh, DBConstants.UPDATE, monitor, this);
return false;
}
catch (LanguageNotFoundException e) {
Msg.error(this, e.getMessage());
return false;
}
catch (VersionException e) {
if (!e.isUpgradable()) {
Msg.error(this, e.getMessage());
return false;
}
}
finally {
dbh.close();
}
dbh = db.openForUpdate(monitor);
p = new ProgramDB(dbh, DBConstants.UPGRADE, monitor, this);
if (!p.isChanged()) {
return false;
}
p.save(null, monitor);
}
finally {
if (p != null) {
p.release(this);
}
if (dbh != null) {
dbh.close();
}
db.dispose();
}
return true;
}
}