Unverified Commit 0c38cac5 by Melvin Klimke Committed by GitHub

Add fall through branch to cbranch (#108)

parent 57b92dba
...@@ -14,6 +14,7 @@ import org.apache.commons.lang3.EnumUtils; ...@@ -14,6 +14,7 @@ import org.apache.commons.lang3.EnumUtils;
import bil.*; import bil.*;
import term.*; import term.*;
import internal.*; import internal.*;
import internal.PcodeBlockData;
import symbol.ExternSymbol; import symbol.ExternSymbol;
import serializer.Serializer; import serializer.Serializer;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
...@@ -193,7 +194,7 @@ public class PcodeExtractor extends GhidraScript { ...@@ -193,7 +194,7 @@ public class PcodeExtractor extends GhidraScript {
String destinationAddress = getGotoAddressForDestination(currentBlock); String destinationAddress = getGotoAddressForDestination(currentBlock);
if(destinationAddress != null) { if(destinationAddress != null) {
String instrAddress = lastBlockTerm.getTerm().getDefs().get(lastBlockTerm.getTerm().getDefs().size()-1).getTid().getAddress(); String instrAddress = lastBlockTerm.getTerm().getDefs().get(lastBlockTerm.getTerm().getDefs().size()-1).getTid().getAddress();
addJumpToCurrentBlock(lastBlockTerm.getTerm(), instrAddress, destinationAddress, null); addBranchToCurrentBlock(lastBlockTerm.getTerm(), instrAddress, destinationAddress);
} }
} }
} }
...@@ -289,7 +290,7 @@ public class PcodeExtractor extends GhidraScript { ...@@ -289,7 +290,7 @@ public class PcodeExtractor extends GhidraScript {
return; return;
} }
if(PcodeBlockData.ops.length == 0) { if(PcodeBlockData.ops.length == 0) {
addJumpToCurrentBlock(PcodeBlockData.blocks.get(PcodeBlockData.blocks.size()-1).getTerm(), PcodeBlockData.instruction.getAddress().toString(), PcodeBlockData.instruction.getFallThrough().toString(), null); addBranchToCurrentBlock(PcodeBlockData.blocks.get(PcodeBlockData.blocks.size()-1).getTerm(), PcodeBlockData.instruction.getAddress().toString(), PcodeBlockData.instruction.getFallThrough().toString());
if(PcodeBlockData.instructionIndex < PcodeBlockData.numberOfInstructionsInBlock - 1) { if(PcodeBlockData.instructionIndex < PcodeBlockData.numberOfInstructionsInBlock - 1) {
PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null)); PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null));
} }
...@@ -316,14 +317,16 @@ public class PcodeExtractor extends GhidraScript { ...@@ -316,14 +317,16 @@ public class PcodeExtractor extends GhidraScript {
protected Boolean iteratePcode() { protected Boolean iteratePcode() {
int numberOfPcodeOps = PcodeBlockData.ops.length; int numberOfPcodeOps = PcodeBlockData.ops.length;
Boolean intraInstructionJumpOccured = false; Boolean intraInstructionJumpOccured = false;
for(int pcodeIndex = 0; pcodeIndex < numberOfPcodeOps; pcodeIndex++) { PcodeBlockData.pcodeIndex = 0;
PcodeOp pcodeOp = PcodeBlockData.ops[pcodeIndex]; for(PcodeOp op : PcodeBlockData.ops) {
String mnemonic = pcodeOp.getMnemonic(); PcodeBlockData.pcodeOp = op;
if (this.jumps.contains(mnemonic) || pcodeOp.getOpcode() == PcodeOp.UNIMPLEMENTED) { String mnemonic = PcodeBlockData.pcodeOp.getMnemonic();
intraInstructionJumpOccured = processJump(pcodeOp, mnemonic, numberOfPcodeOps, pcodeIndex, intraInstructionJumpOccured); if (this.jumps.contains(mnemonic) || PcodeBlockData.pcodeOp.getOpcode() == PcodeOp.UNIMPLEMENTED) {
intraInstructionJumpOccured = processJump(mnemonic, numberOfPcodeOps);
} else { } else {
PcodeBlockData.temporaryDefStorage.add(createDefTerm(pcodeIndex, pcodeOp)); PcodeBlockData.temporaryDefStorage.add(createDefTerm());
} }
PcodeBlockData.pcodeIndex++;
} }
return intraInstructionJumpOccured; return intraInstructionJumpOccured;
...@@ -355,7 +358,7 @@ public class PcodeExtractor extends GhidraScript { ...@@ -355,7 +358,7 @@ public class PcodeExtractor extends GhidraScript {
*/ */
protected void addMissingJumpAfterInstructionSplit(Term<Blk> lastBlock) { protected void addMissingJumpAfterInstructionSplit(Term<Blk> lastBlock) {
lastBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage); lastBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage);
addJumpToCurrentBlock(lastBlock.getTerm(), PcodeBlockData.instruction.getAddress().toString(), PcodeBlockData.instruction.getFallThrough().toString(), null); addBranchToCurrentBlock(lastBlock.getTerm(), PcodeBlockData.instruction.getAddress().toString(), PcodeBlockData.instruction.getFallThrough().toString());
PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null)); PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null));
PcodeBlockData.temporaryDefStorage.clear(); PcodeBlockData.temporaryDefStorage.clear();
} }
...@@ -363,84 +366,69 @@ public class PcodeExtractor extends GhidraScript { ...@@ -363,84 +366,69 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param pcodeOp: pcode instruction
* @param mnemonic: pcode mnemonic * @param mnemonic: pcode mnemonic
* @param numberOfPcodeOps: number of pcode instruction in pcode block * @param numberOfPcodeOps: number of pcode instruction in pcode block
* @param pcodeIndex: index of current pcode instruction
* @param intraInstructionJumpOccured: indicator whether a jump occured inside a pcode block
* @return: indicator whether a jump occured inside a pcode block * @return: indicator whether a jump occured inside a pcode block
* *
* Processes jump pcode instruction by checking where it occurs. * Processes jump pcode instruction by checking where it occurs.
* Distinguishes between jumps inside a pcode block and jumps at the end of a pcode block * Distinguishes between jumps inside a pcode block and jumps at the end of a pcode block
*/ */
protected Boolean processJump(PcodeOp pcodeOp, String mnemonic, int numberOfPcodeOps, int pcodeIndex, Boolean intraInstructionJumpOccured) { protected Boolean processJump(String mnemonic, int numberOfPcodeOps) {
int currentBlockCount = PcodeBlockData.blocks.size(); Term<Blk> currentBlock = PcodeBlockData.blocks.get(PcodeBlockData.blocks.size() - 1);
Term<Blk> currentBlock = PcodeBlockData.blocks.get(currentBlockCount - 1);
if(pcodeIndex < numberOfPcodeOps - 1) { if(PcodeBlockData.pcodeIndex < numberOfPcodeOps - 1) {
intraInstructionJumpOccured = processJumpInPcodeBlock(pcodeOp, mnemonic, numberOfPcodeOps, pcodeIndex, intraInstructionJumpOccured, currentBlock); return processJumpInPcodeBlock(mnemonic, numberOfPcodeOps, currentBlock);
PcodeBlockData.temporaryDefStorage.clear();
} else {
intraInstructionJumpOccured = processJumpAtEndOfPcodeBlocks(pcodeOp, mnemonic, numberOfPcodeOps, pcodeIndex, intraInstructionJumpOccured, currentBlock);
} }
return intraInstructionJumpOccured; processJumpAtEndOfPcodeBlocks(mnemonic, numberOfPcodeOps, currentBlock);
return false;
} }
/** /**
* *
* @param pcodeOp: pcode instruction
* @param mnemonic: pcode mnemonic * @param mnemonic: pcode mnemonic
* @param numberOfPcodeOps: number of pcode instruction in pcode block * @param numberOfPcodeOps: number of pcode instruction in pcode block
* @param pcodeIndex: index of current pcode instruction
* @param intraInstructionJumpOccured: indicator whether a jump occured inside a pcode block
* @param currentBlock: current block term * @param currentBlock: current block term
* @return: indicator whether a jump occured inside a pcode block
* *
* Process jumps at the end of pcode blocks * Process jumps at the end of pcode blocks
* If it is a return block, the call return address is changed to the current block * If it is a return block, the call return address is changed to the current block
*/ */
protected Boolean processJumpAtEndOfPcodeBlocks(PcodeOp pcodeOp, String mnemonic, int numberOfPcodeOps, int pcodeIndex, Boolean intraInstructionJumpOccured, Term<Blk> currentBlock) { protected void processJumpAtEndOfPcodeBlocks(String mnemonic, int numberOfPcodeOps, Term<Blk> currentBlock) {
intraInstructionJumpOccured = false; // Case 1: jump at the end of pcode group but not end of ghidra generated block. Create a block for the next assembly instruction.
// Case 2: jump at the end of pcode group but not end of ghidra generated block.
if(PcodeBlockData.instructionIndex < PcodeBlockData.numberOfInstructionsInBlock - 1 && PcodeBlockData.instruction.getDelaySlotDepth() == 0) { if(PcodeBlockData.instructionIndex < PcodeBlockData.numberOfInstructionsInBlock - 1 && PcodeBlockData.instruction.getDelaySlotDepth() == 0) {
PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null)); PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getFallThrough().toString(), null));
} }
// Case 3: jmp at last pcode op at last instruction in ghidra generated block // Case 2: jmp at last pcode op at last instruction in ghidra generated block
// If Case 2 is true, the 'currentBlk' will be the second to last block as the new block is for the next instruction // If Case 1 is true, the 'currentBlk' will be the second to last block as the new block is for the next instruction
if(pcodeOp.getOpcode() == PcodeOp.RETURN && currentBlock.getTid().getId().endsWith("_r")) { if(PcodeBlockData.pcodeOp.getOpcode() == PcodeOp.RETURN && currentBlock.getTid().getId().endsWith("_r")) {
redirectCallReturn(currentBlock, pcodeOp); redirectCallReturn(currentBlock);
return intraInstructionJumpOccured;
} }
currentBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage); currentBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage);
currentBlock.getTerm().addJmp(createJmpTerm(pcodeIndex, pcodeOp, mnemonic)); currentBlock.getTerm().addMultipleJumps(createJmpTerm(false));
PcodeBlockData.temporaryDefStorage.clear(); PcodeBlockData.temporaryDefStorage.clear();
return intraInstructionJumpOccured;
} }
/** /**
* *
* @param pcodeOp: pcode instruction
* @param mnemonic: pcode mnemonic * @param mnemonic: pcode mnemonic
* @param numberOfPcodeOps: number of pcode instruction in pcode block * @param numberOfPcodeOps: number of pcode instruction in pcode block
* @param pcodeIndex: index of current pcode instruction
* @param intraInstructionJumpOccured: indicator whether a jump occured inside a pcode block
* @param currentBlock: current block term * @param currentBlock: current block term
* @return: indicator whether a jump occured inside a pcode block * @return: indicator whether a jump occured inside a pcode block
* *
* Processes a jump inside a pcode block and distinguishes between intra jumps and call return pairs. * Processes a jump inside a pcode block and distinguishes between intra jumps and call return pairs.
*/ */
protected Boolean processJumpInPcodeBlock(PcodeOp pcodeOp, String mnemonic, int numberOfPcodeOps, int pcodeIndex, Boolean intraInstructionJumpOccured, Term<Blk> currentBlock) { protected Boolean processJumpInPcodeBlock(String mnemonic, int numberOfPcodeOps, Term<Blk> currentBlock) {
if(!isCall(pcodeOp)) { Boolean intraInstructionJumpOccured = false;
if(!isCall()) {
intraInstructionJumpOccured = true; intraInstructionJumpOccured = true;
handleIntraInstructionJump(currentBlock.getTerm(), pcodeOp, pcodeIndex); handleIntraInstructionJump(currentBlock.getTerm());
} else { } else {
handleCallReturnPair(currentBlock, pcodeOp, pcodeIndex); handleCallReturnPair(currentBlock);
} }
PcodeBlockData.temporaryDefStorage.clear();
return intraInstructionJumpOccured; return intraInstructionJumpOccured;
} }
...@@ -449,72 +437,93 @@ public class PcodeExtractor extends GhidraScript { ...@@ -449,72 +437,93 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param currentBlock: current block term * @param currentBlock: current block term
* @param pcodeOp: pcode instruction
* @param pcodeIndex: index of current pcode instruction
* *
* Adds an artificial jump to the previous block if an intra jump occurs and creates a new block. * Adds an artificial jump from the previous instructions to the current instruction if an intra jump occurs.
* This is done to isolate the current defs and jumps in an exclusive block.
* The Jump is not added if the instruction is the first of the subroutine or if no defs and jumps have been added yet.
* This might be the case when the current instruction is only preceded by a nop instruction.
*
* In case an artificial jump has to be added, a new block has to be created for the instruction with the intra jump so that
* the previous jump has a valid target TID.
*
* e.g. This example shows one basic block generated by Ghidra which split into 4 basic blocks for proper analysis.
* It also includes the case where a jump from the previous assembly instruction had to be added.
* Each individual assembly instruction is denoted with the [In] keyword and blocks are separated by dashed lines.
* Keep in mind that the target rows for the branches are only placeholders for the actual target TIDs.
*
* 1. [In] ... ...
* 2. RDI = COPY RDX RDI = COPY RDX
* 3. BRANCH [row 5.]
* 4. ---------------
* 5. [In] $U2360:1 = INT_EQUAL RCX, 0:8 $U2360:1 = INT_EQUAL RCX, 0:8
* 6. CBRANCH *[ram]0x1006e1:8, $U2360 CBRANCH *[ram]0x1006e1:8, $U2360
* 7. BRANCH [row 9.]
* 8. ---------------
* 9. RCX = INT_SUB RCX, 1:8 RCX = INT_SUB RCX, 1:8
* 10. ... ----> ...
* 11. $U2380:1 = BOOL_NEGATE ZF $U2380:1 = BOOL_NEGATE ZF
* 11. CBRANCH *[ram]0x1006df:8, $U2380 CBRANCH *[ram]0x1006df:8, $U2380
* 12. BRANCH [row 14.]
* 13. ---------------
* 14. [In] RAX = COPY RCX RAX = COPY RCX
* 15. ... ...
*/ */
protected void handleIntraInstructionJump(Blk currentBlock, PcodeOp pcodeOp, int pcodeIndex) { protected void handleIntraInstructionJump(Blk currentBlock) {
if(PcodeBlockData.instructionIndex > 0 && !(currentBlock.getDefs().size() == 0 && currentBlock.getJmps().size() == 0)) { if(PcodeBlockData.instructionIndex > 0 && !(currentBlock.getDefs().size() == 0 && currentBlock.getJmps().size() == 0)) {
jumpFromPreviousInstructionToNewBlock(currentBlock, pcodeOp, pcodeIndex); addBranchToCurrentBlock(currentBlock, PcodeBlockData.instruction.getFallFrom().toString(), PcodeBlockData.instruction.getAddress().toString());
createNewBlockForIntraInstructionJump();
} else { } else {
currentBlock.addMultipleDefs(PcodeBlockData.temporaryDefStorage); currentBlock.addMultipleDefs(PcodeBlockData.temporaryDefStorage);
currentBlock.addJmp(createJmpTerm(pcodeIndex, pcodeOp, pcodeOp.getMnemonic())); currentBlock.addMultipleJumps(createJmpTerm(true));
}
// Create block for the pcode instructions after the intra jump !Not for the next assembly instruction!
// Check whether the number of jumps is equal to 2, i.e. a pair of CBRANCH, BRANCH was created. If so, increase the pcodeIndex by 1
// so that the next intr block has the correct index.
if(PcodeBlockData.blocks.get(PcodeBlockData.blocks.size() - 1).getTerm().getJmps().size() == 2) {
PcodeBlockData.pcodeIndex +=1;
} }
PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), String.valueOf(pcodeIndex + 1))); PcodeBlockData.blocks.add(createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), String.valueOf(PcodeBlockData.pcodeIndex + 1)));
} }
/** /**
* *
* @param currentBlock: current block term
* @param pcodeOp: pcode instruction
* @param pcodeIndex: index of current pcode instruction
*
* Adds a jump from the previous instruction to a new intra block
*/
protected void jumpFromPreviousInstructionToNewBlock(Blk currentBlock, PcodeOp pcodeOp, int pcodeIndex) {
addJumpToCurrentBlock(currentBlock, PcodeBlockData.instruction.getFallFrom().toString(), PcodeBlockData.instruction.getAddress().toString(), null);
createNewBlockForIntraInstructionJump(pcodeIndex, pcodeOp);
}
/**
*
* @param pcodeOp: pcode instruction
* @return: boolean whether current pcode instruction is a call * @return: boolean whether current pcode instruction is a call
* *
* checks whether the current pcode instruction is a call * checks whether the current pcode instruction is a call
*/ */
protected Boolean isCall(PcodeOp pcodeOp){ protected Boolean isCall(){
return (pcodeOp.getOpcode() == PcodeOp.CALL || pcodeOp.getOpcode() == PcodeOp.CALLIND); switch(PcodeBlockData.pcodeOp.getOpcode()) {
case PcodeOp.CALL:
case PcodeOp.CALLIND:
case PcodeOp.CALLOTHER:
return true;
default:
return false;
}
} }
/** /**
* *
* @param pcodeIndex: index of current pcode instruction
* @param pcodeOp: pcode instruction
*
* Creates a new block for the pcode instructions of the current assembly instruction and the intra jump * Creates a new block for the pcode instructions of the current assembly instruction and the intra jump
*/ */
protected void createNewBlockForIntraInstructionJump(int pcodeIndex, PcodeOp pcodeOp){ protected void createNewBlockForIntraInstructionJump(){
int nextBlockStartIndex;
Term<Blk> newBlock; Term<Blk> newBlock;
// If an assembly instruction's pcode block is split into multiple blocks, the blocks' TIDs have to be distinguished by pcode index as they share the same instruction address // If an assembly instruction's pcode block is split into multiple blocks, the blocks' TIDs have to be distinguished by pcode index as they share the same instruction address
if(PcodeBlockData.temporaryDefStorage.size() > 0) { if(PcodeBlockData.temporaryDefStorage.size() > 0) {
nextBlockStartIndex = PcodeBlockData.temporaryDefStorage.get(0).getTerm().getPcodeIndex(); int nextBlockStartIndex = PcodeBlockData.temporaryDefStorage.get(0).getTerm().getPcodeIndex();
if(nextBlockStartIndex > 0) { if(nextBlockStartIndex == 0) {
newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), String.valueOf(nextBlockStartIndex));
} else {
newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), null); newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), null);
} else {
newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), String.valueOf(nextBlockStartIndex));
} }
} else { } else {
newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), null); newBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), null);
} }
newBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage); newBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage);
newBlock.getTerm().addJmp(createJmpTerm(pcodeIndex, pcodeOp, pcodeOp.getMnemonic())); newBlock.getTerm().addMultipleJumps(createJmpTerm(true));
PcodeBlockData.blocks.add(newBlock); PcodeBlockData.blocks.add(newBlock);
} }
...@@ -524,24 +533,17 @@ public class PcodeExtractor extends GhidraScript { ...@@ -524,24 +533,17 @@ public class PcodeExtractor extends GhidraScript {
* @param currentBlock: current block term * @param currentBlock: current block term
* @param jmpAddress: address of jump instruction * @param jmpAddress: address of jump instruction
* @param gotoAddress: address of where to jump * @param gotoAddress: address of where to jump
* @param suffix: suffix for TID
* *
* Adds a jump to the current block. * Adds a branch to the current block.
* The jump index for the instruction will be the pcode index +1
*/ */
protected void addJumpToCurrentBlock(Blk currentBlock, String jmpAddress, String gotoAddress, String suffix) { protected void addBranchToCurrentBlock(Blk currentBlock, String jumpSiteAddress, String gotoAddress) {
int artificialJmpIndex; int artificialJmpIndex = 1;
if(currentBlock.getDefs().size() == 0) { if(currentBlock.getDefs().size() > 0) {
artificialJmpIndex = 1;
} else {
artificialJmpIndex = currentBlock.getDefs().get(currentBlock.getDefs().size() - 1).getTerm().getPcodeIndex() + 1; artificialJmpIndex = currentBlock.getDefs().get(currentBlock.getDefs().size() - 1).getTerm().getPcodeIndex() + 1;
} }
Tid jmpTid = new Tid(String.format("instr_%s_%s", jmpAddress, artificialJmpIndex), jmpAddress); Tid jmpTid = new Tid(String.format("instr_%s_%s", jumpSiteAddress, artificialJmpIndex), jumpSiteAddress);
Tid gotoTid; Tid gotoTid = new Tid(String.format("blk_%s", gotoAddress), gotoAddress);
if(suffix != null) {
gotoTid = new Tid(String.format("blk_%s_%s", gotoAddress, suffix), gotoAddress);
} else {
gotoTid = new Tid(String.format("blk_%s", gotoAddress), gotoAddress);
}
currentBlock.addJmp(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.GOTO, "BRANCH", new Label((Tid) gotoTid), artificialJmpIndex))); currentBlock.addJmp(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.GOTO, "BRANCH", new Label((Tid) gotoTid), artificialJmpIndex)));
} }
...@@ -567,14 +569,12 @@ public class PcodeExtractor extends GhidraScript { ...@@ -567,14 +569,12 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param currentBlock: current block term * @param currentBlock: current block term
* @param pcodeOp: pcode instruction
* @param pcodeIndex: index of current pcode instruction
* *
* Handles call return pairs by creating a return block and redirecting the call's return to the return block * Handles call return pairs by creating a return block and redirecting the call's return to the return block
*/ */
protected void handleCallReturnPair(Term<Blk> currentBlock, PcodeOp pcodeOp, int pcodeIndex) { protected void handleCallReturnPair(Term<Blk> currentBlock) {
currentBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage); currentBlock.getTerm().addMultipleDefs(PcodeBlockData.temporaryDefStorage);
Term<Jmp> jump = createJmpTerm(pcodeIndex, pcodeOp, pcodeOp.getMnemonic()); Term<Jmp> jump = createJmpTerm(false).get(0);
Term<Blk> returnBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), "r"); Term<Blk> returnBlock = createBlkTerm(PcodeBlockData.instruction.getAddress().toString(), "r");
jump.getTerm().getCall().setReturn_(new Label(new Tid(returnBlock.getTid().getId(), returnBlock.getTid().getAddress()))); jump.getTerm().getCall().setReturn_(new Label(new Tid(returnBlock.getTid().getId(), returnBlock.getTid().getAddress())));
currentBlock.getTerm().addJmp(jump); currentBlock.getTerm().addJmp(jump);
...@@ -585,13 +585,12 @@ public class PcodeExtractor extends GhidraScript { ...@@ -585,13 +585,12 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param currentBlock: current block term * @param currentBlock: current block term
* @param pcodeOp: pcode instruction
* *
* Redirects the call's return address to the artificially created return block * Redirects the call's return address to the artificially created return block
*/ */
protected void redirectCallReturn(Term<Blk> currentBlock, PcodeOp pcodeOp) { protected void redirectCallReturn(Term<Blk> currentBlock) {
Tid jmpTid = new Tid(String.format("instr_%s_%s_r", PcodeBlockData.instruction.getAddress().toString(), 0), PcodeBlockData.instruction.getAddress().toString()); Tid jmpTid = new Tid(String.format("instr_%s_%s_r", PcodeBlockData.instruction.getAddress().toString(), 0), PcodeBlockData.instruction.getAddress().toString());
Term<Jmp> ret = new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.RETURN, pcodeOp.getMnemonic(), createLabel(pcodeOp, null), 0)); Term<Jmp> ret = new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.RETURN, PcodeBlockData.pcodeOp.getMnemonic(), createLabel(null), 0));
currentBlock.getTerm().addJmp(ret); currentBlock.getTerm().addJmp(ret);
} }
...@@ -872,70 +871,104 @@ public class PcodeExtractor extends GhidraScript { ...@@ -872,70 +871,104 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param pCodeCount: Pcode index in current block * @param intraJump: Indicator if jump occured inside pcode block
* @param pcodeOp: Pcode instruction
* @param mnemonic: Pcode instruction mnemonic
* @return: new Jmp Term * @return: new Jmp Term
* *
* Creates a Jmp Term with an unique TID consisting of the prefix jmp, its instruction address and the index of the pcode in the block. * Creates a Jmp Term with an unique TID consisting of the prefix jmp, its instruction address and the index of the pcode in the block.
* Depending on the instruction, it either has a goto label, a goto label and a condition or a call object. * Depending on the instruction, it either has a goto label, a goto label and a condition or a call object.
*/ */
protected Term<Jmp> createJmpTerm(int pCodeCount, PcodeOp pcodeOp, String mnemonic) { protected ArrayList<Term<Jmp>> createJmpTerm(Boolean intraJump) {
Address instrAddr = PcodeBlockData.instruction.getAddress(); String instrAddr = PcodeBlockData.instruction.getAddress().toString();
Tid jmpTid = new Tid(String.format("instr_%s_%s", instrAddr.toString(), pCodeCount), instrAddr.toString()); Tid jmpTid = new Tid(String.format("instr_%s_%s", instrAddr, PcodeBlockData.pcodeIndex), instrAddr);
if (pcodeOp.getOpcode() == PcodeOp.CBRANCH) { ArrayList<Term<Jmp>> jumps = new ArrayList<Term<Jmp>>();
return new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.GOTO, mnemonic, createLabel(pcodeOp, null), createVariable(pcodeOp.getInput(1)), pCodeCount)); int opcode = PcodeBlockData.pcodeOp.getOpcode();
String mnemonic = PcodeBlockData.pcodeOp.getMnemonic();
switch(opcode) {
case PcodeOp.CALL:
case PcodeOp.CALLIND:
case PcodeOp.CALLOTHER:
Call call = createCall();
jumps.add(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.CALL, resolveCallMenmonic(call, mnemonic), call, PcodeBlockData.pcodeIndex)));
break;
case PcodeOp.UNIMPLEMENTED:
jumps.add(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.CALL, "CALLOTHER", createCall(), PcodeBlockData.pcodeIndex)));
break;
case PcodeOp.CBRANCH:
return handleConditionalBranches(jmpTid, intraJump);
case PcodeOp.BRANCH:
case PcodeOp.BRANCHIND:
jumps.add(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.GOTO, mnemonic, createLabel(null), PcodeBlockData.pcodeIndex)));
break;
case PcodeOp.RETURN:
jumps.add(new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.RETURN, mnemonic, createLabel(null), PcodeBlockData.pcodeIndex)));
break;
} }
if (pcodeOp.getOpcode() == PcodeOp.BRANCH || pcodeOp.getOpcode() == PcodeOp.BRANCHIND) {
return new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.GOTO, mnemonic, createLabel(pcodeOp, null), pCodeCount)); return jumps;
} }
if (pcodeOp.getOpcode() == PcodeOp.RETURN) {
return new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.RETURN, mnemonic, createLabel(pcodeOp, null), pCodeCount));
} /**
if (pcodeOp.getOpcode() == PcodeOp.UNIMPLEMENTED) { *
mnemonic = "CALLOTHER"; * @param conditionalTid: jump site TID for CBRANCH
* @param intraJump: indicator if jump is an intra instruction jump
* @return: a pair of CBRANCH BRANCH jmp terms
*
* Creates jmp terms for for a cbranch and an artificial fallthrough branch.
* It checks whether the CBRANCH occured inside a pcode block. If so, the target TID for
* the fall through BRANCH is set to the artificially generated block at the same address with
* the start pcode index of the next block.
*/
protected ArrayList<Term<Jmp>> handleConditionalBranches(Tid conditionalTid, Boolean intraJump) {
ArrayList<Term<Jmp>> branches = new ArrayList<Term<Jmp>>();
String branchSiteAddress = new String(conditionalTid.getAddress());
Tid branchTid = new Tid(String.format("instr_%s_%s", branchSiteAddress, PcodeBlockData.pcodeIndex + 1), branchSiteAddress);
Tid targetTid = new Tid();
if(intraJump) {
targetTid = new Tid(String.format("blk_%s_%s", branchSiteAddress, PcodeBlockData.pcodeIndex + 2), branchSiteAddress);
} else {
targetTid = new Tid(String.format("blk_%s", PcodeBlockData.instruction.getFallThrough().toString()), PcodeBlockData.instruction.getFallThrough().toString());
} }
Term<Jmp> call = new Term<Jmp>(jmpTid, new Jmp(ExecutionType.JmpType.CALL, mnemonic, createCall(mnemonic, pcodeOp), pCodeCount)); branches.add(new Term<Jmp>(conditionalTid, new Jmp(ExecutionType.JmpType.GOTO, PcodeBlockData.pcodeOp.getMnemonic(), createLabel(null), createVariable(PcodeBlockData.pcodeOp.getInput(1)), PcodeBlockData.pcodeIndex)));
call = checkIfCallindResolved(call); branches.add(new Term<Jmp>(branchTid, new Jmp(ExecutionType.JmpType.GOTO, "BRANCH", new Label(targetTid), PcodeBlockData.pcodeIndex + 1)));
return call; return branches;
} }
/** /**
* *
* @param call: indirect call * @param call: indirect call
* @param mnemonic: call mnemonic
* @return: direkt call or indirekt call * @return: direkt call or indirekt call
* *
* Checks whether the indirect call could have been resolved and casts it into a direct call * Checks whether the indirect call could have been resolved and casts it into a direct call
*/ */
protected Term<Jmp> checkIfCallindResolved(Term<Jmp> call) { protected String resolveCallMenmonic(Call call, String mnemonic) {
if (call.getTerm().getMnemonic().equals("CALLIND")) { if (mnemonic.equals("CALLIND") && call.getTarget().getIndirect() == null) {
if (call.getTerm().getCall().getTarget().getIndirect() == null) { return "CALL";
call.getTerm().setMnemonic("CALL");
}
} }
return call; return mnemonic;
} }
/** /**
* @param pCodeCount: Pcode index in current block
* @param pcodeOp: Pcode instruction
* @return: new Def Term * @return: new Def Term
* *
* Creates a Def Term with an unique TID consisting of the prefix def, its instruction address and the index of the pcode in the block. * Creates a Def Term with an unique TID consisting of the prefix def, its instruction address and the index of the pcode in the block.
*/ */
protected Term<Def> createDefTerm(int pcodeIndex, PcodeOp pcodeOp) { protected Term<Def> createDefTerm() {
Address instrAddr = PcodeBlockData.instruction.getAddress(); Address instrAddr = PcodeBlockData.instruction.getAddress();
Tid defTid = new Tid(String.format("instr_%s_%s", instrAddr.toString(), pcodeIndex), instrAddr.toString()); Tid defTid = new Tid(String.format("instr_%s_%s", instrAddr.toString(), PcodeBlockData.pcodeIndex), instrAddr.toString());
if (pcodeOp.getMnemonic().equals("STORE")) { if (PcodeBlockData.pcodeOp.getMnemonic().equals("STORE")) {
return new Term<Def>(defTid, new Def(createExpression(pcodeOp), pcodeIndex)); return new Term<Def>(defTid, new Def(createExpression(), PcodeBlockData.pcodeIndex));
// cast copy instructions that have address outputs into store instructions // cast copy instructions that have address outputs into store instructions
} }
return new Term<Def>(defTid, new Def(createVariable(pcodeOp.getOutput()), createExpression(pcodeOp), pcodeIndex)); return new Term<Def>(defTid, new Def(createVariable(PcodeBlockData.pcodeOp.getOutput()), createExpression(), PcodeBlockData.pcodeIndex));
} }
...@@ -973,16 +1006,15 @@ public class PcodeExtractor extends GhidraScript { ...@@ -973,16 +1006,15 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* @param pcodeOp: Pcode instruction
* @return: new Epxression * @return: new Epxression
* *
* Create an Expression using the input varnodes of the pcode instruction. * Create an Expression using the input varnodes of the pcode instruction.
*/ */
protected Expression createExpression(PcodeOp pcodeOp) { protected Expression createExpression() {
String mnemonic = pcodeOp.getMnemonic(); String mnemonic = PcodeBlockData.pcodeOp.getMnemonic();
List<Variable> in = new ArrayList<Variable>(); List<Variable> in = new ArrayList<Variable>();
for (Varnode input : pcodeOp.getInputs()) { for (Varnode input : PcodeBlockData.pcodeOp.getInputs()) {
in.add(createVariable(input)); in.add(createVariable(input));
} }
...@@ -990,40 +1022,39 @@ public class PcodeExtractor extends GhidraScript { ...@@ -990,40 +1022,39 @@ public class PcodeExtractor extends GhidraScript {
if (inputLen == 1) { if (inputLen == 1) {
return new Expression(mnemonic, in.get(0)); return new Expression(mnemonic, in.get(0));
} else if (inputLen == 2) { }
if (inputLen == 2) {
return new Expression(mnemonic, in.get(0), in.get(1)); return new Expression(mnemonic, in.get(0), in.get(1));
} else {
return new Expression(mnemonic, in.get(0), in.get(1), in.get(2));
} }
return new Expression(mnemonic, in.get(0), in.get(1), in.get(2));
} }
/** /**
* @param pcodeOp: Pcode instruction
* @param fallThrough: fallThrough address of branch/call * @param fallThrough: fallThrough address of branch/call
* @return: new Label * @return: new Label
* *
* Create a Label based on the branch instruction. For indirect branches and calls, it consists of a Variable, for calls of a sub TID * Create a Label based on the branch instruction. For indirect branches and calls, it consists of a Variable, for calls of a sub TID
* and for branches of a blk TID. * and for branches of a blk TID.
*/ */
protected Label createLabel(PcodeOp pcodeOp, Address fallThrough) { protected Label createLabel(Address fallThrough) {
Label jumpLabel; Label jumpLabel;
if (fallThrough == null) { if (fallThrough == null) {
switch(pcodeOp.getOpcode()) { switch(PcodeBlockData.pcodeOp.getOpcode()) {
case PcodeOp.CALL: case PcodeOp.CALL:
case PcodeOp.CALLIND: case PcodeOp.CALLIND:
jumpLabel = handleLabelsForCalls(pcodeOp); jumpLabel = handleLabelsForCalls(PcodeBlockData.pcodeOp);
break; break;
case PcodeOp.BRANCHIND: case PcodeOp.BRANCHIND:
case PcodeOp.RETURN: case PcodeOp.RETURN:
jumpLabel = new Label((Variable) createVariable(pcodeOp.getInput(0))); jumpLabel = new Label((Variable) createVariable(PcodeBlockData.pcodeOp.getInput(0)));
break; break;
case PcodeOp.CALLOTHER: case PcodeOp.CALLOTHER:
case PcodeOp.UNIMPLEMENTED: case PcodeOp.UNIMPLEMENTED:
jumpLabel = null; jumpLabel = null;
break; break;
default: default:
jumpLabel = new Label((Tid) new Tid(String.format("blk_%s", pcodeOp.getInput(0).getAddress().toString()), pcodeOp.getInput(0).getAddress().toString())); jumpLabel = new Label((Tid) new Tid(String.format("blk_%s", PcodeBlockData.pcodeOp.getInput(0).getAddress().toString()), PcodeBlockData.pcodeOp.getInput(0).getAddress().toString()));
break; break;
} }
return jumpLabel; return jumpLabel;
...@@ -1136,23 +1167,25 @@ public class PcodeExtractor extends GhidraScript { ...@@ -1136,23 +1167,25 @@ public class PcodeExtractor extends GhidraScript {
/** /**
* *
* @param mnemonic: Pcode instruction mnemonic
* @param pcodeOp: Pcode instruction
* @return: new Call * @return: new Call
* *
* Creates a Call object, using a target and return Label. * Creates a Call object, using a target and return Label.
*/ */
protected Call createCall(String mnemonic, PcodeOp pcodeOp) { protected Call createCall() {
String callString = null; String callString = null;
if(pcodeOp.getOpcode() == PcodeOp.CALLOTHER) { Call call;
callString = ghidraProgram.getLanguage().getUserDefinedOpName((int) pcodeOp.getInput(0).getOffset()); if(PcodeBlockData.pcodeOp.getOpcode() == PcodeOp.CALLOTHER) {
return new Call(null, createLabel(pcodeOp, PcodeBlockData.instruction.getFallThrough()), callString); callString = ghidraProgram.getLanguage().getUserDefinedOpName((int) PcodeBlockData.pcodeOp.getInput(0).getOffset());
call = new Call(null, createLabel(PcodeBlockData.instruction.getFallThrough()), callString);
} }
if(pcodeOp.getOpcode() == PcodeOp.UNIMPLEMENTED) { else if(PcodeBlockData.pcodeOp.getOpcode() == PcodeOp.UNIMPLEMENTED) {
callString = "unimplemented"; callString = "unimplemented";
return new Call(null, createLabel(pcodeOp, PcodeBlockData.instruction.getFallThrough()), callString); call = new Call(null, createLabel(PcodeBlockData.instruction.getFallThrough()), callString);
} else {
call = new Call(createLabel(null), createLabel(PcodeBlockData.instruction.getFallThrough()));
} }
return new Call(createLabel(pcodeOp, null), createLabel(pcodeOp, PcodeBlockData.instruction.getFallThrough()));
return call;
} }
......
...@@ -40,6 +40,14 @@ public final class PcodeBlockData { ...@@ -40,6 +40,14 @@ public final class PcodeBlockData {
*/ */
public static int instructionIndex; public static int instructionIndex;
/** /**
* contains the current processed pcodeOp of the current assembly instruction.
*/
public static PcodeOp pcodeOp;
/**
* Contains the index of the current pcodeOp of the current assembly instruction.
*/
public static int pcodeIndex;
/**
* Contains the number of assembly instructions in the current Ghidra block * Contains the number of assembly instructions in the current Ghidra block
*/ */
public static long numberOfInstructionsInBlock; public static long numberOfInstructionsInBlock;
......
...@@ -48,5 +48,9 @@ public class Blk { ...@@ -48,5 +48,9 @@ public class Blk {
this.defs.addAll(defs); this.defs.addAll(defs);
} }
public void addMultipleJumps(ArrayList<Term<Jmp>> jmps) {
this.jmps.addAll(jmps);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment