Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

IDAPy OpCode Address Finder (COutPacket)

Skilled Illusionist
Joined
Feb 18, 2010
Messages
320
Reaction score
112
hi

this is an idapy script that prints COutPacket call addresses and their opcode arguments
can be configured to print everything or filter by one/many opcodes

tested and working on v95, v176, and v213
works with and without a pdb applied
skips calls that have broken asm preceding the call instruction
output is ordered by call address
script requires COutPacket::COutPacket(COutPacket *this, int nType) address entered at the beginning
the function calls on the three last lines of the script are the example usages

enjoy

Code:
import idc
import idautils

# coutpacket address
COUTPACKET_CONSTRUCT = 0x0068D090
# max number of previouus instructions before skipping
INSTR_DISTANCE_LIMITER = 10
# remove func args from output strings
REMOVE_FUNC_ARGS = True


def demangle_func_name(mangled_name, clean=True):
    demangle_attr = idc.get_inf_attr(INF_SHORT_DN if clean else INF_LONG_DN)
    return idc.demangle_name(mangled_name, demangle_attr)


def is_push_mnem(addr):
    return idc.GetMnem(addr).lower() == "push"


def get_prev_push_addr(base_addr):
    global INSTR_DISTANCE_LIMITER
    prev_op = idautils.DecodePreviousInstruction(base_addr)
    retVal = idaapi.BADADDR  # static value
    
    for idx in range(INSTR_DISTANCE_LIMITER):
        
        # some calls get rekt by asm segments
        if prev_op is None:
            break
            
        if is_push_mnem(prev_op.ea):
            retVal = prev_op.ea
            break
        
        prev_op = idautils.DecodePreviousInstruction(prev_op.ea)
    
    return retVal


# turn decimal opcode into prettyfied hex opcode
def transform_to_hex(raw_addr, padding):
    hex_addr = hex(raw_addr)  # dec -> hex
    l_stripped_addr = hex_addr[2:-1].upper().rjust(padding, '0')  # remove trailing L, capitalize, strip '0x'
    return "0x" + l_stripped_addr  # add lowercase 0x


# get func name from address and demangle it if its mangled
def process_func_name(addr):
    global REMOVE_FUNC_ARGS
    xref_func_name_raw = idc.get_func_name(addr)  # get containing func name
    xref_func_name_clean = demangle_func_name(xref_func_name_raw)  # demangle name
    
    # if name isnt mangled this returns None
    if xref_func_name_clean is None:
        xref_func_name_clean = xref_func_name_raw
    
    if xref_func_name_clean is not None and REMOVE_FUNC_ARGS:
        xref_func_name_clean = xref_func_name_clean.split('(')[0]        
    
    return xref_func_name_clean


# prints all coutpacket constructor call addresses and the opcode argument
def print_opcodes(filter=None):
    global COUTPACKET_CONSTRUCT
    for xref in idautils.XrefsTo(COUTPACKET_CONSTRUCT):  # iterate xrefs
        func_name = process_func_name(xref.frm)
        
        if func_name is None:
            continue
        
        call_addr = get_prev_push_addr(xref.frm)  # get addr to opcode arg
        call_addr_op_val = idc.get_operand_value(call_addr, 0)  # get opcode arg value
        
        if filter is not None:
            # handle single opcode filter
            if type(filter) is int:
                if call_addr_op_val != filter:
                    continue
            # handle list filter
            elif type(filter) is list:
                if call_addr_op_val not in filter:
                    continue
        
        op_val_leg = transform_to_hex(call_addr_op_val, 4)  # prettify opcode
        xref_addr = transform_to_hex(xref.frm, 9)
        
        print("[{}] | [{}] : {}".format(
            xref_addr, 
            op_val_leg, 
            func_name
        ))


# beginning of script execution

print_opcodes()  # no filter
print_opcodes(0x01C4)  # filter by a single opcode
print_opcodes([0x01C4, 0x01C3])  # filter by a list
 
Back
Top