This article is based on the public release of Ghidra 11.2.
Ghidra’s project based nature allows one to include multiple files into a project. These files can be split into different folders within the project. When running Ghidra headless, one can ingest files (recursively) from a given folder. The ingested files and related folder structure will then be recreated within the Ghidra project. Each ingested file in Ghidra is a Program.
In some cases, it might be useful to interact with one or more Programs within a script. One such use-case is the creation of function signatures for all files within the given Ghidra project. The code snippets within this blog will go over the (recursive) iteration of files within a Ghidra project. The logic to handle each file can be arbitrary, and is out-of-scope for this blog. The file from which the code snippets are used is one I wrote for Trellix.
Ghidra related files and folders are DomainFile and DomainFolder objects respectively. These objects are part of a tree structure, where a folder can have zero or more folder objects connected to it, and each folder can contain zero or more files. The approach to recursively go over each is to first handle all files within a given folder, and then check for the presence of folders within the given folder. For each discovered folder, the same process is repeated.
To obtain the root folder of the project, one can use the current state, as is shown below.
DomainFolder rootFolder = state.getProject().getProjectData().getRootFolder();
Next, one has to iterate over all files within the folder, if any. The list of files can be obtained using the getFiles method, which is found within the DomainFile object. Additionally, the type of file can be of importance. A Ghidra Data Type object cannot be used when creating function signatures, and should thus be omitted. A Program object, however, is required. As such, the content type of the file can be compared using getContentType to get a string representation of the file’s content. This can then be compared to the content type of a program, which resides at ProgramcontentHandler.PROGRAM_CONTENT_TYPE. The code is given below.
private void recursiveIteration(DomainFolder folder, Object output) { for (DomainFile domainFile : folder.getFiles()) { if (domainFile.getContentType().equals(ProgramContentHandler.PROGRAM_CONTENT_TYPE)) { //Arbitrary logic here } } }
To iterate over all folders found within the current folder, the getFolders function found in the DomainFolder object can be used. Due to the recursive nature, returning a value from the function adds more complexity. Instead, the output is stored within an object that is passed as an argument to the function and any of its iterative calls. While there are more ways to resolve this (i.e. the usage of a class-wide accessible or global variable to which is used to store information in), this solution is (more) elegant in its design and usage. Note that in the current template the output variable is of the Object type, which should be changed to whatever is required for the problem at hand.
private void recursiveIteration(DomainFolder folder, Object output) { for (DomainFile domainFile : folder.getFiles()) { if (domainFile.getContentType().equals(ProgramContentHandler.PROGRAM_CONTENT_TYPE)) { //Arbitrary logic here } } for (DomainFolder domainFolder : folder.getFolders()) { //Arbitrary logic here recursiveIteration(domainFolder, output); } }
Additional logic can be inserted into the handling of each folder if need be. By providing a different folder when first calling this method, one does not need to traverse down from the project’s root. Instead, the recursive iteration can start at any given folder, if so desired.
To contact me, you can e-mail me at [info][at][maxkersten][dot][nl], or DM me on Twitter @Libranalysis.