mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-24 03:09:36 +08:00
Candidate release of source code.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user