mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-676 - Updated TableChooserDialog API to allow for bulk transaction
usage
This commit is contained in:
parent
ed3cc10344
commit
83e6e614a5
6 changed files with 118 additions and 488 deletions
|
@ -1,409 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
// New Table Stuff
|
|
||||||
//@category Search
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
|
||||||
import ghidra.app.tablechooser.*;
|
|
||||||
import ghidra.program.model.address.*;
|
|
||||||
import ghidra.program.model.mem.Memory;
|
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
|
||||||
|
|
||||||
public class FindRunsOfPointersWithTableScript extends GhidraScript {
|
|
||||||
private List<PossiblePtrs> resultsArray = new ArrayList<PossiblePtrs>();
|
|
||||||
public static final int LITTLE_ENDIAN = 0;
|
|
||||||
public static final int BIG_ENDIAN = 1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() throws Exception {
|
|
||||||
|
|
||||||
int size = currentProgram.getAddressFactory().getDefaultAddressSpace().getSize();
|
|
||||||
if (size != 32) {
|
|
||||||
println("This script only works on 32-bit programs.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TableChooserExecutor executor = createTableExecutor();
|
|
||||||
TableChooserDialog tableDialog = createTableChooserDialog("Runs of Pointers", executor);
|
|
||||||
configureTableColumns(tableDialog);
|
|
||||||
tableDialog.show();
|
|
||||||
tableDialog.setMessage("Searching...");
|
|
||||||
Memory memory = currentProgram.getMemory();
|
|
||||||
long distance;
|
|
||||||
// TODO add option to work only on selection
|
|
||||||
AddressIterator addrIter = memory.getAddresses(true);
|
|
||||||
//println("Memory range: " + memory.getMinAddress() + " - " + memory.getMaxAddress());
|
|
||||||
Address prevAddress = null;
|
|
||||||
while (addrIter.hasNext() && !monitor.isCancelled()) {
|
|
||||||
Address addr = addrIter.next();
|
|
||||||
try {
|
|
||||||
// get the value in address form of the bytes at address a
|
|
||||||
int addrInt = memory.getInt(addr);
|
|
||||||
long addrLong = addrInt & 0xffffffffL;
|
|
||||||
Address testAddr = addr.getNewAddress(addrLong);
|
|
||||||
|
|
||||||
if ((addrLong != 0) && (memory.contains(testAddr))) {
|
|
||||||
if (prevAddress != null) {
|
|
||||||
distance = addr.subtract(prevAddress);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
distance = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PossiblePtrs pp = new PossiblePtrs(addr, testAddr, distance);
|
|
||||||
resultsArray.add(pp);
|
|
||||||
//println(addr.toString() + " " + testAddr.toString() + " " + distance);
|
|
||||||
prevAddress = addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (MemoryAccessException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (AddressOutOfBoundsException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through the list of pointers and only print out the ones with a run of the same distance between them
|
|
||||||
// keep the one before the run and include the last one with the same distance
|
|
||||||
//println("tableAddress distance tableSize");
|
|
||||||
if (resultsArray.size() == 0) {
|
|
||||||
tableDialog.setMessage("Done! Found no hits");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long dist = resultsArray.get(0).getDistanceFromLast();
|
|
||||||
int tableSize = 0;
|
|
||||||
Address topAddress = null;
|
|
||||||
int i = 1;
|
|
||||||
while (i < resultsArray.size() && !monitor.isCancelled()) {
|
|
||||||
// for(int i=1;i<resultsArray.size();i++){
|
|
||||||
long thisDist = resultsArray.get(i).getDistanceFromLast();
|
|
||||||
if (thisDist == dist) {
|
|
||||||
if (tableSize == 0) {
|
|
||||||
topAddress = resultsArray.get(i - 2).getAddrOfPtr();
|
|
||||||
tableSize = 1;
|
|
||||||
}
|
|
||||||
tableSize++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (tableSize >= 3) {
|
|
||||||
tableSize++;
|
|
||||||
|
|
||||||
Address ref = findRef(topAddress, dist);
|
|
||||||
//println(topAddress.toString() + " " + dist + " " + tableSize);
|
|
||||||
Table pointerTable = new Table(topAddress, dist, tableSize, ref);
|
|
||||||
tableDialog.add(pointerTable);
|
|
||||||
}
|
|
||||||
tableSize = 0;
|
|
||||||
dist = thisDist;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
tableDialog.setMessage("Done! Found " + tableDialog.getRowCount() + " hits");
|
|
||||||
|
|
||||||
// print out results
|
|
||||||
// println("Table address Dist bet ptrs Num ptrs Ref found");
|
|
||||||
// for(int j=0;j<tableArray.size();j++){
|
|
||||||
// Table ptrTable = tableArray.get(j);
|
|
||||||
// String refString = new String();
|
|
||||||
// if(ptrTable.getRef() != null){
|
|
||||||
// refString = " at " + ptrTable.getRef().toString();
|
|
||||||
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
|
|
||||||
// }
|
|
||||||
// else if(searchNonRefd){
|
|
||||||
// refString = "No";
|
|
||||||
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureTableColumns(TableChooserDialog tableDialog) {
|
|
||||||
StringColumnDisplay distanceColumn = new StringColumnDisplay() {
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Dist bet ptrs";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
|
||||||
Table table = (Table) rowObject;
|
|
||||||
return Long.toString(table.getDistance());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
|
|
||||||
Table table1 = (Table) o1;
|
|
||||||
Table table2 = (Table) o2;
|
|
||||||
return (int) (table1.getDistance() - table2.getDistance());
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
StringColumnDisplay numberOfPointersColumn = new StringColumnDisplay() {
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Num ptrs";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
|
||||||
Table table = (Table) rowObject;
|
|
||||||
return Long.toString(table.getNumPointers());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
|
|
||||||
Table table1 = (Table) o1;
|
|
||||||
Table table2 = (Table) o2;
|
|
||||||
return table1.getNumPointers() - table2.getNumPointers();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
StringColumnDisplay referenceFoundColumn = new StringColumnDisplay() {
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Ref found";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
|
||||||
Table table = (Table) rowObject;
|
|
||||||
if (table.getRef() != null) {
|
|
||||||
return " at " + table.getRef();
|
|
||||||
}
|
|
||||||
return "No";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ColumnDisplay<Address> secondAddressColumn =
|
|
||||||
new AbstractComparableColumnDisplay<Address>() {
|
|
||||||
@Override
|
|
||||||
public String getColumnName() {
|
|
||||||
return "Offset Address";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getColumnValue(AddressableRowObject rowObject) {
|
|
||||||
Table table = (Table) rowObject;
|
|
||||||
return table.getAddress().add(100);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tableDialog.addCustomColumn(distanceColumn);
|
|
||||||
tableDialog.addCustomColumn(secondAddressColumn);
|
|
||||||
tableDialog.addCustomColumn(numberOfPointersColumn);
|
|
||||||
tableDialog.addCustomColumn(referenceFoundColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TableChooserExecutor createTableExecutor() {
|
|
||||||
TableChooserExecutor executor = new TableChooserExecutor() {
|
|
||||||
@Override
|
|
||||||
public String getButtonName() {
|
|
||||||
return "Hit Me";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean execute(AddressableRowObject rowObject) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the first ref starting at topAddr and working back dist - pointersize
|
|
||||||
// once a ref is found, stop - it doesn't make much sense that there would be more than one.
|
|
||||||
Address findRef(Address topAddress, long dist) {
|
|
||||||
|
|
||||||
Memory memory = currentProgram.getMemory();
|
|
||||||
Address ref = null;
|
|
||||||
|
|
||||||
//change later to handle 64 bits too
|
|
||||||
byte[] maskBytes = new byte[4];
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
maskBytes[i] = (byte) 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search memory for the byte patterns within the range of topAddr and topAddr - dist
|
|
||||||
// make a structure of found bytes/topAddr offset????
|
|
||||||
boolean noRefFound = true;
|
|
||||||
boolean tryPrevAddr = true;
|
|
||||||
long longIndex = 0;
|
|
||||||
while (noRefFound && tryPrevAddr) {
|
|
||||||
Address testAddr = topAddress.subtract(longIndex);
|
|
||||||
byte[] addressBytes = turnAddressIntoBytes(testAddr);
|
|
||||||
|
|
||||||
//println("TestAddr = " + testAddr.toString());
|
|
||||||
Address found = memory.findBytes(currentProgram.getMinAddress(), addressBytes,
|
|
||||||
maskBytes, true, monitor);
|
|
||||||
if (found != null) {
|
|
||||||
ref = found;
|
|
||||||
// println("Found ref at " + found.toString());
|
|
||||||
noRefFound = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
longIndex++;
|
|
||||||
// check to see if we are at the top of the range of possible refs
|
|
||||||
if (longIndex > (dist - 4)) {// change the four to pointer size when I add 64bit
|
|
||||||
tryPrevAddr = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] turnAddressIntoBytes(Address addr) {
|
|
||||||
// turn addresses into bytes
|
|
||||||
|
|
||||||
byte[] addressBytes = new byte[4]; // only 32-bit for now - change later to add 64 bit
|
|
||||||
// This is the correct way to do turn a long into an address
|
|
||||||
long addrLong = addr.getOffset();
|
|
||||||
|
|
||||||
int endian = getEndian();
|
|
||||||
|
|
||||||
if (endian == BIG_ENDIAN) {
|
|
||||||
// put bytes in forward order
|
|
||||||
addressBytes = bytesForward(addrLong);
|
|
||||||
}
|
|
||||||
else if (endian == LITTLE_ENDIAN) {
|
|
||||||
// put bytes in reverse order
|
|
||||||
addressBytes = bytesReversed(addrLong);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println("Unknown endian - cannot find references.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addressBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytesForward(long addr) {
|
|
||||||
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
bytes[i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytesReversed(long addr) {
|
|
||||||
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
|
|
||||||
for (int i = 3; i >= 0; i--) {
|
|
||||||
bytes[3 - i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find references to the possible table
|
|
||||||
// start looking at the top of the array and work back the distance between the pointers in
|
|
||||||
// the table
|
|
||||||
// Address [] findReferenceToTable(Address topAddress, long dist){
|
|
||||||
//
|
|
||||||
// ArrayList<Address> foundAddrs = new ArrayList<Address>();
|
|
||||||
// long counter = 0;
|
|
||||||
// while((foundAddrs.size() == 0) || (counter == (dist-1))){
|
|
||||||
// List<Address> newList = findReferences(topAddress.subtract(dist-counter));
|
|
||||||
// for(int i=0;i<newList.size();i++){
|
|
||||||
// Address a = (Address)newList.get(i);
|
|
||||||
// foundAddrs.add(a);
|
|
||||||
// }
|
|
||||||
// counter++;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return (Address[]) foundAddrs.toArray();
|
|
||||||
// }
|
|
||||||
|
|
||||||
//public List<Address> findReferences(Address addr){
|
|
||||||
// FindPossibleReferences fpr = new FindPossibleReferences(currentProgram,getEndian());
|
|
||||||
// return fpr.findReferences(addr);
|
|
||||||
//}
|
|
||||||
|
|
||||||
public int getEndian() {
|
|
||||||
|
|
||||||
if (currentProgram.getLanguage().isBigEndian()) {
|
|
||||||
return 1; // BIG_ENDIAN
|
|
||||||
}
|
|
||||||
return 0; // LITTLE_ENDIAN
|
|
||||||
}
|
|
||||||
|
|
||||||
// info about the pushed parameter that gets applied to the calling functions params and locals and referenced data
|
|
||||||
class PossiblePtrs {
|
|
||||||
|
|
||||||
private Address addrOfPtr;
|
|
||||||
private Address possiblePtr;
|
|
||||||
private long distanceFromLast;
|
|
||||||
|
|
||||||
PossiblePtrs(Address addrOfPtr, Address possiblePtr, long distanceFromLast) {
|
|
||||||
|
|
||||||
this.addrOfPtr = addrOfPtr;
|
|
||||||
this.possiblePtr = possiblePtr;
|
|
||||||
this.distanceFromLast = distanceFromLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getAddrOfPtr() {
|
|
||||||
return addrOfPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getPossiblePointer() {
|
|
||||||
return possiblePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getDistanceFromLast() {
|
|
||||||
return distanceFromLast;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Table implements AddressableRowObject {
|
|
||||||
private Address topAddr;
|
|
||||||
private long distance;
|
|
||||||
private int numPointers;
|
|
||||||
Address ref;
|
|
||||||
|
|
||||||
Table(Address topAddr, long distance, int numPointers, Address ref) {
|
|
||||||
this.topAddr = topAddr;
|
|
||||||
this.distance = distance;
|
|
||||||
this.numPointers = numPointers;
|
|
||||||
this.ref = ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getAddress() {
|
|
||||||
return getTopAddr();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getTopAddr() {
|
|
||||||
return topAddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getDistance() {
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumPointers() {
|
|
||||||
return numPointers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getRef() {
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -75,7 +75,9 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
public String getColumnValue(AddressableRowObject rowObject) {
|
||||||
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
||||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
Function func = entry.getProgram()
|
||||||
|
.getFunctionManager()
|
||||||
|
.getFunctionContaining(
|
||||||
entry.getWhyAddr());
|
entry.getWhyAddr());
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -93,7 +95,9 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
public String getColumnValue(AddressableRowObject rowObject) {
|
||||||
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
||||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
Function func = entry.getProgram()
|
||||||
|
.getFunctionManager()
|
||||||
|
.getFunctionContaining(
|
||||||
entry.getAddress());
|
entry.getAddress());
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -148,17 +152,19 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
||||||
return "Fixup SharedReturn";
|
return "Fixup SharedReturn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useBulkTransaction() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(AddressableRowObject rowObject) {
|
public boolean execute(AddressableRowObject rowObject) {
|
||||||
SharedReturnLocations sharedRetLoc = (SharedReturnLocations) rowObject;
|
SharedReturnLocations sharedRetLoc = (SharedReturnLocations) rowObject;
|
||||||
System.out.println("Fixup Shared Return Jump at : " + rowObject.getAddress());
|
println("Fixup Shared Return Jump at : " + rowObject.getAddress());
|
||||||
|
|
||||||
Program cp = sharedRetLoc.getProgram();
|
Program cp = sharedRetLoc.getProgram();
|
||||||
Address entry = sharedRetLoc.getAddress();
|
Address entry = sharedRetLoc.getAddress();
|
||||||
|
|
||||||
// gonna change something, have to open a transaction
|
|
||||||
int trans = cp.startTransaction("Fixup Shared Return Jump at " + entry);
|
|
||||||
try {
|
|
||||||
addBookMark(cp, entry, "Shared Return Jump");
|
addBookMark(cp, entry, "Shared Return Jump");
|
||||||
|
|
||||||
if (!sharedRetLoc.getStatus().equals("fixed")) {
|
if (!sharedRetLoc.getStatus().equals("fixed")) {
|
||||||
|
@ -166,11 +172,6 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
|
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
|
||||||
}
|
|
||||||
finally {
|
|
||||||
cp.endTransaction(trans, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // don't remove row
|
return false; // don't remove row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,9 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
public String getColumnValue(AddressableRowObject rowObject) {
|
||||||
NoReturnLocations entry = (NoReturnLocations) rowObject;
|
NoReturnLocations entry = (NoReturnLocations) rowObject;
|
||||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
Function func = entry.getProgram()
|
||||||
|
.getFunctionManager()
|
||||||
|
.getFunctionContaining(
|
||||||
entry.getAddress());
|
entry.getAddress());
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -269,6 +271,11 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
||||||
return "Fixup NoReturn";
|
return "Fixup NoReturn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useBulkTransaction() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(AddressableRowObject rowObject) {
|
public boolean execute(AddressableRowObject rowObject) {
|
||||||
NoReturnLocations noRetLoc = (NoReturnLocations) rowObject;
|
NoReturnLocations noRetLoc = (NoReturnLocations) rowObject;
|
||||||
|
@ -283,9 +290,6 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gonna change something, have to open a transaction
|
|
||||||
int trans = cp.startTransaction("Fixup No Return at " + entry);
|
|
||||||
try {
|
|
||||||
addBookMark(cp, entry, "Non Returning Function");
|
addBookMark(cp, entry, "Non Returning Function");
|
||||||
|
|
||||||
if (!noRetLoc.isFixed()) {
|
if (!noRetLoc.isFixed()) {
|
||||||
|
@ -293,10 +297,6 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation());
|
addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation());
|
||||||
}
|
|
||||||
finally {
|
|
||||||
cp.endTransaction(trans, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // don't remove row
|
return false; // don't remove row
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,8 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
navigatable.addNavigatableListener(this);
|
navigatable.addNavigatableListener(this);
|
||||||
table.installNavigation(goToService, navigatable);
|
table.installNavigation(goToService, navigatable);
|
||||||
}
|
}
|
||||||
table.getSelectionModel().addListSelectionListener(
|
table.getSelectionModel()
|
||||||
|
.addListSelectionListener(
|
||||||
e -> setOkEnabled(table.getSelectedRowCount() > 0));
|
e -> setOkEnabled(table.getSelectedRowCount() > 0));
|
||||||
|
|
||||||
GhidraTableFilterPanel<AddressableRowObject> filterPanel =
|
GhidraTableFilterPanel<AddressableRowObject> filterPanel =
|
||||||
|
@ -241,7 +242,14 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
monitor.initialize(rowObjects.size());
|
monitor.initialize(rowObjects.size());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<AddressableRowObject> deleted = doProcessRowObjects(rowObjects, monitor);
|
List<AddressableRowObject> deleted;
|
||||||
|
if (executor.useBulkTransaction()) {
|
||||||
|
deleted = doProcessRowsInTransaction(rowObjects, monitor);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deleted = doProcessRows(rowObjects, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
for (AddressableRowObject rowObject : deleted) {
|
for (AddressableRowObject rowObject : deleted) {
|
||||||
model.removeObject(rowObject);
|
model.removeObject(rowObject);
|
||||||
}
|
}
|
||||||
|
@ -254,8 +262,9 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AddressableRowObject> doProcessRowObjects(List<AddressableRowObject> rowObjects,
|
private List<AddressableRowObject> doProcessRows(List<AddressableRowObject> rowObjects,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
|
|
||||||
List<AddressableRowObject> deleted = new ArrayList<>();
|
List<AddressableRowObject> deleted = new ArrayList<>();
|
||||||
for (AddressableRowObject rowObject : rowObjects) {
|
for (AddressableRowObject rowObject : rowObjects) {
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
|
@ -280,6 +289,18 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<AddressableRowObject> doProcessRowsInTransaction(
|
||||||
|
List<AddressableRowObject> rowObjects, TaskMonitor monitor) {
|
||||||
|
|
||||||
|
int tx = program.startTransaction("Table Chooser: " + getTitle());
|
||||||
|
try {
|
||||||
|
return doProcessRows(rowObjects, monitor);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(tx, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addCustomColumn(ColumnDisplay<?> columnDisplay) {
|
public void addCustomColumn(ColumnDisplay<?> columnDisplay) {
|
||||||
model.addCustomColumn(columnDisplay);
|
model.addCustomColumn(columnDisplay);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.tablechooser;
|
package ghidra.app.tablechooser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface clients must implement to use the {@link TableChooserDialog}. This class is the
|
||||||
|
* callback that is used to process items from the dialog's table as users select one or more
|
||||||
|
* rows in the table and then press the table's "apply" button.
|
||||||
|
*
|
||||||
|
* <P>See the notes on {@link #useBulkTransaction()}. We recommend you override that method to
|
||||||
|
* return true.
|
||||||
|
*/
|
||||||
public interface TableChooserExecutor {
|
public interface TableChooserExecutor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,4 +41,30 @@ public interface TableChooserExecutor {
|
||||||
* @return true if the rowObject should be removed from the table, false otherwise
|
* @return true if the rowObject should be removed from the table, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean execute(AddressableRowObject rowObject);
|
public boolean execute(AddressableRowObject rowObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When true, the calls to {@link #execute(AddressableRowObject)} will be wrapped in a
|
||||||
|
* transaction. This allows clients to not use transactions themselves. This can increase
|
||||||
|
* performance when the user selects a large number of rows in the table to be executed, as
|
||||||
|
* this API will only use on transaction for all rows, instead of one per row.
|
||||||
|
*
|
||||||
|
* <P>When true, this will use one transaction per button press of the
|
||||||
|
* {@link TableChooserDialog}. Thus, if the user only processes a single row per button
|
||||||
|
* press, then there is no performance gain over the traditional use of transactions.
|
||||||
|
*
|
||||||
|
* <P><B>We recommend clients override this method to return true</B>.
|
||||||
|
*
|
||||||
|
* <P>Note: when false is returned from this method, <b>no transaction is created before the
|
||||||
|
* call to {@link #execute(AddressableRowObject)}</b>--the client is responsible for
|
||||||
|
* transaction management in this case.
|
||||||
|
*
|
||||||
|
* <P>For backward compatibility, this method defaults to returning false. You must override
|
||||||
|
* this method to return true in your code to make use of the single bulk transaction.
|
||||||
|
*
|
||||||
|
* @return true to use bulk transactions; false to use no transaction at all when calling
|
||||||
|
* {@link #execute(AddressableRowObject)}; default is false
|
||||||
|
*/
|
||||||
|
public default boolean useBulkTransaction() {
|
||||||
|
return false; // false by default for backward compatibility
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,7 @@ import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.ReferenceIterator;
|
import ghidra.program.model.symbol.ReferenceIterator;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.*;
|
||||||
import ghidra.util.UndefinedFunction;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
@ -157,10 +156,9 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the configurable columns for the TableDialog. More columns could
|
* Builds the configurable columns for the TableDialog. More columns could be added.
|
||||||
* be added.
|
|
||||||
*
|
*
|
||||||
* @param tableChooserDialog
|
* @param tableChooserDialog the dialog
|
||||||
*/
|
*/
|
||||||
private void configureTableColumns(TableChooserDialog tableChooserDialog) {
|
private void configureTableColumns(TableChooserDialog tableChooserDialog) {
|
||||||
// First column added is the Constant value that is found.
|
// First column added is the Constant value that is found.
|
||||||
|
@ -254,7 +252,9 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
@Override
|
@Override
|
||||||
public String getColumnValue(AddressableRowObject rowObject) {
|
public String getColumnValue(AddressableRowObject rowObject) {
|
||||||
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
||||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
Function func = entry.getProgram()
|
||||||
|
.getFunctionManager()
|
||||||
|
.getFunctionContaining(
|
||||||
entry.getAddress());
|
entry.getAddress());
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -299,7 +299,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
* script by creating an artificial ScriptState. This is a useful technique
|
* script by creating an artificial ScriptState. This is a useful technique
|
||||||
* for other scripts as well.
|
* for other scripts as well.
|
||||||
*
|
*
|
||||||
* @return
|
* @return the executor
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private TableChooserExecutor createTableExecutor() {
|
private TableChooserExecutor createTableExecutor() {
|
||||||
|
@ -311,26 +311,22 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
return "Create Structure";
|
return "Create Structure";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useBulkTransaction() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(AddressableRowObject rowObject) {
|
public boolean execute(AddressableRowObject rowObject) {
|
||||||
ConstUseLocation constLoc = (ConstUseLocation) rowObject;
|
ConstUseLocation constLoc = (ConstUseLocation) rowObject;
|
||||||
System.out.println("Follow Structure : " + rowObject.getAddress());
|
println("Follow Structure : " + rowObject.getAddress());
|
||||||
|
|
||||||
Program cp = constLoc.getProgram();
|
Program cp = constLoc.getProgram();
|
||||||
Address entry = constLoc.getAddress();
|
Address entry = constLoc.getAddress();
|
||||||
|
|
||||||
// If we will change something in program, have to open a
|
println("Create Structure at " + entry);
|
||||||
// transaction
|
|
||||||
int trans = cp.startTransaction("Run Script" + entry);
|
|
||||||
try {
|
|
||||||
System.out.println("Create Structure at " + entry);
|
|
||||||
|
|
||||||
runScript("CreateStructure.java", cp, entry);
|
runScript("CreateStructure.java", cp, entry);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
cp.endTransaction(trans, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // don't remove row from display table
|
return false; // don't remove row from display table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +343,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exc) {
|
catch (Exception exc) {
|
||||||
exc.printStackTrace();
|
Msg.error(this, "Exception running script", exc);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Script does not exist: " + name);
|
throw new IllegalArgumentException("Script does not exist: " + name);
|
||||||
}
|
}
|
||||||
|
@ -393,7 +389,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
* decompiler. In the decompiler this could be a local/parameter at any
|
* decompiler. In the decompiler this could be a local/parameter at any
|
||||||
* point in the decompiler. In the listing, it must be a parameter variable.
|
* point in the decompiler. In the listing, it must be a parameter variable.
|
||||||
*
|
*
|
||||||
* @return
|
* @return the varnode
|
||||||
*/
|
*/
|
||||||
private Varnode getVarnodeLocation() {
|
private Varnode getVarnodeLocation() {
|
||||||
Varnode var = null;
|
Varnode var = null;
|
||||||
|
@ -559,7 +555,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
* - accumulate entries. Don't like passing it, but this way the
|
* - accumulate entries. Don't like passing it, but this way the
|
||||||
* user gets immediate feedback as locations are found
|
* user gets immediate feedback as locations are found
|
||||||
* @return a map of Addresses->constants (constants could be NULL)
|
* @return a map of Addresses->constants (constants could be NULL)
|
||||||
* @throws CancelledException
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private HashMap<Address, Long> backtrackToConstant(Varnode var,
|
private HashMap<Address, Long> backtrackToConstant(Varnode var,
|
||||||
TableChooserDialog tableChooserDialog) throws CancelledException {
|
TableChooserDialog tableChooserDialog) throws CancelledException {
|
||||||
|
@ -587,15 +583,12 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
* Backtrack to a constant given a start position of a parameter of a given
|
* Backtrack to a constant given a start position of a parameter of a given
|
||||||
* function Useful if you want to start from a function paramter.
|
* function Useful if you want to start from a function paramter.
|
||||||
*
|
*
|
||||||
* @param f
|
* @param f function to start in
|
||||||
* - function to start in
|
* @param paramIndex parameter index to backtrack from
|
||||||
* @param paramIndex
|
* @param tableChooserDialog accumulate entries. Don't like passing it, but this way the
|
||||||
* - parameter index to backtrack from
|
|
||||||
* @param tableChooserDialog
|
|
||||||
* - accumulate entries. Don't like passing it, but this way the
|
|
||||||
* user gets immediate feedback as locations are found
|
* user gets immediate feedback as locations are found
|
||||||
* @return a map of Addresses->constants (constants could be NULL)
|
* @return a map of Addresses to constants (constants could be NULL)
|
||||||
* @throws CancelledException
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private HashMap<Address, Long> backtrackParamToConstant(Function f, int paramIndex,
|
private HashMap<Address, Long> backtrackParamToConstant(Function f, int paramIndex,
|
||||||
TableChooserDialog tableChooserDialog) throws CancelledException {
|
TableChooserDialog tableChooserDialog) throws CancelledException {
|
||||||
|
@ -699,14 +692,7 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
this.addConstantProblem(tableDialog, address, problem);
|
this.addConstantProblem(tableDialog, address, problem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
|
||||||
* Analyze a functions references
|
|
||||||
*
|
|
||||||
* @param constUse
|
|
||||||
* @param funcVarUse
|
|
||||||
* @param funcList
|
|
||||||
*/
|
|
||||||
public void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
|
|
||||||
Program prog, Function f, Address refAddr, FunctionParamUse funcVarUse, int paramIndex,
|
Program prog, Function f, Address refAddr, FunctionParamUse funcVarUse, int paramIndex,
|
||||||
ArrayList<PcodeOp> defUseList, ArrayList<FunctionParamUse> funcList) {
|
ArrayList<PcodeOp> defUseList, ArrayList<FunctionParamUse> funcList) {
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
|
@ -722,12 +708,9 @@ public class ShowConstantUse extends GhidraScript {
|
||||||
Iterator<PcodeOpAST> ops = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
Iterator<PcodeOpAST> ops = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
||||||
while (ops.hasNext() && !monitor.isCancelled()) {
|
while (ops.hasNext() && !monitor.isCancelled()) {
|
||||||
PcodeOpAST pcodeOpAST = ops.next();
|
PcodeOpAST pcodeOpAST = ops.next();
|
||||||
// System.out.println(pcodeOpAST);
|
|
||||||
if (pcodeOpAST.getOpcode() == PcodeOp.CALL) {
|
if (pcodeOpAST.getOpcode() == PcodeOp.CALL) {
|
||||||
// get the second parameter
|
// get the second parameter
|
||||||
Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param
|
Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param is the call dest
|
||||||
// is the
|
|
||||||
// call dest
|
|
||||||
if (parm == null) {
|
if (parm == null) {
|
||||||
constUse.put(instr.getAddress(), null);
|
constUse.put(instr.getAddress(), null);
|
||||||
String problem = " *** Warning, it appears that function '" +
|
String problem = " *** Warning, it appears that function '" +
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue