mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Added extensions GnuDisassembler and SleighDevTools
This commit is contained in:
parent
cdbe651627
commit
a15c70950f
43 changed files with 2349 additions and 22 deletions
|
@ -0,0 +1,320 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Compare Sliegh disassembly with external disassembly results
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.PseudoInstruction;
|
||||
import ghidra.app.util.disassemble.GNUExternalDisassembler;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.UnknownInstructionException;
|
||||
import ghidra.program.model.listing.BookmarkType;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
public class CompareSleighExternal extends GhidraScript {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (currentProgram == null) {
|
||||
return;
|
||||
}
|
||||
AddressSetView set = currentSelection;
|
||||
if (set == null || set.isEmpty()) {
|
||||
set = currentProgram.getMemory().getLoadedAndInitializedAddressSet();
|
||||
}
|
||||
|
||||
putEquivalent("xzr", "x31"); // Think they messed up and allowed x31, there is no x31
|
||||
putEquivalent("wzr", "w31"); // Think they messed up and allowed w31, there is no w31
|
||||
putEquivalent("r12", "ip");
|
||||
|
||||
int completed = 0;
|
||||
monitor.initialize(set.getNumAddresses());
|
||||
|
||||
AddressIterator addresses = set.getAddresses(true);
|
||||
|
||||
PseudoDisassembler pseudoDisassembler = new PseudoDisassembler(currentProgram);
|
||||
|
||||
GNUExternalDisassembler dis = new GNUExternalDisassembler();
|
||||
|
||||
long align = currentProgram.getLanguage().getInstructionAlignment();
|
||||
while (addresses.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Address addr = addresses.next();
|
||||
|
||||
completed++;
|
||||
|
||||
// only on valid boundaries
|
||||
if ((addr.getOffset() % align) != 0) {
|
||||
continue;
|
||||
}
|
||||
clearBad(addr);
|
||||
|
||||
monitor.setProgress(completed);
|
||||
|
||||
CodeUnit cu = currentProgram.getListing().getCodeUnitAt(addr);
|
||||
if (cu == null) {
|
||||
continue;
|
||||
}
|
||||
String str = dis.getDisassembly(cu);
|
||||
|
||||
str = str.toLowerCase();
|
||||
|
||||
PseudoInstruction pinst = null;
|
||||
try {
|
||||
pinst = pseudoDisassembler.disassemble(addr);
|
||||
} catch (UnknownInstructionException e) {
|
||||
// didn't get an instruction, did external not get one?
|
||||
if (str.startsWith(".inst") && str.endsWith("undefined")) {
|
||||
continue;
|
||||
}
|
||||
markErrorBad(addr,"Unimplemented Instruction", str);
|
||||
continue;
|
||||
}
|
||||
// didn't get an instruction, did external not get one?
|
||||
if (pinst == null && str.startsWith(".inst") && str.endsWith("undefined")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pinst == null) {
|
||||
markErrorBad(addr,"Unimplemented Instruction", str);
|
||||
continue;
|
||||
}
|
||||
|
||||
// collapse both instruction to strings, compare removing whitespace, and to-lower
|
||||
String pStr = pinst.toString().toLowerCase().replaceAll("\\s","");
|
||||
String eStr = str.toLowerCase().replaceAll("\\s", "");
|
||||
|
||||
// simple equivalence
|
||||
if (pStr.equals(eStr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String mnemonic = pinst.getMnemonicString().toLowerCase();
|
||||
if (!str.startsWith(mnemonic)) {
|
||||
markBad(addr,"Mnemonic Disagreement", str + " != " + mnemonic);
|
||||
continue;
|
||||
}
|
||||
|
||||
int start = str.indexOf(" ");
|
||||
|
||||
for (int opIndex = 0; opIndex < pinst.getNumOperands(); opIndex++) {
|
||||
// try to parse the operand string from the instruction
|
||||
int sepEnd = str.indexOf(",", start);
|
||||
|
||||
String extOp = getExtOpStr(str, start, sepEnd);
|
||||
start = sepEnd + 1;
|
||||
|
||||
String valStr = null;
|
||||
|
||||
// TODO: could remove all characters, making sure none are left!
|
||||
int loc = 0;
|
||||
boolean subRegList = false;
|
||||
List<Object> opObjList = pinst.getDefaultOperandRepresentationList(opIndex);
|
||||
for (Object object : opObjList) {
|
||||
if (object instanceof Character) {
|
||||
Character ch = (Character) object;
|
||||
ch = Character.toLowerCase(ch);
|
||||
loc = extOp.indexOf(ch);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+1);
|
||||
continue;
|
||||
}
|
||||
if (ch.equals(',')) {
|
||||
if (subRegList) {
|
||||
continue;
|
||||
}
|
||||
// gotta move into next string, must be embedded comma
|
||||
sepEnd = str.indexOf(",", start);
|
||||
|
||||
extOp = getExtOpStr(str, start, sepEnd);
|
||||
start = sepEnd + 1;
|
||||
continue;
|
||||
}
|
||||
if (ch.equals(' ')) {
|
||||
continue;
|
||||
}
|
||||
markBad(addr,"Missing String Markup", ch.toString());
|
||||
break;
|
||||
}
|
||||
if (object instanceof Scalar) {
|
||||
// find the scalar, hex or decimal
|
||||
Scalar scalar = (Scalar) object;
|
||||
valStr = scalar.toString(16, false, false, "0x", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = scalar.toString(16, true, false, "0x", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = scalar.toString(10, false, true, "", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = scalar.toString(10, false, false, "", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = scalar.toString(16, false, false, "", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = scalar.toString(16, true, false, "", "");
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
markBad(addr,"Missing Scalar", valStr);
|
||||
break;
|
||||
}
|
||||
if (object instanceof Register) {
|
||||
Register reg = (Register) object;
|
||||
loc = extOp.indexOf(reg.getName().toLowerCase());
|
||||
if (loc != -1) {
|
||||
// check for '-' first
|
||||
if (extOp.charAt(0) == '-') {
|
||||
extOp = extOp.substring(1);
|
||||
loc = 0;
|
||||
subRegList = false;
|
||||
}
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+reg.getName().length());
|
||||
if (extOp.length() > 0 && extOp.charAt(0) == '-') {
|
||||
subRegList = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for equivalent register
|
||||
String equivReg = regGetEquivalent(reg.getName());
|
||||
if (equivReg != null) {
|
||||
loc = extOp.indexOf(equivReg);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+equivReg.length());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
loc = extOp.indexOf('-'); // could be a register list, assume we will find beginning and end register
|
||||
if (loc != -1) {
|
||||
continue;
|
||||
}
|
||||
markBad(addr,"Missing Register", reg.toString());
|
||||
break;
|
||||
}
|
||||
if (object instanceof Address) {
|
||||
Address dest = (Address) object;
|
||||
valStr = dest.toString(false,true);
|
||||
valStr = "0x" + valStr;
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = dest.toString(false,false);
|
||||
valStr = "0x" + valStr;
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = dest.toString(false,true);
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
valStr = dest.toString(false,false);
|
||||
loc = extOp.indexOf(valStr);
|
||||
if (loc != -1) {
|
||||
extOp = extOp.substring(0,loc) + extOp.substring(loc+valStr.length());
|
||||
continue;
|
||||
}
|
||||
markBad(addr,"Missing Address", dest.toString());
|
||||
}
|
||||
}
|
||||
extOp = extOp.trim();
|
||||
if (extOp.length() > 0 && !extOp.startsWith(";") && !extOp.startsWith("//") && !extOp.equals("#") && !extOp.matches("[0x]+")) {
|
||||
markBad(addr,"Missing characters", extOp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HashMap<String, String> equivRegisters = new HashMap<String, String>();
|
||||
|
||||
private String regGetEquivalent(String name) {
|
||||
return equivRegisters.get(name);
|
||||
}
|
||||
|
||||
private void putEquivalent(String name, String equiv) {
|
||||
equivRegisters.put(name, equiv);
|
||||
}
|
||||
|
||||
private String getExtOpStr(String str, int start, int sepEnd) {
|
||||
String opS = null;
|
||||
if (start == -1) {
|
||||
return "";
|
||||
}
|
||||
if (sepEnd == -1) {
|
||||
opS = str.substring(start);
|
||||
} else {
|
||||
opS = str.substring(start, sepEnd);
|
||||
}
|
||||
String extOp = opS.trim();
|
||||
return extOp;
|
||||
}
|
||||
|
||||
private void markBad(Address addr, String type, String error) {
|
||||
currentProgram.getBookmarkManager().setBookmark(addr, BookmarkType.WARNING,
|
||||
type,
|
||||
error);
|
||||
}
|
||||
|
||||
private void markErrorBad(Address addr, String type, String error) {
|
||||
currentProgram.getBookmarkManager().setBookmark(addr, BookmarkType.ERROR,
|
||||
Disassembler.ERROR_BOOKMARK_CATEGORY,
|
||||
error);
|
||||
}
|
||||
|
||||
private void clearBad(Address addr) {
|
||||
AddressSet set = new AddressSet(addr);
|
||||
try {
|
||||
currentProgram.getBookmarkManager().removeBookmarks(set, BookmarkType.WARNING, monitor);
|
||||
currentProgram.getBookmarkManager().removeBookmarks(set, BookmarkType.ERROR, monitor);
|
||||
} catch (CancelledException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue