{"id":13787415,"url":"https://github.com/HackOvert/GhidraSnippets","last_synced_at":"2025-05-12T00:31:01.229Z","repository":{"id":37939487,"uuid":"224438500","full_name":"HackOvert/GhidraSnippets","owner":"HackOvert","description":"Python snippets for Ghidra's Program and Decompiler APIs","archived":false,"fork":false,"pushed_at":"2023-07-19T16:07:24.000Z","size":45,"stargazers_count":743,"open_issues_count":2,"forks_count":64,"subscribers_count":21,"default_branch":"master","last_synced_at":"2024-11-18T00:37:26.710Z","etag":null,"topics":["decompiler","ghidra","ghidra-snippets"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HackOvert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-11-27T13:35:09.000Z","updated_at":"2024-11-13T05:32:10.000Z","dependencies_parsed_at":"2024-01-10T02:36:55.293Z","dependency_job_id":"b7f27170-a5d4-4a55-ade6-be822bbece58","html_url":"https://github.com/HackOvert/GhidraSnippets","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HackOvert%2FGhidraSnippets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HackOvert%2FGhidraSnippets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HackOvert%2FGhidraSnippets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HackOvert%2FGhidraSnippets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HackOvert","download_url":"https://codeload.github.com/HackOvert/GhidraSnippets/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253655805,"owners_count":21943069,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decompiler","ghidra","ghidra-snippets"],"created_at":"2024-08-03T20:00:34.134Z","updated_at":"2025-05-12T00:30:59.422Z","avatar_url":"https://github.com/HackOvert.png","language":null,"funding_links":[],"categories":["Resources"],"sub_categories":["By Purpose"],"readme":"# Ghidra Snippets\n*Ghidra Snippets* is a collection of Python examples showing how to work with [Ghidra](https://ghidra-sre.org/) APIs. There are three primary APIs covered here, the [Flat Program API][1], the [Flat Decompiler API][2], and everything else (\"Complex API\"). The Flat APIs are 'simple' versions of the full fledged Complex Ghidra API. They are a great starting point for anyone looking to develop Ghidra modules and/or scripts.\n\nAt some point however, you need to reach outside of the Flat APIs to do really interesting things. Everything here is just a mashup to get the job done. There's more than one way to accomplish each task so make sure you ask yourself if these snippets are really what you need before copy/pasta.\n\n# Latest Release \u0026 API Docs\n* Loooking for the latest release of Ghidra? [Download it here][0]. \n* Loooking for the latest API Docs? In Ghidra's UI, select **Help** -\u003e **Ghidra API Help** to unpack the docs and view them.\n* Just want a quick online API reference? [Ghidra.re](https://ghidra.re/) hosts an online version of the [API docs](https://ghidra.re/ghidra_docs/api/index.html) (may not be up to date).\n\n# Contributing\n\nFeel free to submit pull requests to master on this repo with any modifications you see fit. Most of these snippets are meant to be verbose, but if you know of a better way to do something, please share it via pull request or submitting an issue. Thanks!\n\n# Table of Contents\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with the Flat APIs\u003c/summary\u003e\n\n* [`Using the FlatProgramAPI`](#using-the-flatprogramapi)\n* [`Using the FlatDecompilerAPI`](#using-the-flatdecompilerapi)\n* [`Using the FlatDebuggerAPI`](#using-the-flatdebuggerapi)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Projects\u003c/summary\u003e\n\n* [`Get the name and location on disk of the current project`](#get-the-name-and-location-on-disk-of-the-current-project)\n* [`List all programs in the current project`](#list-all-programs-in-the-current-project)\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Programs\u003c/summary\u003e\n\n* [`List the current program name and location on disk`](#list-the-current-program-name-and-location-on-disk)\n* [`List the name and size of program sections`](#list-the-name-and-size-of-program-sections)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Functions\u003c/summary\u003e\n\n* [`Enumerate all functions printing their name and address`](#enumerate-all-functions-printing-their-name-and-address)\n* [`Get a function name by address`](#get-a-function-name-by-address)\n* [`Get a function address by name`](#get-a-function-address-by-name)\n* [`Get cross references to a function`](#get-cross-references-to-a-function)\n* [`Analyzing function call arguments`](#analyzing-function-call-arguments)\n* [`Analyzing function call arguments at cross references`](#analyzing-function-call-arguments-at-cross-references)\n* [`Rename functions based on strings`](#rename-functions-based-on-strings)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Basic Blocks\u003c/summary\u003e\n\n* [`Print details about basic blocks in a select function`](#print-details-about-basic-blocks-in-a-select-function)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Instructions\u003c/summary\u003e\n\n* [`Print all instructions in a select function`](#print-all-instructions-in-a-select-function)\n* [`Find all calls and jumps to a register`](#find-all-calls-and-jumps-to-a-register)\n* [`Count all mnemonics in a binary`](#count-all-mnemonics-in-a-binary)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Variables\u003c/summary\u003e\n\n* [`Get a stack variable from a Varnode or VarnodeAST`](#get-a-stack-variable-from-a-varnode-or-varnodeast)\n* [`Get stack variables from a PcodeOpAST`](#get-a-stack-variable-from-a-pcodeopast)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with the Decompiler\u003c/summary\u003e\n\n* [`Print decompiled code for a specific function`](#print-decompiled-code-for-a-specific-function)\n* [`Getting variable information from the decompiler`](#getting-variable-information-from-the-decompiler)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Comments\u003c/summary\u003e\n\n* [`Get all Automatic comments for a function`](#get-all-automatic-comments-for-a-function)\n* [`Get specific comment types for all functions`](#get-specific-comment-types-for-all-functions)\n\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with PCode\u003c/summary\u003e\n\n* [`Emulating a function`](#emulating-a-function)\n* [`Dumping Raw PCode`](#dumping-raw-pcode)\n* [`Dumping Refined PCode`](#dumping-refined-pcode)\n* [`Plotting a Function AST`](#plotting-a-function-ast)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWorking with Graphs\u003c/summary\u003e\n\n* [`Creating a Call Graph`](#creating-a-call-graph)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eMiscellaneous\u003c/summary\u003e\n\n* [`Program Slices`](#program-slices)\n\n\u003c/details\u003e\n\n## Working with the Flat APIs\nAs stated in the introduction, the simplest method of using Ghidra's API is via the Flat APIs. As of Ghidra 10.2 this includes FlatProgramAPI, FlatDecompilerAPI, and the most recent FlatDebuggerAPI. The Flat APIs are designed to offer a stable API interface to some of Ghidra's high level functionality. The simplicity and convenience offered by the Flat APIs can be quickly eclipsed by their limited functionality. However, if what you need to do is offered via the Flat APIs, it's highly recommended you use them.\n\n### Using the FlatProgramAPI\nThe `FlatProgramAPI` is a simple interface to Ghidra's program related functionality. This includes functions, data, instructions, etc.\n\n```python\nfrom ghidra.program.flatapi import FlatProgramAPI\n\nstate = getState()\nprogram = state.getCurrentProgram()\nfpapi = FlatProgramAPI(program)\n\nfor x in dir(fpapi): print(x)\nprint(fpapi.currentProgram)\nprint(fpapi.firstFunction)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nMAX_REFERENCES_TO\n__class__\n\u003c...snip...\u003e\naddressFactory\nanalyze\nanalyzeAll\n\u003c...snip...\u003e\ncurrentProgram\ndisassemble\n\u003c...snip...\u003e\nfindStrings\nfirstData\nfirstFunction\nfirstInstruction\ngetAddressFactory\ngetBookmarks\n\u003c...snip...\u003e\nbug - .ProgramDB\n_init\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### Using the FlatDecompilerAPI\nThe `FlatDecompilerAPI` is a simple interface to Ghidra's decompiler and requires an instance of the `FlatProgramAPI` for initialization in order to do anything useful. In other words, we need a target program to use the decompiler.\n\n```python\nfrom ghidra.app.decompiler.flatapi import FlatDecompilerAPI\nfrom ghidra.program.flatapi import FlatProgramAPI\n\nfpapi = FlatProgramAPI(getState().getCurrentProgram())\nfdapi = FlatDecompilerAPI(fpapi)\n\nfor x in dir(fdapi): print(x)\n\nmain_decomp = fdapi.decompile(fpapi.getFunction('main'))\nprint(main_decomp)\n\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n\u003c...snip...\u003e\ndecompile\ndecompiler\ndispose\nequals\ngetClass\ngetDecompiler\nhashCode\ninitialize\nnotify\nnotifyAll\ntoString\nwait\n\nint main(void)\n\n{\n  int retVal;\n  long in_FS_OFFSET;\n  int choice;\n  char *local_38 [5];\n  long stackCookie;\n  \n  stackCookie = *(long *)(in_FS_OFFSET + 0x28);\n  choice = 0;\n  local_38[0] = \"My secret\";\n  local_38[1] = \"Red\";\n  local_38[2] = \"Green\";\n  local_38[3] = \"Blue\";\n  printf(\"Choice: \");\n  __isoc99_fscanf(stdin,\"%d\",\u0026choice);\n  if ((choice == 0) || (3 \u003c choice)) {\n    printf(\"Invalid choice: %d!\\n\",(ulong)(uint)choice);\n    retVal = -1;\n  }\n  else {\n    printf(\"data[%d]: %s\\n\",(ulong)(uint)choice,local_38[(int)(char)choice]);\n    retVal = 0;\n  }\n  if (stackCookie != *(long *)(in_FS_OFFSET + 0x28)) {\n                    /* WARNING: Subroutine does not return */\n    __stack_chk_fail();\n  }\n  return retVal;\n}\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### Using the FlatDebuggerAPI\nThe `FlatDebuggerAPI` is a simple interface to Ghidra's debugger and trace functionality. This is a new feature as of Ghidra 10.2 and yet to be documented in the Ghidra 10.2 API docs. For some extra context about this API, see [DemoDebuggerScript.java](https://github.com/NationalSecurityAgency/ghidra/blob/Ghidra_10.2_build/Ghidra/Debug/Debugger/ghidra_scripts/DemoDebuggerScript.java). As I learn more about this API I'll update this section.\n\n```python\nfrom ghidra.debug.flatapi import FlatDebuggerAPI\n\nfdapi = FlatDebuggerAPI\n\nfor x in dir(fdapi): print(x)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n\u003c...snip...\u003e\nkill\nlaunch\nlaunchOffers\n\u003c...snip...\u003e\nwriteMemory\nwriteRegister\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n## Working with Projects\nA Ghidra *Project* (class [GhidraProject][4]) contains a logical set of program binaries related to a reverse engineering effort. Projects can be shared (collaborative) or non-shared (private). The snippets in this section deal with bulk import and analysis, locating project files on disk, and more.\n\n### Get the name and location on disk of the current project\nIf you're looking to automate analysis using headless scripts you'll likley have to deal with project management. This includes adding binaries to existing projects, cleaning up old projects, or perhaps syncing analysis to shared projects.\n\n```python\nstate = getState()\nproject = state.getProject()\nprogram = state.getCurrentProgram()\nlocator = project.getProjectData().getProjectLocator()\nprint(\"type(state):           {}\".format(type(state)))\nprint(\"type(project):         {}\".format(type(project)))\nprint(\"type(program):         {}\".format(type(program)))\nprint(\"type(locator):         {}\".format(type(locator)))\nprint(\"Project Name:          {}\".format(locator.getName()))\nprint(\"Files in this project: {}\".format(project.getProjectData().getFileCount()))\nprint(\"Is a remote project:   {}\".format(locator.isTransient()))\nprint(\"Project location:      {}\".format(locator.getLocation()))\nprint(\"Project directory:     {}\".format(locator.getProjectDir()))\nprint(\"Lock file:             {}\".format(locator.getProjectLockFile()))\nprint(\"Marker file:           {}\".format(locator.getMarkerFile()))\nprint(\"Project URL:           {}\".format(locator.getURL()))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\ntype(state):           \u003ctype 'ghidra.app.script.GhidraState'\u003e\ntype(project):         \u003ctype 'ghidra.framework.project.DefaultProject'\u003e\ntype(program):         \u003ctype 'ghidra.program.database.ProgramDB'\u003e\ntype(locator):         \u003ctype 'ghidra.framework.model.ProjectLocator'\u003e\nProject Name:          pcodeproject\nFiles in this project: 4\nIs a remote project:   0\nProject location:      C:\\Users\\username\\Desktop\\pcode\nProject directory:     C:\\Users\\username\\Desktop\\pcode\\pcodeproject.rep\nLock file:             C:\\Users\\username\\Desktop\\pcode\\pcodeproject.lock\nMarker file:           C:\\Users\\username\\Desktop\\pcode\\pcodeproject.gpr\nProject URL:           ghidra:/C:/Users/username/Desktop/pcode/pcodeproject\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### List all programs in the current project\nA Ghidra project is a logical collection binaries that relate to a specific RE effort. This might be a single executable with multiple shared objects, or multiple executables with numerous third-party libraries, kernel modules, and drivers.\n\n```python\nstate = getState()\nproject = state.getProject()\nlocator = project.getProjectData().getProjectLocator()\nprojectMgr = project.getProjectManager()\nactiveProject = projectMgr.getActiveProject()\nprojectData = activeProject.getProjectData()\nrootFolder = projectData.getRootFolder()\n\nprint(\"type(state):           {}\".format(type(state)))\nprint(\"type(project):         {}\".format(type(project)))\nprint(\"type(projectMgr):      {}\".format(type(projectMgr)))\nprint(\"type(activeProject):   {}\".format(type(activeProject)))\nprint(\"type(projectData):     {}\".format(type(projectData)))\nprint(\"type(rootFolder):      {}\".format(type(rootFolder)))\n\nprojectName = locator.getName()\nfileCount = projectData.getFileCount()\nfiles = rootFolder.getFiles()\n\nprint(\"The project '{}' has {} files in it:\".format(projectName, fileCount))\nfor file in files:\n\tprint(\"\\t{}\".format(file))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\ntype(state):           \u003ctype 'ghidra.app.script.GhidraState'\u003e\ntype(project):         \u003ctype 'ghidra.framework.project.DefaultProject'\u003e\ntype(projectMgr):      \u003ctype 'ghidra.GhidraRun$GhidraProjectManager'\u003e\ntype(activeProject):   \u003ctype 'ghidra.framework.project.DefaultProject'\u003e\ntype(projectData):     \u003ctype 'ghidra.framework.data.ProjectFileManager'\u003e\ntype(rootFolder):      \u003ctype 'ghidra.framework.data.RootGhidraFolder'\u003e\nThe project 'pcodeproject' has 4 files in it:\n\tpcodeproject:/WinSCP.exe\n\tpcodeproject:/deobExampleX86\n\tpcodeproject:/deobHookExampleX86\n\tpcodeproject:/server\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Working with Programs\nA *Program* is a binary component within a Ghidra Project. The snippets in this section deal with gathering information about the Programs within a Project.\n\n### List the current program name and location on disk\n```python\nstate = getState()\ncurrentProgram = state.getCurrentProgram()\nname = currentProgram.getName()\nlocation = currentProgram.getExecutablePath()\nprint(\"The currently loaded program is: '{}'\".format(name))\nprint(\"Its location on disk is: '{}'\".format(location))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nThe currently loaded program is: 'deobExampleX86'\nIts location on disk is: '/C:/Users/username/Desktop/pcode/emulation/deobExampleX86'\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### List the name and size of program sections\n```python\nblocks = currentProgram.getMemory().getBlocks()\nfor block in blocks:\n\tprint(\"Name: {}, Size: {}\".format(block.getName(), block.getSize()))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nName: segment_2.1, Size: 568\nName: .interp, Size: 28\nName: .note.ABI-tag, Size: 32\nName: .note.gnu.build-id, Size: 36\nName: .gnu.hash, Size: 36\nName: .dynsym, Size: 360\nName: .dynstr, Size: 192\nName: .gnu.version, Size: 30\nName: .gnu.version_r, Size: 48\nName: .rela.dyn, Size: 216\nName: .rela.plt, Size: 192\nName: .init, Size: 23\nName: .plt, Size: 144\nName: .plt.got, Size: 8\nName: .text, Size: 706\nName: .fini, Size: 9\nName: .rodata, Size: 134\nName: .eh_frame_hdr, Size: 68\nName: .eh_frame, Size: 296\nName: .init_array, Size: 8\nName: .fini_array, Size: 8\nName: .dynamic, Size: 496\nName: .got, Size: 128\nName: .data, Size: 16\nName: .bss, Size: 16\nName: EXTERNAL, Size: 104\nName: .comment, Size: 43\nName: .shstrtab, Size: 254\nName: .strtab, Size: 672\nName: .symtab, Size: 1728\nName: _elfSectionHeaders, Size: 1856\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Working with Functions\nA *Function* is a subroutine within an Program. The snippets in this section deal with gathering information about Functions and modifying them within an Program.\n\n### Enumerate all functions printing their name and address\nThere are at least two ways to do this. The output is the same for each method.\n```python\n# Method 1:\nfunc = getFirstFunction()\nwhile func is not None:\n    print(\"Function: {} @ 0x{}\".format(func.getName(), func.getEntryPoint()))\n    func = getFunctionAfter(func)\n\n# Method 2:\nfm = currentProgram.getFunctionManager()\nfuncs = fm.getFunctions(True) # True means 'forward'\nfor func in funcs: \n    print(\"Function: {} @ 0x{}\".format(func.getName(), func.getEntryPoint()))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nFunction: _alloca_probe @ 0x1400a8e00\nFunction: FUN_1400a8e70 @ 0x1400a8e70\n... snip ...\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### Get a function name by address\nThis snippet will help you correlate addresses with associated function names.\n\n```python\n# helper function to get a Ghidra Address type\ndef getAddress(offset):\n    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)\n\n# get a FunctionManager reference for the current program\nfunctionManager = currentProgram.getFunctionManager()\n\n# getFunctionAt() only works with function entryPoint addresses!\n# returns `None` if address is not the address of the first\n# instruction in a defined function. Consider using\n# getFunctionContaining() method instead.\naddr = getAddress(0x00100690)\nfuncName = functionManager.getFunctionAt(addr).getName()\nprint(funcName)\n\n# check if a specific address resides in a function\naddr = getAddress(0x00100691)\nprint(functionManager.isInFunction(addr))\n\n# get the function an address belongs to, returns `None` if the address\n# is not part of a defined function.\naddr = getAddress(0x00100691)\nprint(functionManager.getFunctionContaining(addr))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nmain\nTrue\nmain\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### Get a function address by name\nHave a name for a function but want the entry point address for it? This will help you do that. Just remember that two or more functions can share the same name (due to function overloading), so Ghidra will return an array (Python list) you have to consider iterating over.\n\n```python\n# Note that multiple functions can share the same name, so Ghidra's API\n# returns a list of `Function` types. Just keep this in mind.\nname = \"main\"\nfuncs = getGlobalFunctions(name)\nprint(\"Found {} function(s) with the name '{}'\".format(len(funcs), name))\nfor func in funcs:\n\tprint(\"{} is located at 0x{}\".format(func.getName(), func.getEntryPoint()))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nFound 1 function(s) with the name 'main'\nmain is located at 0x00100690\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n### Get cross references to a function\nGhidra makes it easy to find all cross references to a function using `getReferencesTo`. To use this, you'll just need the function's entry address which can be acquired using the `getEntryPoint` method on a function object.  Let's take a look at an example where we find all cross references to functions named \"system\".\n\n```python\nfm = currentProgram.getFunctionManager()\nfuncs = fm.getFunctions(True)\nfor func in funcs:\n  if func.getName() == \"system\":\n    print(\"\\nFound 'system' @ 0x{}\".format(func.getEntryPoint()))\n    entry_point = func.getEntryPoint()\n    references = getReferencesTo(entry_point)\n    for xref in references:\n      print(xref)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nFound 'system' @ 0x004024a0\nFrom: 0040bd34 To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\nFrom: 0040a66c To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\nFrom: 00411dd8 To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\nFrom: 004155d8 To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\nFrom: 00415b20 To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\nFrom: 00415d4c To: 004024a0 Type: UNCONDITIONAL_CALL Op: 0 DEFAULT\n\nFound 'system' @ 0x004300fc\nFrom: 0042f2ec To: 004300fc Type: DATA Op: 0 DEFAULT\nFrom: 004024a8 To: 004300fc Type: UNCONDITIONAL_CALL Op: 0 ANALYSIS\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Analyzing function call arguments\nThis snippet uses a `TARGET_ADDR` which should be the address of a call to return the call arguments at that address. Thanks to [gipi](https://github.com/gipi) for [suggesting](https://github.com/HackOvert/GhidraSnippets/issues/4) this much cleaner way to obtain function call arguments than previously listed!\n\n```python\nfrom ghidra.app.decompiler import DecompileOptions\nfrom ghidra.app.decompiler import DecompInterface\nfrom ghidra.util.task import ConsoleTaskMonitor\n\n# # Disassembly shows: 00434f6c    CALL    FUN_00433ff0\n# # Decompiler shows:  uVar1 = FUN_00433ff0(param_1,param_2,param_3);\nTARGET_ADDR = toAddr(0x00434f6c)\n\noptions = DecompileOptions()\nmonitor = ConsoleTaskMonitor()\nifc = DecompInterface()\nifc.setOptions(options)\nifc.openProgram(currentProgram)\n\nfunc = getFunctionContaining(TARGET_ADDR)\nres = ifc.decompileFunction(func, 60, monitor)\nhigh_func = res.getHighFunction()\npcodeops = high_func.getPcodeOps(TARGET_ADDR)\nop = pcodeops.next()\nprint(op.getInputs())\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\narray(ghidra.program.model.pcode.Varnode, [(ram, 0x433ff0, 8), (stack, 0x4, 4), (stack, 0x8, 4), (stack, 0xc, 4)])\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Analyzing function call arguments at cross references\nIn this snippet we locate cross references to a target function (`TARGET_FUNC`) and show how we can analyze the arguments passed to each call. This can be helpful in analyzing malware, or potentially vulnerable functions.  For malware analysis, this may help \"decrypt\" strings, or in vulnerability research this may help locate functions that may be vulnerable if called with an incorrect value.  The specific analysis performed on the arguments of a called target function are up to you. This snippet will allow you to add your own analysis as you see fit.\n\n```python\nfrom ghidra.app.decompiler import DecompileOptions\nfrom ghidra.app.decompiler import DecompInterface\nfrom ghidra.util.task import ConsoleTaskMonitor\n\nTARGET_FUNC = \"FUN_62de9540\"\n\n# Step 1. Get functions that call the target function ('callers')\ntarget_addr = 0\ncallers = []\nfuncs = getGlobalFunctions(TARGET_FUNC)\nfor func in funcs:\n    if func.getName() == TARGET_FUNC:\n        print(\"\\nFound {} @ 0x{}\".format(TARGET_FUNC, func.getEntryPoint()))\n        target_addr = func.getEntryPoint()\n        references = getReferencesTo(target_addr)\n        for xref in references:\n            call_addr = xref.getFromAddress()\n            caller = getFunctionContaining(call_addr)\n            callers.append(caller)\n        break\n\n# deduplicate callers\ncallers = list(set(callers))\n\n# Step 2. Decompile all callers and find PCODE CALL operations leading to `target_add`\noptions = DecompileOptions()\nmonitor = ConsoleTaskMonitor()\nifc = DecompInterface()\nifc.setOptions(options)\nifc.openProgram(currentProgram)\n\nfor caller in callers:\n    res = ifc.decompileFunction(caller, 60, monitor)\n    high_func = res.getHighFunction()\n    lsm = high_func.getLocalSymbolMap()\n    symbols = lsm.getSymbols()\n    if high_func:\n        opiter = high_func.getPcodeOps()\n        while opiter.hasNext():\n            op = opiter.next()\n            mnemonic = str(op.getMnemonic())\n            if mnemonic == \"CALL\":\n                inputs = op.getInputs()\n                addr = inputs[0].getAddress()\n                args = inputs[1:] # List of VarnodeAST types\n                if addr == target_addr:\n                    print(\"Call to {} at {} has {} arguments: {}\".format(addr, op.getSeqnum().getTarget(), len(args), args))\n                    for arg in args:\n                        # Do stuff with each `arg` here...\n                        # Not sure what to do? Check out this great article by Lars A. Wallenborn for some ideas:\n                        # https://blag.nullteilerfrei.de/2020/02/02/defeating-sodinokibi-revil-string-obfuscation-in-ghidra/\n                        # Specifically, search for the function implementation of \"traceVarnodeValue\"\n                        pass\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nFound FUN_62de9540 @ 0x62de9540\nCall to 62de9540 at 62dede09 has 0 arguments: array(ghidra.program.model.pcode.Varnode)\nCall to 62de9540 at 62dee3c1 has 0 arguments: array(ghidra.program.model.pcode.Varnode)\nCall to 62de9540 at 62def2b2 has 0 arguments: array(ghidra.program.model.pcode.Varnode)\nCall to 62de9540 at 62dea894 has 3 arguments: array(ghidra.program.model.pcode.Varnode, [(stack, 0x4, 4), (const, 0x0, 4), (const, 0x0, 4)])\nCall to 62de9540 at 62ded7ec has 3 arguments: array(ghidra.program.model.pcode.Varnode, [(stack, 0x8, 4), (unique, 0x10000168, 4), (const, 0x0, 4)])\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n\n### Rename functions based on strings\nIn some cases strings will either hint at or give the name of a function when symbols aren't available.  In these cases, we can rename functions based on these strings to help perform reverse engineering.  This becomes a daunting task when there are hundreds or thousands of these cases, making the process of copy, rename, paste, a soul crushing task.  The power of tools like Ghidra is that you can script this.  Take for example this decompiled function found in a binary:\n\n```\nundefined4 FUN_00056b58(void)\n{\n\tundefined4 in_r3;\n\n\tregister_function(1, \"core_Init_Database\", FUN_00058294);\n\tregister_function(1, \"core_Clear_Database\", FUN_00058374);\n\tregister_function(1, \"core_Auth_Database\", FUN_00058584);\n\tregister_function(1, \"core_Add_User_Database\", FUN_00058650);\n\t\n\t// ... hundreds more in this function and in others ...\n\t\n\treturn in_r3;\n}\n```\n\nIn this function, we have calls to a `register_function` which correlates an event string with a handler function.  We want to rename these functions so that `FUN_00058294` becomes `core_Init_Database` and so on.  Below is code that performs this task for every `register_function` in the target binary.\n\n```python\nfrom ghidra.app.decompiler import DecompileOptions\nfrom ghidra.app.decompiler import DecompInterface\nfrom ghidra.util.task import ConsoleTaskMonitor\n\ndef getString(addr):\n\tmem = currentProgram.getMemory()\n\tcore_name_str = \"\"\n\twhile True:\n\t\tbyte = mem.getByte(addr.add(len(core_name_str)))\n\t\tif byte == 0:\n\t\t\treturn core_name_str\n\t\tcore_name_str += chr(byte)\n\n# Get decompiler interface\noptions = DecompileOptions()\nmonitor = ConsoleTaskMonitor()\nifc = DecompInterface()\nifc.setOptions(options)\nifc.openProgram(currentProgram)\n\n# Get reference to `register_function`\nfm = currentProgram.getFunctionManager()\nfuncs = fm.getFunctions(True)\nregister_function = None\nfor func in funcs:\n\tif func.getName() == \"register_function\":\n\t\tregister_function = func\n\t\tbreak\n\n# Get xrefs to \"register_function\"\nentry_point = register_function.getEntryPoint()\nxrefs = getReferencesTo(entry_point)\ncallers = []\nfor xref in xrefs:\n\tfrom_addr = xref.getFromAddress()\n\tcaller = fm.getFunctionContaining(from_addr)\n\tif caller not in callers:\n\t\tcallers.append(caller)\n\n# Process callers (functions calling `register_function`)\nfor caller in callers:\n\tif not caller:\n\t\tcontinue\n\tres = ifc.decompileFunction(caller, 60, monitor)\n\thf = res.getHighFunction()\n\topiter = hf.getPcodeOps()\n\twhile opiter.hasNext():\n\t\top = opiter.next()\n\t\tmnemonic = op.getMnemonic()\n\t\tif mnemonic == \"CALL\":\n\t\t\tcall_target = op.getInput(0)\n\t\t\tif call_target.getAddress() == entry_point:\n\t\t\t\tcore_name = op.getInput(2)\n\t\t\t\tcore_func = op.getInput(3)\n\t\t\t\tcore_name_def = core_name.getDef()\n\t\t\t\tcore_name_addr = toAddr(core_name_def.getInput(0).getOffset())\n\t\t\t\tcore_string = getString(core_name_addr)\n\t\t\t\tcore_func_addr = toAddr(core_func.getDef().getInput(1).getOffset())\n\t\t\t\tcore_func_obj = fm.getFunctionAt(core_func_addr)\n\t\t\t\tcore_func_obj.setName(core_string, ghidra.program.model.symbol.SourceType.DEFAULT)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nundefined4 FUN_00056b58(void)\n{\n\tundefined4 in_r3;\n\n\tregister_function(1, \"core_Init_Database\", core_Init_Database);\n\tregister_function(1, \"core_Clear_Database\", core_Clear_Database);\n\tregister_function(1, \"core_Auth_Database\", core_Auth_Database);\n\tregister_function(1, \"core_Add_User_Database\", core_Add_User_Database);\n\t\n\t// ... hundreds more in this function and in others ...\n\t\n\treturn in_r3;\n}\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n\n\n## Working with Instructions\n\n### Print all instructions in a select function\nJust like `objdump` or a `disas` command in GDB, Ghidra provides a way to dump instructions if you need.  You might do this to generate input for another application, or for documenting issues found during analysis. Whatever you use case might be, you can easily acquire the address, opcodes, and instruction text for a target function, or specific addresses.\n\n```python\nfrom binascii import hexlify\n\nlisting = currentProgram.getListing()\nmain_func = getGlobalFunctions(\"main\")[0] # assume there's only 1 function named 'main'\naddrSet = main_func.getBody()\ncodeUnits = listing.getCodeUnits(addrSet, True) # true means 'forward'\n\nfor codeUnit in codeUnits:\n\tprint(\"0x{} : {:16} {}\".format(codeUnit.getAddress(), hexlify(codeUnit.getBytes()), codeUnit.toString()))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n0x00100690 : 55               PUSH RBP\n0x00100691 : 4889e5           MOV RBP,RSP\n0x00100694 : 4883ec30         SUB RSP,0x30\n0x00100698 : 897ddc           MOV dword ptr [RBP + -0x24],EDI\n0x0010069b : 488975d0         MOV qword ptr [RBP + -0x30],RSI\n0x0010069f : 488d051a010000   LEA RAX,[0x1007c0]\n0x001006a6 : 488945f0         MOV qword ptr [RBP + -0x10],RAX\n0x001006aa : c745e800000000   MOV dword ptr [RBP + -0x18],0x0\n0x001006b1 : eb4d             JMP 0x00100700\n0x001006b3 : 488b45f0         MOV RAX,qword ptr [RBP + -0x10]\n0x001006b7 : 4889c7           MOV RDI,RAX\n0x001006ba : e83bffffff       CALL 0x001005fa\n0x001006bf : 8945ec           MOV dword ptr [RBP + -0x14],EAX\n0x001006c2 : 8b55ec           MOV EDX,dword ptr [RBP + -0x14]\n0x001006c5 : 488b45f0         MOV RAX,qword ptr [RBP + -0x10]\n0x001006c9 : 488d3570092000   LEA RSI,[0x301040]\n0x001006d0 : 4889c7           MOV RDI,RAX\n0x001006d3 : e84fffffff       CALL 0x00100627\n0x001006d8 : 488945f8         MOV qword ptr [RBP + -0x8],RAX\n0x001006dc : 8b45e8           MOV EAX,dword ptr [RBP + -0x18]\n0x001006df : 8d5001           LEA EDX,[RAX + 0x1]\n0x001006e2 : 8955e8           MOV dword ptr [RBP + -0x18],EDX\n0x001006e5 : 488b55f8         MOV RDX,qword ptr [RBP + -0x8]\n0x001006e9 : 89c6             MOV ESI,EAX\n0x001006eb : 4889d7           MOV RDI,RDX\n0x001006ee : e88fffffff       CALL 0x00100682\n0x001006f3 : 8b45ec           MOV EAX,dword ptr [RBP + -0x14]\n0x001006f6 : 4898             CDQE\n0x001006f8 : 4883c001         ADD RAX,0x1\n0x001006fc : 480145f0         ADD qword ptr [RBP + -0x10],RAX\n0x00100700 : 488b45f0         MOV RAX,qword ptr [RBP + -0x10]\n0x00100704 : 0fb600           MOVZX EAX,byte ptr [RAX]\n0x00100707 : 84c0             TEST AL,AL\n0x00100709 : 75a8             JNZ 0x001006b3\n0x0010070b : b800000000       MOV EAX,0x0\n0x00100710 : c9               LEAVE\n0x00100711 : c3               RET\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Find all calls and jumps to a register\nThis snippet shows how to find all instructions in an x86 program that are calls or jumps to a regitser. This information can be useful when attempting to track down a crash by researching code flow in hard-to-debug targets. `getRegister` returns `None` when the specified index is not a regitser. We use `startswith('J')` to account for all jump variants. This is not architecture agnostic and a little goofy but it gets the job done.\n\n```python\nlisting = currentProgram.getListing()\nfunc = getFirstFunction()\nentryPoint = func.getEntryPoint()\ninstructions = listing.getInstructions(entryPoint, True)\n\nfor instruction in instructions:\n    addr = instruction.getAddress()\n    oper = instruction.getMnemonicString()\n    if (oper.startswith('CALL') or oper.startswith('J') and instruction.getRegister(0)):\n        print(\"0x{} : {}\".format(addr, instruction))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n0x001004c8 : CALL RAX\n0x00100544 : JMP RAX\n0x00100595 : JMP RDX\n0x00100771 : CALL R15\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Count all mnemonics in a binary\nWhile recently preparing to teach some introductary x86, I wanted to know the most used mnemonics appearing in a given application to make sure I covered them. This is insanely easy to do in Binary Ninja, but a bit more involved in Ghidra. Essentially, we track mnemonics in a dictionary and increment the count as we process all instructions in a binary.  \n\nThis requires getting a `InstructionDB` and using the `getMnemonicString` method to determine the mnemonic of the native assembly instruction. At the end of this snippet, we copy/pasta code from StackOverflow to sort our collected data without really thinking about how it works and we call it a day. All joking aside, this is a pretty neat way to prioritize which instructions you should focus on learning if you're learning a new architecture and don't know where to begin.\n\n```python\ninstructions = {}\naf = currentProgram.getAddressFactory()\n\nfunc = getFirstFunction()\naddr = af.getAddress(str(func.getEntryPoint()))\nins = getInstructionAt(addr)\n\nwhile ins is not None:\n    mnemonic = ins.getMnemonicString()\n    if mnemonic in instructions:\n        instructions[mnemonic] += 1\n    else:\n        instructions[mnemonic] = 1\n    ins = ins.getNext()\n\nins_sorted = [ (i,mnem) for mnem,i in instructions.iteritems() ]\nins_sorted.sort(reverse=True)\nfor i,mnem in ins_sorted:\n    print(\"{}: {}\".format(i, mnem))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n178636: MOV\n43836: CALL\n35709: LEA\n25479: CMP\n19316: ADD\n18943: JZ\n15751: SUB\n14636: TEST\n14236: POP\n13384: PUSH\n\u003c...snip...\u003e\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n## Working with Variables\n\n### Get a stack variable from a Varnode or VarnodeAST\nWhen working with refined PCode you'll almost exclusively be dealing with `VarnodeAST` or `PCodeOpAST` objects. Correlating these objects to stack variables is not something exposed by the Ghidra API (as far as I can tell in v9.2.2). This leads to a complex mess of taking a varnode and comparing it to the decompiler's stack variable symbols for a given function.  It's not intutitive, and quite frankly, it's been the most confusing and complex thing I've done with the Ghidra API to date. \n\nThis function works when you're passing a Varnode/AST of a simple variable, say something like this:\n\n```c\nmemset(local_88,0,0x10);\n```\n\nIf you want to know what that the first argument (`local_88`) is named \"local_88\" and get its size, you can use this function.  If that first parameter include nested `PCodeOpAST`s however, say something like `(char *)local_a8`, this function will not work because the variable is \"wrapped\" inside of a `CAST` operation. In order to work, this needs to be paired with `get_vars_from_varnode` (ctrl-f to find its definition) to unwrap this onion, isolate the variable VarnodeAST, and then pass it here. There's an example of doing that in this document under the heading \"Get stack variables from a PcodeOpAST\".\n\n```python\ndef get_stack_var_from_varnode(func, varnode):\n    if type(varnode) not in [Varnode, VarnodeAST]:\n        raise Exception(\"Invalid value. Expected `Varnode` or `VarnodeAST`, got {}.\".format(type(varnode)))\n    \n    bitness_masks = {\n        '16': 0xffff,\n        '32': 0xffffffff,\n        '64': 0xffffffffffffffff,\n    }\n\n    try:\n      addr_size = currentProgram.getMetadata()['Address Size']\n      bitmask = bitness_masks[addr_size]\n    except KeyError:\n      raise Exception(\"Unsupported bitness: {}. Add a bit mask for this target.\".format(addr_size))\n\n    local_variables = func.getAllVariables()\n    vndef = varnode.getDef()\n    if vndef:\n        vndef_inputs = vndef.getInputs()\n        for defop_input in vndef_inputs:\n            defop_input_offset = defop_input.getAddress().getOffset() \u0026 bitmask\n            for lv in local_variables:\n                unsigned_lv_offset = lv.getMinAddress().getUnsignedOffset() \u0026 bitmask\n                if unsigned_lv_offset == defop_input_offset:\n                    return lv\n        \n        # If we get here, varnode is likely a \"acStack##\" variable.\n        hf = get_high_function(func)\n        lsm = hf.getLocalSymbolMap()\n        for vndef_input in vndef_inputs:\n            defop_input_offset = vndef_input.getAddress().getOffset() \u0026 bitmask\n            for symbol in lsm.getSymbols():\n                if symbol.isParameter(): \n                    continue\n                if defop_input_offset == symbol.getStorage().getFirstVarnode().getOffset() \u0026 bitmask:\n                    return symbol\n\n    # unable to resolve stack variable for given varnode\n    return None\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n# This output corresponds to this line of code:\n#   memset(local_88,0,0x10);\n# In PCode this line looks like this:\n#   ---  CALL (ram, 0x102370, 8) , (unique, 0x620, 8) , (const, 0x0, 4) , (const, 0x10, 8)\n# The address of `memset` is: (ram, 0x102370, 8)\n# The `local_88` variable is: (unique, 0x620, 8)\n# We'll pass `(unique, 0x620, 8)` to `get_stack_var_from_varnode` to get the following output\n# which will be a list of `ghidra.program.database.function.LocalVariableDB`.\n\n[undefined2 local_88@Stack[-0x88]:2]\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Get stack variables from a PcodeOpAST\nIf you took a look at the code under the section \"Get a stack variable from a Varnode or VarnodeAST\", you'll probably be asking why that code works for something like: `memset(local_88,0,0x10);` but it fails for `strchr((char *)local_a8,10);`. The reason is that `local_88` is a `VarnodeAST` while `(char *)local_a8` is a `PcodeOpAST`. In other words, the `local_a8` varnode is \"wrapped\" inside of a `PcodeOpAST` and you can't associate it to any kind of meaningful value without first \"unwrapping\" it. Of course, a wrapped `VarnodeAST` could be wrapped in numerous `CAST` operations and `INT_ADD` operations, etc.  So how do we handle this? Recursion. * shudder *. \n\nFair warning, recursion is my computer science nemisis. If you look at this code and think \"this is odd\" - you're probably right!\n\nThat being said, let's slap something like `(char *)local_a8` into this function and see if we can get the associated variable name(s) out of it. It's perfectly fine to pass a `PcodeOpAST` with multiple variables (e.g. `(long)iVar2 + local_a0`) into this function. It will just return a list of all variables contained in that `VarnodeAST`.\n\n```python\ndef get_vars_from_varnode(func, node, variables=None):\n    if type(node) not in [PcodeOpAST, VarnodeAST]:\n        raise Exception(\"Invalid value passed. Got {}.\".format(type(node)))\n\n    # create `variables` list on first call. Do not make `variables` default to [].\n    if variables == None:\n        variables = []\n\n    # We must use `getDef()` on VarnodeASTs\n    if type(node) == VarnodeAST:\n        # For `get_stack_var_from_varnode` see:\n        # https://github.com/HackOvert/GhidraSnippets \n        # Ctrl-F for \"get_stack_var_from_varnode\"\n        var = get_stack_var_from_varnode(func, node)\n        if var and type(var) != HighSymbol:\n            variables.append(var.getName())\n        node = node.getDef()\n        if node:\n            variables = get_vars_from_varnode(func, node, variables)\n\n    # We must call `getInputs()` on PcodeOpASTs\n    elif type(node) == PcodeOpAST:\n        nodes = list(node.getInputs())\n        for node in nodes:\n            if type(node.getHigh()) == HighLocal:\n                variables.append(node.getHigh().getName())\n            else:\n                variables = get_vars_from_varnode(func, node, variables)\n\n    return variables\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nPython output goes here...\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n## Working with Basic Blocks\nBasic Blocks are collections of continuous non-branching instructions within Functions. They are joined by conditional and non-conditional branches, revealing valuable information about a program and function's code flow. This section deals with examples working with Basic Block models.\n\n### Print details about basic blocks in a select function\n```python\nfrom ghidra.program.model.block import BasicBlockModel\nfrom ghidra.util.task import ConsoleTaskMonitor\n\nfuncName = 'main'\nblockModel = BasicBlockModel(currentProgram)\nmonitor = ConsoleTaskMonitor()\nfunc = getGlobalFunctions(funcName)[0]\n\nprint(\"Basic block details for function '{}':\".format(funcName))\nblocks = blockModel.getCodeBlocksContaining(func.getBody(), monitor)\n\n# print first block\nprint(\"\\t[*] {} \".format(func.getEntryPoint()))\n\n# print any remaining blocks\nwhile(blocks.hasNext()):\n    bb = blocks.next()\n    dest = bb.getDestinations(monitor)\n    while(dest.hasNext()):\n        dbb = dest.next()\n        # For some odd reason `getCodeBlocksContaining()` and `.next()`\n        # return the root basic block after CALL instructions (x86). To filter\n        # these out, we use `getFunctionAt()` which returns `None` if the address\n        # is not the entry point of a function. See:\n        # https://github.com/NationalSecurityAgency/ghidra/issues/855\n        if not getFunctionAt(dbb.getDestinationAddress()):\n            print(\"\\t[*] {} \".format(dbb))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nBasic block details for function 'main':\n\t[*] 00100690 \n\t[*] 001006b1 -\u003e 00100700 \n\t[*] 001006fc -\u003e 00100700 \n\t[*] 00100709 -\u003e 001006b3 \n\t[*] 00100709 -\u003e 0010070b \n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Working with the Decompiler\n\n### Print decompiled code for a specific function\nGhidra's decompiler is an exceptional resource. In certain cases you might want to extract the decompiler output for a list of functions. Here's an easy way to gather that information.  Just add your own file I/O code to dump everything to individual files for analysis.\n\n```python\nfrom ghidra.app.decompiler import DecompInterface\nfrom ghidra.util.task import ConsoleTaskMonitor\n\nprogram = getCurrentProgram()\nifc = DecompInterface()\nifc.openProgram(program)\n\n# here we assume there is only one function named `main`\nfunction = getGlobalFunctions('main')[0]\n\n# decompile the function and print the pseudo C\nresults = ifc.decompileFunction(function, 0, ConsoleTaskMonitor())\nprint(results.getDecompiledFunction().getC())\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nundefined8 main(void)\n\n{\n  uint uVar1;\n  undefined8 uVar2;\n  uint local_20;\n  undefined1 *local_18;\n  \n  local_18 = data;\n  local_20 = 0;\n  while (*local_18 != '\\0') {\n    uVar1 = length(local_18);\n    uVar2 = deobfuscate(local_18,buffer,(ulong)uVar1);\n    use_string(uVar2,(ulong)local_20,uVar2);\n    local_18 = local_18 + (long)(int)uVar1 + 1;\n    local_20 = local_20 + 1;\n  }\n  return 0;\n}\n\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Getting variable information from the decompiler\nGhidra's decompiler performs a lot of analysis in order to recover variable information.  If you're interested in getting this information you'll need to use the decompiler interface to get a high function and its symbols.  Once you have this data, you can enumerate the symbols and retrieve information about variables in the target function.  Let's take a look at an example decompiled function:\n\n```c++\nundefined8 func(int param_1,int param_2)\n{\n  long in_FS_OFFSET;\n  uint auStack88 [8];\n  undefined4 auStack56 [10];\n  long local_10;\n  \n  local_10 = *(long *)(in_FS_OFFSET + 0x28);\n  auStack56[param_1] = 1;\n  printf(\"%d\\n\",(ulong)auStack88[param_2]);\n  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {\n    __stack_chk_fail();\n  }\n  return 0;\n}\n```\n\nThe decompiled function above shows two stack variables that seem interesting to us; auStack88 and auStack56.  Let's get that information programmatically.\n\n```python\nfrom ghidra.app.decompiler import DecompileOptions\nfrom ghidra.app.decompiler import DecompInterface\nfrom ghidra.util.task import ConsoleTaskMonitor\n\nfunc_name = \"func\"\nfunc = getGlobalFunctions(func_name)[0]\noptions = DecompileOptions()\nmonitor = ConsoleTaskMonitor()\nifc = DecompInterface()\nifc.setOptions(options)\nifc.openProgram(func.getProgram())\nres = ifc.decompileFunction(func, 60, monitor)\nhigh_func = res.getHighFunction()\nlsm = high_func.getLocalSymbolMap()\nsymbols = lsm.getSymbols()\n\nfor i, symbol in enumerate(symbols):\n    print(\"\\nSymbol {}:\".format(i+1))\n    print(\"  name:         {}\".format(symbol.name))\n    print(\"  dataType:     {}\".format(symbol.dataType))\n    print(\"  getPCAddress: 0x{}\".format(symbol.getPCAddress()))\n    print(\"  size:         {}\".format(symbol.size))\n    print(\"  storage:      {}\".format(symbol.storage))\n    print(\"  parameter:    {}\".format(symbol.parameter))\n    print(\"  readOnly:     {}\".format(symbol.readOnly))\n    print(\"  typeLocked:   {}\".format(symbol.typeLocked))\n    print(\"  nameLocked:   {}\".format(symbol.nameLocked))\n    print(\"  slot:         {}\".format(symbol.slot))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nSymbol 1:\n  name:         auStack56\n  dataType:     undefined4[10]\n  getPCAddress: 0xNone\n  size:         40\n  parameter:    0\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         -1\n  storage:      Stack[-0x38]:40\n\nSymbol 2:\n  name:         auStack88\n  dataType:     uint[8]\n  getPCAddress: 0xNone\n  size:         32\n  parameter:    0\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         -1\n  storage:      Stack[-0x58]:32\n\nSymbol 3:\n  name:         in_FS_OFFSET\n  dataType:     long\n  getPCAddress: 0x001006a9\n  size:         8\n  parameter:    0\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         -1\n  storage:      FS_OFFSET:8\n\nSymbol 4:\n  name:         local_10\n  dataType:     long\n  getPCAddress: 0xNone\n  size:         8\n  parameter:    0\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         -1\n  storage:      Stack[-0x10]:8\n\nSymbol 5:\n  name:         param_1\n  dataType:     int\n  getPCAddress: 0x001006a9\n  size:         4\n  parameter:    1\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         0\n  storage:      EDI:4\n\nSymbol 6:\n  name:         param_2\n  dataType:     int\n  getPCAddress: 0x001006a9\n  size:         4\n  parameter:    1\n  readOnly:     0\n  typeLocked:   0\n  nameLocked:   0\n  slot:         1\n  storage:      ESI:4\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Working with Comments\n\n### Get all Automatic comments for a function\n\nGhidra adds \"automatic comments\" (light gray in color) in the EOL field. Here's how you can access those comments.\n\n```python\nfrom ghidra.app.util import DisplayableEol\n\nlisting = currentProgram.getListing()\nfunc = getGlobalFunctions(\"frame_dummy\")[0]\naddrSet = func.getBody()\ncodeUnits = listing.getCodeUnits(addrSet, True)\n\nfor codeUnit in codeUnits:\n\tdeol = DisplayableEol(codeUnit, True, True, True, True, 5, True)\n\tif deol.hasAutomatic():\n\t\tac = deol.getAutomaticComment()\n\t\tprint(type(ac))\n\t\tprint(ac)\n\t\tprint(ac[0])\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n\u003ctype 'array.array'\u003e\narray(java.lang.String, [u'undefined register_tm_clones()'])\nundefined register_tm_clones()\n... snip ...\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Get specific comment types for all functions\n\nGhidra supports 5 unique comment types users can add to their projects. This snippet shows you show to print all comments by type. This snippet is a slightly modified version of what user `u/securisec` posted in the Ghidra subreddit, `r/ghidra`. Thanks!\n\n```python\nfm = currentProgram.getFunctionManager()\nlisting = currentProgram.getListing()\nfuncs = fm.getFunctions(True) # True means iterate forward\n\ncomment_types = { \n    0: 'EOL', \n    1: 'PRE', \n    2: 'POST',\n    3: 'PLATE',\n    4: 'REPEATABLE',\n}\n\nfor func in funcs: \n    addrSet = func.getBody()\n    codeUnits = listing.getCodeUnits(addrSet, True)\n    for codeUnit in codeUnits:\n        for i, comment_type in comment_types.items():\n            comment = codeUnit.getComment(i)\n            if comment is not None:\n                comment = comment.decode(\"utf-8\")\n                print(\"[{} : {}] {}: {}\".format(func.name, codeUnit.address, comment_type, comment))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n[TclCompileSwitchCmd : 00058f3c] EOL: EOL COMMENT 000\n[TclCompileSwitchCmd : 00058f3c] PRE: PRE-COMMENT 111\n[TclCompileSwitchCmd : 00058f3c] POST: POST COMMENT 222\n[TclCompileSwitchCmd : 00058f3c] PLATE: PLATE COMMENT 333\n[TclCompileSwitchCmd : 00058f3c] REPEATABLE: REPEATABLE COMMENT 444\n[getpagesize : 00110000] EOL: Grocery list: milk, cookies, santa trap\n[getpagesize : 00110000] PRE: getpagesize@@GLIBC_2.0\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Working with PCode\n\n### Emulating a function\nInstruction emulation is an extremely powerful technique to asist in static code analysis.  Rarely however, do we have the full memory context in which dynamic code executes. So while emulation can bring an element of 'dynamic' analysis to static RE, it's typically plagued with problems of unknown memory state. For simple code this might be no problem. For object oriented code this can be a major difficulty.  Either way, some element of emulation can help tremendously in speeding up analysis.  Ghidra uses its internal intermediate representation (PCode) to define what instructions do. Emulation is the process of tracking these changes in a cumulative state. Unfortunely Ghidra doesn't provide fancy GUI controls around the emulator (yet), but it's fully scriptable. Ghidra v9.1 added emprovements to the `EmulatorHelper` class, which is really quite amazing. Here's a simple example of what you can do with it.\n\n```python\nfrom ghidra.app.emulator import EmulatorHelper\nfrom ghidra.program.model.symbol import SymbolUtilities\n\n# == Helper functions ======================================================\ndef getAddress(offset):\n    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)\n\ndef getSymbolAddress(symbolName):\n    symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, None)\n    if (symbol != None):\n        return symbol.getAddress()\n    else:\n        raise(\"Failed to locate label: {}\".format(symbolName))\n\ndef getProgramRegisterList(currentProgram):\n    pc = currentProgram.getProgramContext()\n    return pc.registers\n\n# == Main function =========================================================\ndef main():\n    CONTROLLED_RETURN_OFFSET = 0\n\n    # Identify function to be emulated\n    mainFunctionEntry = getSymbolAddress(\"main\")\n\n    # Establish emulation helper, please check out the API docs\n    # for `EmulatorHelper` - there's a lot of helpful things\n    # to help make architecture agnostic emulator tools.\n    emuHelper = EmulatorHelper(currentProgram)\n\n    # Set controlled return location so we can identify return from emulated function\n    controlledReturnAddr = getAddress(CONTROLLED_RETURN_OFFSET)\n\n    # Set initial RIP\n    mainFunctionEntryLong = int(\"0x{}\".format(mainFunctionEntry), 16)\n    emuHelper.writeRegister(emuHelper.getPCRegister(), mainFunctionEntryLong)\n\n    # For x86_64 `registers` contains 872 registers! You probably don't\n    # want to print all of these. Just be aware, and print what you need.\n    # To see all supported registers. just print `registers`.\n    # We won't use this, it's just here to show you how to query\n    # valid registers for your target architecture.\n    registers = getProgramRegisterList(currentProgram)\n\n    # Here's a list of all the registers we want printed after each\n    # instruction. Modify this as you see fit, based on your architecture.\n    reg_filter = [\n        \"RIP\", \"RAX\", \"RBX\", \"RCX\", \"RDX\", \"RSI\", \"RDI\", \n        \"RSP\", \"RBP\", \"rflags\"\n    ]\n\n    # Setup your desired starting state. By default, all registers\n    # and memory will be 0. This may or may not be acceptable for\n    # you. So please be aware.\n    emuHelper.writeRegister(\"RAX\", 0x20)\n    emuHelper.writeRegister(\"RSP\", 0x000000002FFF0000)\n    emuHelper.writeRegister(\"RBP\", 0x000000002FFF0000)\n    \n    # There are a couple of ways to write memory, use `writeMemoryValue` if you want\n    # to set a small typed value (e.g. uint64). Use `writeMemory` if you're mapping in\n    # a lot of memory (e.g. from a debugger memory dump). Note that each of these\n    # methods write with different endianess, see the example output.\n    emuHelper.writeMemoryValue(getAddress(0x000000000008C000), 4, 0x99AABBCC)  # writes big endian\n    emuHelper.writeMemory(getAddress(0x00000000000CF000), b'\\x99\\xAA\\xBB\\xCC') # writes little endian\n\n    # You can verify writes worked, or just read memory at select points\n    # during emulation. Here's a couple of examples:\n    mem1 = emuHelper.readMemory(getAddress(0x000000000008C000), 4)\n    mem2 = emuHelper.readMemory(getAddress(0x00000000000CF000), 4)\n    print(\"Memory at 0x000000000008C000: {}\".format(mem1))\n    print(\"Memory at 0x00000000000CF000: {}\".format(mem2))\n\n    print(\"Emulation starting at 0x{}\".format(mainFunctionEntry))\n    while monitor.isCancelled() is False:\n        \n        # Check the current address in the program counter, if it's\n        # zero (our `CONTROLLED_RETURN_OFFSET` value) stop emulation.\n        # Set this to whatever end target you want.\n        executionAddress = emuHelper.getExecutionAddress()  \n        if (executionAddress == controlledReturnAddr):\n            print(\"Emulation complete.\")\n            return\n\n        # Print current instruction and the registers we care about\n        print(\"Address: 0x{} ({})\".format(executionAddress, getInstructionAt(executionAddress)))\n        for reg in reg_filter:\n            reg_value = emuHelper.readRegister(reg)\n            print(\"  {} = {:#018x}\".format(reg, reg_value))\n\n        # single step emulation\n        success = emuHelper.step(monitor)\n        if (success == False):\n            lastError = emuHelper.getLastError()\n            printerr(\"Emulation Error: '{}'\".format(lastError))\n            return\n\n    # Cleanup resources and release hold on currentProgram\n    emuHelper.dispose()\n\n# == Invoke main ===========================================================\nmain()\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nMemory at 0x000000000008C000: array('b', [-52, -69, -86, -103])\nMemory at 0x00000000000CF000: array('b', [-103, -86, -69, -52])\nEmulation starting at 0x00100690\nAddress: 0x00100690 (PUSH RBP)\n  RIP = 0x0000000000100690\n  RAX = 0x0000000000000020\n  RBX = 0x0000000000000000\n  RCX = 0x0000000000000000\n  RDX = 0x0000000000000000\n  RSI = 0x0000000000000000\n  RDI = 0x0000000000000000\n  RSP = 0x000000002fff0000\n  RBP = 0x000000002fff0000\n  rflags = 0x0000000000000000\nAddress: 0x00100691 (MOV RBP,RSP)\n  RIP = 0x0000000000100691\n  RAX = 0x0000000000000020\n  RBX = 0x0000000000000000\n  RCX = 0x0000000000000000\n  RDX = 0x0000000000000000\n  RSI = 0x0000000000000000\n  RDI = 0x0000000000000000\n  RSP = 0x000000002ffefff8\n  RBP = 0x000000002fff0000\n  rflags = 0x0000000000000000\nAddress: 0x00100694 (SUB RSP,0x30)\n  RIP = 0x0000000000100694\n  RAX = 0x0000000000000020\n  RBX = 0x0000000000000000\n  RCX = 0x0000000000000000\n  RDX = 0x0000000000000000\n  RSI = 0x0000000000000000\n  RDI = 0x0000000000000000\n  RSP = 0x000000002ffefff8\n  RBP = 0x000000002ffefff8\n  rflags = 0x0000000000000000\nAddress: 0x00100698 (MOV dword ptr [RBP + -0x24],EDI)\n  RIP = 0x0000000000100698\n  RAX = 0x0000000000000020\n  RBX = 0x0000000000000000\n  RCX = 0x0000000000000000\n  RDX = 0x0000000000000000\n  RSI = 0x0000000000000000\n  RDI = 0x0000000000000000\n  RSP = 0x000000002ffeffc8\n  RBP = 0x000000002ffefff8\n  rflags = 0x0000000000000000\n... snip ...\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Dumping Raw PCode\nPCode exists in two primary forms you as a user should consider, \"raw\" and \"refined\".  In documentation both forms are simply referred to as \"PCode\" making it confusing to talk about - so I distinguish between the forms using raw and refined. Just know theses are not universally accepted terms. \n\nSo raw PCode is the first pass, and the form that's displayed in the \"Listing\" pane inside the Ghidra UI.  It's extremely verbose and explicit. This is the form you want to use when emulating, if you're writing a symbolic executor, or anything of the sort.  If you want details from the decompiler passes, you want to analyze refined PCode, not this stuff!  So what does it look like and how do you access it? Let's take a look.\n\n```python\ndef dump_raw_pcode(func):\n    func_body = func.getBody()\n    listing = currentProgram.getListing()\n    opiter = listing.getInstructions(func_body, True)\n    while opiter.hasNext():\n        op = opiter.next()\n        raw_pcode = op.getPcode()\n        print(\"{}\".format(op))\n        for entry in raw_pcode:\n            print(\"  {}\".format(entry))\n\nfunc = getGlobalFunctions(\"main\")[0]    # assumes only one function named `main`\ndump_raw_pcode(func)            \t    # dump raw pcode as strings\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\nNote that this looks different from the raw pcode you'll see in the UI (if you enable the PCode field) but it is exactly the same. It's just not formatted to print the same.  Please run this against your own target function and you'll see what I mean.\n\n```\nPUSH RBP\n  (unique, 0x2510, 8) COPY (register, 0x28, 8)\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (unique, 0x2510, 8)\nMOV RBP,RSP\n  (register, 0x28, 8) COPY (register, 0x20, 8)\nSUB RSP,0x50\n  (register, 0x200, 1) INT_LESS (register, 0x20, 8) , (const, 0x50, 8)\n  (register, 0x20b, 1) INT_SBORROW (register, 0x20, 8) , (const, 0x50, 8)\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x50, 8)\n  (register, 0x207, 1) INT_SLESS (register, 0x20, 8) , (const, 0x0, 8)\n  (register, 0x206, 1) INT_EQUAL (register, 0x20, 8) , (const, 0x0, 8)\nMOV dword ptr [RBP + -0x44],EDI\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffbc, 8)\n  (unique, 0x1fd0, 4) COPY (register, 0x38, 4)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1fd0, 4)\nMOV qword ptr [RBP + -0x50],RSI\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffb0, 8)\n  (unique, 0x1ff0, 8) COPY (register, 0x30, 8)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1ff0, 8)\nMOV RAX,qword ptr FS:[0x28]\n  (unique, 0x9e0, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8)\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8)\n  (register, 0x0, 8) COPY (unique, 0x1ff0, 8)\nMOV qword ptr [RBP + -0x8],RAX\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xfffffffffffffff8, 8)\n  (unique, 0x1ff0, 8) COPY (register, 0x0, 8)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1ff0, 8)\nXOR EAX,EAX\n  (register, 0x200, 1) COPY (const, 0x0, 1)\n  (register, 0x20b, 1) COPY (const, 0x0, 1)\n  (register, 0x0, 4) INT_XOR (register, 0x0, 4) , (register, 0x0, 4)\n  (register, 0x0, 8) INT_ZEXT (register, 0x0, 4)\n  (register, 0x207, 1) INT_SLESS (register, 0x0, 4) , (const, 0x0, 4)\n  (register, 0x206, 1) INT_EQUAL (register, 0x0, 4) , (const, 0x0, 4)\nCMP dword ptr [RBP + -0x44],0x1\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffbc, 8)\n  (unique, 0x1fe0, 4) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (register, 0x200, 1) INT_LESS (unique, 0x1fe0, 4) , (const, 0x1, 4)\n  (unique, 0x1fe0, 4) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (register, 0x20b, 1) INT_SBORROW (unique, 0x1fe0, 4) , (const, 0x1, 4)\n  (unique, 0x1fe0, 4) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (unique, 0x5950, 4) INT_SUB (unique, 0x1fe0, 4) , (const, 0x1, 4)\n  (register, 0x207, 1) INT_SLESS (unique, 0x5950, 4) , (const, 0x0, 4)\n  (register, 0x206, 1) INT_EQUAL (unique, 0x5950, 4) , (const, 0x0, 4)\nJG 0x00100743\n  (unique, 0x2220, 1) BOOL_NEGATE (register, 0x206, 1)\n  (unique, 0x2230, 1) INT_EQUAL (register, 0x20b, 1) , (register, 0x207, 1)\n  (unique, 0x2250, 1) BOOL_AND (unique, 0x2220, 1) , (unique, 0x2230, 1)\n   ---  CBRANCH (ram, 0x100743, 8) , (unique, 0x2250, 1)\nMOV RAX,qword ptr [RBP + -0x50]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffb0, 8)\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (register, 0x0, 8) COPY (unique, 0x1ff0, 8)\nMOV RAX,qword ptr [RAX]\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (register, 0x0, 8)\n  (register, 0x0, 8) COPY (unique, 0x1ff0, 8)\nMOV RSI,RAX\n  (register, 0x30, 8) COPY (register, 0x0, 8)\nLEA RDI,[0x1008a4]\n  (register, 0x38, 8) COPY (const, 0x1008a4, 8)\nMOV EAX,0x0\n  (register, 0x0, 8) COPY (const, 0x0, 8)\nCALL 0x001005d0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x100739, 8)\n   ---  CALL (ram, 0x1005d0, 8)\nMOV EAX,0x1\n  (register, 0x0, 8) COPY (const, 0x1, 8)\nJMP 0x001007ff\n   ---  BRANCH (ram, 0x1007ff, 8)\nMOV RAX,0x4242424241414141\n  (register, 0x0, 8) COPY (const, 0x4242424241414141, 8)\nMOV qword ptr [RBP + -0x1c],RAX\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffe4, 8)\n  (unique, 0x1ff0, 8) COPY (register, 0x0, 8)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1ff0, 8)\nMOV word ptr [RBP + -0x14],0x43\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffec, 8)\n  (unique, 0x1fc0, 2) COPY (const, 0x43, 2)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1fc0, 2)\nMOV qword ptr [RBP + -0x2c],0x0\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffd4, 8)\n  (unique, 0x2000, 8) COPY (const, 0x0, 8)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x2000, 8)\nLEA RDX,[RBP + -0x1c]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffe4, 8)\n  (register, 0x10, 8) COPY (unique, 0x620, 8)\nLEA RAX,[RBP + -0x2c]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffd4, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RDX\n  (register, 0x30, 8) COPY (register, 0x10, 8)\nMOV RDI,RAX\n  (register, 0x38, 8) COPY (register, 0x0, 8)\nCALL 0x001005b0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x100772, 8)\n   ---  CALL (ram, 0x1005b0, 8)\nLEA RAX,[RBP + -0x2c]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffd4, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RAX\n  (register, 0x30, 8) COPY (register, 0x0, 8)\nLEA RDI,[0x1008b6]\n  (register, 0x38, 8) COPY (const, 0x1008b6, 8)\nMOV EAX,0x0\n  (register, 0x0, 8) COPY (const, 0x0, 8)\nCALL 0x001005d0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x10078a, 8)\n   ---  CALL (ram, 0x1005d0, 8)\nMOV qword ptr [RBP + -0x24],0x0\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffdc, 8)\n  (unique, 0x2000, 8) COPY (const, 0x0, 8)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x2000, 8)\nMOV RAX,qword ptr [RBP + -0x50]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffb0, 8)\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (register, 0x0, 8) COPY (unique, 0x1ff0, 8)\nADD RAX,0x8\n  (register, 0x200, 1) INT_CARRY (register, 0x0, 8) , (const, 0x8, 8)\n  (register, 0x20b, 1) INT_SCARRY (register, 0x0, 8) , (const, 0x8, 8)\n  (register, 0x0, 8) INT_ADD (register, 0x0, 8) , (const, 0x8, 8)\n  (register, 0x207, 1) INT_SLESS (register, 0x0, 8) , (const, 0x0, 8)\n  (register, 0x206, 1) INT_EQUAL (register, 0x0, 8) , (const, 0x0, 8)\nMOV RDX,qword ptr [RAX]\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (register, 0x0, 8)\n  (register, 0x10, 8) COPY (unique, 0x1ff0, 8)\nLEA RAX,[RBP + -0x24]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffdc, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RDX\n  (register, 0x30, 8) COPY (register, 0x10, 8)\nMOV RDI,RAX\n  (register, 0x38, 8) COPY (register, 0x0, 8)\nCALL 0x001005b0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x1007ac, 8)\n   ---  CALL (ram, 0x1005b0, 8)\nLEA RAX,[RBP + -0x24]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffdc, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RAX\n  (register, 0x30, 8) COPY (register, 0x0, 8)\nLEA RDI,[0x1008c2]\n  (register, 0x38, 8) COPY (const, 0x1008c2, 8)\nMOV EAX,0x0\n  (register, 0x0, 8) COPY (const, 0x0, 8)\nCALL 0x001005d0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x1007c4, 8)\n   ---  CALL (ram, 0x1005d0, 8)\nMOV dword ptr [RBP + -0x31],0x39393939\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffcf, 8)\n  (unique, 0x1fe0, 4) COPY (const, 0x39393939, 4)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1fe0, 4)\nMOV byte ptr [RBP + -0x2d],0x0\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffd3, 8)\n  (unique, 0x1fa0, 1) COPY (const, 0x0, 1)\n   ---  STORE (const, 0x1b1, 4) , (unique, 0x620, 8) , (unique, 0x1fa0, 1)\nLEA RDX,[RBP + -0x31]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffcf, 8)\n  (register, 0x10, 8) COPY (unique, 0x620, 8)\nLEA RAX,[RBP + -0x12]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffee, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RDX\n  (register, 0x30, 8) COPY (register, 0x10, 8)\nMOV RDI,RAX\n  (register, 0x38, 8) COPY (register, 0x0, 8)\nCALL 0x001005b0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x1007e2, 8)\n   ---  CALL (ram, 0x1005b0, 8)\nLEA RAX,[RBP + -0x12]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xffffffffffffffee, 8)\n  (register, 0x0, 8) COPY (unique, 0x620, 8)\nMOV RSI,RAX\n  (register, 0x30, 8) COPY (register, 0x0, 8)\nLEA RDI,[0x1008cf]\n  (register, 0x38, 8) COPY (const, 0x1008cf, 8)\nMOV EAX,0x0\n  (register, 0x0, 8) COPY (const, 0x0, 8)\nCALL 0x001005d0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x1007fa, 8)\n   ---  CALL (ram, 0x1005d0, 8)\nMOV EAX,0x0\n  (register, 0x0, 8) COPY (const, 0x0, 8)\nMOV RCX,qword ptr [RBP + -0x8]\n  (unique, 0x620, 8) INT_ADD (register, 0x28, 8) , (const, 0xfffffffffffffff8, 8)\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x620, 8)\n  (register, 0x8, 8) COPY (unique, 0x1ff0, 8)\nXOR RCX,qword ptr FS:[0x28]\n  (unique, 0x9e0, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8)\n  (register, 0x200, 1) COPY (const, 0x0, 1)\n  (register, 0x20b, 1) COPY (const, 0x0, 1)\n  (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8)\n  (register, 0x8, 8) INT_XOR (register, 0x8, 8) , (unique, 0x1ff0, 8)\n  (register, 0x207, 1) INT_SLESS (register, 0x8, 8) , (const, 0x0, 8)\n  (register, 0x206, 1) INT_EQUAL (register, 0x8, 8) , (const, 0x0, 8)\nJZ 0x00100813\n   ---  CBRANCH (ram, 0x100813, 8) , (register, 0x206, 1)\nCALL 0x001005c0\n  (register, 0x20, 8) INT_SUB (register, 0x20, 8) , (const, 0x8, 8)\n   ---  STORE (const, 0x1b1, 8) , (register, 0x20, 8) , (const, 0x100813, 8)\n   ---  CALL (ram, 0x1005c0, 8)\nLEAVE\n  (register, 0x20, 8) COPY (register, 0x28, 8)\n  (register, 0x28, 8) LOAD (const, 0x1b1, 8) , (register, 0x20, 8)\n  (register, 0x20, 8) INT_ADD (register, 0x20, 8) , (const, 0x8, 8)\nRET\n  (register, 0x288, 8) LOAD (const, 0x1b1, 8) , (register, 0x20, 8)\n  (register, 0x20, 8) INT_ADD (register, 0x20, 8) , (const, 0x8, 8)\n   ---  RETURN (register, 0x288, 8)\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Dumping Refined PCode\nPCode exists in two primary forms you as a user should consider, \"raw\" and \"refined\".  In documentation both forms are simply referred to as \"PCode\" making it confusing to talk about - so I distinguish between the forms using raw and refined. Just know theses are not universally accepted terms. \n\nSo refined PCode is heavily processed. It highly relates to the output you see in the decompiler, and if you're interested in making use of the Ghidra decompiler passes, this is the form of PCode you'll want to analyze. There are many interesting aspects of refined PCode we do not cover here, including `unique` values and name spaces. Just know that what might appear to be simple has a lot of analysis backing it and digging into these refined PCode elements are worth your time.\n\n```python\nfrom ghidra.util.task import ConsoleTaskMonitor\nfrom ghidra.app.decompiler import DecompileOptions, DecompInterface\n\n# == helper functions =============================================================================\ndef get_high_function(func):\n    options = DecompileOptions()\n    monitor = ConsoleTaskMonitor()\n    ifc = DecompInterface()\n    ifc.setOptions(options)\n    ifc.openProgram(getCurrentProgram())\n    # Setting a simplification style will strip useful `indirect` information.\n    # Please don't use this unless you know why you're using it.\n    #ifc.setSimplificationStyle(\"normalize\") \n    res = ifc.decompileFunction(func, 60, monitor)\n    high = res.getHighFunction()\n    return high\n\ndef dump_refined_pcode(func, high_func):\n    opiter = high_func.getPcodeOps()\n    while opiter.hasNext():\n        op = opiter.next()\n        print(\"{}\".format(op.toString()))\n        \n# == run examples =================================================================================\nfunc = getGlobalFunctions(\"main\")[0]    # assumes only one function named `main`\nhf = get_high_function(func)            # we need a high function from the decompiler\ndump_refined_pcode(func, hf)            # dump straight refined pcode as strings\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\nNotice how this looks quite different than the raw PCode.\n\n```\n(unique, 0x10000110, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8)\n(unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8)\n(unique, 0x9e0, 8) CAST (unique, 0x10000110, 8)\n(unique, 0x2250, 1) INT_SLESS (register, 0x38, 4) , (const, 0x2, 4)\n ---  CBRANCH (ram, 0x100743, 1) , (unique, 0x2250, 1)\n(unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (register, 0x30, 8)\n ---  CALL (ram, 0x1005d0, 8) , (unique, 0x100000a8, 8) , (unique, 0x1ff0, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x32, 4)\n(stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x32, 4)\n(stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x32, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x32, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x32, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x32, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x32, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (unique, 0x1ff0, 8) , (const, 0x32, 4)\n(unique, 0x100000a8, 8) COPY (const, 0x1008a4, 8)\n ---  BRANCH (ram, 0x1007ff, 1)\n(stack, 0xffffffffffffffdc, 8) COPY (const, 0x4242424241414141, 8)\n(stack, 0xffffffffffffffe4, 2) COPY (const, 0x43, 2)\n(stack, 0xffffffffffffffcc, 8) COPY (const, 0x0, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffdc, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffcc, 8)\n ---  CALL (ram, 0x1005b0, 8) , (unique, 0x10000118, 8) , (unique, 0x10000120, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x5d, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x5d, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x5d, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x5d, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (unique, 0x1ff0, 8) , (const, 0x5d, 4)\n(unique, 0x10000118, 8) CAST (unique, 0x620, 8)\n(unique, 0x10000120, 8) CAST (unique, 0x620, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffcc, 8)\n ---  CALL (ram, 0x1005d0, 8) , (unique, 0x100000b0, 8) , (unique, 0x620, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x65, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x65, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x65, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x65, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x65, 4)\n(unique, 0x100000b0, 8) COPY (const, 0x1008b6, 8)\n(stack, 0xffffffffffffffd4, 8) COPY (const, 0x0, 8)\n(register, 0x0, 8) PTRADD (register, 0x30, 8) , (const, 0x1, 8) , (const, 0x8, 8)\n(unique, 0x10000128, 8) LOAD (const, 0x1b1, 4) , (register, 0x0, 8)\n(unique, 0x1ff0, 8) CAST (unique, 0x10000128, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffd4, 8)\n ---  CALL (ram, 0x1005b0, 8) , (unique, 0x10000130, 8) , (unique, 0x1ff0, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x79, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x79, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x79, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x79, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x79, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x79, 4)\n(unique, 0x10000130, 8) CAST (unique, 0x620, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffd4, 8)\n ---  CALL (ram, 0x1005d0, 8) , (unique, 0x100000b8, 8) , (unique, 0x620, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x81, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x81, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x81, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x81, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x81, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x81, 4)\n(unique, 0x100000b8, 8) COPY (const, 0x1008c2, 8)\n(stack, 0xffffffffffffffc7, 4) COPY (const, 0x39393939, 4)\n(stack, 0xffffffffffffffcb, 1) COPY (const, 0x0, 1)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffc7, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffe6, 8)\n ---  CALL (ram, 0x1005b0, 8) , (unique, 0x620, 8) , (unique, 0x10000138, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x90, 4)\n(stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x90, 4)\n(stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x90, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x90, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x90, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x90, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x90, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x90, 4)\n(unique, 0x10000138, 8) CAST (unique, 0x620, 8)\n(unique, 0x620, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffe6, 8)\n ---  CALL (ram, 0x1005d0, 8) , (unique, 0x100000c0, 8) , (unique, 0x620, 8)\n(register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x98, 4)\n(stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x98, 4)\n(stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x98, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x98, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x98, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x98, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x98, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x98, 4)\n(unique, 0x100000c0, 8) COPY (const, 0x1008cf, 8)\n(register, 0x0, 8) INT_ZEXT (unique, 0x1000009c, 1)\n(register, 0x110, 8) MULTIEQUAL (register, 0x110, 8) , (register, 0x110, 8)\n(unique, 0x1000009c, 1) INT_SLESS (register, 0x38, 4) , (const, 0x2, 4)\n(stack, 0xffffffffffffffc7, 4) MULTIEQUAL (stack, 0xffffffffffffffc7, 4) , (stack, 0xffffffffffffffc7, 4)\n(stack, 0xffffffffffffffcb, 1) MULTIEQUAL (stack, 0xffffffffffffffcb, 1) , (stack, 0xffffffffffffffcb, 1)\n(stack, 0xffffffffffffffcc, 8) MULTIEQUAL (stack, 0xffffffffffffffcc, 8) , (stack, 0xffffffffffffffcc, 8)\n(stack, 0xffffffffffffffd4, 8) MULTIEQUAL (stack, 0xffffffffffffffd4, 8) , (stack, 0xffffffffffffffd4, 8)\n(stack, 0xffffffffffffffdc, 8) MULTIEQUAL (stack, 0xffffffffffffffdc, 8) , (stack, 0xffffffffffffffdc, 8)\n(stack, 0xffffffffffffffe4, 2) MULTIEQUAL (stack, 0xffffffffffffffe4, 2) , (stack, 0xffffffffffffffe4, 2)\n(stack, 0xfffffffffffffff0, 8) MULTIEQUAL (stack, 0xfffffffffffffff0, 8) , (stack, 0xfffffffffffffff0, 8)\n(unique, 0x10000140, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8)\n(unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8)\n(register, 0x206, 1) INT_NOTEQUAL (stack, 0xfffffffffffffff0, 8) , (unique, 0x1ff0, 8)\n(unique, 0x9e0, 8) CAST (unique, 0x10000140, 8)\n ---  CBRANCH (ram, 0x100813, 1) , (register, 0x206, 1)\n ---  CALL (ram, 0x1005c0, 8)\n ---  RETURN (const, 0x1, 4)\n(stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x42, 4)\n(stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x42, 4)\n(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x42, 4)\n(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x42, 4)\n(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x42, 4)\n(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x42, 4)\n(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x42, 4)\n ---  RETURN (const, 0x0, 8) , (register, 0x0, 8)\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n### Plotting a Function AST\nGhidra does not define a default graph provider, so you cannot graph abstract synatax trees out of the box.  Here's a snippet that takes elements from Ghidra's Graph Java snippets and hacks them together to get an SVG version of a function's AST.  This requires you to have `GraphViz` installed with the `dot` binary in your `PATH`, and `networkx` and `pydot` accessible from the Ghidra Jython console.  Basically, I just copy my Python2 site-packages over to my ghidra_scripts directory and everything works.  Keep in mind that if your Python module uses a natively compiled element (like Matplot lib does), you won't be able to use it in Jython. If you know of a way, please let me know.\n\n```python\nimport networkx as nx\nimport pydot\n\nfrom ghidra.app.script import GhidraScript\nfrom ghidra.util.task import ConsoleTaskMonitor\nfrom ghidra.app.decompiler import DecompileOptions, DecompInterface\nfrom ghidra.program.model.pcode import PcodeOp\n\ndef buildAST(func):\n    options = DecompileOptions()\n    monitor = ConsoleTaskMonitor()\n    ifc = DecompInterface()\n    ifc.setOptions(options)\n    ifc.openProgram(getCurrentProgram())\n    ifc.setSimplificationStyle(\"normalize\")\n    res = ifc.decompileFunction(func, 60, monitor)\n    high = res.getHighFunction()\n    return high\n\ndef buildGraph(graph, func, high):\n    vertices = {}\n    opiter = getPcodeOpIterator(high)\n    while opiter.hasNext():\n        op = opiter.next()\n        vert = createOpVertex(func, op)\n        graph.add_node(vert)\n        for i in range(0, op.getNumInputs()):\n            opcode = op.getOpcode()\n            if (i == 0 and (opcode == PcodeOp.LOAD or opcode == PcodeOp.STORE)):\n                continue\n            if (i == 1 and opcode == PcodeOp.INDIRECT):\n                continue\n            vn = op.getInput(i)\n            if (vn != None):\n                v = getVarnodeVertex(graph, vertices, vn)\n                graph.add_edge(v, vert)\n\n        outvn = op.getOutput()\n        if (outvn != None):\n            outv = getVarnodeVertex(graph, vertices, outvn)\n            if (outv != None):\n                graph.add_edge(vert, outv)\n\ndef createOpVertex(func, op):\n    name = op.getMnemonic()\n    id = getOpKey(op)\n    opcode = op.getOpcode()\n    if ((opcode == PcodeOp.LOAD) or (opcode == PcodeOp.STORE)):\n        vn = op.getInput(0)\n        addrspace = currentProgram.getAddressFactory().getAddressSpace(vn.getOffset())\n        name += ' ' + addrspace.getName()\n    elif (opcode == PcodeOp.INDIRECT):\n        vn = op.getInput(1)\n        if (vn != None):\n            indOp = high.getOpRef(vn.getOffset())\n            if (indOp != None):\n                name += \" (\" + indOp.getMnemonic() + \")\"\n    return \"{}_{}\".format(name, id)\n\ndef createVarnodeVertex(graph, vn):\n    name = str(vn.getAddress())\n    id = getVarnodeKey(vn)\n    if (vn.isRegister()):\n        reg = currentProgram.getRegister(vn.getAddress(), vn.getSize())\n        if (reg != None):\n            name = reg.getName()\n    return \"{}_{}\".format(name, id)\n\ndef getVarnodeVertex(graph, vertices, vn):\n    res = None\n    try:\n        res = vertices[str(vn.getUniqueId())]\n    except KeyError:\n        res = None\n    if (res == None):\n        res = createVarnodeVertex(graph, vn)\n        vertices[str(vn.getUniqueId())] = res\n    return res\n\ndef getAddress(offset):\n    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)\n\ndef getOpKey(op):\n    sq = op.getSeqnum()\n    id = str(sq.getTarget()) + \" o \" + str(op.getSeqnum().getTime())\n    return id\n\ndef getPcodeOpIterator(high):\n    return high.getPcodeOps()\n\ndef getVarnodeKey(vn):\n    op = vn.getDef()\n    id = \"\"\n    if (op != None):\n        id = str(op.getSeqnum().getTarget()) + \" v \" + str(vn.getUniqueId())\n    else:\n        id = \"i v \" + str(vn.getUniqueId())\n    return id\n\ndef main():\n    graph = nx.DiGraph()\n    listing = currentProgram.getListing()\n    func = getFunctionContaining(getAddress(0x00100690))\n    high = buildAST(func)\n    buildGraph(graph, func, high)\n\n    dot_data = nx.nx_pydot.to_pydot(graph)\n    svg = pydot.graph_from_dot_data(dot_data.to_string())[0].create_svg()\n    svg_path = \"C:\\\\Users\\\\username\\\\Desktop\\\\test.svg\"\n    f = open(svg_path, 'w')\n    f.write(svg)\n    f.close()\n\n    print(\"Wrote pydot SVG of graph to: {}\\nNodes: {}, Edges: {}\".format(svg_path, len(graph.nodes), len(graph.edges)))\n\nmain()\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\n# also writes a file called 'test.svg' to the Windows Desktop for user 'username'.\nWrote pydot SVG of graph to: C:\\Users\\username\\Desktop\\test.svg\nNodes: 47, Edges: 48\n```\n\u003c/details\u003e\n\n\n## Working with Graphs\n\n### Creating a Call Graph\nGhidra's complex API allows for the creation of various graph structures including directional graphs (digraphs). This example shows how to create a DiGraph of vertices (functions) and edges (calls from/to). \n\nNote that adding a vertex or an edge between two vertex entries does not reuse or override them! This is because, while many nodes share the same name, they contain unique hash codes (keys). If you were looking to trim this graph to include only unqiue nodes, you would need to consider both the name of the symbol and its address to account for overridden functions. \n\nIn its current form, this DiGraph is unlikely to be of any use to you. But the building blocks of creating interesting control flow graphs (CFG), program dependence graphs (PDG), data dependency graphs (DDG), and other graphs are all here.\n\n```python\nfrom ghidra.util.graph import DirectedGraph\nfrom ghidra.util.graph import Edge\nfrom ghidra.util.graph import Vertex\n\ndef getAddress(offset):\n    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)\n\ndigraph = DirectedGraph()\nlisting = currentProgram.getListing()\nfm = currentProgram.getFunctionManager()\n\nfuncs = fm.getFunctions(True) # True mean iterate forward\nfor func in funcs: \n\t# Add function vertices\n\tprint(\"Function: {} @ 0x{}\".format(func.getName(), func.getEntryPoint())) # FunctionDB\n\tdigraph.add(Vertex(func))\n\t\n\t# Add edges for static calls\n\tentryPoint = func.getEntryPoint()\n\tinstructions = listing.getInstructions(entryPoint, True)\n\tfor instruction in instructions:\n\t\taddr = instruction.getAddress()\n\t\toper = instruction.getMnemonicString()\n\t\tif oper == \"CALL\":\n\t\t\tprint(\"    0x{} : {}\".format(addr, instruction))\n\t\t\tflows = instruction.getFlows()\n\t\t\tif len(flows) == 1:\n\t\t\t\ttarget_addr = \"0x{}\".format(flows[0])\n\t\t\t\tdigraph.add(Edge(Vertex(func), Vertex(fm.getFunctionAt(getAddress(target_addr)))))\n\nprint(\"DiGraph info:\")\nedges = digraph.edgeIterator()\nwhile edges.hasNext():\n\tedge = edges.next()\n\tfrom_vertex = edge.from()\n\tto_vertex = edge.to()\n\tprint(\"  Edge from {} to {}\".format(from_vertex, to_vertex))\n\nvertices = digraph.vertexIterator()\nwhile vertices.hasNext():\n\tvertex = vertices.next()\n\tprint(\"  Vertex: {} (key: {})\".format(vertex, vertex.key()))\n    # some extra stuff you might want to see\n\t#print(\"    type(vertex):      {}\".format(type(vertex)))\n\t#print(\"    vertex.hashCode(): {}\".format(vertex.hashCode()))\n\t#print(\"    vertex.referent(): {}\".format(vertex.referent()))\n\t#print(\"    type(referent):    {}\".format(type(vertex.referent())))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput example\u003c/summary\u003e\n\n```\nFunction: main @ 0x0010064a\n    0x00100691 : CALL 0x00100520\n    0x001006cc : CALL 0x001004f0\n    0x001006e9 : CALL qword ptr [R12 + RBX*0x8]\n\u003c...snip...\u003e\n\nDiGraph info:\n  Edge from _init to __gmon_start__\n  Edge from _init to __libc_start_main\n  Edge from _init to __cxa_finalize\n  Edge from _init to deregister_tm_clones\n  Edge from _init to printf\n  Edge from _init to _init\n  Edge from printf to __libc_start_main\n  Edge from printf to __cxa_finalize\n  \u003c...snip...\u003e\n  Vertex: _init (key: 3690)\n  Vertex: main (key: 3803)\n  Vertex: main (key: 3804)\n  Vertex: printf (key: 3805)\n  Vertex: main (key: 3807)\n  Vertex: _init (key: 3808)\n  Vertex: __libc_csu_init (key: 3810)\n  Vertex: _init (key: 3812)\n  Vertex: __libc_csu_fini (key: 3814)\n  \u003c...snip...\u003e\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n## Miscellaneous\n\n### Program Slices\nGiven a specific varnode, Ghidra is able to generate backward and forward program slices. This functionality is contained in the `DecompilerUtils` class as four functions; `getBackwardSlice`, `getForwardSlice`, `getForwardSliceToPCodeOps`, and `getBackwardSliceToPCodeOps`.\n\nYou can read more about program slicing online, but the idea is to focus on a specific varnode (say a variable) and slice away anything unrelated to it so you're left with a slice of program related to the element you're interested in. In the Ghidra UI you can right-click a variable and select a program slice option and Ghidra will highlight the slice.  If you right-click and don't see an option, you're not clicking on a compatable varnode / element, try something else.\n\n```python\nfrom ghidra.util.task import ConsoleTaskMonitor\nfrom ghidra.app.decompiler import DecompileOptions, DecompInterface\nfrom ghidra.app.decompiler.component import DecompilerUtils\n\n# == helper functions =============================================================================\ndef get_high_function(func):\n    options = DecompileOptions()\n    monitor = ConsoleTaskMonitor()\n    ifc = DecompInterface()\n    ifc.setOptions(options)\n    ifc.openProgram(getCurrentProgram())\n    res = ifc.decompileFunction(func, 60, monitor)\n    high = res.getHighFunction()\n    return high\n\n# == run examples =================================================================================\nfunc = getGlobalFunctions(\"main\")[0]\nhf = get_high_function(func)\nlsm = hf.getLocalSymbolMap()\nsymbols = lsm.getSymbols()\n\nfor symbol in symbols:\n    print(\"\\nSymbol name: {}\".format(symbol.getName()))\n    hv = symbol.getHighVariable()\n    # Try this snippet with `hv.getInstances()` to enumerate slices for all instances!\n    varnode = hv.getRepresentative()\n    print(\"Varnode: {}\".format(varnode))\n    fs = DecompilerUtils.getForwardSlice(varnode)\n    print(\"Forward Slice: {}\".format(fs))\n    bs = DecompilerUtils.getBackwardSlice(varnode)\n    print(\"Backward Slice: {}\".format(bs))\n    bswo = DecompilerUtils.getBackwardSliceToPCodeOps(varnode)\n    print(\"Backward Slice w/ PCode Ops: {}\".format(bswo))\n    fswo = DecompilerUtils.getForwardSliceToPCodeOps(varnode)\n    print(\"Forward Slice w/ PCode Ops: {}\".format(fswo))\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eOutput examples\u003c/summary\u003e\n\nYou might think these slices are returning arrays (Python lists) with the name varnodes duplacted over and over - but that's not the case. Each use has a unique ID that ties it to other operations and uses. The printed varnodes may look the same, but these are all unique instances with more data under the hood. Experiment a bit and you'll see what I mean.\n\n```\nSymbol name: local_1c\nVarnode: (stack, 0xffffffffffffffe4, 2)\nForward Slice: [(stack, 0xffffffffffffffe4, 2), (stack, 0xffffffffffffffe4, 2), (stack, 0xffffffffffffffe4, 2), (stack, 0xffffffffffffffe4, 2)]\nBackward Slice: [(stack, 0xffffffffffffffe4, 2)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x32, 4), (stack, 0xffffffffffffffe4, 2) MULTIEQUAL (stack, 0xffffffffffffffe4, 2) , (stack, 0xffffffffffffffe4, 2), (stack, 0xffffffffffffffe4, 2) INDIRECT (stack, 0xffffffffffffffe4, 2) , (const, 0x42, 4)]\n\nSymbol name: local_24\nVarnode: (stack, 0xffffffffffffffdc, 8)\nForward Slice: [(stack, 0xffffffffffffffdc, 8), (stack, 0xffffffffffffffdc, 8), (stack, 0xffffffffffffffdc, 8), (stack, 0xffffffffffffffdc, 8)]\nBackward Slice: [(stack, 0xffffffffffffffdc, 8)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x32, 4), (stack, 0xffffffffffffffdc, 8) MULTIEQUAL (stack, 0xffffffffffffffdc, 8) , (stack, 0xffffffffffffffdc, 8), (stack, 0xffffffffffffffdc, 8) INDIRECT (stack, 0xffffffffffffffdc, 8) , (const, 0x42, 4)]\n\nSymbol name: local_35\nVarnode: (stack, 0xffffffffffffffcb, 1)\nForward Slice: [(stack, 0xffffffffffffffcb, 1), (stack, 0xffffffffffffffcb, 1), (stack, 0xffffffffffffffcb, 1), (stack, 0xffffffffffffffcb, 1)]\nBackward Slice: [(stack, 0xffffffffffffffcb, 1)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x42, 4), (stack, 0xffffffffffffffcb, 1) INDIRECT (stack, 0xffffffffffffffcb, 1) , (const, 0x32, 4), (stack, 0xffffffffffffffcb, 1) MULTIEQUAL (stack, 0xffffffffffffffcb, 1) , (stack, 0xffffffffffffffcb, 1)]\n\nSymbol name: param_1\nVarnode: (register, 0x38, 4)\nForward Slice: [(register, 0x38, 4), (unique, 0x2250, 1), (register, 0x0, 8), (unique, 0x1000009c, 1)]\nBackward Slice: [(register, 0x38, 4)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(unique, 0x2250, 1) INT_SLESS (register, 0x38, 4) , (const, 0x2, 4), (register, 0x0, 8) INT_ZEXT (unique, 0x1000009c, 1), (unique, 0x1000009c, 1) INT_SLESS (register, 0x38, 4) , (const, 0x2, 4),  ---  CBRANCH (ram, 0x100743, 1) , (unique, 0x2250, 1),  ---  RETURN (const, 0x0, 8) , (register, 0x0, 8)]\n\nSymbol name: param_2\nVarnode: (register, 0x30, 8)\nForward Slice: [(register, 0x30, 8), (unique, 0x1ff0, 8), (unique, 0x1ff0, 8), (unique, 0x10000128, 8), (register, 0x0, 8)]\nBackward Slice: [(register, 0x30, 8)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (register, 0x30, 8), (unique, 0x10000128, 8) LOAD (const, 0x1b1, 4) , (register, 0x0, 8),  ---  CALL (ram, 0x1005d0, 8) , (unique, 0x100000a8, 8) , (unique, 0x1ff0, 8), (register, 0x0, 8) PTRADD (register, 0x30, 8) , (const, 0x1, 8) , (const, 0x8, 8), (unique, 0x1ff0, 8) CAST (unique, 0x10000128, 8),  ---  CALL (ram, 0x1005b0, 8) , (unique, 0x10000130, 8) , (unique, 0x1ff0, 8)]\n\nSymbol name: in_FS_OFFSET\nVarnode: (register, 0x110, 8)\nForward Slice: [(stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (unique, 0x9e0, 8), (stack, 0xfffffffffffffff0, 8), (unique, 0x1ff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (register, 0x110, 8), (register, 0x110, 8), (register, 0x206, 1), (register, 0x110, 8), (register, 0x110, 8), (unique, 0x9e0, 8), (register, 0x110, 8), (unique, 0x1ff0, 8), (register, 0x110, 8), (register, 0x110, 8), (register, 0x110, 8), (unique, 0x10000110, 8), (register, 0x110, 8), (unique, 0x10000140, 8)]\nBackward Slice: [(register, 0x110, 8)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(unique, 0x10000140, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8), (register, 0x206, 1) INT_NOTEQUAL (stack, 0xfffffffffffffff0, 8) , (unique, 0x1ff0, 8), (stack, 0xfffffffffffffff0, 8) INDIRECT (unique, 0x1ff0, 8) , (const, 0x5d, 4), (unique, 0x9e0, 8) CAST (unique, 0x10000110, 8), (unique, 0x9e0, 8) CAST (unique, 0x10000140, 8), (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x79, 4), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x5d, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x65, 4), (stack, 0xfffffffffffffff0, 8) MULTIEQUAL (stack, 0xfffffffffffffff0, 8) , (stack, 0xfffffffffffffff0, 8), (unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x79, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x81, 4), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x90, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (unique, 0x1ff0, 8) , (const, 0x32, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x98, 4),  ---  CBRANCH (ram, 0x100813, 1) , (register, 0x206, 1), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x42, 4), (unique, 0x10000110, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x32, 4), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x98, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x90, 4), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x65, 4), (register, 0x110, 8) MULTIEQUAL (register, 0x110, 8) , (register, 0x110, 8), (register, 0x110, 8) INDIRECT (register, 0x110, 8) , (const, 0x81, 4)]\n\nSymbol name: local_10\nVarnode: (stack, 0xfffffffffffffff0, 8)\nForward Slice: [(stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (register, 0x206, 1), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8), (stack, 0xfffffffffffffff0, 8)]\nBackward Slice: [(stack, 0xfffffffffffffff0, 8), (const, 0x5d, 4), (register, 0x110, 8), (unique, 0x10000110, 8), (unique, 0x9e0, 8), (const, 0x1b1, 4), (const, 0x28, 8), (unique, 0x1ff0, 8)]\nBackward Slice w/ PCode Ops: [(unique, 0x1ff0, 8) LOAD (const, 0x1b1, 4) , (unique, 0x9e0, 8), (unique, 0x10000110, 8) INT_ADD (register, 0x110, 8) , (const, 0x28, 8), (stack, 0xfffffffffffffff0, 8) INDIRECT (unique, 0x1ff0, 8) , (const, 0x5d, 4), (unique, 0x9e0, 8) CAST (unique, 0x10000110, 8)]\nForward Slice w/ PCode Ops: [(stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x65, 4), (stack, 0xfffffffffffffff0, 8) MULTIEQUAL (stack, 0xfffffffffffffff0, 8) , (stack, 0xfffffffffffffff0, 8), (register, 0x206, 1) INT_NOTEQUAL (stack, 0xfffffffffffffff0, 8) , (unique, 0x1ff0, 8), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x42, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x81, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x90, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x98, 4), (stack, 0xfffffffffffffff0, 8) INDIRECT (stack, 0xfffffffffffffff0, 8) , (const, 0x79, 4),  ---  CBRANCH (ram, 0x100813, 1) , (register, 0x206, 1)]\n\nSymbol name: local_1a\nVarnode: (stack, 0xffffffffffffffe6, 10)\nForward Slice: [(stack, 0xffffffffffffffe6, 10)]\nBackward Slice: [(stack, 0xffffffffffffffe6, 10)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: []\n\nSymbol name: local_34\nVarnode: (stack, 0xffffffffffffffcc, 8)\nForward Slice: [(stack, 0xffffffffffffffcc, 8), (stack, 0xffffffffffffffcc, 8), (stack, 0xffffffffffffffcc, 8), (stack, 0xffffffffffffffcc, 8)]\nBackward Slice: [(stack, 0xffffffffffffffcc, 8)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x32, 4), (stack, 0xffffffffffffffcc, 8) MULTIEQUAL (stack, 0xffffffffffffffcc, 8) , (stack, 0xffffffffffffffcc, 8), (stack, 0xffffffffffffffcc, 8) INDIRECT (stack, 0xffffffffffffffcc, 8) , (const, 0x42, 4)]\n\nSymbol name: local_2c\nVarnode: (stack, 0xffffffffffffffd4, 8)\nForward Slice: [(stack, 0xffffffffffffffd4, 8), (stack, 0xffffffffffffffd4, 8), (stack, 0xffffffffffffffd4, 8), (stack, 0xffffffffffffffd4, 8)]\nBackward Slice: [(stack, 0xffffffffffffffd4, 8)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x32, 4), (stack, 0xffffffffffffffd4, 8) MULTIEQUAL (stack, 0xffffffffffffffd4, 8) , (stack, 0xffffffffffffffd4, 8), (stack, 0xffffffffffffffd4, 8) INDIRECT (stack, 0xffffffffffffffd4, 8) , (const, 0x42, 4)]\n\nSymbol name: local_39\nVarnode: (stack, 0xffffffffffffffc7, 4)\nForward Slice: [(stack, 0xffffffffffffffc7, 4), (stack, 0xffffffffffffffc7, 4), (stack, 0xffffffffffffffc7, 4), (stack, 0xffffffffffffffc7, 4)]\nBackward Slice: [(stack, 0xffffffffffffffc7, 4)]\nBackward Slice w/ PCode Ops: []\nForward Slice w/ PCode Ops: [(stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x32, 4), (stack, 0xffffffffffffffc7, 4) MULTIEQUAL (stack, 0xffffffffffffffc7, 4) , (stack, 0xffffffffffffffc7, 4), (stack, 0xffffffffffffffc7, 4) INDIRECT (stack, 0xffffffffffffffc7, 4) , (const, 0x42, 4)]\n```\n\u003c/details\u003e\n\n\u003cbr\u003e[⬆ Back to top](#table-of-contents)\n\n\n[0]: https://ghidra-sre.org/\n[1]: https://ghidra.re/ghidra_docs/api/ghidra/program/flatapi/FlatProgramAPI.html\n[2]: https://ghidra.re/ghidra_docs/api/ghidra/app/decompiler/flatapi/FlatDecompilerAPI.html\n[3]: https://ghidra.re/ghidra_docs/api/ghidra/framework/model/Project.html\n[4]: https://ghidra.re/ghidra_docs/api/ghidra/base/project/GhidraProject.html\n[5]: https://ghidra.re/ghidra_docs/api/ghidra/program/model/listing/Program.html\n[6]: https://ghidra.re/ghidra_docs/api/ghidra/program/database/ProgramDB.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHackOvert%2FGhidraSnippets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHackOvert%2FGhidraSnippets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHackOvert%2FGhidraSnippets/lists"}