4

I was wondering if anyone knows how to assign a struct to a stack variable using IDAPython (like when we do Alt+Q); Doing this for addresses in .data is not a problem, but I can't figure out a way to do it over the stack struct that IDA creates for a given function.

There seems to be two APIs in idaapi to do this:

def set_member_tinfo2(*args):
  """
  set_member_tinfo2(sptr, mptr, memoff, tif, flags) -> smt_code_t
  """

def set_member_tinfo(*args):
"""
set_member_tinfo(til, sptr, mptr, memoff, type, fields, flags) -> bool
"""
return _idaapi.set_member_tinfo(*args)

The problem is that I don't know how to get a 'type' (type_t) or 'tif' (tinfo_t) from the struct I have in my locals. The code I have so far is something like this:

# 00000000167ED lea     r8, [rbp+190h+var_170]

lea_addr = 0x167ED
# Get the stack struct
current_func = idaapi.get_func(lea_addr)
stack_id = idc.GetFrame(current_func)
stack_struc = idaapi.get_struc(stack_id)

# Get the stack operand offset value and stack member
stack_member_offset = idc.GetOperandValue(lea_addr, 1)
stack_member = stack_struc.get_member(stack_member_offset)

target_struct_id = idaapi.get_struc_id("_CONFIG")
target_struc = idaapi.get_struc(target_struct_id )

My goal is to assign the _CONFIG struct I have in my idb local to var_170. I should call set_member_tinfo2 passing a tinfo_t of my _CONFIG struct but I can't figure out how to get it.

In the idc module there is another function called 'SetMemberType' which looks simpler but I've tried this one in several ways without success. For example:

idc.SetMemberType(stack_id, stack_member_offset, idc.FF_STRU|idc.FF_DATA, target_struct_id, 0)

It always returns False.


Thanks @Bambu, I've actually tried your method but it didn't work for me either. What I've finally found that works is to first undefine the stack members that are defined by IDA (except for the ones you already defined and the base 'r' member) and then defining a new bytes member with the size of the struct. After that, change the type with SetMemberType.

def delete_all_function_stack_members(func_ea):
    members, base = retrieve_stack_members(func_ea)
    stack_id = idc.GetFrame(func_ea)
    for k, v in members.items():
        if k != base:
            idc.DelStrucMember(stack_id, k)
    g_functions_stack.add(func_ea)

delete_all_function_stack_members(current_func)
AddStrucMember(stack_id, "config", stack_member_offset, FF_BYTE|FF_DATA, -1, GetStrucSize(target_struct_id))
idc.SetMemberType(stack_id, stack_member_offset, idc.FF_STRU|idc.FF_DATA, target_struct_id, 1)
3

What I've finally found that works is to first undefine the stack members that are defined by IDA (except for the ones you already defined and the base 'r' member) and then defining a new bytes member with the size of the struct. After that, change the type with SetMemberType.

def delete_all_function_stack_members(func_ea):
    members, base = retrieve_stack_members(func_ea)
    stack_id = idc.GetFrame(func_ea)
    for k, v in members.items():
        if k != base:
            idc.DelStrucMember(stack_id, k)
    g_functions_stack.add(func_ea)

delete_all_function_stack_members(current_func)
AddStrucMember(stack_id, "config", stack_member_offset, FF_BYTE|FF_DATA, -1, GetStrucSize(target_struct_id))
idc.SetMemberType(stack_id, stack_member_offset, idc.FF_STRU|idc.FF_DATA, target_struct_id, 1)
1

You can get a tinfo_t for your _CONFIG struct by using parse_decl2. Then applying it using idaapi.set_member_tinfo2.

After you get the stack_struc and stack_member you could do something like this:

tinfo = idaapi.tinfo_t()
idaapi.parse_decl2(idaapi.cvar.idati, '_CONFIG;', tinfo, idaapi.PT_TYP)
idaapi.set_member_tinfo2(stack_struc, stack_member, 0, tinfo, idaapi.SET_MEMTI_COMPATIBLE)

Note: the ; at the end of _CONFIG; is required.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.