4

The ordinary, manual way of redefining a struct member to become a function pointer would be to press on it, hit 'Y', and enter the proper declaration in the popup box. For example, for struct member fncQuery, I would change the string to: BOOL (__cdecl *fncQuery)(char *cmdID)

This would be helpful; When I next identify a call to this function pointer, I would mark the appropriate call [reg+offset] line as this function pointer, and IDA will re-analyze and comment the parameters for me.

I have a thousand struct each with at least one such function pointer member, and corresponding lists of the descriptions of these functions' parameters and return values. Understandably, I want to match them up by an IDAPython script rather than by hand. However, I can't find an equivalent for the 'Y' button for scripts:

  • AddStrucMember does not cut it as far as I know - I can declare a member to become a pointer to a struct by giving it a structID, but that's not what I need.

  • SetMemberType is the same as the previous.

  • SetType requires a linear address and a type string - which would be perfect except linear addresses are exclusive to the code section, so I can't touch structure member definitions with SetType.

In my search I've found someone who conjured up dark magic, incorporating low level idaapi into his IDAPython script, to detect if a struct member has the same name as a known function, and if it does, "gets" the type of that function and "sets" it onto the member. Specifically, such horrible calls are seen (taken out of context of its definitions, you'll have to trust me when I say this runs properly and the first function call fills up its many outparameters with meaningful values):

get_named_type = g_dll.get_named_type
get_named_type.argtypes = [
  ctypes.c_void_p, #const til_t *ti,
  ctypes.c_char_p, #const char *name,
  ctypes.c_int, #int ntf_flags,
  ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const type_t **type=NULL,
  ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fields=NULL,
  ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const char **cmt=NULL,
  ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)), #const p_list **fieldcmts=NULL,
  ctypes.POINTER(ctypes.c_ulong), #sclass_t *sclass=NULL,
  ctypes.POINTER(ctypes.c_ulong), #uint32 *value=NULL);
]

get_named_type(
            til,
            funcname,
            idaapi.NTF_SYMM,
            ctypes.byref(typ_type),
            ctypes.byref(typ_fields),
            ctypes.byref(typ_cmt),
            ctypes.byref(typ_fieldcmts),
            ctypes.byref(typ_sclass),
            ctypes.byref(value)
type_arr = ctypes.create_string_buffer(0x400)
            type_arr[0] = chr(idaapi.BT_PTR)
            manualTypeCopy(type_arr, 1, len(type_arr), typ_type)
            ret = g_dll.set_member_tinfo(
                til,
                struc,
                memb,
                ctypes.c_uint(0),
                type_arr,
                typ_fields,
                ctypes.c_uint(0),
            )

The work behind the scenes on "get_named_type" eludes me, and looking into its source (and fashioning something from it for my use) may be strong headed and premature.

Do you know of an easier way my need can be fulfilled ? I just need to define structure members as function pointers from an IDAPython script. Please help !

3

The Y key equivalent is indeed the SetType (or, rather, ApplyType) function, and it normally accepts addresses. However, you actually can pass the structure member ID as the "address" to set the member's type info.

  • I tried and couldn't get it to succeed. Unless the type syntax needs to be fundamentally different somehow, SetType(memberid, "int") failed whereas SetType(linear_address_of_some_data, "int") succeeded. Edit: ApplyType() at least seems to return True as opposed to SetType(), but when I detect such a fptr call in my code and tag it as such it still does not automatically mark the parameters as the IDs I gave to them Second edit: SetType() succeeds despite the False return value (and the documentation that claims that's a failure.) So this works. Thanks. – Sleeptime Jul 2 '14 at 13:54
2

There is a better way to do it which does not involve setting particular type to structure member.

You can create a header file with corresponding structure definition and import it by calling

idc.ParseTypes(filename, idc.PT_FILE | idc.PT_PAK1)
idc.Til2Idb(-1, strname)

In addition you can try to look to source code of Milan Bohacek's hexrays_tools plugin and try to export corresponding functions to your own python module.

Source of the plugin is available here, link from hex-rays plugin contest page

Explanation of how to export Hexrays internal into python calls can be found in hexrays blog but you should take specific care of GIL (see here )

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.