Files
2025-03-13 16:17:53 +01:00

126 lines
3.2 KiB
Python

"""
summary: list operands representing a "path" to a (possibly nested) structure member
description:
It is possible to assign, to instruction operands, the notion of "structure
offset", which really is a pointer to a specific offset in a type, leading
to a possible N-deep path within types.
E.g., assuming the following types
struct c
{
int foo;
int bar;
int baz;
int quux;
int trail;
};
struct b
{
int gap;
c c_instance;
};
struct a
{
int count;
b b_instance;
};
and assuming an instruction that initially looks like this:
mov eax, 10h
by pressing `t`, the user will be able set the "structure offset"
to either:
* `c.trail`
* `b.c_instance.quux`
* `a.b_inscance.c_instance.baz`
Here's why IDA offers `a.b_inscance.c_instance.baz`:
0000 struct a
{
0000 int count;
0004 struct b
{
0004 int gap;
0008 struct c
{
0008 int foo;
000C int bar;
0010 int baz;
0014 int quux;
0018 int trail;
};
};
};
This sample shows how to programmatically retrieve information about
that "structure member path" that an operand was made pointing to.
keywords: bookmarks
level: advanced
"""
from typing import List
import ida_bytes
import ida_pro
import ida_ua
import ida_typeinf
import ida_nalt
import ida_netnode
def get_struct_paths(ea: int, opnum: int) -> List[str]:
flags = ida_bytes.get_full_flags(ea)
if not ida_bytes.is_stroff(flags, opnum):
# requested operand not a structure
return []
insn = ida_ua.insn_t()
ins_sz = ida_ua.decode_insn(insn, ea)
if ins_sz == 0:
# could not disassemble
return []
num_ops = 0
# ;! nice idea to inject via Swig a '__len__' method to the instruction
# object that does that.
while insn.ops[num_ops].type != ida_ua.o_void:
num_ops += 1
op = insn.ops[opnum]
if op.type == ida_ua.o_imm:
value = op.value
else:
value = op.addr
path, delta = ida_bytes.get_stroff_path(insn.ea, opnum)
out = []
for tid in path:
tif = ida_typeinf.tinfo_t(tid=tid)
sz = tif.get_size()
if delta + value == sz:
out.append(f"size {tif.get_type_name()}")
else:
for idx, mem in enumerate(tif.iter_udt()):
off = mem.offset // 8 # udm.offset is in bits
size = mem.size // 8 # udm.size is in bits
if off - delta <= value < off - delta + size:
name = ida_typeinf.get_tid_name(tif.get_udm_tid(idx))
diff = value - (off - delta)
if diff > 0:
out.append(f"{name}+{diff}")
else:
out.append(f"{name}")
return out