Skip to content

Instantly share code, notes, and snippets.

@icecr4ck
Last active November 14, 2024 07:32
Show Gist options
  • Save icecr4ck/9dea9d1de052f0b2b417abf0046cc0f6 to your computer and use it in GitHub Desktop.
Save icecr4ck/9dea9d1de052f0b2b417abf0046cc0f6 to your computer and use it in GitHub Desktop.
Notes on CTREE usage with IDAPython

IDAPython CTREE

Important links

Description

The CTREE is built from the optimized microcode (maturity at CMAT_FINAL), it represents an AST-like tree with C statements and expressions. It can be printed as C code.

Play with decompiled function

Decompile a function

ea = idaapi.here()
cfunc = idaapi.decompile(ea)

Get decompiled function from pseudocode widget

w = idaapi.get_current_widget()
# if widget type is pseudocode
if idaapi.get_widget_type(w) == idaapi.BWN_PSEUDOCODE:
    vu = idaapi.get_widget_vdui(w)
    cfunc = vu.cfunc

Refresh pseudocode in widget

vu.refresh_ctext()

Get local variables

lvars = cfunc.get_lvars()

Get calling convention

tinfo = idaapi.tinfo_t()
cfunc.get_func_type(tinfo)
funcdata = idaapi.func_type_data_t()
tinfo.get_func_details(funcdata)
cc = funcdata.cc # can be one of CM_CC_* -> examples: CM_CC_CDECL, CM_CC_STDCALL, CM_CC_FASTCALL

Get arguments

for i in cfunc.argidx:
    tinfo = lvars[i].type()

Manipulate types of local variables

tinfo = lvars[0].type()
if tinfo.is_funcptr():
    number_of_args = tinfo.get_nargs()
    rettype = tinfo.get_rettype()
    for i in number_of_args:
        tinfo_arg = tinfo.get_nth_arg(i)

Exploring the CTREE

Create a CTREE visitor

import idaapi

class my_super_visitor(idaapi.ctree_visitor_t):
  def __init__(self):
      idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST) # CV_FAST does not keep parents nodes in CTREE
    
   def visit_insn(self, i):
      return 0
   
   def visit_expr(self, e):
      if e.op != idaapi.cot_asg:
          return 0
      
      return 0
          
cfunc = idaapi.decompile(idc.here())
v = my_super_visitor()
v.apply_to(cfunc.body, None)

Type of expressions and statements

enum ctype_t
{
  cot_empty    = 0,
  cot_comma    = 1,   ///< x, y
  cot_asg      = 2,   ///< x = y
  cot_asgbor   = 3,   ///< x |= y
  cot_asgxor   = 4,   ///< x ^= y
  cot_asgband  = 5,   ///< x &= y
  cot_asgadd   = 6,   ///< x += y
  cot_asgsub   = 7,   ///< x -= y
  cot_asgmul   = 8,   ///< x *= y
  cot_asgsshr  = 9,   ///< x >>= y signed
  cot_asgushr  = 10,  ///< x >>= y unsigned
  cot_asgshl   = 11,  ///< x <<= y
  cot_asgsdiv  = 12,  ///< x /= y signed
  cot_asgudiv  = 13,  ///< x /= y unsigned
  cot_asgsmod  = 14,  ///< x %= y signed
  cot_asgumod  = 15,  ///< x %= y unsigned
  cot_tern     = 16,  ///< x ? y : z
  cot_lor      = 17,  ///< x || y
  cot_land     = 18,  ///< x && y
  cot_bor      = 19,  ///< x | y
  cot_xor      = 20,  ///< x ^ y
  cot_band     = 21,  ///< x & y
  cot_eq       = 22,  ///< x == y int or fpu (see EXFL_FPOP)
  cot_ne       = 23,  ///< x != y int or fpu (see EXFL_FPOP)
  cot_sge      = 24,  ///< x >= y signed or fpu (see EXFL_FPOP)
  cot_uge      = 25,  ///< x >= y unsigned
  cot_sle      = 26,  ///< x <= y signed or fpu (see EXFL_FPOP)
  cot_ule      = 27,  ///< x <= y unsigned
  cot_sgt      = 28,  ///< x >  y signed or fpu (see EXFL_FPOP)
  cot_ugt      = 29,  ///< x >  y unsigned
  cot_slt      = 30,  ///< x <  y signed or fpu (see EXFL_FPOP)
  cot_ult      = 31,  ///< x <  y unsigned
  cot_sshr     = 32,  ///< x >> y signed
  cot_ushr     = 33,  ///< x >> y unsigned
  cot_shl      = 34,  ///< x << y
  cot_add      = 35,  ///< x + y
  cot_sub      = 36,  ///< x - y
  cot_mul      = 37,  ///< x * y
  cot_sdiv     = 38,  ///< x / y signed
  cot_udiv     = 39,  ///< x / y unsigned
  cot_smod     = 40,  ///< x % y signed
  cot_umod     = 41,  ///< x % y unsigned
  cot_fadd     = 42,  ///< x + y fp
  cot_fsub     = 43,  ///< x - y fp
  cot_fmul     = 44,  ///< x * y fp
  cot_fdiv     = 45,  ///< x / y fp
  cot_fneg     = 46,  ///< -x fp
  cot_neg      = 47,  ///< -x
  cot_cast     = 48,  ///< (type)x
  cot_lnot     = 49,  ///< !x
  cot_bnot     = 50,  ///< ~x
  cot_ptr      = 51,  ///< *x, access size in 'ptrsize'
  cot_ref      = 52,  ///< &x
  cot_postinc  = 53,  ///< x++
  cot_postdec  = 54,  ///< x--
  cot_preinc   = 55,  ///< ++x
  cot_predec   = 56,  ///< --x
  cot_call     = 57,  ///< x(...)
  cot_idx      = 58,  ///< x[y]
  cot_memref   = 59,  ///< x.m
  cot_memptr   = 60,  ///< x->m, access size in 'ptrsize'
  cot_num      = 61,  ///< n
  cot_fnum     = 62,  ///< fpc
  cot_str      = 63,  ///< string constant
  cot_obj      = 64,  ///< obj_ea
  cot_var      = 65,  ///< v
  cot_insn     = 66,  ///< instruction in expression, internal representation only
  cot_sizeof   = 67,  ///< sizeof(x)
  cot_helper   = 68,  ///< arbitrary name
  cot_type     = 69,  ///< arbitrary type
  cot_last     = cot_type,
  cit_empty    = 70,  ///< instruction types start here
  cit_block    = 71,  ///< block-statement: { ... }
  cit_expr     = 72,  ///< expression-statement: expr;
  cit_if       = 73,  ///< if-statement
  cit_for      = 74,  ///< for-statement
  cit_while    = 75,  ///< while-statement
  cit_do       = 76,  ///< do-statement
  cit_switch   = 77,  ///< switch-statement
  cit_break    = 78,  ///< break-statement
  cit_continue = 79,  ///< continue-statement
  cit_return   = 80,  ///< return-statement
  cit_goto     = 81,  ///< goto-statement
  cit_asm      = 82,  ///< asm-statement
  cit_end
};
@arizvisa
Copy link

Make sure you use lvar_locator_t if you plan on keeping an lvar_t around since lvar_t can go out of scope in-between ctree/mba refreshes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment