Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
func_renamer.py 4.65 KiB
# Restore func names in stripped Golang binary
#@author Egor Zaytsev & QwErTy
#@category CERN.Golang
#@keybinding 
#@menupath 
#@toolbar 

"""
Initial script for IDA by Egor Zaytsev
https://gitlab.com/zaytsevgu/goutils
ported to GHIDRA by QwErTy (QwErTyReverse on Telegram)
GNU General Public License v3.0
https://github.com/ghidraninja/ghidra_scripts/
"""

from ghidra.program.model.symbol.SourceType import *
import string
import random

addressFactory = currentProgram.getAddressFactory()
functionManager = currentProgram.getFunctionManager()
dataTypeManager = currentProgram.getDataTypeManager()
listing = currentProgram.getListing()
memory = currentProgram.getMemory()

DWORD = dataTypeManager.getDataType("/dword")
QWORD = dataTypeManager.getDataType("/qword")
CSTRING = dataTypeManager.getDataType("/TerminatedCString")

class bitZ(object):
    def __init__(self, ptr, size, maker):
        self.ptr = ptr
        self.size = size
        self.maker = maker

def addressToInt(ghidra_addr):
    return int(ghidra_addr.toString(), 16)

def intToAddress(addr):
    return addressFactory.getAddress(hex(addr))

def MakeDword(addr):
    addr = intToAddress(addr)
    listing.clearCodeUnits(addr, addr, False)
    listing.createData(addr, DWORD)

    return int(listing.getDataAt(addr).value.toString(), 16)

def MakeQword(addr):
    addr = intToAddress(addr)
    listing.clearCodeUnits(addr, addr, False)
    listing.createData(addr, QWORD)

    return int(listing.getDataAt(addr).value.toString(), 16)

def MakeString(addr):
    addr = intToAddress(addr)
    listing.clearCodeUnits(addr, addr, False)
    listing.createData(addr, CSTRING)
    return listing.getDataAt(addr).value

bits32 = bitZ(MakeDword, 4, MakeDword)
bits64 = bitZ(MakeDword, 8, MakeQword)

def get_bitness():
    ptr = bits32
    if currentProgram.defaultPointerSize == 8:
        ptr = bits64
    return ptr

def process_segment(handler, name=".gopclntab"):
    segments = memory.getBlocks() 
    position = 0

    for i in segments:
        if i.getName() == name:
            position = i
            break
    if position == 0:
        GoRenameSectionless()
        # raise Exception("Couldn't find segment")
    else:
        h = handler(addressToInt(position.getStart()), get_bitness())

def go_renamer(beg, ptr):
    base = beg
    pos = beg + 8 #skip header
    size = ptr.ptr(pos)
    pos += ptr.size
    end = pos + (size * ptr.size * 2)
    print "%x" % end
    while pos < end:
        offset = ptr.ptr(pos + ptr.size)
        ptr.maker(pos)
        ptr.maker(pos+ptr.size)
        pos += ptr.size * 2
        ptr.maker(base+offset)
        func_addr = ptr.ptr(base+offset)

        name_offset = MakeDword(base+offset+ptr.size)

        name = MakeString(base + name_offset)
        name += "_" + hex(func_addr)[2:].upper()

        name = name.replace('.','_').replace("<-",'_chan_left_').replace('*','_ptr_').replace('-','_').replace(';','').replace('"','').replace('\\','')
        name = name.replace('(','').replace(')','').replace('/','_').replace(' ','_').replace(',','comma').replace('{','').replace('}','')
        
        func = functionManager.getFunctionAt(intToAddress(func_addr))

        if func != None:
            old_name = func.getName()
            func.setName(name, USER_DEFINED)
            print "%s renamed as %s" % (old_name, name)
        else:
            func = createFunction(intToAddress(func_addr), name)
            print "Created function %s" % name

def tryLocateGopcltab():
    addr = getFirstFunction().getBody().getMinAddress() # Get some valid address in .text segment. Returns ghidra address
    while True:
        possible_loc = memory.findBytes(addr, b"\xFB\xFF\xFF\xFF\x00\x00", b"\xFF\xFF\xFF\xFF\xFF\xFF", True, monitor) #header of gopclntab

        if possible_loc == None:
            return None

        if check_is_gopclntab(addressToInt(possible_loc)):
            return possible_loc

        addr = possible_loc+1
    return None

def check_is_gopclntab(addr):
    ptr = get_bitness()
    first_entry = ptr.ptr(addr+8+ptr.size)
    first_entry_off = ptr.ptr(addr+8+ptr.size*2)
    addr_func = addr+first_entry_off
    func_loc = ptr.ptr(addr_func)
    if func_loc == first_entry:
        return True
    return False

def GoRename():
    process_segment(go_renamer)

def GoRenameSectionless():
    addr = tryLocateGopcltab()
    if addr is not None:
        addr = addressToInt(addr)
        print "Possible Gopclnab found at: %x" % addr
        go_renamer(addr, get_bitness())
    else:
        print "Coulnd't find gopclntab. Is this a Go binary?"

GoRename()