Some of my ghidra scripts

AllCyclomaticComplexity.java

This a script to calculate the cyclomatic complexity of all the functions, as the name implies the metric is correlated with function complexity, it is the sum of unique paths within the CFG. read more about it here.

Ghidra offers the functionality actually, this is just a wrapper to loop over all functions and sort them. What is nice about the ghidra console is when you print a function name you can click it.

/* ###
 * IP: GHIDRA
 * REVIEWED: YES
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//Script to compute and print the cyclomatic complexity of the current function.
//@category Functions

import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import ghidra.program.util.CyclomaticComplexity;
import java.io.*;
import java.util.*; 


public class AllCyclomaticComplexity extends GhidraScript {
    @Override
    protected void run() throws Exception {
        if (currentProgram == null) {
            printerr("no current program");
            return;
        }

        Function function = getFirstFunction();

        int count = 0;
        FileWriter f0 = new FileWriter("/tmp/output.txt");

        String newLine = System.getProperty("line.separator");

        List<Tuple<String, Integer>> lst = new ArrayList<Tuple<String, Integer>>();  
        while (true) {

            if (monitor.isCancelled() || function == null) {
                break;
            }

            CyclomaticComplexity cyclomaticComplexity = new CyclomaticComplexity();
            int cyc = cyclomaticComplexity.calculateCyclomaticComplexity(function, monitor);
            f0.write("complexity: " + function.getName() + " "+ cyc + newLine);
            lst.add(new Tuple<String, Integer>(function.getName(), cyc));
            function = getFunctionAfter(function);
            count++;
        }
        println("Sorting by cyclomatic complexity");
        Collections.sort(lst, new ComparatorFunc());

        for (Tuple<String, Integer> x: lst) {
            println("complexity: " + x.x + " is " + x.y);
        }

        println("found forward = " + count);
        f0.close();

    }
}

class Tuple<X, Y> { 
    public final X x; 
    public final Y y; 
    public Tuple(X x, Y y) { 
        this.x = x; 
        this.y = y; 
    } 
} 

class ComparatorFunc implements Comparator<Tuple<String, Integer>>  {
    // @Override
    public int compare(Tuple<String, Integer> o1, Tuple<String, Integer> o2) {
        return o1.y.compareTo(o2.y);
    }
}

XorMemoryScriptBackward.java

This is the same as XorMemoryScript.java that is shipped by default in ghidra, except that it XOR backward, I actually unpacked a malware sample this way, it xored .text but backwards.

/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//XOR's the memory of the current program.
//@category Memory

import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressIterator;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;

public class XorMemoryScriptBackward extends GhidraScript {

    @Override
    public void run() throws Exception {

        // default to the current memory block
        Memory memory = currentProgram.getMemory();
        MemoryBlock block = memory.getBlock(currentAddress);
        AddressSetView set = new AddressSet(block.getStart(),block.getEnd());

        if (currentSelection != null && !currentSelection.isEmpty()) {
            set = currentSelection;
        }

        byte[] xorValues = askBytes("XorValue", "Values to xor with selected memory:");

        int valueLength = xorValues.length;
        int xorIndex = 0;

        AddressIterator aIter = set.getAddresses(false);

        while (aIter.hasNext() && !monitor.isCancelled()) {
            Address addr = aIter.next();
            monitor.setMessage(addr.toString());
            byte xorValue = xorValues[xorIndex];
            byte b = memory.getByte(addr);
            b = (byte) (b ^ xorValue);
            memory.setByte(addr, b);
            xorIndex += 1;
            xorIndex = xorIndex % valueLength;
        }
    }

}

Author: Aziz Knani

Date: 2023-03-22 Wed 00:01

Emacs 26.3 (Org mode 9.1.9)

Tunisian flag