mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
126 lines
3.2 KiB
Python
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
|