Last active
January 9, 2024 17:52
-
-
Save YSaxon/7fdacfbdd9a187e8ef8bd3e965e9e100 to your computer and use it in GitHub Desktop.
Ghidra Xor Decoder script for a particular xor obfuscation type I encountered
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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