├── PCodeDumpMF.java ├── PCodeDumpSF.java ├── README.md └── TestHighlight.java /PCodeDumpMF.java: -------------------------------------------------------------------------------- 1 | /* ### 2 | * IP: GHIDRA 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | //Decompile the function at the cursor and its callees, then output facts files corresponding to the pcodes 17 | //@category PCode 18 | 19 | import java.io.File; 20 | import java.io.FileNotFoundException; 21 | import java.io.PrintWriter; 22 | import java.util.HashMap; 23 | import java.util.HashSet; 24 | import java.util.Iterator; 25 | import java.util.Set; 26 | 27 | import ghidra.app.decompiler.DecompInterface; 28 | import ghidra.app.decompiler.DecompileException; 29 | import ghidra.app.decompiler.DecompileOptions; 30 | import ghidra.app.decompiler.DecompileResults; 31 | import ghidra.app.script.GhidraScript; 32 | import ghidra.framework.plugintool.PluginTool; 33 | import ghidra.program.model.address.Address; 34 | import ghidra.program.model.data.AbstractFloatDataType; 35 | import ghidra.program.model.data.AbstractIntegerDataType; 36 | import ghidra.program.model.data.Array; 37 | import ghidra.program.model.data.BooleanDataType; 38 | import ghidra.program.model.data.DataType; 39 | import ghidra.program.model.data.DataTypeComponent; 40 | import ghidra.program.model.data.Enum; 41 | import ghidra.program.model.data.FunctionDefinition; 42 | import ghidra.program.model.data.GenericCallingConvention; 43 | import ghidra.program.model.data.ParameterDefinition; 44 | import ghidra.program.model.data.Pointer; 45 | import ghidra.program.model.data.Structure; 46 | import ghidra.program.model.data.TypeDef; 47 | import ghidra.program.model.data.Union; 48 | import ghidra.program.model.listing.Function; 49 | import ghidra.program.model.pcode.FunctionPrototype; 50 | import ghidra.program.model.pcode.HighConstant; 51 | import ghidra.program.model.pcode.HighFunction; 52 | import ghidra.program.model.pcode.HighGlobal; 53 | import ghidra.program.model.pcode.HighLocal; 54 | import ghidra.program.model.pcode.HighOther; 55 | import ghidra.program.model.pcode.HighParam; 56 | import ghidra.program.model.pcode.HighSymbol; 57 | import ghidra.program.model.pcode.HighVariable; 58 | import ghidra.program.model.pcode.PcodeBlock; 59 | import ghidra.program.model.pcode.PcodeBlockBasic; 60 | import ghidra.program.model.pcode.PcodeOp; 61 | import ghidra.program.model.pcode.PcodeOpAST; 62 | import ghidra.program.model.pcode.SequenceNumber; 63 | import ghidra.program.model.pcode.Varnode; 64 | import ghidra.program.model.pcode.VarnodeAST; 65 | import ghidra.program.model.symbol.Symbol; 66 | import ghidra.program.model.symbol.SymbolIterator; 67 | import ghidra.program.model.symbol.SymbolTable; 68 | 69 | public class PCodeDump extends GhidraScript { 70 | 71 | String SEP = ":"; 72 | String TAB = "\t"; 73 | 74 | Set toProcess = new HashSet(); 75 | Set isEP = new HashSet(); 76 | File outputDirectory; 77 | PrintWriter ia; 78 | HashMap pws = new HashMap(); 79 | HashMap pairs; 80 | HashSet types = new HashSet(); 81 | HashMap extraGlobals = new HashMap(); 82 | 83 | @Override 84 | protected void run() throws Exception { 85 | PluginTool tool = state.getTool(); 86 | if (tool == null) { 87 | println("Script is not running in GUI"); 88 | } 89 | outputDirectory = askDirectory("Select Directory for Results", "OK"); 90 | try { 91 | File f = new File(outputDirectory,"input_assist.dl"); 92 | ia = new PrintWriter(f); 93 | pws.put("input_assist.dl", ia); 94 | ia.println(".decl S2N(key:symbol, n:number)"); 95 | ia.println(".input S2N"); 96 | File f2 = new File(outputDirectory, "S2N.facts"); 97 | PrintWriter pw = new PrintWriter(f2); 98 | pws.put("S2N", pw); 99 | } catch (FileNotFoundException e) { 100 | e.printStackTrace(); 101 | } 102 | 103 | DecompileOptions options = new DecompileOptions(); 104 | DecompInterface ifc = new DecompInterface(); 105 | ifc.setOptions(options); 106 | ifc.setSimplificationStyle("decompile"); 107 | 108 | if (!ifc.openProgram(this.currentProgram)) { 109 | throw new DecompileException("Decompiler", "Unable to initialize: "+ifc.getLastMessage()); 110 | } 111 | 112 | toProcess = new HashSet(); 113 | Function func = this.getFunctionContaining(this.currentAddress); 114 | if (func != null) { 115 | collectFunctions(func); 116 | isEP.add(func); 117 | } else { 118 | for (Function f : this.currentProgram.getFunctionManager().getFunctions(true)) { 119 | collectFunctions(f); 120 | isEP.add(f); 121 | } 122 | for (Function f : this.currentProgram.getFunctionManager().getExternalFunctions()) { 123 | collectFunctions(f); 124 | } 125 | } 126 | for (Function f : toProcess) { 127 | processFunction(ifc, f); 128 | if (monitor.isCancelled()) break; 129 | } 130 | 131 | closeFiles(); 132 | } 133 | 134 | private void collectFunctions(Function f) { 135 | if (toProcess.contains(f)) return; 136 | toProcess.add(f); 137 | Set calledFunctions = f.getCalledFunctions(monitor); 138 | for (Function function : calledFunctions) { 139 | collectFunctions(function); 140 | } 141 | } 142 | 143 | protected void processFunction(DecompInterface ifc, Function f) { 144 | pairs = new HashMap(); 145 | System.out.println("processing "+f.getName()+SEP+f.getEntryPoint()); 146 | 147 | SymbolIterator externalSymbols = f.getProgram().getSymbolTable().getSymbols(f.getName()); 148 | while (externalSymbols.hasNext()) { 149 | Symbol next = externalSymbols.next(); 150 | if (!next.isExternal()) { 151 | Address address = next.getAddress(); 152 | export("HFUNC_LOCAL_EP", f.getEntryPoint().toString(), address.toString()); 153 | } 154 | } 155 | HighFunction high = getHighFunction(ifc, f); 156 | if (high == null) { 157 | String id = funcID(f); 158 | export("HFUNC_FUNC", id, id); 159 | export("HFUNC_TOSTR", id, id); 160 | export("HFUNC_PROTO", id, id); 161 | export("HFUNC_EP", id, f.getEntryPoint().toString()); 162 | export("HFUNC_ISEXT", id, "true"); 163 | return; 164 | } 165 | 166 | HashSet set = new HashSet(); 167 | Iterator opiter = high.getPcodeOps(); 168 | while (opiter.hasNext()) { 169 | PcodeOpAST op = opiter.next(); 170 | if (op != null) { 171 | set.add(op); 172 | exportPcode(high, op); 173 | } 174 | } 175 | exportPcodeOpSequence(high, set); 176 | exportHighFunction(high); 177 | } 178 | 179 | private void closeFiles() { 180 | for (PrintWriter pw : pws.values()) { 181 | pw.flush(); 182 | pw.close(); 183 | } 184 | } 185 | 186 | private HighFunction getHighFunction(DecompInterface ifc, Function func) { 187 | DecompileResults res = ifc.decompileFunction(func, 300, null); 188 | HighFunction high = res.getHighFunction(); 189 | if (high == null) { 190 | System.err.println(func+" returned null HighFunction"); 191 | } 192 | return high; 193 | } 194 | 195 | private void export(String label, String key, String value) { 196 | try { 197 | String fname = label+".facts"; 198 | PrintWriter pw = pws.get(fname); 199 | if (pw == null) { 200 | File f = new File(outputDirectory, fname); 201 | pw = new PrintWriter(f); 202 | pws.put(fname, pw); 203 | ia.println(".decl "+label+"(key:symbol, value:symbol)"); 204 | ia.println(".input "+label); 205 | } 206 | if (!pairs.containsKey(label+key)) { 207 | pw.println(key+TAB+value); 208 | pairs.put(label+key, value); 209 | } 210 | //System.out.println(label+"\t"+key+"\t"+value); 211 | } catch (FileNotFoundException e) { 212 | e.printStackTrace(); 213 | } 214 | } 215 | 216 | private void exportL(String label, String key, long value) { 217 | try { 218 | String fname = label+".facts"; 219 | PrintWriter pw = pws.get(fname); 220 | if (pw == null) { 221 | File f = new File(outputDirectory, fname); 222 | pw = new PrintWriter(f); 223 | pws.put(fname, pw); 224 | ia.println(".decl "+label+"(key:symbol, value:number)"); 225 | ia.println(".input "+label); 226 | } 227 | if (!pairs.containsKey(label+key)) { 228 | pw.println(key+TAB+value); 229 | pairs.put(label+key, Long.toString(value)); 230 | } 231 | //System.out.println(label+"\t"+key+"\t"+value); 232 | } catch (FileNotFoundException e) { 233 | e.printStackTrace(); 234 | } 235 | } 236 | 237 | private void exportN(String label, String key, int index, String value) { 238 | if (value == null) { 239 | System.err.println(label+" key:"+key+" index:"+index+" NULL"); 240 | return; 241 | } 242 | try { 243 | String fname = label+".facts"; 244 | PrintWriter pw = pws.get(fname); 245 | if (pw == null) { 246 | File f = new File(outputDirectory, fname); 247 | pw = new PrintWriter(f); 248 | pws.put(fname, pw); 249 | if (value.equals("")) { 250 | ia.println(".decl "+label+"(key:symbol, n:number)"); 251 | } else { 252 | ia.println(".decl "+label+"(key:symbol, n:number, value:symbol)"); 253 | } 254 | ia.println(".input "+label); 255 | } 256 | if (!pairs.containsKey(label+key+index)) { 257 | pw.println(key+TAB+index+TAB+value); 258 | pairs.put(label+key+index, value); 259 | } 260 | //System.out.println(label+"\t"+key+"\t"+index+"\t"+value); 261 | exportS2N(index); 262 | } catch (FileNotFoundException e) { 263 | e.printStackTrace(); 264 | } 265 | } 266 | 267 | private void exportNL(String label, String key, int index, long value) { 268 | try { 269 | String fname = label + ".facts"; 270 | PrintWriter pw = pws.get(fname); 271 | if (pw == null) { 272 | File f = new File(outputDirectory, fname); 273 | pw = new PrintWriter(f); 274 | pws.put(fname, pw); 275 | ia.println(".decl " + label + "(key:symbol, n:number, value:number)"); 276 | ia.println(".input " + label); 277 | } 278 | if (!pairs.containsKey(label + key + index)) { 279 | pw.println(key + TAB + index + TAB + value); 280 | pairs.put(label + key + index, Long.toString(value)); 281 | } 282 | // System.out.println(label+"\t"+key+"\t"+index+"\t"+value); 283 | exportS2N(index); 284 | } catch (FileNotFoundException e) { 285 | e.printStackTrace(); 286 | } 287 | } 288 | 289 | private void exportS2N(int n) { 290 | if (!pairs.containsKey("S2N"+n)) { 291 | pws.get("S2N").println(Integer.toString(n)+TAB+n); 292 | pairs.put("S2N"+n, Integer.toString(n)); 293 | } 294 | } 295 | 296 | private void exportPcode(HighFunction hfn, PcodeOpAST op) { 297 | SequenceNumber sn = op.getSeqnum(); 298 | String outstr = op.toString(); 299 | if (sn != null) { 300 | outstr = sn.getTarget()+SEP+sn.getTime(); 301 | } 302 | String id = pcodeID(hfn,op); 303 | export("PCODE_TOSTR", id, funcID(hfn.getFunction())+SEP+outstr); 304 | export("PCODE_MNEMONIC", id, op.getMnemonic()); 305 | export("PCODE_OPCODE", id, Integer.toString(op.getOpcode())); 306 | export("PCODE_PARENT", id, bbID(hfn,op.getParent())); 307 | export("PCODE_TARGET", id, op.getSeqnum().getTarget().toString()); 308 | exportN("PCODE_INPUT_COUNT", id, op.getNumInputs(), ""); 309 | for (int i = 0; i < op.getNumInputs(); ++i) { 310 | VarnodeAST vni = (VarnodeAST) op.getInput(i); 311 | if (vni != null) { 312 | // OK, this is a little weird, but PTRSUBs with first arg == 0 313 | // are (usually) global variables at address == second arg 314 | if (op.getMnemonic().equals("PTRSUB") && (i == 0)) { 315 | if (vni.getAddress().getOffset() == 0) { 316 | VarnodeAST next = (VarnodeAST) op.getInput(1); 317 | HighVariable high = next.getHigh(); 318 | if (high != null) { 319 | extraGlobals.put(high, next); 320 | } 321 | } 322 | } 323 | exportN("PCODE_INPUT", id, i, vnodeID(hfn,vni)); 324 | exportVarnode(hfn,vni); 325 | } 326 | } 327 | VarnodeAST vno = (VarnodeAST) op.getOutput(); 328 | if (vno != null) { 329 | export("PCODE_OUTPUT", id, vnodeID(hfn,vno)); 330 | exportVarnode(hfn, vno); 331 | } 332 | } 333 | 334 | private void exportVarnode(HighFunction hfn, VarnodeAST vn) { 335 | String id = vnodeID(hfn,vn); 336 | export("VNODE_ADDRESS", id, vn.getAddress().toString()); 337 | if (vn.isAddress()) { 338 | export("VNODE_IS_ADDRESS", id, "true"); 339 | } 340 | if (vn.isAddrTied()) { 341 | export("VNODE_IS_ADDRTIED", id, "true"); 342 | } 343 | export("VNODE_PC_ADDRESS", id, vn.getPCAddress().toString()); 344 | export("VNODE_DESC", id, vn.toString()); 345 | long offset = vn.getOffset(); 346 | exportL("VNODE_OFFSET", id, offset); 347 | if (offset < Integer.MAX_VALUE && offset > Integer.MIN_VALUE) { 348 | exportL("VNODE_OFFSET_N", id, offset); 349 | } 350 | export("VNODE_SIZE", id, Integer.toString(vn.getSize())); 351 | export("VNODE_SPACE", id, vn.getAddress().getAddressSpace().getName()); 352 | HighVariable hv = vn.getHigh(); 353 | if (hv == null) { 354 | //export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.toString()); 355 | export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+vn.toString()); 356 | } else { 357 | if (hv instanceof HighConstant && hv.getDataType() instanceof Pointer) { 358 | if (offset != 0) { 359 | extraGlobals.put(hv, vn); 360 | } 361 | } 362 | //export("VNODE_TOSTR", id, funcID(hfn.getFunction())+hvarName(hfn,hv)); 363 | export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+hvarName(hfn,hv)); 364 | export("VNODE_HVAR", id, hvarID(hfn,hv)); 365 | exportHighVariable(hfn, hv, true); 366 | } 367 | if (vn.getDef() != null) { 368 | export("VNODE_DEF", id, pcodeID(hfn, vn.getDef())); 369 | } 370 | } 371 | 372 | private void exportHighVariable(HighFunction hfn, HighVariable hv, boolean dontDescend) { 373 | String id = hvarID(hfn,hv); 374 | export("HVAR_NAME", id, hvarName(hfn,hv)); 375 | export("HVAR_SIZE", id, Integer.toString(hv.getSize())); 376 | if (hv instanceof HighGlobal) { 377 | export("HVAR_CLASS", id, "global"); 378 | } 379 | if (hv instanceof HighLocal) { 380 | export("HVAR_CLASS", id, "local"); 381 | Address pcAddress = ((HighLocal)hv).getPCAddress(); 382 | if (pcAddress != null) { 383 | export("HVAR_SCOPE", id, pcAddress.toString()); 384 | } 385 | } 386 | if (hv instanceof HighConstant) { 387 | export("HVAR_CLASS", id, "constant"); 388 | } 389 | if (hv instanceof HighOther) { 390 | export("HVAR_CLASS", id, "other"); 391 | } 392 | DataType dataType = hv.getDataType(); 393 | if (dataType != null) { 394 | export("HVAR_TYPE", id, dtID(dataType)); 395 | exportType(dataType); 396 | } 397 | if (!dontDescend) { 398 | VarnodeAST representative = (VarnodeAST) hv.getRepresentative(); 399 | if (representative != null) { 400 | export("HVAR_REPRESENTATIVE", id, vnodeID(hfn,representative)); 401 | exportVarnode(hfn, representative); 402 | } 403 | Varnode[] instances = hv.getInstances(); 404 | for (Varnode varnode : instances) { 405 | exportVarnode(hfn, (VarnodeAST)varnode); 406 | } 407 | } 408 | } 409 | 410 | private void exportType(DataType dataType) { 411 | String id = dtID(dataType); 412 | if (types.contains(id)) return; 413 | types.add(id); 414 | 415 | export("TYPE_NAME", id, id); 416 | exportN("TYPE_LENGTH", id, dataType.getLength(), ""); 417 | while (dataType instanceof TypeDef) { 418 | TypeDef typedef = (TypeDef) dataType; 419 | dataType = typedef.getBaseDataType(); 420 | } 421 | if (dataType instanceof Pointer) { 422 | export("TYPE_POINTER", id, "true"); 423 | DataType baseType = ((Pointer) dataType).getDataType(); 424 | if (baseType != null) { 425 | export("TYPE_POINTER_BASE", id, dtID(baseType)); 426 | exportType(baseType); 427 | } else { 428 | System.err.println("TEST"); 429 | } 430 | } 431 | if (dataType instanceof Array) { 432 | export("TYPE_ARRAY", id, "true"); 433 | Array arr = (Array) dataType; 434 | export("TYPE_ARRAY_BASE", id, dtID(arr.getDataType())); 435 | exportN("TYPE_ARRAY_N", id, arr.getNumElements(), ""); 436 | exportN("TYPE_ARRAY_ELEMENT_LENGTH", id, arr.getElementLength(), ""); 437 | exportType(arr.getDataType()); 438 | } 439 | if (dataType instanceof Structure) { 440 | export("TYPE_STRUCT", id, "true"); 441 | Structure struct = (Structure) dataType; 442 | exportN("TYPE_STRUCT_FIELD_COUNT", id, struct.getNumComponents(), ""); 443 | for (int i = 0; i < struct.getNumComponents(); i++) { 444 | DataTypeComponent dtc = struct.getComponent(i); 445 | exportComponent("TYPE_STRUCT", id, i, dtc); 446 | } 447 | } 448 | if (dataType instanceof Union) { 449 | export("TYPE_UNION", id, "true"); 450 | Union union = (Union) dataType; 451 | exportN("TYPE_UNION_FIELD_COUNT", id, union.getNumComponents(), ""); 452 | for (int i = 0; i < union.getNumComponents(); i++) { 453 | DataTypeComponent dtc = union.getComponent(i); 454 | exportComponent("TYPE_UNION", id, i, dtc); 455 | } 456 | } 457 | if (dataType instanceof FunctionDefinition) { 458 | export("TYPE_FUNC", id, "true"); 459 | FunctionDefinition fd = (FunctionDefinition) dataType; 460 | export("TYPE_FUNC_RET", id, fd.getReturnType().toString()); 461 | exportType(fd.getReturnType()); 462 | export("TYPE_FUNC_VARARGS", id, Boolean.toString(fd.hasVarArgs())); 463 | ParameterDefinition[] arguments = fd.getArguments(); 464 | exportN("TYPE_FUNC_PARAM_COUNT", id, arguments.length, ""); 465 | for (int i = 0; i < arguments.length; i++) { 466 | exportN("TYPE_FUNC_PARAM", id, i, arguments[i].toString()); 467 | exportType(arguments[i].getDataType()); 468 | } 469 | } 470 | if (dataType instanceof BooleanDataType) { 471 | export("TYPE_BOOLEAN", id, "true"); 472 | } 473 | if (dataType instanceof AbstractIntegerDataType) { 474 | export("TYPE_INTEGER", id, "true"); 475 | } 476 | if (dataType instanceof AbstractFloatDataType) { 477 | export("TYPE_FLOAT", id, "true"); 478 | } 479 | if (dataType instanceof Enum) { 480 | export("TYPE_ENUM", id, "true"); 481 | } 482 | } 483 | 484 | private void exportComponent(String label, String id, int i, DataTypeComponent dtc) { 485 | String dtcid = dtID(dtc.getDataType()); 486 | exportN(label+"_FIELD", id, i, dtcid); 487 | exportNL(label+"_OFFSET", id, i, dtc.getOffset()); 488 | exportNL(label+"_OFFSET_N", id, i, dtc.getOffset()); 489 | if (dtc.getFieldName() != null) { 490 | exportN(label+"_FIELD_NAME", id, i, dtc.getFieldName()); 491 | exportN(label+"_FIELD_NAME_BY_OFFSET", id, dtc.getOffset(), dtc.getFieldName()); 492 | } 493 | exportS2N(dtc.getOffset()); 494 | exportType(dtc.getDataType()); 495 | } 496 | 497 | private void exportHighFunction(HighFunction hfn) { 498 | for (PcodeBlockBasic bb : hfn.getBasicBlocks()) { 499 | String bbid = bbID(hfn,bb); 500 | export("BB_HFUNC", bbid, hfuncID(hfn)); 501 | if (bb.getStart() != null) { 502 | export("BB_START", bbid, bb.getStart().toString()); 503 | } 504 | for (int i = 0; i < bb.getInSize(); i++) { 505 | export("BB_IN", bbid, bbID(hfn,bb.getIn(i))); 506 | } 507 | for (int i = 0; i < bb.getOutSize(); i++) { 508 | export("BB_OUT", bbid, bbID(hfn,bb.getOut(i))); 509 | } 510 | if (bb.getOutSize() > 1) { 511 | export("BB_TOUT", bbid, bbID(hfn,bb.getTrueOut())); 512 | export("BB_FOUT", bbid, bbID(hfn,bb.getFalseOut())); 513 | } 514 | } 515 | String id = hfuncID(hfn); 516 | export("HFUNC_FUNC", id, funcID(hfn.getFunction())); 517 | export("HFUNC_TOSTR", id, funcID(hfn.getFunction())); 518 | export("HFUNC_CSPEC", id, hfn.getCompilerSpec().toString()); 519 | export("HFUNC_LANG", id, hfn.getLanguage().toString()); 520 | export("HFUNC_EP", id, hfn.getFunction().getEntryPoint().toString()); 521 | FunctionPrototype proto = hfn.getFunctionPrototype(); 522 | if (proto != null) { 523 | export("HFUNC_PROTO", id, funcID(hfn.getFunction())); 524 | exportPrototype(hfn, proto, funcID(hfn.getFunction())); 525 | } 526 | Function f = hfn.getFunction(); 527 | Function thunk = f.getThunkedFunction(false); 528 | if (thunk != null && thunk.isExternal()) { 529 | export("HFUNC_ISEXT", id, "true"); 530 | } 531 | if (isEP.contains(f)) { 532 | export("HFUNC_ISEP", id, "true"); 533 | } 534 | 535 | Iterator symbols = hfn.getLocalSymbolMap().getSymbols(); 536 | while (symbols.hasNext()) { 537 | HighSymbol hs = symbols.next(); 538 | String hsid = hsID(hfn,hs); 539 | export("SYMBOL_HFUNC", hsid, id); 540 | HighVariable hv = hs.getHighVariable(); 541 | if (hv != null) { 542 | export("SYMBOL_HVAR", hsid, hvarID(hfn,hv)); 543 | exportHighVariable(hfn, hv, false); 544 | } 545 | } 546 | } 547 | 548 | private void exportPrototype(HighFunction hfn, FunctionPrototype proto, String id) { 549 | exportN("PROTO_PARAMETER_COUNT", id, proto.getNumParams(), ""); 550 | for (int i = 0; i < proto.getNumParams(); i++) { 551 | HighParam param = proto.getParam(i); 552 | exportN("PROTO_PARAMETER", id, i, hvarID(hfn,param)); 553 | exportN("PROTO_PARAMETER_S", id, i, hvarID(hfn,param)); 554 | export("PROTO_PARAMETER_DATATYPE", hvarID(hfn,param), dtID(param.getDataType())); 555 | exportType(param.getDataType()); 556 | VarnodeAST rep = (VarnodeAST) param.getRepresentative(); 557 | export("PROTO_REPRESENTATIVE", hvarID(hfn,param), vnodeID(hfn, rep)); 558 | exportVarnode(hfn, rep); 559 | } 560 | /* 561 | ParameterDefinition[] parameterDefinitions = proto.getParameterDefinitions(); 562 | if (parameterDefinitions != null) { 563 | for (ParameterDefinition def : parameterDefinitions) { 564 | exportN("PROTO_PARAMETER_DEFINITION", id, def.getOrdinal(), def.getName()); 565 | export("PROTO_PARAMETER_DATATYPE", def.getName(), dtID(def.getDataType())); 566 | exportType(def.getDataType()); 567 | } 568 | } 569 | */ 570 | DataType returnType = proto.getReturnType(); 571 | export("PROTO_RETTYPE", id, dtID(returnType)); 572 | exportType(returnType); 573 | GenericCallingConvention cc = proto.getGenericCallingConvention(); 574 | if (cc != null) { 575 | export("PROTO_CALLING_CONVENTION", id, cc.toString()); 576 | } 577 | export("PROTO_IS_VOID", id, Boolean.toString(proto.hasNoReturn())); 578 | export("PROTO_HAS_THIS", id, Boolean.toString(proto.hasThisPointer())); 579 | export("PROTO_IS_VARARG", id, Boolean.toString(proto.isVarArg())); 580 | export("PROTO_IS_INLINE", id, Boolean.toString(proto.isInline())); 581 | export("PROTO_IS_CONSTRUCTOR", id, Boolean.toString(proto.isConstructor())); 582 | export("PROTO_IS_DESTRUCTOR", id, Boolean.toString(proto.isDestructor())); 583 | } 584 | 585 | private void exportPcodeOpSequence(HighFunction hfn, HashSet set) { 586 | Iterator opiter = hfn.getPcodeOps(); 587 | HashSet seenParents = new HashSet(); 588 | HashMap first = new HashMap(); 589 | HashMap last = new HashMap(); 590 | while (opiter.hasNext()) { 591 | PcodeOpAST op = opiter.next(); 592 | PcodeBlockBasic parent = op.getParent(); 593 | if (seenParents.contains(parent)) { 594 | continue; 595 | } 596 | Iterator iterator = parent.getIterator(); 597 | PcodeOp prev = null; 598 | PcodeOp next = null; 599 | while (iterator.hasNext()) { 600 | next = iterator.next(); 601 | if (prev == null && set.contains(next)) { 602 | first.put(parent, next); 603 | } 604 | if (prev != null && set.contains(prev) && set.contains(next)) { 605 | export("PCODE_NEXT", pcodeID(hfn, prev), pcodeID(hfn, next)); 606 | } 607 | prev = next; 608 | } 609 | if (next != null && set.contains(next)) { 610 | last.put(parent, next); 611 | } 612 | seenParents.add(parent); 613 | } 614 | for (PcodeBlock block : first.keySet()) { 615 | PcodeOpAST ast = (PcodeOpAST) first.get((block)); 616 | export("BB_FIRST", bbID(hfn, block), pcodeID(hfn, ast)); 617 | } 618 | for (PcodeBlock block : last.keySet()) { 619 | export("BB_LAST", bbID(hfn, block), pcodeID(hfn, last.get(block))); 620 | } 621 | } 622 | 623 | private String pcodeID(HighFunction hfn, PcodeOp op) { 624 | SequenceNumber sn = op.getSeqnum(); 625 | if (sn != null) { 626 | return hfuncID(hfn)+SEP+sn.getTarget()+SEP+sn.getTime(); 627 | } 628 | return hfuncID(hfn)+SEP+"NO_SEQNUM"+SEP+op.toString(); 629 | } 630 | 631 | private String vnodeID(HighFunction hfn, VarnodeAST vn) { 632 | return hfuncID(hfn)+SEP+Integer.toString(vn.getUniqueId()); 633 | } 634 | 635 | private String hvarID(HighFunction hfn, HighVariable hv) { 636 | return hfuncID(hfn)+SEP+hvarName(hfn, hv); 637 | } 638 | private String hvarName(HighFunction hfn, HighVariable hv) { 639 | if (hv.getName() == null) { 640 | SymbolTable symbolTable = hfn.getFunction().getProgram().getSymbolTable(); 641 | Varnode rep = hv.getRepresentative(); 642 | Address addr = rep.getAddress(); 643 | if (extraGlobals.containsKey(hv)) { 644 | VarnodeAST vn = extraGlobals.get(hv); 645 | addr = currentAddress.getNewAddress(vn.getOffset()); 646 | } 647 | Symbol symbol = symbolTable.getPrimarySymbol(addr); 648 | if (symbol == null) { 649 | return Integer.toString(hv.hashCode()); 650 | } 651 | export("HVAR_CLASS", hfuncID(hfn)+SEP+symbol.getName(), "global"); 652 | return symbol.getName(); 653 | } 654 | return hv.getName(); 655 | } 656 | 657 | private String hsID(HighFunction hfn, HighSymbol hs) { 658 | return hfuncID(hfn)+SEP+hs.getName(); 659 | } 660 | 661 | private String funcID(Function fn) { 662 | return fn.getName(true)+"@"+fn.getEntryPoint(); 663 | } 664 | 665 | private String hfuncID(HighFunction fn) { 666 | return fn.toString(); 667 | } 668 | 669 | private String bbID(HighFunction hfn, PcodeBlock bb) { 670 | if (bb.getStart() != null) { 671 | return hfuncID(hfn)+SEP+bb.hashCode(); 672 | } 673 | return hfuncID(hfn)+SEP+"unknown block"; 674 | } 675 | 676 | private String dtID(DataType dt) { 677 | if (dt.getName() != null) { 678 | return dt.getName().replaceAll(" ", ""); 679 | } 680 | return dt.toString(); 681 | } 682 | 683 | } 684 | -------------------------------------------------------------------------------- /PCodeDumpSF.java: -------------------------------------------------------------------------------- 1 | /* ### 2 | * IP: GHIDRA 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | //Decompile the function at the cursor and its callees, then output facts files corresponding to the pcodes 17 | //@category PCode 18 | 19 | import java.io.File; 20 | import java.io.FileNotFoundException; 21 | import java.io.PrintWriter; 22 | import java.util.HashMap; 23 | import java.util.HashSet; 24 | import java.util.Iterator; 25 | import java.util.Set; 26 | 27 | import ghidra.app.decompiler.DecompInterface; 28 | import ghidra.app.decompiler.DecompileException; 29 | import ghidra.app.decompiler.DecompileOptions; 30 | import ghidra.app.decompiler.DecompileResults; 31 | import ghidra.app.script.GhidraScript; 32 | import ghidra.framework.plugintool.PluginTool; 33 | import ghidra.program.model.address.Address; 34 | import ghidra.program.model.data.AbstractFloatDataType; 35 | import ghidra.program.model.data.AbstractIntegerDataType; 36 | import ghidra.program.model.data.Array; 37 | import ghidra.program.model.data.BooleanDataType; 38 | import ghidra.program.model.data.DataType; 39 | import ghidra.program.model.data.DataTypeComponent; 40 | import ghidra.program.model.data.Enum; 41 | import ghidra.program.model.data.FunctionDefinition; 42 | import ghidra.program.model.data.GenericCallingConvention; 43 | import ghidra.program.model.data.ParameterDefinition; 44 | import ghidra.program.model.data.Pointer; 45 | import ghidra.program.model.data.Structure; 46 | import ghidra.program.model.data.TypeDef; 47 | import ghidra.program.model.data.Union; 48 | import ghidra.program.model.listing.Function; 49 | import ghidra.program.model.pcode.FunctionPrototype; 50 | import ghidra.program.model.pcode.HighConstant; 51 | import ghidra.program.model.pcode.HighFunction; 52 | import ghidra.program.model.pcode.HighGlobal; 53 | import ghidra.program.model.pcode.HighLocal; 54 | import ghidra.program.model.pcode.HighOther; 55 | import ghidra.program.model.pcode.HighParam; 56 | import ghidra.program.model.pcode.HighSymbol; 57 | import ghidra.program.model.pcode.HighVariable; 58 | import ghidra.program.model.pcode.PcodeBlock; 59 | import ghidra.program.model.pcode.PcodeBlockBasic; 60 | import ghidra.program.model.pcode.PcodeOp; 61 | import ghidra.program.model.pcode.PcodeOpAST; 62 | import ghidra.program.model.pcode.SequenceNumber; 63 | import ghidra.program.model.pcode.Varnode; 64 | import ghidra.program.model.pcode.VarnodeAST; 65 | import ghidra.program.model.symbol.Symbol; 66 | import ghidra.program.model.symbol.SymbolIterator; 67 | import ghidra.program.model.symbol.SymbolTable; 68 | 69 | public class PCodeDumpSF extends GhidraScript { 70 | 71 | String SEP = ":"; 72 | String TAB = "\t"; 73 | String QUOTE = "\""; 74 | 75 | Set toProcess = new HashSet(); 76 | Set isEP = new HashSet(); 77 | File outputDirectory; 78 | PrintWriter ia; 79 | //HashMap pws = new HashMap(); 80 | HashSet decls = new HashSet(); 81 | HashMap pairs; 82 | HashSet types = new HashSet(); 83 | HashMap extraGlobals = new HashMap(); 84 | 85 | @Override 86 | protected void run() throws Exception { 87 | PluginTool tool = state.getTool(); 88 | if (tool == null) { 89 | println("Script is not running in GUI"); 90 | } 91 | outputDirectory = askDirectory("Select Directory for Results", "OK"); 92 | try { 93 | File f = new File(outputDirectory,currentProgram.getName()+".facts"); 94 | ia = new PrintWriter(f); 95 | //pws.put("input_assist.dl", ia); 96 | //ia.println("table S2N[string, int]"); 97 | //File f2 = new File(outputDirectory, "S2N.facts"); 98 | //PrintWriter pw = new PrintWriter(f2); 99 | //pws.put("S2N", pw); 100 | } catch (FileNotFoundException e) { 101 | e.printStackTrace(); 102 | } 103 | 104 | DecompileOptions options = new DecompileOptions(); 105 | DecompInterface ifc = new DecompInterface(); 106 | ifc.setOptions(options); 107 | ifc.setSimplificationStyle("decompile"); 108 | 109 | if (!ifc.openProgram(this.currentProgram)) { 110 | throw new DecompileException("Decompiler", "Unable to initialize: "+ifc.getLastMessage()); 111 | } 112 | 113 | toProcess = new HashSet(); 114 | Function func = this.getFunctionContaining(this.currentAddress); 115 | if (func != null) { 116 | collectFunctions(func); 117 | isEP.add(func); 118 | } else { 119 | for (Function f : this.currentProgram.getFunctionManager().getFunctions(true)) { 120 | collectFunctions(f); 121 | isEP.add(f); 122 | } 123 | for (Function f : this.currentProgram.getFunctionManager().getExternalFunctions()) { 124 | collectFunctions(f); 125 | } 126 | } 127 | for (Function f : toProcess) { 128 | processFunction(ifc, f); 129 | if (monitor.isCancelled()) break; 130 | } 131 | 132 | closeFiles(); 133 | } 134 | 135 | private void collectFunctions(Function f) { 136 | if (toProcess.contains(f)) return; 137 | toProcess.add(f); 138 | Set calledFunctions = f.getCalledFunctions(monitor); 139 | for (Function function : calledFunctions) { 140 | collectFunctions(function); 141 | } 142 | } 143 | 144 | protected void processFunction(DecompInterface ifc, Function f) { 145 | pairs = new HashMap(); 146 | System.out.println("processing "+f.getName()+SEP+f.getEntryPoint()); 147 | 148 | SymbolIterator externalSymbols = f.getProgram().getSymbolTable().getSymbols(f.getName()); 149 | while (externalSymbols.hasNext()) { 150 | Symbol next = externalSymbols.next(); 151 | if (!next.isExternal()) { 152 | Address address = next.getAddress(); 153 | export("HFUNC_LOCAL_EP", f.getEntryPoint().toString(), address.toString()); 154 | } 155 | } 156 | HighFunction high = getHighFunction(ifc, f); 157 | if (high == null) { 158 | String id = funcID(f); 159 | export("HFUNC_FUNC", id, id); 160 | export("HFUNC_TOSTR", id, id); 161 | export("HFUNC_PROTO", id, id); 162 | export("HFUNC_EP", id, f.getEntryPoint().toString()); 163 | export("HFUNC_ISEXT", id, "true"); 164 | return; 165 | } 166 | 167 | HashSet set = new HashSet(); 168 | Iterator opiter = high.getPcodeOps(); 169 | while (opiter.hasNext()) { 170 | PcodeOpAST op = opiter.next(); 171 | if (op != null) { 172 | set.add(op); 173 | exportPcode(high, op); 174 | } 175 | } 176 | exportPcodeOpSequence(high, set); 177 | exportHighFunction(high); 178 | } 179 | 180 | private void closeFiles() { 181 | //for (PrintWriter pw : pws.values()) { 182 | // pw.flush(); 183 | // pw.close(); 184 | //} 185 | ia.close(); 186 | } 187 | 188 | private HighFunction getHighFunction(DecompInterface ifc, Function func) { 189 | DecompileResults res = ifc.decompileFunction(func, 300, null); 190 | HighFunction high = res.getHighFunction(); 191 | if (high == null) { 192 | System.err.println(func+" returned null HighFunction"); 193 | } 194 | return high; 195 | } 196 | 197 | private void export(String label, String key, String value) { 198 | key = key.replaceAll(QUOTE, "'"); 199 | value = value.replaceAll(QUOTE, "'"); 200 | if (!decls.contains(label)) { 201 | ia.println("table "+label+"[string, string]"); 202 | decls.add(label); 203 | } 204 | if (!pairs.containsKey(label+key)) { 205 | ia.println(label+"["+QUOTE+key+QUOTE+","+QUOTE+value+QUOTE+"]"); 206 | pairs.put(label+key, value); 207 | } 208 | } 209 | 210 | private void exportL(String label, String key, long value) { 211 | key = key.replaceAll(QUOTE, "'"); 212 | if (!decls.contains(label)) { 213 | ia.println("table " + label + "[string, int]"); 214 | decls.add(label); 215 | } 216 | if (!pairs.containsKey(label + key)) { 217 | ia.println(label + "[" + QUOTE + key + QUOTE + "," + value + "]"); 218 | pairs.put(label + key, Long.toString(value)); 219 | } 220 | } 221 | 222 | private void exportN(String label, String key, int index, String value) { 223 | key = key.replaceAll(QUOTE, "'"); 224 | value = value.replaceAll(QUOTE, "'"); 225 | if (!decls.contains(label)) { 226 | if (value.equals("")) { 227 | ia.println("table "+label+"[string, int]"); 228 | } else { 229 | ia.println("table "+label+"[string, int, string]"); 230 | } 231 | decls.add(label); 232 | } 233 | if (!pairs.containsKey(label+key+index)) { 234 | if (value.equals("")) { 235 | ia.println(label+"["+QUOTE+key+QUOTE+","+index+"]"); 236 | } else { 237 | ia.println(label+"["+QUOTE+key+QUOTE+","+index+","+QUOTE+value+QUOTE+"]"); 238 | } 239 | pairs.put(label+key+index, value); 240 | } 241 | } 242 | 243 | private void exportNL(String label, String key, int index, long value) { 244 | key = key.replaceAll(QUOTE, "'"); 245 | if (!decls.contains(label)) { 246 | ia.println("table " + label + "[string, int, int]"); 247 | decls.add(label); 248 | } 249 | if (!pairs.containsKey(label + key + index)) { 250 | ia.println(label + "[" + QUOTE + key + QUOTE + "," + index + "," + value + "]"); 251 | pairs.put(label + key + index, Long.toString(value)); 252 | } 253 | } 254 | 255 | private void exportPcode(HighFunction hfn, PcodeOpAST op) { 256 | SequenceNumber sn = op.getSeqnum(); 257 | String outstr = op.toString(); 258 | if (sn != null) { 259 | outstr = sn.getTarget()+SEP+sn.getTime(); 260 | } 261 | String id = pcodeID(hfn,op); 262 | export("PCODE_TOSTR", id, funcID(hfn.getFunction())+SEP+outstr); 263 | export("PCODE_MNEMONIC", id, op.getMnemonic()); 264 | export("PCODE_OPCODE", id, Integer.toString(op.getOpcode())); 265 | export("PCODE_PARENT", id, bbID(hfn,op.getParent())); 266 | export("PCODE_TARGET", id, op.getSeqnum().getTarget().toString()); 267 | exportN("PCODE_INPUT_COUNT", id, op.getNumInputs(), ""); 268 | for (int i = 0; i < op.getNumInputs(); ++i) { 269 | VarnodeAST vni = (VarnodeAST) op.getInput(i); 270 | if (vni != null) { 271 | // OK, this is a little weird, but PTRSUBs with first arg == 0 272 | // are (usually) global variables at address == second arg 273 | if (op.getMnemonic().equals("PTRSUB") && (i == 0)) { 274 | if (vni.getAddress().getOffset() == 0) { 275 | VarnodeAST next = (VarnodeAST) op.getInput(1); 276 | HighVariable high = next.getHigh(); 277 | if (high != null) { 278 | extraGlobals.put(high, next); 279 | } 280 | } 281 | } 282 | exportN("PCODE_INPUT", id, i, vnodeID(hfn,vni)); 283 | exportVarnode(hfn,vni); 284 | } 285 | } 286 | VarnodeAST vno = (VarnodeAST) op.getOutput(); 287 | if (vno != null) { 288 | export("PCODE_OUTPUT", id, vnodeID(hfn,vno)); 289 | exportVarnode(hfn, vno); 290 | } 291 | } 292 | 293 | private void exportVarnode(HighFunction hfn, VarnodeAST vn) { 294 | String id = vnodeID(hfn,vn); 295 | export("VNODE_ADDRESS", id, vn.getAddress().toString()); 296 | if (vn.isAddress()) { 297 | export("VNODE_IS_ADDRESS", id, "true"); 298 | } 299 | if (vn.isAddrTied()) { 300 | export("VNODE_IS_ADDRTIED", id, "true"); 301 | } 302 | export("VNODE_PC_ADDRESS", id, vn.getPCAddress().toString()); 303 | export("VNODE_DESC", id, vn.toString()); 304 | long offset = vn.getOffset(); 305 | exportL("VNODE_OFFSET", id, offset); 306 | if (offset < Integer.MAX_VALUE && offset > Integer.MIN_VALUE) { 307 | exportL("VNODE_OFFSET_N", id, offset); 308 | } 309 | export("VNODE_SIZE", id, Integer.toString(vn.getSize())); 310 | export("VNODE_SPACE", id, vn.getAddress().getAddressSpace().getName()); 311 | HighVariable hv = vn.getHigh(); 312 | if (hv == null) { 313 | //export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.toString()); 314 | export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+vn.toString()); 315 | } else { 316 | if (hv instanceof HighConstant && hv.getDataType() instanceof Pointer) { 317 | if (offset != 0) { 318 | extraGlobals.put(hv, vn); 319 | } 320 | } 321 | //export("VNODE_TOSTR", id, funcID(hfn.getFunction())+hvarName(hfn,hv)); 322 | export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+hvarName(hfn,hv)); 323 | export("VNODE_HVAR", id, hvarID(hfn,hv)); 324 | exportHighVariable(hfn, hv, true); 325 | } 326 | if (vn.getDef() != null) { 327 | export("VNODE_DEF", id, pcodeID(hfn, vn.getDef())); 328 | } 329 | } 330 | 331 | private void exportHighVariable(HighFunction hfn, HighVariable hv, boolean dontDescend) { 332 | String id = hvarID(hfn,hv); 333 | export("HVAR_NAME", id, hvarName(hfn,hv)); 334 | export("HVAR_SIZE", id, Integer.toString(hv.getSize())); 335 | if (hv instanceof HighGlobal) { 336 | export("HVAR_CLASS", id, "global"); 337 | } 338 | if (hv instanceof HighLocal) { 339 | export("HVAR_CLASS", id, "local"); 340 | Address pcAddress = ((HighLocal)hv).getPCAddress(); 341 | if (pcAddress != null) { 342 | export("HVAR_SCOPE", id, pcAddress.toString()); 343 | } 344 | } 345 | if (hv instanceof HighConstant) { 346 | export("HVAR_CLASS", id, "constant"); 347 | } 348 | if (hv instanceof HighOther) { 349 | export("HVAR_CLASS", id, "other"); 350 | } 351 | DataType dataType = hv.getDataType(); 352 | if (dataType != null) { 353 | export("HVAR_TYPE", id, dtID(dataType)); 354 | exportType(dataType); 355 | } 356 | if (!dontDescend) { 357 | VarnodeAST representative = (VarnodeAST) hv.getRepresentative(); 358 | if (representative != null) { 359 | export("HVAR_REPRESENTATIVE", id, vnodeID(hfn,representative)); 360 | exportVarnode(hfn, representative); 361 | } 362 | Varnode[] instances = hv.getInstances(); 363 | for (Varnode varnode : instances) { 364 | exportVarnode(hfn, (VarnodeAST)varnode); 365 | } 366 | } 367 | } 368 | 369 | private void exportType(DataType dataType) { 370 | String id = dtID(dataType); 371 | if (types.contains(id)) return; 372 | types.add(id); 373 | 374 | export("TYPE_NAME", id, id); 375 | exportN("TYPE_LENGTH", id, dataType.getLength(), ""); 376 | while (dataType instanceof TypeDef) { 377 | TypeDef typedef = (TypeDef) dataType; 378 | dataType = typedef.getBaseDataType(); 379 | } 380 | if (dataType instanceof Pointer) { 381 | export("TYPE_POINTER", id, "true"); 382 | DataType baseType = ((Pointer) dataType).getDataType(); 383 | if (baseType != null) { 384 | export("TYPE_POINTER_BASE", id, dtID(baseType)); 385 | exportType(baseType); 386 | } else { 387 | System.err.println("TEST"); 388 | } 389 | } 390 | if (dataType instanceof Array) { 391 | export("TYPE_ARRAY", id, "true"); 392 | Array arr = (Array) dataType; 393 | export("TYPE_ARRAY_BASE", id, dtID(arr.getDataType())); 394 | exportN("TYPE_ARRAY_N", id, arr.getNumElements(), ""); 395 | exportN("TYPE_ARRAY_ELEMENT_LENGTH", id, arr.getElementLength(), ""); 396 | exportType(arr.getDataType()); 397 | } 398 | if (dataType instanceof Structure) { 399 | export("TYPE_STRUCT", id, "true"); 400 | Structure struct = (Structure) dataType; 401 | exportN("TYPE_STRUCT_FIELD_COUNT", id, struct.getNumComponents(), ""); 402 | for (int i = 0; i < struct.getNumComponents(); i++) { 403 | DataTypeComponent dtc = struct.getComponent(i); 404 | exportComponent("TYPE_STRUCT", id, i, dtc); 405 | } 406 | } 407 | if (dataType instanceof Union) { 408 | export("TYPE_UNION", id, "true"); 409 | Union union = (Union) dataType; 410 | exportN("TYPE_UNION_FIELD_COUNT", id, union.getNumComponents(), ""); 411 | for (int i = 0; i < union.getNumComponents(); i++) { 412 | DataTypeComponent dtc = union.getComponent(i); 413 | exportComponent("TYPE_UNION", id, i, dtc); 414 | } 415 | } 416 | if (dataType instanceof FunctionDefinition) { 417 | export("TYPE_FUNC", id, "true"); 418 | FunctionDefinition fd = (FunctionDefinition) dataType; 419 | export("TYPE_FUNC_RET", id, fd.getReturnType().toString()); 420 | exportType(fd.getReturnType()); 421 | export("TYPE_FUNC_VARARGS", id, Boolean.toString(fd.hasVarArgs())); 422 | ParameterDefinition[] arguments = fd.getArguments(); 423 | exportN("TYPE_FUNC_PARAM_COUNT", id, arguments.length, ""); 424 | for (int i = 0; i < arguments.length; i++) { 425 | exportN("TYPE_FUNC_PARAM", id, i, arguments[i].toString()); 426 | exportType(arguments[i].getDataType()); 427 | } 428 | } 429 | if (dataType instanceof BooleanDataType) { 430 | export("TYPE_BOOLEAN", id, "true"); 431 | } 432 | if (dataType instanceof AbstractIntegerDataType) { 433 | export("TYPE_INTEGER", id, "true"); 434 | } 435 | if (dataType instanceof AbstractFloatDataType) { 436 | export("TYPE_FLOAT", id, "true"); 437 | } 438 | if (dataType instanceof Enum) { 439 | export("TYPE_ENUM", id, "true"); 440 | } 441 | } 442 | 443 | private void exportComponent(String label, String id, int i, DataTypeComponent dtc) { 444 | String dtcid = dtID(dtc.getDataType()); 445 | exportN(label+"_FIELD", id, i, dtcid); 446 | exportNL(label+"_OFFSET", id, i, dtc.getOffset()); 447 | exportNL(label+"_OFFSET_N", id, i, dtc.getOffset()); 448 | if (dtc.getFieldName() != null) { 449 | exportN(label+"_FIELD_NAME", id, i, dtc.getFieldName()); 450 | exportN(label+"_FIELD_NAME_BY_OFFSET", id, dtc.getOffset(), dtc.getFieldName()); 451 | } 452 | exportType(dtc.getDataType()); 453 | } 454 | 455 | private void exportHighFunction(HighFunction hfn) { 456 | for (PcodeBlockBasic bb : hfn.getBasicBlocks()) { 457 | String bbid = bbID(hfn,bb); 458 | export("BB_HFUNC", bbid, hfuncID(hfn)); 459 | if (bb.getStart() != null) { 460 | export("BB_START", bbid, bb.getStart().toString()); 461 | } 462 | for (int i = 0; i < bb.getInSize(); i++) { 463 | export("BB_IN", bbid, bbID(hfn,bb.getIn(i))); 464 | } 465 | for (int i = 0; i < bb.getOutSize(); i++) { 466 | export("BB_OUT", bbid, bbID(hfn,bb.getOut(i))); 467 | } 468 | if (bb.getOutSize() > 1) { 469 | export("BB_TOUT", bbid, bbID(hfn,bb.getTrueOut())); 470 | export("BB_FOUT", bbid, bbID(hfn,bb.getFalseOut())); 471 | } 472 | } 473 | String id = hfuncID(hfn); 474 | export("HFUNC_FUNC", id, funcID(hfn.getFunction())); 475 | export("HFUNC_TOSTR", id, funcID(hfn.getFunction())); 476 | export("HFUNC_CSPEC", id, hfn.getCompilerSpec().toString()); 477 | export("HFUNC_LANG", id, hfn.getLanguage().toString()); 478 | export("HFUNC_EP", id, hfn.getFunction().getEntryPoint().toString()); 479 | FunctionPrototype proto = hfn.getFunctionPrototype(); 480 | if (proto != null) { 481 | export("HFUNC_PROTO", id, funcID(hfn.getFunction())); 482 | exportPrototype(hfn, proto, funcID(hfn.getFunction())); 483 | } 484 | Function f = hfn.getFunction(); 485 | Function thunk = f.getThunkedFunction(false); 486 | if (thunk != null && thunk.isExternal()) { 487 | export("HFUNC_ISEXT", id, "true"); 488 | } 489 | if (isEP.contains(f)) { 490 | export("HFUNC_ISEP", id, "true"); 491 | } 492 | 493 | Iterator symbols = hfn.getLocalSymbolMap().getSymbols(); 494 | while (symbols.hasNext()) { 495 | HighSymbol hs = symbols.next(); 496 | String hsid = hsID(hfn,hs); 497 | export("SYMBOL_HFUNC", hsid, id); 498 | HighVariable hv = hs.getHighVariable(); 499 | if (hv != null) { 500 | export("SYMBOL_HVAR", hsid, hvarID(hfn,hv)); 501 | exportHighVariable(hfn, hv, false); 502 | } 503 | } 504 | } 505 | 506 | private void exportPrototype(HighFunction hfn, FunctionPrototype proto, String id) { 507 | exportN("PROTO_PARAMETER_COUNT", id, proto.getNumParams(), ""); 508 | for (int i = 0; i < proto.getNumParams(); i++) { 509 | HighParam param = proto.getParam(i); 510 | exportN("PROTO_PARAMETER", id, i, hvarID(hfn,param)); 511 | exportN("PROTO_PARAMETER_S", id, i, hvarID(hfn,param)); 512 | export("PROTO_PARAMETER_DATATYPE", hvarID(hfn,param), dtID(param.getDataType())); 513 | exportType(param.getDataType()); 514 | VarnodeAST rep = (VarnodeAST) param.getRepresentative(); 515 | export("PROTO_REPRESENTATIVE", hvarID(hfn,param), vnodeID(hfn, rep)); 516 | exportVarnode(hfn, rep); 517 | } 518 | /* 519 | ParameterDefinition[] parameterDefinitions = proto.getParameterDefinitions(); 520 | if (parameterDefinitions != null) { 521 | for (ParameterDefinition def : parameterDefinitions) { 522 | exportN("PROTO_PARAMETER_DEFINITION", id, def.getOrdinal(), def.getName()); 523 | export("PROTO_PARAMETER_DATATYPE", def.getName(), dtID(def.getDataType())); 524 | exportType(def.getDataType()); 525 | } 526 | } 527 | */ 528 | DataType returnType = proto.getReturnType(); 529 | export("PROTO_RETTYPE", id, dtID(returnType)); 530 | exportType(returnType); 531 | GenericCallingConvention cc = proto.getGenericCallingConvention(); 532 | if (cc != null) { 533 | export("PROTO_CALLING_CONVENTION", id, cc.toString()); 534 | } 535 | export("PROTO_IS_VOID", id, Boolean.toString(proto.hasNoReturn())); 536 | export("PROTO_HAS_THIS", id, Boolean.toString(proto.hasThisPointer())); 537 | export("PROTO_IS_VARARG", id, Boolean.toString(proto.isVarArg())); 538 | export("PROTO_IS_INLINE", id, Boolean.toString(proto.isInline())); 539 | export("PROTO_IS_CONSTRUCTOR", id, Boolean.toString(proto.isConstructor())); 540 | export("PROTO_IS_DESTRUCTOR", id, Boolean.toString(proto.isDestructor())); 541 | } 542 | 543 | private void exportPcodeOpSequence(HighFunction hfn, HashSet set) { 544 | Iterator opiter = hfn.getPcodeOps(); 545 | HashSet seenParents = new HashSet(); 546 | HashMap first = new HashMap(); 547 | HashMap last = new HashMap(); 548 | while (opiter.hasNext()) { 549 | PcodeOpAST op = opiter.next(); 550 | PcodeBlockBasic parent = op.getParent(); 551 | if (seenParents.contains(parent)) { 552 | continue; 553 | } 554 | Iterator iterator = parent.getIterator(); 555 | PcodeOp prev = null; 556 | PcodeOp next = null; 557 | while (iterator.hasNext()) { 558 | next = iterator.next(); 559 | if (prev == null && set.contains(next)) { 560 | first.put(parent, next); 561 | } 562 | if (prev != null && set.contains(prev) && set.contains(next)) { 563 | export("PCODE_NEXT", pcodeID(hfn, prev), pcodeID(hfn, next)); 564 | } 565 | prev = next; 566 | } 567 | if (next != null && set.contains(next)) { 568 | last.put(parent, next); 569 | } 570 | seenParents.add(parent); 571 | } 572 | for (PcodeBlock block : first.keySet()) { 573 | PcodeOpAST ast = (PcodeOpAST) first.get((block)); 574 | export("BB_FIRST", bbID(hfn, block), pcodeID(hfn, ast)); 575 | } 576 | for (PcodeBlock block : last.keySet()) { 577 | export("BB_LAST", bbID(hfn, block), pcodeID(hfn, last.get(block))); 578 | } 579 | } 580 | 581 | private String pcodeID(HighFunction hfn, PcodeOp op) { 582 | SequenceNumber sn = op.getSeqnum(); 583 | if (sn != null) { 584 | return hfuncID(hfn)+SEP+sn.getTarget()+SEP+sn.getTime(); 585 | } 586 | return hfuncID(hfn)+SEP+"NO_SEQNUM"+SEP+op.toString(); 587 | } 588 | 589 | private String vnodeID(HighFunction hfn, VarnodeAST vn) { 590 | return hfuncID(hfn)+SEP+Integer.toString(vn.getUniqueId()); 591 | } 592 | 593 | private String hvarID(HighFunction hfn, HighVariable hv) { 594 | return hfuncID(hfn)+SEP+hvarName(hfn, hv); 595 | } 596 | private String hvarName(HighFunction hfn, HighVariable hv) { 597 | if (hv.getName() == null) { 598 | SymbolTable symbolTable = hfn.getFunction().getProgram().getSymbolTable(); 599 | Varnode rep = hv.getRepresentative(); 600 | Address addr = rep.getAddress(); 601 | if (extraGlobals.containsKey(hv)) { 602 | VarnodeAST vn = extraGlobals.get(hv); 603 | addr = currentAddress.getNewAddress(vn.getOffset()); 604 | } 605 | Symbol symbol = symbolTable.getPrimarySymbol(addr); 606 | if (symbol == null) { 607 | return Integer.toString(hv.hashCode()); 608 | } 609 | export("HVAR_CLASS", hfuncID(hfn)+SEP+symbol.getName(), "global"); 610 | return symbol.getName(); 611 | } 612 | return hv.getName(); 613 | } 614 | 615 | private String hsID(HighFunction hfn, HighSymbol hs) { 616 | return hfuncID(hfn)+SEP+hs.getName(); 617 | } 618 | 619 | private String funcID(Function fn) { 620 | return fn.getName(true)+"@"+fn.getEntryPoint(); 621 | } 622 | 623 | private String hfuncID(HighFunction fn) { 624 | return fn.toString(); 625 | } 626 | 627 | private String bbID(HighFunction hfn, PcodeBlock bb) { 628 | if (bb.getStart() != null) { 629 | return hfuncID(hfn)+SEP+bb.hashCode(); 630 | } 631 | return hfuncID(hfn)+SEP+"unknown block"; 632 | } 633 | 634 | private String dtID(DataType dt) { 635 | if (dt.getName() != null) { 636 | return dt.getName().replaceAll(" ", ""); 637 | } 638 | return dt.toString(); 639 | } 640 | 641 | } 642 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ghidra_pcode_scripts 2 | a few Ghidra scripts for dumping PCode data 3 | -------------------------------------------------------------------------------- /TestHighlight.java: -------------------------------------------------------------------------------- 1 | /* ### 2 | * IP: GHIDRA 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | //Set program highlight based on results files 17 | //@category PCode 18 | 19 | import java.awt.Color; 20 | import java.io.BufferedReader; 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.InputStream; 24 | 25 | import org.python.jline.internal.InputStreamReader; 26 | 27 | import ghidra.app.plugin.core.colorizer.ColorizingService; 28 | import ghidra.app.script.GhidraScript; 29 | import ghidra.framework.plugintool.PluginTool; 30 | import ghidra.program.model.address.Address; 31 | import ghidra.program.model.address.AddressFormatException; 32 | import ghidra.program.model.address.AddressSet; 33 | 34 | public class TestHighlight extends GhidraScript { 35 | 36 | AddressSet selection = new AddressSet(); 37 | 38 | @Override 39 | protected void run() throws Exception { 40 | PluginTool tool = state.getTool(); 41 | if (tool == null) { 42 | println("Script is not running in GUI"); 43 | return; 44 | } 45 | ColorizingService color = tool.getService(ColorizingService.class); 46 | if (color == null) { 47 | println("Can't find ColorizingService"); 48 | return; 49 | } 50 | File f = askFile("Results File", "OK"); 51 | InputStream in = new FileInputStream(f); 52 | BufferedReader br = new BufferedReader(new InputStreamReader(in)); 53 | String line; 54 | while ((line = br.readLine()) != null) { 55 | matchLine(color, line); 56 | } 57 | this.setCurrentHighlight(selection); 58 | this.setCurrentSelection(selection); 59 | br.close(); 60 | } 61 | 62 | private void matchLine(ColorizingService color, String line) { 63 | String[] tokens = line.split("\t"); 64 | String src = tokens[0]; 65 | String vn = tokens[1]; 66 | String[] subtokens = vn.split(":"); 67 | String addr = subtokens[1]; 68 | try { 69 | Address address = currentAddress.getAddress(addr); 70 | selection.add(address); 71 | Color c = new Color(src.hashCode()); 72 | color.setBackgroundColor(address, address, c); 73 | selection.add(address); 74 | } catch (AddressFormatException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | 79 | } 80 | --------------------------------------------------------------------------------