9

Is there a way to run ghidra from command line ?

GUI interface is very heavy.

What i want is just to get functions list and decompile them in c.

Thanks

Bob5421
  • 797
  • 1
  • 9
  • 20

4 Answers4

10

Check my answer here.

All you have to do is to use ./analyzeHeadless script, which comes with ghidra:

./analyzeHeadless ghidra-project-directory -import binary-file -postscript yourpythonscript

You can either use java or python 2.7. You can check the ghidra api here.

You can write the script (in python) in the following way:

from  ghidra.app.decompiler import DecompInterface
from ghidra.util.task import ConsoleTaskMonitor

# get the current program
# here currentProgram is predefined

program = currentProgram
decompinterface = DecompInterface()
decompinterface.openProgram(program);
functions = program.getFunctionManager().getFunctions(True)
for function in list(functions):
    print(function)
    # decompile each function
    tokengrp = decompinterface.decompileFunction(function, 0, ConsoleTaskMonitor())
    print(tokengrp.getDecompiledFunction().getC())
R4444
  • 1,807
  • 10
  • 30
4

The Ghidra decompiler was integrated into radare2, which is a command line disassembler (among other things).

You need to install the r2ghidra-dec package. You can then use the afl command to print the function list and the pdg command to show Ghidra's decompiled output for a given function.

For example:

[0x080484d0]> afl
0x080484d0    1 50           entry0
0x08048503    1 4            fcn.08048503
0x08048480    1 6            sym.imp.__libc_start_main
0x08048530    4 50   -> 41   sym.deregister_tm_clones
0x08048570    4 58   -> 54   sym.register_tm_clones
0x080485b0    3 34   -> 31   entry.fini0
0x080485e0    1 6            entry.init0
0x08048780    1 2            sym.__libc_csu_fini
0x08048520    1 4            sym.__x86.get_pc_thunk.bx
0x0804865f    1 63           sym.vuln
0x08048430    1 6            sym.imp.gets
0x08048714    1 4            loc.get_return_address
0x08048420    1 6            sym.imp.printf
0x08048784    1 20           sym._fini
0x08048720    4 93           sym.__libc_csu_init
0x08048510    1 2            sym._dl_relocate_static_pie
0x0804869e    1 118          main
0x08048490    1 6            sym.imp.setvbuf
0x08048450    1 6            sym.imp.getegid
0x080484b0    1 6            sym.imp.setresgid
0x08048460    1 6            sym.imp.puts
0x080485e6    3 121          sym.flag
0x080484a0    1 6            sym.imp.fopen
0x08048470    1 6            sym.imp.exit
0x08048440    1 6            sym.imp.fgets
0x080483e8    3 35           sym._init
[0x080484d0]> pdg @ sym.vuln

// WARNING: Variable defined which should be unmapped: var_4h
// WARNING: [r2ghidra] Removing arg arg_4h because it doesn't fit into ProtoModel

void sym.vuln(void)
{
    undefined4 uVar1;
    int32_t unaff_EBX;
    char *s;
    int32_t var_4h;

    sym.__x86.get_pc_thunk.bx();
    sym.imp.gets(&s);
    uVar1 = loc.get_return_address();
    sym.imp.printf(unaff_EBX + 0x19c, uVar1);
    return;
}
Dvd848
  • 559
  • 2
  • 5
2

One way is using Ghidra's CppExporter class within a Java class that extends GhidraScript class. Ghidra's source code contains some sample codes that could be found at the following link : Decompiler samples. I took one of them and improved a bit the code.

The code below has to be copied in a file called Decompile.java Then, you have to run Ghidra's analyzeHeadless binary tool.

<ghidra_root>/support/analyzeHeadless <ghidra_project_dir> <project_name> \
    -import <path_to_binary> -postscript <your_path>/Decompile.java <out_C_file_path>

Command example :

./analyzeHeadless MyProjDir MyProj -import libX.so -postscript Decompile.java libX_dec.c

Note : You might have to create project dir if it does not already exist.

Decompile.java example :

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import ghidra.app.plugin.core.script.Ingredient;
import ghidra.app.plugin.core.script.IngredientDescription;
import ghidra.app.script.GatherParamPanel;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.Option;
import ghidra.app.util.OptionException;
import ghidra.app.util.exporter.CppExporter;
import ghidra.app.util.exporter.ExporterException;

public class Decompile extends GhidraScript implements Ingredient {
    private static Logger log;

    public Decompile() {
        log = LogManager.getLogger(Decompile.class);
    }

    public void export(String filename) {
        File outputFile = new File(filename);
        CppExporter cppExporter = new CppExporter();
        cppExporter.setExporterServiceProvider(state.getTool());

        List<Option> options = new ArrayList<Option>();
        Option cppExportHeaderOption =
                new Option(CppExporter.CREATE_HEADER_FILE, new Boolean(false));
        options.add(cppExportOption);
        try {
            cppExporter.setOptions(options);
        } catch (OptionException e) {
            log.error("Unable to set cppExporter options", e);
            return;
        }

        try {
            cppExporter.export(outputFile, currentProgram, null, monitor);
        } catch (IOException e) {
            log.error("Failed writing decompiled code as output", e);
        } catch (ExporterException e) {
            log.error("Failed to export with cppExporter", e);
        }
    }

    @Override
    public void run() throws Exception {
        IngredientDescription[] ingredients = getIngredientDescriptions();
        for (IngredientDescription ingredient : ingredients) {
            state.addParameter(ingredient.getID(), ingredient.getLabel(),
                    ingredient.getType(), ingredient.getDefaultValue());
        }

        String[] args = getScriptArgs();
        export(args[0]);
    }

    @Override
    public IngredientDescription[] getIngredientDescriptions() {
        IngredientDescription[] retVal = new IngredientDescription[] {
          new IngredientDescription(
                "COutputFile", "Output C File", GatherParamPanel.FILE, "")};
        return retVal;
    }
}
vhamon
  • 121
  • 3
1

I wrote this script that takes in a binary and spews out the C source to a file. Just had to slightly modify ghidra's Ghidra/Features/Decompiler/ghidra_scripts/Decompile.java script.

https://github.com/h4sh5/ghidra-headless-decompile

Haoxi Tan
  • 11
  • 1
  • Please provide the core details of the solution in your answer and not only link to code that accomplishes that. It will make it far more useful as a reference in the future. – tmr232 Aug 05 '19 at 12:40