Skip to content

Instantly share code, notes, and snippets.

@YSaxon
Last active January 9, 2024 17:52
Show Gist options
  • Save YSaxon/7fdacfbdd9a187e8ef8bd3e965e9e100 to your computer and use it in GitHub Desktop.
Save YSaxon/7fdacfbdd9a187e8ef8bd3e965e9e100 to your computer and use it in GitHub Desktop.
Ghidra Xor Decoder script for a particular xor obfuscation type I encountered
import re
from ghidra.program.model.data import Undefined
from java.io import File
from ghidra.app.util.exporter import CppExporter
from ghidra.util.task import TaskMonitor
from ghidra.app.util import Option
from ghidra.program.model.listing import Function
from ghidra.program.database.symbol import FunctionSymbol
from ghidra.app.decompiler import DecompInterface
from ghidra.program.model.listing import CodeUnit
from ghidra.program.model.scalar import Scalar
from ghidra.program.model.data import StringDataType
from ghidra.program.model.data import Undefined
import os
from ghidra.app.plugin.core.colorizer import ColorizingService
import ghidra.app.plugin.core.colorizer.ColorizingService
# Constants
TMP_FILE_PATH="/tmp/{}_datadiv_decode_funcs.c".format(currentProgram.getDomainFile().getPathname().replace('/', '_'))
HIGHLIGHT_COLOR = java.awt.Color(255, 255, 0) # Yellow color for highlighting
REDO_EXPORT = False # Set this to True if you want to force re-exporting
colorizingService = state.getTool().getService(ColorizingService)
listing = currentProgram.getListing()
# Function to decode XORed bytes
def xor_decode(bytes, xor_value):
buf = "".join([chr((b ^ xor_value) & 0xFF) for b in bytes])
return buf
def process_xor_deobfuscation(addrObj, xor_value, xor_value_num_bytes):
if all([
colorizingService.getBackgroundColor(addrObj.add(i)) == HIGHLIGHT_COLOR for i in range(xor_value_num_bytes)
]):
print("Skipping address: {}, XOR value: {}, {} bytes, all have been highlighted already".format(addrObj, xor_value, xor_value_num_bytes))
return
print("Processing address: {}, XOR value: {}, {} bytes".format(addrObj, xor_value, xor_value_num_bytes))
byte_vals = [b for b in getBytes(addrObj, xor_value_num_bytes)]
decoded_data = xor_decode(byte_vals, xor_value)
# Modify bytes directly in Ghidra's listing
for i, b in enumerate(decoded_data):
byte_addr=addrObj.add(i)
if colorizingService.getBackgroundColor(addrObj) == HIGHLIGHT_COLOR:
print("skipping individual highlighted byte {} + {} ...".format(addrObj, i))
continue
setByte(byte_addr, ord(b))
setBackgroundColor(byte_addr, HIGHLIGHT_COLOR)
program = getCurrentProgram()
function_manager = program.getFunctionManager()
regex = r"((?:DAT_(\w+))|(?:uRam(\w+)|_DAT_(\w+)))\s?=\s?\1\s?\^\s?((?:0x)?\w+);"
if not os.path.exists(TMP_FILE_PATH) or REDO_EXPORT:
# Extended regex to catch individual bytes and pointers with specific XOR values
for function in function_manager.getFunctions(True):
print("Processing function: ", function)
if function.getName().startswith(".datadiv_decode"):
function.addTag('EXPORT')
exporter = CppExporter()
opts = [
Option(CppExporter.FUNCTION_TAG_EXCLUDE, False),
Option(CppExporter.FUNCTION_TAG_FILTERS, 'EXPORT')
]
exporter.setOptions(opts)
exporter.setExporterServiceProvider(state.getTool())
f = File(TMP_FILE_PATH)
exporter.export(f, currentProgram, None, TaskMonitor.DUMMY)
with open(TMP_FILE_PATH, "r") as f:
exported = f.read()
matches = re.finditer(regex, exported, re.MULTILINE)
for matchNum, match in enumerate(matches, start=1):
groups = match.groups()
address = groups[1] or groups[2] or groups[3]
xor_value = int(groups[4], 16) if '0x' in groups[4] else int(groups[4])
if '0x' in groups[4]:
xor_value_num_bytes = (len(groups[4]) // 2) - 1
else:
xor_value_num_bytes = xor_value.bit_length() // 8
addrObj = currentProgram.getAddressFactory().getAddress(address)
process_xor_deobfuscation(addrObj, xor_value, xor_value_num_bytes)
@YSaxon
Copy link
Author

YSaxon commented Oct 13, 2023

Note to self that I made some improvements locally that I haven't uploaded to here yet

@YSaxon
Copy link
Author

YSaxon commented Oct 13, 2023

I don't have time to double check that this is a working copy, if it isn't you could always use the previous one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment