Latest available version: IDA and decompilers v8.4.240527sp2 see all releases
Hex-Rays logo State-of-the-art binary code analysis tools
email icon
* Hex-Rays Decompiler project
* Copyright (c) 2007-2024 by Hex-Rays,
* Sample plugin for Hex-Rays Decompiler.
* It installs a custom instruction optimization rule:
* mov #N, var.4 mov #N, var.4
* xor var@1.1, #M, var@1.1 => mov #NM, var@1.1
* where NM == (N>>8)^M
* We need this rule because the decompiler cannot propagate the second
* byte of VAR into the xor instruction.
* The XOR opcode can be replaced by any other, we do not rely on it.
* Also operand sizes can vary.
* This improves the decompiler output for some obfuscated code.
#include <hexrays.hpp>
// find backwards the instruction that defines anything from LST
static const minsn_t *find_prev_def(
const mblock_t *blk,
const mlist_t &lst,
const minsn_t *ins)
const minsn_t *p = ins;
while ( (p=p->prev) != nullptr )
mlist_t def = blk->build_def_list(*p, MAY_ACCESS|FULL_XDSU);
if ( def.has_common(lst) )
return p;
struct glbprop_t : public optinsn_t
virtual int idaapi func(mblock_t *blk, minsn_t *ins, int /*optflags*/) override
if ( ins->r.t != mop_n )
return 0; // we want a constant as the second operand
if ( ins->r.size > 2 )
return 0; // bigger sizes are handled by the decompiler without problems
// build list of data used by INS
mlist_t use = blk->build_use_list(*ins, MAY_ACCESS);
// find the instruction that defines anything from USE
const minsn_t *di = find_prev_def(blk, use, ins);
if ( di == nullptr )
return 0; // not found
if ( di->opcode != m_mov || di->l.t != mop_n )
return 0; // must be 'mov #N, ...'
// compare the destination of DI and the left operand of INS
mop_t v1 = ins->l;
const mop_t &v2 = di->d;
if ( v1.t != v2.t )
return 0; // operand types are different
// if operand sizes are the same, hexrays can handle it without our help
// if the size of INS->L is bigger than the size of DI->D, may not propagate
// we handle only the case where the size of INS->L is less than the size
// of DI->D because the hexrays sometimes has problems with it.
if ( v1.size >= v2.size )
return 0;
// this is not very efficient... but acceptable
int off = 0;
while ( !v1.equal_mops(v2, EQ_IGNSIZE) )
if ( ++off >= v2.size )
return 0;
if ( !v1.shift_mop(-1) )
return 0;
// found a match! shift N in order to propagate the correct part of it
// we don't truncate the high bits, it will happen in make_number()
uint64 N = di->l.value(false);
N >>= (off * 8);
// store the new value in INS
ins->l.make_number(N, ins->l.size, di->l.nnn->ea, di->l.nnn->opnum);
// optimize the instruction, it is highly likely that we will get
// a much simpler instruction like 'mov'
return 1; // success, we made one change
struct plugin_ctx_t : public plugmod_t
glbprop_t glbprop;
virtual bool idaapi run(size_t) override;
bool idaapi plugin_ctx_t::run(size_t)
warning("The '%s' plugin is fully automatic", PLUGIN.wanted_name);
return false;
static plugmod_t *idaapi init()
return nullptr; // no decompiler
const char *hxver = get_hexrays_version();
msg("Hex-rays version %s has been detected, %s ready to use\n",
hxver, PLUGIN.wanted_name);
return new plugin_ctx_t;
static const char comment[] = "Sample16 plugin for Hex-Rays decompiler";
plugin_t PLUGIN =
PLUGIN_HIDE // Plugin should not appear in the Edit, Plugins menu
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
comment, // long comment about the plugin
nullptr, // multiline help about the plugin
"Propagation helper", // the preferred short name of the plugin
nullptr, // the preferred hotkey to run the plugin
Microcode of one basic block.
Definition: hexrays.hpp:3805
mlist_t build_def_list(const minsn_t &ins, maymust_t maymust) const
Build def-list of an instruction.
Definition: hexrays.hpp:11157
mlist_t build_use_list(const minsn_t &ins, maymust_t maymust) const
Build use-list of an instruction.
Definition: hexrays.hpp:11149
Microinstruction class #insn.
Definition: hexrays.hpp:3465
mop_t r
right operand
Definition: hexrays.hpp:3475
minsn_t * prev
prev insn in doubly linked list. check also previ()
Definition: hexrays.hpp:3472
mop_t l
left operand
Definition: hexrays.hpp:3474
int optimize_solo(int optflags=0)
Optimize one instruction without context.
Definition: hexrays.hpp:3609
mop_t d
destination operand
Definition: hexrays.hpp:3476
mcode_t opcode
instruction opcode
Definition: hexrays.hpp:3469
A microinstruction operand.
Definition: hexrays.hpp:2441
mopt_t t
Operand type.
Definition: hexrays.hpp:2445
int size
Operand size.
Definition: hexrays.hpp:2465
bool equal_mops(const mop_t &rop, int eqflags) const
Compare operands.
Definition: hexrays.hpp:10671
void make_number(uint64 _value, int _size, ea_t _ea=BADADDR, int opnum=0)
Create an integer constant operand.
Definition: hexrays.hpp:10605
uint64 value(bool is_signed) const
Retrieve value of a constant integer operand.
Definition: hexrays.hpp:2834
bool shift_mop(int offset)
Shift the operand.
Definition: hexrays.hpp:10731
HexRays SDK header file.
bool init_hexrays_plugin(int flags=0)
Check that your plugin is compatible with hex-rays decompiler.
Definition: hexrays.hpp:8601
#define EQ_IGNSIZE
ignore source operand sizes
Definition: hexrays.hpp:3654
const mopt_t mop_n
immediate number constant
Definition: hexrays.hpp:2257
void install_optinsn_handler(optinsn_t *opt)
Install an instruction level custom optimizer.
Definition: hexrays.hpp:10477
void term_hexrays_plugin()
Stop working with hex-rays decompiler.
Definition: hexrays.hpp:8609
bool remove_optinsn_handler(optinsn_t *opt)
Remove an instruction level custom optimizer.
Definition: hexrays.hpp:10483
const char * get_hexrays_version()
Get decompiler version.
Definition: hexrays.hpp:11511
ea_t ea
address of the original processor instruction
Definition: hexrays.hpp:769
int opnum
operand number in the instruction
Definition: hexrays.hpp:770
User defined callback to optimize individual microcode instructions.
Definition: hexrays.hpp:2109
virtual int func(mblock_t *blk, minsn_t *ins, int optflags)=0
Optimize an instruction.