逆向工程 - Ghidra - Python - Write Exports/Functions To C



ExportAllToC.java

import java.io.File;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;

import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.script.GhidraScript;

import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionIterator;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.symbol.Symbol;

public class ExportAllToC extends GhidraScript {
    private DecompInterface decompiler;

    @Override
    public void run() throws Exception {
        if (currentProgram == null) {
            println("No program is open.");
            return;
        }

        String outputDir = askString(
            "Output Directory",
            "Directory:",
            "/tmp/ghidra-decompiled"
        );

        File root = new File(outputDir);
        File exportsDir = new File(root, "exports");
        File functionsDir = new File(root, "functions");

        exportsDir.mkdirs();
        functionsDir.mkdirs();

        println("Output directory: " + root.getAbsolutePath());

        decompiler = new DecompInterface();

        DecompileOptions options = new DecompileOptions();
        decompiler.setOptions(options);

        decompiler.toggleCCode(true);
        decompiler.toggleSyntaxTree(false);
        decompiler.setSimplificationStyle("decompile");

        if (!decompiler.openProgram(currentProgram)) {
            println("Failed to initialize decompiler.");
            return;
        }

        println("");
        println("========================================");
        println("Exported Functions");
        println("========================================");

        Set<Address> exportedAddresses = new HashSet<>();

        for (Symbol symbol : currentProgram.getSymbolTable().getAllSymbols(true)) {
            monitor.checkCanceled();

            if (!symbol.isExternalEntryPoint()) {
                continue;
            }

            Address address = symbol.getAddress();

            Function function =
                currentProgram.getFunctionManager().getFunctionAt(address);

            if (function == null) {
                println("Export without function: "
                        + symbol.getName()
                        + " @ "
                        + address);

                continue;
            }

            exportedAddresses.add(function.getEntryPoint());

            File file = new File(
                exportsDir,
                makeSafeFilename(symbol.getName()) + ".c"
            );

            decompileFunction(function, file, symbol.getName());
        }

        println("");
        println("========================================");
        println("All Functions");
        println("========================================");

        FunctionManager fm =
            currentProgram.getFunctionManager();

        FunctionIterator functions =
            fm.getFunctions(true);

        int count = 0;

        while (functions.hasNext()) {
            monitor.checkCanceled();

            Function function = functions.next();

            count++;

            Address entry =
                function.getEntryPoint();

            String name =
                function.getName();

            File file = new File(
                functionsDir,
                makeSafeFilename(name)
                + "_"
                + entry.toString()
                + ".c"
            );

            println(
                "[" + count + "] "
                + name
                + " @ "
                + entry
            );

            decompileFunction(function, file, name);
        }

        decompiler.dispose();

        println("");
        println("========================================");
        println("Finished");
        println("========================================");

        println("Export directory : "
                + exportsDir.getAbsolutePath());

        println("Functions directory : "
                + functionsDir.getAbsolutePath());

        println("Functions : " + count);
    }


    private void decompileFunction(
        Function function,
        File outputFile,
        String displayName) throws Exception {

        try {
            DecompileResults result =
                decompiler.decompileFunction(
                    function,
                    60,
                    monitor
                );

            PrintWriter out =
                new PrintWriter(outputFile);

            out.println("/*");
            out.println(" * Ghidra decompilation");
            out.println(" *");
            out.println(" * Function : "
                        + displayName);
            out.println(" * Address  : "
                        + function.getEntryPoint());
            out.println(" * Program  : "
                        + currentProgram.getName());
            out.println(" */");
            out.println();

            if (result == null) {
                out.println(
                    "/* Decompiler returned NULL */"
                );

            }
            else if (!result.decompileCompleted()) {
                out.println(
                    "/* Decompilation failed */"
                );

                out.println(
                    "/* "
                    + result.getErrorMessage()
                    + " */"
                );

            }
            else {
                String c =
                    result.getDecompiledFunction().getC();

                if (c != null && !c.isEmpty()) {
                    out.println(c);
                }
                else {
                    out.println(
                        "/* Empty decompiler output */"
                    );
                }
            }

            out.close();

        }
        catch (Exception e) {
            println(
                "ERROR: "
                + displayName
                + " @ "
                + function.getEntryPoint()
                + " : "
                + e.getMessage()
            );
        }
    }

    private String makeSafeFilename(String name) {
        if (name == null || name.isEmpty()) {
            return "unknown";
        }

        return name.replaceAll(
            "[^a-zA-Z0-9_.-]",
            "_"
        );
    }
}