Appcall typedobj issues

What is the trick to get this working with Appcall? Both 32 and 64 bit do not seem to work.

def get_struct_info(struct_name: str):
    sid = idaapi.get_named_type_tid(struct_name)
    tif = idaapi.tinfo_t(tid=sid)
    udt = idaapi.udt_type_data_t()
    tif.get_udt_details(udt)
    members_info = [{
        "name": member.name,
        "offset": member.offset//8,
        "size": member.type.get_size(),
        "type": member.type.dstr()
    } for member in udt ]

    return tif.get_size(), members_info

example_struct_ea = 0x7E758366E8
size, members = get_struct_info('example_struct')
mem_bytes = idaapi.get_bytes(example_struct_ea, size)

print(f'{mem_bytes=}')
for member in members:
    offset = member["offset"]
    size = member["size"]
    print(f'{member=} {mem_bytes[offset: offset+size].hex()}')

mem_bytes=b'Q\x00\x00\x00\x00\x00\x00\n@\x00\x00\x00#\x01\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
member={'name': 'arg1', 'offset': 0, 'size': 4, 'type': 'uint32_t'} 51000000
member={'name': 'arg2', 'offset': 4, 'size': 2, 'type': 'uint16_t'} 0000
member={'name': 'arg3', 'offset': 6, 'size': 2, 'type': 'uint16_t'} 000a
member={'name': 'arg4', 'offset': 8, 'size': 1, 'type': 'uint8_t'} 40
member={'name': 'arg5', 'offset': 12, 'size': 4, 'type': 'uint32_t'} 23010000
member={'name': 'arg6', 'offset': 16, 'size': 2, 'type': 'uint16_t'} 0100
member={'name': 'arg7', 'offset': 20, 'size': 8, 'type': 'void *'} 0100000000000000

example_struct_typedobj = idaapi.Appcall.typedobj("example_struct;")
ok, header = example_struct_typedobj.retrieve(example_struct_ea)

print(f'{ok}, {header}')
0, -1
print(example_struct_typedobj.size)
28

print(idaapi.inf_is_64bit())
True

I can manually parse structures, but I’d love to use Appcalls dot notation. I had code that worked for this (32 bit) on 8.4 but maybe the API changed a bit on 9.0?

1 Like

I suppose I could do this

args = dict()
for member in members:
    offset = member["offset"]
    size = member["size"]
    args.update({member["name"]: mem_bytes[offset: offset+size]})

and then call with this to get what I want.

idaapi.Appcall.obj(**args).arg1
idaapi.Appcall.obj(**args).arg2
...
...
1 Like

Ok… well. I can’t explain why but

Python>idaapi.Appcall.typedobj('example_struct;').retrieve(0x7E758366E8)[1].arg1
0x51
Python>idaapi.Appcall.typedobj('example_struct;').retrieve(0x7E758366E8)[1].arg2
0x0
Python>idaapi.Appcall.typedobj('example_struct;').retrieve(0x7E758366E8)[1].arg3
0xa00

Works in the GUI but when running CLI (headless) None of this works. Glad I wasn’t going crazy.

Any thoughts?

1 Like

I realize the namespace is different between “idapro headless module” and GUI but I’m still curious if this is a bug or intended behavior.

1 Like

Could you prepare a small binary and exact steps to reproduce the issue? Unfortunately, it’s a bit difficult to say what could be the problem from just this description.

1 Like

For any ARM ELF 32bit/64bit binary, if you can simply create an appcall typedobj and retrieve arbitrary data like in my example above using idapro.open_database (headless) then I’ll consider the issue on my end. for example

idaapi.Appcall.typedobj('example_struct;').retrieve(0x7E758366E8)

Where example_struct is some structure and 0x7E758366E8 is whatever address you have with whatever bytes for the typedobj to “retrieve” and interpret/disaply.

For the same ARM ELF 32 or 64 bit database:

  • GUI: Expected results (structured output)

  • Headless: I get -1

1 Like

It’s possible in 9.1 this is fixed per change log:

BUGFIX: idalib: Python plugins or processsor modules would not work in idalib context started from an external Python process

I’ll give it a go and report back!

1 Like

IIRC Appcall requires an active debugger. I think debuggers do not yet work properly in idalib, but you may be able to use the “classic” batch mode (ida -Sscript.py).

1 Like

I opened up the db I was working in, in 9.1 and instead of

print(f'{ok}, {header}')
0, -1

I now get

print(f'{ok}, {header}')
1, <ida_idaapi.object_t object at 0x13b4867b0>

In summary, my solution for Appcall not returning an object for typedobj retrieve was to update to 9.1

We’re all good now! Thanks team!

1 Like

Great, thanks for the update!