RzAnalysis: Generalize ROP core search to Gadget for future JOP/COP support (#6130)
This commit is contained in:
parent
02f3ae94d2
commit
4e5a8e4826
24 changed files with 972 additions and 721 deletions
|
|
@ -164,8 +164,8 @@ RZ_API RzAnalysis *rz_analysis_new(RZ_NULLABLE const char *sdb_types_path) {
|
|||
}
|
||||
}
|
||||
analysis->ht_global_var = ht_sp_new(HT_STR_DUP, NULL, (HtSPFreeValue)rz_analysis_var_global_free);
|
||||
analysis->ht_rop_semantics = NULL;
|
||||
analysis->ht_rop = NULL;
|
||||
analysis->ht_gadget_semantics = NULL;
|
||||
analysis->ht_gadget = NULL;
|
||||
analysis->global_var_tree = NULL;
|
||||
analysis->il_vm = NULL;
|
||||
analysis->hash = rz_hash_new();
|
||||
|
|
@ -220,7 +220,7 @@ RZ_API void rz_analysis_free(RZ_NULLABLE RzAnalysis *a) {
|
|||
rz_list_free(a->imports);
|
||||
rz_str_constpool_fini(&a->constpool);
|
||||
ht_sp_free(a->ht_global_var);
|
||||
ht_up_free(a->ht_rop_semantics);
|
||||
ht_up_free(a->ht_gadget_semantics);
|
||||
ht_sp_free(a->plugins);
|
||||
rz_analysis_debug_info_free(a->debug_info);
|
||||
ht_sp_free(a->ht_virtual_xrefs);
|
||||
|
|
@ -513,14 +513,14 @@ RZ_API void rz_analysis_set_xrefs_to(RZ_NONNULL RzAnalysis *analysis, HtUP *xref
|
|||
analysis->ht_xrefs_to = xrefs_to;
|
||||
}
|
||||
|
||||
RZ_API RZ_BORROW HtUP *rz_analysis_get_rop_semantics(RZ_NONNULL RzAnalysis *analysis) {
|
||||
RZ_API RZ_BORROW HtUP *rz_analysis_get_gadget_semantics(RZ_NONNULL RzAnalysis *analysis) {
|
||||
rz_return_val_if_fail(analysis, NULL);
|
||||
return analysis->ht_rop_semantics;
|
||||
return analysis->ht_gadget_semantics;
|
||||
}
|
||||
|
||||
RZ_API void rz_analysis_set_rop_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics) {
|
||||
RZ_API void rz_analysis_set_gadget_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *gadget_semantics) {
|
||||
rz_return_if_fail(analysis);
|
||||
analysis->ht_rop_semantics = rop_semantics;
|
||||
analysis->ht_gadget_semantics = gadget_semantics;
|
||||
}
|
||||
|
||||
RZ_API RZ_BORROW RzAnalysisCallbacks *rz_analysis_get_callbacks(RZ_NONNULL RzAnalysis *analysis) {
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ struct rz_analysis_t {
|
|||
RzPlatformTarget *arch_target;
|
||||
RzPlatformTargetIndex *platform_target;
|
||||
HtSP *ht_global_var; // global variables
|
||||
HtUP *ht_rop_semantics; ///< cache rop gadget semantic information
|
||||
HtUP *ht_rop; ///< cache rop gadget address list
|
||||
HtUP *ht_gadget_semantics; ///< cache gadget semantic information
|
||||
HtUP *ht_gadget; ///< cache gadget address list
|
||||
RBTree global_var_tree; // global variables by address. must not overlap
|
||||
RzHash *hash;
|
||||
RzAnalysisDebugInfo *debug_info; ///< store all debug info parsed from DWARF, etc..
|
||||
|
|
|
|||
|
|
@ -3632,12 +3632,12 @@ RZ_API int rz_core_config_init(RzCore *core) {
|
|||
SETDESC(n, "Set grep(~) as case smart/sensitive/insensitive");
|
||||
SETOPTIONS(n, "smart", "sensitive", "insensitive", NULL);
|
||||
|
||||
/* rop */
|
||||
SETI("rop.len", 5, "Maximum ROP gadget length");
|
||||
SETBPREF("rop.cache", "false", "Cache rop gadget results(experimental)");
|
||||
SETBPREF("rop.subchains", "false", "Display every length gadget from rop.len=X to 2 in /Rl");
|
||||
SETBPREF("rop.conditional", "false", "Include conditional jump, calls and returns in ropsearch");
|
||||
SETBPREF("rop.comments", "false", "Display comments in rop search output");
|
||||
/* gadget */
|
||||
SETI("gadget.len", 5, "Maximum number of instructions per gadget");
|
||||
SETBPREF("gadget.cache", "false", "Cache gadget results(experimental)");
|
||||
SETBPREF("gadget.subchains", "false", "Display every length gadget from gadget.len=X to 2");
|
||||
SETBPREF("gadget.conditional", "false", "Include conditional jump, calls and returns in gadget search");
|
||||
SETBPREF("gadget.comments", "false", "Display comments in gadget search output");
|
||||
|
||||
/* io */
|
||||
SETCB("io.cache", "false", &cb_io_cache, "Change both of io.cache.{read,write}");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2010-2021 pancake <pancake@nopcode.org>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
|
|
@ -9,7 +10,7 @@
|
|||
#include <rz_search.h>
|
||||
#include <rz_types_base.h>
|
||||
|
||||
#include "cmd_search_rop.c"
|
||||
#include "cmd_search_gadget.c"
|
||||
#include "rz_cons.h"
|
||||
#include <rz_config.h>
|
||||
#include <rz_flag.h>
|
||||
|
|
@ -44,19 +45,34 @@ struct search_parameters {
|
|||
bool regex_search;
|
||||
};
|
||||
|
||||
static RzGadgetType gadget_type_from_cmd(const char *cmd_name) {
|
||||
rz_return_val_if_fail(cmd_name && cmd_name[0] && cmd_name[1], RZ_GADGET_TYPE_ROP);
|
||||
switch (cmd_name[1]) {
|
||||
case 'J':
|
||||
return RZ_GADGET_TYPE_JOP;
|
||||
case 'C':
|
||||
return RZ_GADGET_TYPE_COP;
|
||||
case 'R':
|
||||
default:
|
||||
return RZ_GADGET_TYPE_ROP;
|
||||
}
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_info_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
const char *input = argc > 1 ? argv[1] : "";
|
||||
if (!input) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_rop_gadget_info(core, context);
|
||||
RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]);
|
||||
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, false, RZ_GADGET_PRINT, RZ_GADGET_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_gadget_info(core, context);
|
||||
return status;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
RzPVector /*<RzRopConstraint *>*/ *constraints = rz_core_rop_constraint_map_parse(core, argc, argv);
|
||||
RzPVector /*<RzGadgetConstraint *>*/ *constraints = rz_core_gadget_constraint_map_parse(core, argc, argv);
|
||||
if (!constraints) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
|
|
@ -65,15 +81,17 @@ RZ_IPI RzCmdStatus rz_cmd_query_gadget_handler(RzCore *core, int argc, const cha
|
|||
return RZ_CMD_STATUS_INVALID;
|
||||
}
|
||||
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, NULL, false,
|
||||
RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON, state);
|
||||
RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]);
|
||||
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, NULL, false,
|
||||
RZ_GADGET_PRINT | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON, state);
|
||||
if (!context) {
|
||||
rz_pvector_free(constraints);
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
context->constraints = constraints;
|
||||
const RzCmdStatus cmd_status = rz_core_rop_search(core, context);
|
||||
rz_core_rop_search_context_free(context);
|
||||
const RzCmdStatus cmd_status = rz_core_gadget_search(core, context);
|
||||
rz_core_gadget_search_context_free(context);
|
||||
return cmd_status;
|
||||
}
|
||||
|
||||
|
|
@ -82,29 +100,39 @@ RZ_IPI RzCmdStatus rz_cmd_search_gadget_handler(RzCore *core, int argc, const ch
|
|||
if (!input) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, true, RZ_ROP_GADGET_PRINT, RZ_ROP_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_rop_search(core, context);
|
||||
rz_core_rop_search_context_free(context);
|
||||
|
||||
RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]);
|
||||
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, true, RZ_GADGET_PRINT, RZ_GADGET_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_gadget_search(core, context);
|
||||
rz_core_gadget_search_context_free(context);
|
||||
return status;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
const char *input = argc > 1 ? argv[1] : "";
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, input, false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_rop_search(core, context);
|
||||
rz_core_rop_search_context_free(context);
|
||||
|
||||
RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]);
|
||||
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, input, false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON, state);
|
||||
RzCmdStatus status = rz_core_gadget_search(core, context);
|
||||
rz_core_gadget_search_context_free(context);
|
||||
return status;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_rop_search_stack_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_STACK, state);
|
||||
RzCmdStatus status = rz_core_rop_gadget_info(core, context);
|
||||
RzGadgetType gadget_type = RZ_GADGET_TYPE_ROP;
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, argv[1], false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_STACK, state);
|
||||
RzCmdStatus status = rz_core_gadget_info(core, context);
|
||||
return status;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_cmd_rop_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(core, argv[1], false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_SIZE, state);
|
||||
RzCmdStatus status = rz_core_rop_gadget_info(core, context);
|
||||
RZ_IPI RzCmdStatus rz_cmd_gadget_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
||||
|
||||
RzGadgetType gadget_type = gadget_type_from_cmd(argv[0]);
|
||||
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(core, gadget_type, argv[1], false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_SIZE, state);
|
||||
RzCmdStatus status = rz_core_gadget_info(core, context);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2009-2016 Alexandru Caciulescu <alex.darredevil@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
|
@ -7,7 +8,7 @@
|
|||
#include "rz_core.h"
|
||||
#include "rz_list.h"
|
||||
#include "rz_types_base.h"
|
||||
#include "rz_rop.h"
|
||||
#include "rz_gadget.h"
|
||||
|
||||
static void skip_whitespace(const char *str, ut64 *idx) {
|
||||
if (*idx >= strlen(str)) {
|
||||
|
|
@ -194,8 +195,8 @@ static bool parse_il_op(const char *str, ut64 *idx, bool *is_compound_op, RzILOp
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool rop_constraint_set_regs(RzRopConstraint *rc,
|
||||
RzRopILInstructionType il_type,
|
||||
static bool gadget_constraint_set_regs(RzGadgetConstraint *rc,
|
||||
RzGadgetILInstructionType il_type,
|
||||
RZ_NONNULL const RzRegItem *dst,
|
||||
RZ_NONNULL const RzRegItem *src0,
|
||||
RZ_NULLABLE const RzRegItem *src1) {
|
||||
|
|
@ -213,7 +214,7 @@ static bool rop_constraint_set_regs(RzRopConstraint *rc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool rop_constraint_set_op(RzRopConstraint *rc, RzILOpPureCode op) {
|
||||
static bool gadget_constraint_set_op(RzGadgetConstraint *rc, RzILOpPureCode op) {
|
||||
if (op >= RZ_IL_OP_PURE_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -226,8 +227,8 @@ static bool rop_constraint_set_op(RzRopConstraint *rc, RzILOpPureCode op) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool rop_constraint_set_const(RzRopConstraint *rc,
|
||||
RzRopILInstructionType il_type,
|
||||
static bool gadget_constraint_set_const(RzGadgetConstraint *rc,
|
||||
RzGadgetILInstructionType il_type,
|
||||
RZ_NONNULL const RzRegItem *dst,
|
||||
RZ_NULLABLE const RzRegItem *src0,
|
||||
ut64 const_value) {
|
||||
|
|
@ -245,7 +246,7 @@ static bool rop_constraint_set_const(RzRopConstraint *rc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstraint *rc) {
|
||||
static bool parse_compound_op(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) {
|
||||
ut64 idx = 0;
|
||||
ut64 const_value = 0;
|
||||
bool inc_dec = false;
|
||||
|
|
@ -284,14 +285,14 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai
|
|||
|
||||
if (constant_status && is_compound_op) {
|
||||
// dst = dst (math op) num
|
||||
return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, dst_reg, const_value) &&
|
||||
rop_constraint_set_op(rc, op);
|
||||
return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, dst_reg, const_value) &&
|
||||
gadget_constraint_set_op(gadget_constraint, op);
|
||||
}
|
||||
|
||||
if (src_reg && is_compound_op) {
|
||||
// dst = dst (math op) src
|
||||
return rop_constraint_set_regs(rc, MOV_OP_REG, dst_reg, dst_reg, src_reg) &&
|
||||
rop_constraint_set_op(rc, op);
|
||||
return gadget_constraint_set_regs(gadget_constraint, MOV_OP_REG, dst_reg, dst_reg, src_reg) &&
|
||||
gadget_constraint_set_op(gadget_constraint, op);
|
||||
}
|
||||
|
||||
if (!inc_dec) {
|
||||
|
|
@ -301,11 +302,11 @@ static bool parse_compound_op(const RzCore *core, const char *str, RzRopConstrai
|
|||
const_value = 1;
|
||||
// dst (math op)= 1
|
||||
|
||||
return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, dst_reg, const_value) &&
|
||||
rop_constraint_set_op(rc, op);
|
||||
return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, dst_reg, const_value) &&
|
||||
gadget_constraint_set_op(gadget_constraint, op);
|
||||
}
|
||||
|
||||
static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstraint *rc) {
|
||||
static bool parse_reg_to_const(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) {
|
||||
ut64 idx = 0;
|
||||
ut64 const_value = 0;
|
||||
const RzRegItem *dst_reg = parse_register(core, str, &idx);
|
||||
|
|
@ -317,10 +318,10 @@ static bool parse_reg_to_const(const RzCore *core, const char *str, RzRopConstra
|
|||
return false;
|
||||
}
|
||||
|
||||
return rop_constraint_set_const(rc, MOV_CONST, dst_reg, NULL, const_value);
|
||||
return gadget_constraint_set_const(gadget_constraint, MOV_CONST, dst_reg, NULL, const_value);
|
||||
}
|
||||
|
||||
static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstraint *rc) {
|
||||
static bool parse_reg_to_reg(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) {
|
||||
ut64 idx = 0;
|
||||
const RzRegItem *src_reg = NULL;
|
||||
const RzRegItem *dst_reg = parse_register(core, str, &idx);
|
||||
|
|
@ -341,10 +342,10 @@ static bool parse_reg_to_reg(const RzCore *core, const char *str, RzRopConstrain
|
|||
return false;
|
||||
}
|
||||
|
||||
return rop_constraint_set_regs(rc, MOV_REG, dst_reg, src_reg, NULL);
|
||||
return gadget_constraint_set_regs(gadget_constraint, MOV_REG, dst_reg, src_reg, NULL);
|
||||
}
|
||||
|
||||
static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstraint *rc) {
|
||||
static bool parse_reg_op_const(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) {
|
||||
ut64 idx = 0;
|
||||
ut64 const_value = 0;
|
||||
RzILOpPureCode op = RZ_IL_OP_PURE_MAX;
|
||||
|
|
@ -360,14 +361,14 @@ static bool parse_reg_op_const(const RzCore *core, const char *str, RzRopConstra
|
|||
goto compound;
|
||||
}
|
||||
|
||||
return rop_constraint_set_const(rc, MOV_OP_CONST, dst_reg, src_reg, const_value) &&
|
||||
rop_constraint_set_op(rc, op);
|
||||
return gadget_constraint_set_const(gadget_constraint, MOV_OP_CONST, dst_reg, src_reg, const_value) &&
|
||||
gadget_constraint_set_op(gadget_constraint, op);
|
||||
|
||||
compound:
|
||||
return parse_compound_op(core, str, rc);
|
||||
return parse_compound_op(core, str, gadget_constraint);
|
||||
}
|
||||
|
||||
static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstraint *rc) {
|
||||
static bool parse_reg_op_reg(const RzCore *core, const char *str, RzGadgetConstraint *gadget_constraint) {
|
||||
ut64 idx = 0;
|
||||
RzILOpPureCode op = RZ_IL_OP_PURE_MAX;
|
||||
const RzRegItem *src_reg0 = NULL;
|
||||
|
|
@ -391,63 +392,65 @@ static bool parse_reg_op_reg(const RzCore *core, const char *str, RzRopConstrain
|
|||
goto compound;
|
||||
}
|
||||
|
||||
return rop_constraint_set_regs(rc, MOV_OP_REG, dst_reg, src_reg0, src_reg1) &&
|
||||
rop_constraint_set_op(rc, op);
|
||||
return gadget_constraint_set_regs(gadget_constraint, MOV_OP_REG, dst_reg, src_reg0, src_reg1) &&
|
||||
gadget_constraint_set_op(gadget_constraint, op);
|
||||
|
||||
compound:
|
||||
return parse_compound_op(core, str, rc);
|
||||
return parse_compound_op(core, str, gadget_constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a new RzRopSearchContext object.
|
||||
* \brief Create a new RzGadgetSearchContext object.
|
||||
* \param core RZ_NONNULL Pointer to the RzCore structure containing configuration settings.
|
||||
* \param greparg RZ_NULLABLE Pointer to a string containing the grep argument.
|
||||
* \param regexp Flag specifying whether regular expressions should be used.
|
||||
* \param mask ROP request mask specifying the ROP request parameters.
|
||||
* \param detail_mask search ROP gadgets given details.
|
||||
* \param mask Gadget request mask specifying the Gadget request parameters.
|
||||
* \param detail_mask search gadgets given details.
|
||||
* \param state RZ_BORROW Pointer to the command state output structure.
|
||||
* \return RZ_OUT A pointer to the newly created RzRopSearchContext object, or NULL if memory allocation fails.
|
||||
* \return RZ_OUT A pointer to the newly created RzGadgetSearchContext object, or NULL if memory allocation fails.
|
||||
*
|
||||
* This function allocates and initializes a new RzRopSearchContext object.
|
||||
* This function allocates and initializes a new RzGadgetSearchContext object.
|
||||
*/
|
||||
RZ_API RZ_OWN RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, const bool regexp,
|
||||
const RzRopRequestMask mask, const RzRopDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state) {
|
||||
RZ_API RZ_OWN RzGadgetSearchContext *rz_core_gadget_search_context_new(RZ_NONNULL const RzCore *core, const RzGadgetType gadget_type, RZ_NULLABLE const char *greparg, const bool regexp,
|
||||
const RzGadgetRequestMask mask, const RzGadgetDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state) {
|
||||
|
||||
rz_return_val_if_fail(core, NULL);
|
||||
RzRopSearchContext *context = RZ_NEW0(RzRopSearchContext);
|
||||
RzGadgetSearchContext *context = RZ_NEW0(RzGadgetSearchContext);
|
||||
if (!context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->type = gadget_type;
|
||||
context->greparg = rz_str_dup(greparg);
|
||||
context->arch = rz_config_get(core->config, "asm.arch");
|
||||
context->regexp = regexp;
|
||||
context->mask = mask;
|
||||
context->detail_mask = detail_mask;
|
||||
context->state = state;
|
||||
context->max_instr = rz_config_get_i(core->config, "rop.len");
|
||||
context->max_instr = rz_config_get_i(core->config, "gadget.len");
|
||||
context->max_count = rz_config_get_i(core->config, "search.maxhits");
|
||||
context->increment = 1;
|
||||
context->from = 0;
|
||||
context->to = 0;
|
||||
context->end_list = NULL;
|
||||
context->unique_hitlists = NULL;
|
||||
context->crop = rz_config_get_i(core->config, "rop.conditional");
|
||||
context->subchain = rz_config_get_i(core->config, "rop.subchain");
|
||||
context->cache = rz_config_get_i(core->config, "rop.cache");
|
||||
context->allow_conditional = rz_config_get_b(core->config, "gadget.conditional");
|
||||
context->comments = rz_config_get_b(core->config, "gadget.comments");
|
||||
context->subchains = rz_config_get_b(core->config, "gadget.subchains");
|
||||
context->cache = rz_config_get_b(core->config, "gadget.cache");
|
||||
context->ret_val = false;
|
||||
context->buf = NULL;
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free an RzRopSearchContext object.
|
||||
* \param context RZ_NULLABLE Pointer to the RzRopSearchContext object to free.
|
||||
* \brief Free an RzGadgetSearchContext object.
|
||||
* \param context RZ_NULLABLE Pointer to the RzGadgetSearchContext object to free.
|
||||
*
|
||||
* Frees the memory allocated for an RzRopSearchContext object.
|
||||
* Frees the memory allocated for an RzGadgetSearchContext object.
|
||||
* Note: Other elements must be freed by the caller/callee.
|
||||
*/
|
||||
RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context) {
|
||||
RZ_API void rz_core_gadget_search_context_free(RZ_NULLABLE RzGadgetSearchContext *context) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -462,77 +465,77 @@ RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *cont
|
|||
* \brief Analyze and parse a constraint string.
|
||||
* \param core Pointer to the RzCore object.
|
||||
* \param str The constraint string to analyze.
|
||||
* \param rop_constraint Pointer to the RzRopConstraint object to store the parsed result.
|
||||
* \param gadget_constraint Pointer to the RzGadgetConstraint object to store the parsed result.
|
||||
* \return true if the constraint string is successfully parsed, false otherwise.
|
||||
*
|
||||
* This function analyzes a given constraint string and attempts to parse it into
|
||||
* the provided RzRopConstraint. It tries four different parsing methods:
|
||||
* the provided RzGadgetConstraint. It tries four different parsing methods:
|
||||
*
|
||||
* The function returns true if any of these parsing methods succeed.
|
||||
*/
|
||||
RZ_API bool rz_core_rop_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str,
|
||||
RZ_NULLABLE RZ_OUT RzRopConstraint *rop_constraint) {
|
||||
RZ_API bool rz_core_gadget_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str,
|
||||
RZ_NULLABLE RZ_OUT RzGadgetConstraint *gadget_constraint) {
|
||||
rz_return_val_if_fail(core && str, false);
|
||||
if (!rop_constraint) {
|
||||
if (!gadget_constraint) {
|
||||
return false;
|
||||
}
|
||||
return parse_reg_to_const(core, str, rop_constraint) ||
|
||||
parse_reg_to_reg(core, str, rop_constraint) ||
|
||||
parse_reg_op_const(core, str, rop_constraint) ||
|
||||
parse_reg_op_reg(core, str, rop_constraint);
|
||||
return parse_reg_to_const(core, str, gadget_constraint) ||
|
||||
parse_reg_to_reg(core, str, gadget_constraint) ||
|
||||
parse_reg_op_const(core, str, gadget_constraint) ||
|
||||
parse_reg_op_reg(core, str, gadget_constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Parse the given token into a rop constraint
|
||||
* \brief Parse the given token into a gadget constraint
|
||||
* \param core Pointer to the RzCore object.
|
||||
* \param token Input string in the form `key=value`(Eg: rbx=rdx, r12=1)`
|
||||
* \return \p RzRopConstraint if parsing is successful else NULL
|
||||
* \return \p RzGadgetConstraint if parsing is successful else NULL
|
||||
*
|
||||
|
||||
* The function parses the given token and parses according to the predefined ROP constriant type
|
||||
* The function parses the given token and parses according to the predefined gadget constraint type
|
||||
*/
|
||||
RZ_API RZ_OWN RzRopConstraint *rz_core_rop_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token) {
|
||||
RZ_API RZ_OWN RzGadgetConstraint *rz_core_gadget_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token) {
|
||||
rz_return_val_if_fail(core && token, NULL);
|
||||
|
||||
if (RZ_STR_ISEMPTY(token)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RzRopConstraint *rop_constraint = RZ_NEW0(RzRopConstraint);
|
||||
if (!rop_constraint) {
|
||||
free(rop_constraint);
|
||||
RzGadgetConstraint *gadget_constraint = RZ_NEW0(RzGadgetConstraint);
|
||||
if (!gadget_constraint) {
|
||||
free(gadget_constraint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RzList *l = rz_str_split_duplist(token, "=", true);
|
||||
if (rz_list_empty(l)) {
|
||||
rz_list_free(l);
|
||||
free(rop_constraint);
|
||||
free(gadget_constraint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!rz_core_rop_analyze_constraint(core, token, rop_constraint)) {
|
||||
free(rop_constraint);
|
||||
if (!rz_core_gadget_analyze_constraint(core, token, gadget_constraint)) {
|
||||
free(gadget_constraint);
|
||||
rz_list_free(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rz_list_free(l);
|
||||
return rop_constraint;
|
||||
return gadget_constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Parse rop constraint map
|
||||
* \brief Parse gadget constraint map
|
||||
* \param core Pointer to the RzCore object.
|
||||
* \param argc Number of arguments.
|
||||
* \param argv Array of arguments.
|
||||
* \return RzPVector of RzRopConstraint objects.
|
||||
* \return RzPVector of RzGadgetConstraint objects.
|
||||
*
|
||||
* This function parses a list of arguments into a RzPVector of RzRopConstraint objects.
|
||||
* This function parses a list of arguments into a RzPVector of RzGadgetConstraint objects.
|
||||
*/
|
||||
RZ_API RZ_OWN RzPVector /*<RzRopConstraint *>*/ *rz_core_rop_constraint_map_parse(const RZ_NONNULL RzCore *core, const int argc, const char **argv) {
|
||||
RZ_API RZ_OWN RzPVector /*<RzGadgetConstraint *>*/ *rz_core_gadget_constraint_map_parse(const RZ_NONNULL RzCore *core, const int argc, const char **argv) {
|
||||
rz_return_val_if_fail(core && argv && RZ_STR_ISNOTEMPTY(argv[0]), false);
|
||||
RzPVector *constr_map = rz_pvector_new((RzPVectorFree)rz_core_rop_constraint_free);
|
||||
RzPVector *constr_map = rz_pvector_new((RzPVectorFree)rz_core_gadget_constraint_free);
|
||||
if (!constr_map) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -548,11 +551,11 @@ RZ_API RZ_OWN RzPVector /*<RzRopConstraint *>*/ *rz_core_rop_constraint_map_pars
|
|||
RzListIter *it;
|
||||
char *token;
|
||||
rz_list_foreach (l, it, token) {
|
||||
RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, token);
|
||||
if (!rop_constraint) {
|
||||
RzGadgetConstraint *gadget_constraint = rz_core_gadget_constraint_parse_args(core, token);
|
||||
if (!gadget_constraint) {
|
||||
continue;
|
||||
}
|
||||
rz_pvector_push(constr_map, rop_constraint);
|
||||
rz_pvector_push(constr_map, gadget_constraint);
|
||||
}
|
||||
rz_list_free(l);
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ static const RzCmdDescDetail cmd_search_cryptographic_material_details[2];
|
|||
static const RzCmdDescDetail cmd_search_file_details[2];
|
||||
static const RzCmdDescDetail cmd_query_gadget_details[5];
|
||||
static const RzCmdDescDetail cmd_rop_search_stack_details[2];
|
||||
static const RzCmdDescDetail cmd_rop_search_size_details[2];
|
||||
static const RzCmdDescDetail cmd_gadget_search_size_details[2];
|
||||
static const RzCmdDescDetail cmd_search_value_details[3];
|
||||
static const RzCmdDescDetail cmd_search_hex_details[2];
|
||||
static const RzCmdDescDetail cmd_search_hex_regex_details[2];
|
||||
|
|
@ -163,7 +163,7 @@ static const RzCmdDescArg cmd_search_gadget_args[2];
|
|||
static const RzCmdDescArg cmd_query_gadget_args[2];
|
||||
static const RzCmdDescArg cmd_detail_gadget_args[2];
|
||||
static const RzCmdDescArg cmd_rop_search_stack_args[2];
|
||||
static const RzCmdDescArg cmd_rop_search_size_args[2];
|
||||
static const RzCmdDescArg cmd_gadget_search_size_args[2];
|
||||
static const RzCmdDescArg cmd_search_value_args[3];
|
||||
static const RzCmdDescArg cmd_search_value_alias_v1_args[2];
|
||||
static const RzCmdDescArg cmd_search_value_alias_v2_args[2];
|
||||
|
|
@ -2259,16 +2259,16 @@ static const RzCmdDescHelp cmd_rop_search_stack_help = {
|
|||
.args = cmd_rop_search_stack_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescDetailEntry cmd_rop_search_size_Usage_space_example_detail_entries[] = {
|
||||
static const RzCmdDescDetailEntry cmd_gadget_search_size_Usage_space_example_detail_entries[] = {
|
||||
{ .text = "Search ROP gadgets with the size less than 0x20", .arg_str = NULL, .comment = "/Rl \"<0x20\"" },
|
||||
{ .text = "Search ROP gadgets with the size 0x10", .arg_str = NULL, .comment = "/Rl =0x10" },
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescDetail cmd_rop_search_size_details[] = {
|
||||
{ .name = "Usage example", .entries = cmd_rop_search_size_Usage_space_example_detail_entries },
|
||||
static const RzCmdDescDetail cmd_gadget_search_size_details[] = {
|
||||
{ .name = "Usage example", .entries = cmd_gadget_search_size_Usage_space_example_detail_entries },
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescArg cmd_rop_search_size_args[] = {
|
||||
static const RzCmdDescArg cmd_gadget_search_size_args[] = {
|
||||
{
|
||||
.name = "Gadget size",
|
||||
.type = RZ_CMD_ARG_TYPE_STRING,
|
||||
|
|
@ -2278,10 +2278,10 @@ static const RzCmdDescArg cmd_rop_search_size_args[] = {
|
|||
},
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescHelp cmd_rop_search_size_help = {
|
||||
static const RzCmdDescHelp cmd_gadget_search_size_help = {
|
||||
.summary = "Search rop gadgets given gadget size",
|
||||
.details = cmd_rop_search_size_details,
|
||||
.args = cmd_rop_search_size_args,
|
||||
.details = cmd_gadget_search_size_details,
|
||||
.args = cmd_gadget_search_size_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescHelp slash_v_help = {
|
||||
|
|
@ -21856,8 +21856,8 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
|
|||
RzCmdDesc *cmd_rop_search_stack_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rs", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_rop_search_stack_handler, &cmd_rop_search_stack_help);
|
||||
rz_warn_if_fail(cmd_rop_search_stack_cd);
|
||||
|
||||
RzCmdDesc *cmd_rop_search_size_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rl", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_rop_search_size_handler, &cmd_rop_search_size_help);
|
||||
rz_warn_if_fail(cmd_rop_search_size_cd);
|
||||
RzCmdDesc *cmd_gadget_search_size_cd = rz_cmd_desc_argv_state_new(core->rcmd, slash_R_cd, "/Rl", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_gadget_search_size_handler, &cmd_gadget_search_size_help);
|
||||
rz_warn_if_fail(cmd_gadget_search_size_cd);
|
||||
|
||||
RzCmdDesc *slash_v_cd = rz_cmd_desc_group_state_new(core->rcmd, slash__cd, "/v", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_TABLE, rz_cmd_search_value_handler, &cmd_search_value_help, &slash_v_help);
|
||||
rz_warn_if_fail(slash_v_cd);
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ RZ_IPI RzCmdStatus rz_cmd_detail_gadget_handler(RzCore *core, int argc, const ch
|
|||
// "/Rs"
|
||||
RZ_IPI RzCmdStatus rz_cmd_rop_search_stack_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
|
||||
// "/Rl"
|
||||
RZ_IPI RzCmdStatus rz_cmd_rop_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
|
||||
RZ_IPI RzCmdStatus rz_cmd_gadget_search_size_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
|
||||
// "/v"
|
||||
RZ_IPI RzCmdStatus rz_cmd_search_value_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
|
||||
// "/v1"
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ commands:
|
|||
- text: "Search ROP gadgets with 0x100 stack changes"
|
||||
comment: "/Rs =0x100"
|
||||
- name: "/Rl"
|
||||
cname: cmd_rop_search_size
|
||||
cname: cmd_gadget_search_size
|
||||
summary: Search rop gadgets given gadget size
|
||||
type: RZ_CMD_DESC_TYPE_ARGV_STATE
|
||||
modes:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
13
librz/core/gadget_internal.h
Normal file
13
librz/core/gadget_internal.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#ifndef RZ_GADGET_INTERNAL_H
|
||||
#define RZ_GADGET_INTERNAL_H
|
||||
|
||||
#include <rz_analysis.h>
|
||||
|
||||
// ROP (Return-Oriented Programming)
|
||||
RZ_IPI bool rz_gadget_rop_is_end_gadget(const RzAnalysisOp *aop, const bool allow_conditional);
|
||||
RZ_IPI bool rz_gadget_rop_is_valid_terminator(const RzAnalysisOp *aop, const bool allow_conditional);
|
||||
|
||||
#endif
|
||||
52
librz/core/gadget_rop.c
Normal file
52
librz/core/gadget_rop.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "gadget_internal.h"
|
||||
|
||||
static bool is_cond_end_gadget(const RzAnalysisOp *aop) {
|
||||
switch (aop->type) {
|
||||
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_CCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_CRET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_gadget_rop_is_end_gadget(const RzAnalysisOp *aop, const bool allow_conditional) {
|
||||
switch (aop->type) {
|
||||
case RZ_ANALYSIS_OP_TYPE_TRAP:
|
||||
case RZ_ANALYSIS_OP_TYPE_RET:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_ICALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_IRCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_RJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_IJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_IRJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_JMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_CALL:
|
||||
if (allow_conditional) {
|
||||
return is_cond_end_gadget(aop);
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_gadget_rop_is_valid_terminator(const RzAnalysisOp *aop, const bool allow_conditional) {
|
||||
switch (aop->type) {
|
||||
case RZ_ANALYSIS_OP_TYPE_RET:
|
||||
if (allow_conditional) {
|
||||
return is_cond_end_gadget(aop);
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +63,8 @@ rz_core_sources = [
|
|||
'libs.c',
|
||||
'project.c',
|
||||
'project_migrate.c',
|
||||
'rop.c',
|
||||
'gadget.c',
|
||||
'gadget_rop.c',
|
||||
'rtr.c',
|
||||
#'rtr_http.c',
|
||||
#'rtr_shell.c',
|
||||
|
|
|
|||
|
|
@ -733,6 +733,27 @@ RZ_API bool rz_project_migrate_v20_v21(RzProject *prj, RzSerializeResultInfo *re
|
|||
return true;
|
||||
}
|
||||
|
||||
// --
|
||||
// Migration 21 -> 22
|
||||
//
|
||||
// Changes from <TODO:AT-LAST>:
|
||||
// Renamed ROP search configs to gadget search for generalization:
|
||||
// - `rop.X` to `gadget.X`
|
||||
|
||||
RZ_API bool rz_project_migrate_v21_v22(RzProject *prj, RzSerializeResultInfo *res) {
|
||||
Sdb *core_db;
|
||||
RZ_SERIALIZE_SUB(prj, core_db, res, "core", return false;);
|
||||
Sdb *config_db;
|
||||
RZ_SERIALIZE_SUB(core_db, config_db, res, "config", return false;);
|
||||
sdb_rename(config_db, "rop.len", "gadget.len");
|
||||
sdb_rename(config_db, "rop.cache", "gadget.cache");
|
||||
sdb_rename(config_db, "rop.subchains", "gadget.subchains");
|
||||
sdb_rename(config_db, "rop.conditional", "gadget.conditional");
|
||||
sdb_rename(config_db, "rop.comments", "gadget.comments");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) = {
|
||||
rz_project_migrate_v1_v2,
|
||||
rz_project_migrate_v2_v3,
|
||||
|
|
@ -754,6 +775,7 @@ static bool (*const migrations[])(RzProject *prj, RzSerializeResultInfo *res) =
|
|||
rz_project_migrate_v18_v19,
|
||||
rz_project_migrate_v19_v20,
|
||||
rz_project_migrate_v20_v21,
|
||||
rz_project_migrate_v21_v22,
|
||||
};
|
||||
|
||||
/// Migrate the given project to the current version in-place
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ include_files = [
|
|||
'rz_platform.h',
|
||||
'rz_project.h',
|
||||
'rz_reg.h',
|
||||
'rz_rop.h',
|
||||
'rz_gadget.h',
|
||||
'rz_search.h',
|
||||
'rz_sign.h',
|
||||
'rz_skiplist.h',
|
||||
|
|
|
|||
|
|
@ -1370,8 +1370,8 @@ RZ_API RZ_BORROW HtUP *rz_analysis_get_xrefs_from(RZ_NONNULL RzAnalysis *analysi
|
|||
RZ_API void rz_analysis_set_xrefs_from(RZ_NONNULL RzAnalysis *analysis, HtUP *xrefs_from);
|
||||
RZ_API RZ_BORROW HtUP *rz_analysis_get_xrefs_to(RZ_NONNULL RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_set_xrefs_to(RZ_NONNULL RzAnalysis *analysis, HtUP *xrefs_to);
|
||||
RZ_API RZ_BORROW HtUP *rz_analysis_get_rop_semantics(RZ_NONNULL RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_set_rop_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics);
|
||||
RZ_API RZ_BORROW HtUP *rz_analysis_get_gadget_semantics(RZ_NONNULL RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_set_gadget_semantics(RZ_NONNULL RzAnalysis *analysis, HtUP *rop_semantics);
|
||||
RZ_API RZ_BORROW RzAnalysisCallbacks *rz_analysis_get_callbacks(RZ_NONNULL RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_set_os(RZ_NONNULL RzAnalysis *analysis, RZ_NULLABLE const char *os);
|
||||
RZ_API const char *rz_analysis_get_os(RZ_NONNULL RzAnalysis *analysis);
|
||||
|
|
|
|||
222
librz/include/rz_gadget.h
Normal file
222
librz/include/rz_gadget.h
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#ifndef RZ_GADGET_H
|
||||
#define RZ_GADGET_H
|
||||
|
||||
/**
|
||||
* \file rz_gadget.h
|
||||
* \brief Gadget (ROP, JOP, COP) related APIs and structures.
|
||||
*
|
||||
* This file contains definitions, structures, and function prototypes for handling ROP, JOP and COP gadgets and constraints.
|
||||
*/
|
||||
|
||||
#include <rz_cmd.h>
|
||||
#include <rz_il.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Information about a register.
|
||||
*/
|
||||
typedef struct rz_gadget_reg_info_t {
|
||||
char *name;
|
||||
bool is_mem_read; ///< Register involved in Memory read.
|
||||
bool is_pc_write; ///< PC write flag.
|
||||
bool is_var_read; ///< Register involved in Variable read.
|
||||
bool is_var_write; ///< Register involved in Variable write.
|
||||
bool is_mem_write; ///< Register involved in Memory write.
|
||||
ut64 init_val;
|
||||
ut64 new_val;
|
||||
ut64 bits; ///< Register bits for capturing cast
|
||||
RzILOpPure *value_transformations; ///< TODO: Captures Value transformations.
|
||||
} RzGadgetRegInfo;
|
||||
|
||||
/**
|
||||
* \brief Information about a gadget.
|
||||
*/
|
||||
typedef struct rz_gadget_info_t {
|
||||
ut64 address; ///< Gadget address.
|
||||
ut64 stack_change; ///< Stack change.
|
||||
ut64 curr_pc_val; ///< Current PC value.
|
||||
ut32 size; ///< Gadget size.
|
||||
bool is_pc_write; ///< PC write flag.
|
||||
bool is_syscall; ///< Syscall flag.
|
||||
RzIterator /*RzAnalysisBytes *>*/ *analysis_cache; ///< Stores \p RzAnalysisBytes for the gadget.
|
||||
RzPVector /*<RzGadgetRegInfo *>*/ *modified_registers; ///< Modified registers.
|
||||
RzList /*<RzGadgetRegInfo *>*/ *dependencies; ///< Dependencies.
|
||||
} RzGadgetInfo;
|
||||
|
||||
/**
|
||||
* \brief Type of gadget to search for.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_GADGET_TYPE_ROP, ///< Return-Oriented Programming.
|
||||
RZ_GADGET_TYPE_JOP, ///< Jump-Oriented Programming.
|
||||
RZ_GADGET_TYPE_COP, ///< Call-Oriented Programming.
|
||||
} RzGadgetType;
|
||||
|
||||
/**
|
||||
* \brief Types of IL instructions for Gadget constraints.
|
||||
*/
|
||||
typedef enum rz_gadget_il_instr_type {
|
||||
MOV_CONST, ///< reg <- const
|
||||
MOV_REG, ///< reg <- reg
|
||||
MOV_OP_CONST, ///< reg <- reg OP const
|
||||
MOV_OP_REG, ///< reg <- reg OP reg
|
||||
SYSCALL, ///< syscall
|
||||
} RzGadgetILInstructionType;
|
||||
|
||||
/**
|
||||
* \brief Argument types for Gadget constraints.
|
||||
*/
|
||||
typedef enum {
|
||||
SRC_REG,
|
||||
DST_REG,
|
||||
SRC_CONST,
|
||||
SRC_REG_SECOND,
|
||||
OP,
|
||||
NUM_ARGS
|
||||
} RzGadgetArgType;
|
||||
|
||||
/**
|
||||
* \brief Gadget request mask for filtering gadgets.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_GADGET_PRINT = 1 << 0, ///< Print Gadget.
|
||||
RZ_GADGET_PRINT_DETAIL = 1 << 1, ///< Detailed Gadget.
|
||||
RZ_GADGET_ANALYZE = 1 << 2, ///< Detailed Gadget.
|
||||
RZ_GADGET_ALL = RZ_GADGET_PRINT | RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE ///< All Gadget requests.
|
||||
} RzGadgetRequestMask;
|
||||
|
||||
/**
|
||||
* \brief Gadget search mask for filtering gadgets given details.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_GADGET_DETAIL_SEARCH_NON = 0,
|
||||
RZ_GADGET_DETAIL_SEARCH_STACK = 1 << 0, ///< Search gadgets by stack changes.
|
||||
RZ_GADGET_DETAIL_SEARCH_SIZE = 1 << 1, ///< Search gadgets by gadget sizes.
|
||||
// RZ_GADGET_DETAIL_SEARCH_WRITE = 1 << 2, ///< Search gadgets by written registers.
|
||||
// RZ_GADGET_DETAIL_SEARCH_READ = 1 << 3, ///< Search gadgets by read registers.
|
||||
} RzGadgetDetailSearchMask;
|
||||
|
||||
/**
|
||||
* \brief Filter conditions while searching gadgets by stack changes.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_GADGET_DETAIL_CMP_EQ = 1, ///< ==
|
||||
RZ_GADGET_DETAIL_CMP_GT = 1 << 1, ///< >
|
||||
RZ_GADGET_DETAIL_CMP_GE = RZ_GADGET_DETAIL_CMP_GT | RZ_GADGET_DETAIL_CMP_EQ, ///< >=
|
||||
RZ_GADGET_DETAIL_CMP_LT = 1 << 2, ///< <
|
||||
RZ_GADGET_DETAIL_CMP_LE = RZ_GADGET_DETAIL_CMP_LT | RZ_GADGET_DETAIL_CMP_EQ, ///< <=
|
||||
} RzGadgetDetailSearchCmpOp;
|
||||
|
||||
/**
|
||||
* \brief Pair representing an end gadget with instruction offset and delay size.
|
||||
*/
|
||||
typedef struct rz_gadget_endlist_pair_t {
|
||||
int instr_offset; ///< Instruction offset.
|
||||
int delay_size; ///< Delay size.
|
||||
} RzGadgetEndListPair;
|
||||
|
||||
/**
|
||||
* \brief Structure representing a Gadget constraint.
|
||||
*/
|
||||
typedef struct rz_gadget_constraint_t {
|
||||
RzGadgetILInstructionType type; ///< IL instruction type.
|
||||
char *args[NUM_ARGS]; ///< Arguments.
|
||||
} RzGadgetConstraint;
|
||||
|
||||
/**
|
||||
* \brief Structure representing a Gadget search context.
|
||||
*/
|
||||
typedef struct rz_gadget_search_context_t {
|
||||
RzGadgetType type; ///< Type of gadget to search for.
|
||||
ut8 max_instr; ///< Gadget search max length.
|
||||
bool subchains; ///< Display every length gadget from gadget.len=X to 2.
|
||||
bool allow_conditional; ///< Include conditional jump, calls and returns in gadget search.
|
||||
bool comments; ///< Display comments in gadget search output.
|
||||
char *greparg; ///< Grep argument string.
|
||||
const char *arch; ///< Architecture of the binary.
|
||||
bool regexp; ///< Regular expression argument flag.
|
||||
bool cache; ///< Cache the search results.
|
||||
RzGadgetRequestMask mask; ///< Mask for kind of gadget request operation.
|
||||
RzGadgetDetailSearchMask detail_mask; ///< Mask for searching gadgets given details.
|
||||
RzCmdStateOutput *state; ///< Command state output.
|
||||
int increment; ///< Gadget search increment value.
|
||||
ut64 max_count; ///< Maximum number of hits (0: no limit).
|
||||
ut64 from; ///< Start address to start gadget search.
|
||||
ut64 to; ///< End address to stop gadget search.
|
||||
RzList /*<RzGadgetEndListPair *>*/ *end_list; ///< List of end gadgets.
|
||||
HtSU *unique_hitlists; ///< Cache unique gadget hitlists.
|
||||
bool ret_val; ///< Flag to indicate return the search results.
|
||||
RzStrBuf *buf; ///< String buffer for storing search results.
|
||||
RzPVector /*<RzGadgetConstraint *>*/ *constraints; ///< User constraints for filtering.
|
||||
} RzGadgetSearchContext;
|
||||
|
||||
/**
|
||||
* \brief Enum for different Gadget register events.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_GADGET_EVENT_VAR_READ,
|
||||
RZ_GADGET_EVENT_VAR_WRITE,
|
||||
RZ_GADGET_EVENT_MEM_READ,
|
||||
RZ_GADGET_EVENT_MEM_WRITE,
|
||||
RZ_GADGET_EVENT_PC_WRITE,
|
||||
RZ_GADGET_EVENT_COUNT ///< This should always be the last element.
|
||||
} RzGadgetEvent;
|
||||
|
||||
/**
|
||||
* \brief Function pointer type for event check functions.
|
||||
*/
|
||||
typedef bool (*rz_gadget_event_check_fn)(const RzGadgetRegInfo *);
|
||||
|
||||
/**
|
||||
* \brief Array of event check functions.
|
||||
*/
|
||||
extern rz_gadget_event_check_fn rz_gadget_event_functions[RZ_GADGET_EVENT_COUNT];
|
||||
|
||||
// Command APIs
|
||||
RZ_API RzCmdStatus rz_core_gadget_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context);
|
||||
RZ_API RzCmdStatus rz_core_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzGadgetSearchContext *context);
|
||||
RZ_API bool rz_core_gadget_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str,
|
||||
RZ_NULLABLE RZ_OUT RzGadgetConstraint *gadget_constraint);
|
||||
RZ_API RZ_OWN RzPVector /*<RzGadgetConstraint *>*/ *rz_core_gadget_constraint_map_parse(const RZ_NONNULL RzCore *core, int argc, const char **argv);
|
||||
RZ_API bool rz_core_handle_gadget_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzGadgetSearchContext *context, RZ_NONNULL RzPVector /*<RzCoreAsmHit *>*/ *hitlist);
|
||||
RZ_API RZ_NULLABLE RZ_OWN RzList /*<char *>*/ *rz_core_gadget_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp);
|
||||
|
||||
// Gadget Search Context APIs
|
||||
RZ_API RZ_OWN RzGadgetSearchContext *rz_core_gadget_search_context_new(RZ_NONNULL const RzCore *core, const RzGadgetType gadget_type, RZ_NULLABLE const char *greparg, bool regexp,
|
||||
RzGadgetRequestMask mask, RzGadgetDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state);
|
||||
RZ_API void rz_core_gadget_search_context_free(RZ_NULLABLE RzGadgetSearchContext *context);
|
||||
|
||||
// Gadget Constraint APIs
|
||||
RZ_API void rz_core_gadget_constraint_free(RZ_NULLABLE void *data);
|
||||
RZ_API RZ_OWN RzGadgetConstraint *rz_core_gadget_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token);
|
||||
|
||||
// Gadget Info APIs
|
||||
RZ_API void rz_core_gadget_info_free(RZ_NULLABLE RzGadgetInfo *gadget_info);
|
||||
RZ_API void rz_core_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzGadgetInfo *gadget_info,
|
||||
RZ_NONNULL RzGadgetRegInfo *reg_info, bool is_dependency);
|
||||
RZ_API void rz_core_gadget_info_update_register(const RZ_INOUT RzGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzGadgetRegInfo *new_reg_info);
|
||||
RZ_API RZ_OWN RzGadgetInfo *rz_core_gadget_info_new(ut64 address);
|
||||
RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_dup(RZ_BORROW RZ_NONNULL RzGadgetRegInfo *src);
|
||||
RZ_API void rz_core_gadget_reg_info_free(RZ_NULLABLE RzGadgetRegInfo *reg_info);
|
||||
RZ_API RZ_OWN RzGadgetRegInfo *rz_core_gadget_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt,
|
||||
ut64 init_val, ut64 new_val);
|
||||
RZ_API RZ_BORROW RzGadgetRegInfo *rz_core_gadget_info_get_modified_register(const RZ_NONNULL RzGadgetInfo *gadget_info,
|
||||
const RZ_NONNULL char *name);
|
||||
RZ_API bool rz_core_gadget_info_has_register(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name);
|
||||
RZ_API RZ_OWN RzPVector /*<RzGadgetRegInfo *>*/ *rz_core_gadget_get_reg_info_by_event(const RZ_NONNULL RzGadgetInfo *gadget_info, RzGadgetEvent event);
|
||||
RZ_API RZ_OWN RzPVector /*<RzGadgetRegInfo *>*/ *rz_core_gadget_get_reg_info_by_reg_names(const RZ_NONNULL RzGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /*<char *>*/ *registers);
|
||||
RZ_API bool rz_core_gadget_reg_info_has_event(const RZ_NONNULL RzGadgetInfo *gadget_info,
|
||||
RzGadgetEvent event, const RZ_NULLABLE char *reg_name);
|
||||
RZ_API RZ_OWN RzPVector /*<RzGadgetRegInfo *>*/ *rz_core_gadget_reg_info_find(const RZ_NONNULL RzGadgetInfo *gadget_info, const RZ_NONNULL char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // RZ_GADGET_H
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RZ_PROJECT_VERSION 21
|
||||
#define RZ_PROJECT_VERSION 22
|
||||
|
||||
typedef Sdb RzProject;
|
||||
|
||||
|
|
@ -66,6 +66,7 @@ RZ_API bool rz_project_migrate_v17_v18(RzProject *prj, RzSerializeResultInfo *re
|
|||
RZ_API bool rz_project_migrate_v18_v19(RzProject *prj, RzSerializeResultInfo *res);
|
||||
RZ_API bool rz_project_migrate_v19_v20(RzProject *prj, RzSerializeResultInfo *res);
|
||||
RZ_API bool rz_project_migrate_v20_v21(RzProject *prj, RzSerializeResultInfo *res);
|
||||
RZ_API bool rz_project_migrate_v21_v22(RzProject *prj, RzSerializeResultInfo *res);
|
||||
RZ_API bool rz_project_migrate(RzProject *prj, unsigned long version, RzSerializeResultInfo *res);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -1,210 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#ifndef RZ_ROP_H
|
||||
#define RZ_ROP_H
|
||||
|
||||
/**
|
||||
* \file rz_rop.h
|
||||
* \brief Return-Oriented Programming (ROP) related APIs and structures..
|
||||
*
|
||||
* This file contains definitions, structures, and function prototypes for handling ROP gadgets and constraints.
|
||||
*/
|
||||
|
||||
#include <rz_cmd.h>
|
||||
#include <rz_il.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Information about a register.
|
||||
*/
|
||||
typedef struct rz_rop_reg_info_t {
|
||||
char *name;
|
||||
bool is_mem_read; ///< Register involved in Memory read.
|
||||
bool is_pc_write; ///< PC write flag.
|
||||
bool is_var_read; ///< Register involved in Variable read.
|
||||
bool is_var_write; ///< Register involved in Variable write.
|
||||
bool is_mem_write; ///< Register involved in Memory write.
|
||||
ut64 init_val;
|
||||
ut64 new_val;
|
||||
ut64 bits; ///< Register bits for capturing cast
|
||||
RzILOpPure *value_transformations; ///< TODO: Captures Value transformations.
|
||||
} RzRopRegInfo;
|
||||
|
||||
/**
|
||||
* \brief Information about a ROP gadget.
|
||||
*/
|
||||
typedef struct rz_rop_gadget_info_t {
|
||||
ut64 address; ///< Gadget address.
|
||||
ut64 stack_change; ///< Stack change.
|
||||
ut64 curr_pc_val; ///< Current PC value.
|
||||
ut32 size; ///< Gadget size.
|
||||
bool is_pc_write; ///< PC write flag.
|
||||
bool is_syscall; ///< Syscall flag.
|
||||
RzIterator /*RzAnalysisBytes *>*/ *analysis_cache; ///< Stores \p RzAnalysisBytes for the gadget.
|
||||
RzPVector /*<RzRopRegInfo *>*/ *modified_registers; ///< Modified registers.
|
||||
RzList /*<RzRopRegInfo *>*/ *dependencies; ///< Dependencies.
|
||||
} RzRopGadgetInfo;
|
||||
|
||||
/**
|
||||
* \brief Types of IL instructions for ROP constraints.
|
||||
*/
|
||||
typedef enum rz_rop_il_instr_type {
|
||||
MOV_CONST, ///< reg <- const
|
||||
MOV_REG, ///< reg <- reg
|
||||
MOV_OP_CONST, ///< reg <- reg OP const
|
||||
MOV_OP_REG, ///< reg <- reg OP reg
|
||||
SYSCALL, ///< syscall
|
||||
} RzRopILInstructionType;
|
||||
|
||||
/**
|
||||
* \brief Argument types for ROP constraints.
|
||||
*/
|
||||
typedef enum {
|
||||
SRC_REG,
|
||||
DST_REG,
|
||||
SRC_CONST,
|
||||
SRC_REG_SECOND,
|
||||
OP,
|
||||
NUM_ARGS
|
||||
} RzRopArgType;
|
||||
|
||||
/**
|
||||
* \brief ROP request mask for filtering gadgets.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_ROP_GADGET_PRINT = 1 << 0, ///< Print ROP gadgets.
|
||||
RZ_ROP_GADGET_PRINT_DETAIL = 1 << 1, ///< Detailed ROP gadgets.
|
||||
RZ_ROP_GADGET_ANALYZE = 1 << 2, ///< Detailed ROP gadgets.
|
||||
RZ_ROP_GADGET_ALL = RZ_ROP_GADGET_PRINT | RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE ///< All ROP gadgets requests.
|
||||
} RzRopRequestMask;
|
||||
|
||||
/**
|
||||
* \brief ROP search mask for filtering gadgets given details.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_ROP_DETAIL_SEARCH_NON = 0,
|
||||
RZ_ROP_DETAIL_SEARCH_STACK = 1 << 0, ///< Search ROP gadgets by stack changes.
|
||||
RZ_ROP_DETAIL_SEARCH_SIZE = 1 << 1, ///< Search ROP gadgets by gadget sizes.
|
||||
// RZ_ROP_DETAIL_SEARCH_WRITE = 1 << 2, ///< Search ROP gadgets by written registers.
|
||||
// RZ_ROP_DETAIL_SEARCH_READ = 1 << 3, ///< Search ROP gadgets by read registers.
|
||||
} RzRopDetailSearchMask;
|
||||
|
||||
/**
|
||||
* \brief Filter conditions while searching ROP gadgets by stack changes.
|
||||
*/
|
||||
typedef enum {
|
||||
ROP_DETAIL_CMP_EQ = 1, // ==
|
||||
ROP_DETAIL_CMP_GT = 1 << 1, // >
|
||||
ROP_DETAIL_CMP_GE = ROP_DETAIL_CMP_GT | ROP_DETAIL_CMP_EQ, // >=
|
||||
ROP_DETAIL_CMP_LT = 1 << 2, // <
|
||||
ROP_DETAIL_CMP_LE = ROP_DETAIL_CMP_LT | ROP_DETAIL_CMP_EQ, // <=
|
||||
} RopDetailSearchCmpOp;
|
||||
|
||||
/**
|
||||
* \brief Pair representing an end gadget with instruction offset and delay size.
|
||||
*/
|
||||
typedef struct rz_rop_endlist_pair_t {
|
||||
int instr_offset; ///< Instruction offset.
|
||||
int delay_size; ///< Delay size.
|
||||
} RzRopEndListPair;
|
||||
|
||||
/**
|
||||
* \brief Structure representing a ROP constraint.
|
||||
*/
|
||||
typedef struct rz_rop_constraint_t {
|
||||
RzRopILInstructionType type; ///< IL instruction type.
|
||||
char *args[NUM_ARGS]; ///< Arguments.
|
||||
} RzRopConstraint;
|
||||
|
||||
/**
|
||||
* \brief Structure representing a ROP search context.
|
||||
*/
|
||||
typedef struct rz_rop_search_context_t {
|
||||
ut8 max_instr; ///< Rop search max length.
|
||||
ut8 subchain; ///< Display every length gadget from rop.len=X to 2 in /Rl.
|
||||
ut8 crop; ///< Include conditional jump, calls and returns in ropsearch.
|
||||
char *greparg; ///< Grep argument string.
|
||||
const char *arch; ///< Architecture of the binary.
|
||||
bool regexp; ///< Regular expression argument flag.
|
||||
bool cache; ///< Cache the search results.
|
||||
RzRopRequestMask mask; ///< Mask for kind of rop request operation.
|
||||
RzRopDetailSearchMask detail_mask; ///< Mask for searching gadgets given details.
|
||||
RzCmdStateOutput *state; ///< Command state output.
|
||||
int increment; ///< ROP search increment value.
|
||||
ut64 max_count; ///< Maximum number of hits (0: no limit).
|
||||
ut64 from; ///< Start address to start rop search.
|
||||
ut64 to; ///< End address to stop rop search.
|
||||
RzList /*<RzRopEndListPair *>*/ *end_list; ///< List of end gadgets.
|
||||
HtSU *unique_hitlists; ///< Cache unique ROP hitlists.
|
||||
bool ret_val; ///< Flag to indicate return the search results.
|
||||
RzStrBuf *buf; ///< String buffer for storing search results.
|
||||
RzPVector /*<RzRopConstraint *>*/ *constraints; ///< User constraints for filtering.
|
||||
} RzRopSearchContext;
|
||||
|
||||
/**
|
||||
* \brief Enum for different ROP register events.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_ROP_EVENT_VAR_READ,
|
||||
RZ_ROP_EVENT_VAR_WRITE,
|
||||
RZ_ROP_EVENT_MEM_READ,
|
||||
RZ_ROP_EVENT_MEM_WRITE,
|
||||
RZ_ROP_EVENT_PC_WRITE,
|
||||
RZ_ROP_EVENT_COUNT // This should always be the last element
|
||||
} RzRopEvent;
|
||||
|
||||
/**
|
||||
* \brief Function pointer type for event check functions.
|
||||
*/
|
||||
typedef bool (*rz_rop_event_check_fn)(const RzRopRegInfo *);
|
||||
|
||||
/**
|
||||
* \brief Array of event check functions.
|
||||
*/
|
||||
extern rz_rop_event_check_fn rz_rop_event_functions[RZ_ROP_EVENT_COUNT];
|
||||
|
||||
// Command APIs
|
||||
RZ_API RzCmdStatus rz_core_rop_search(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context);
|
||||
RZ_API RzCmdStatus rz_core_rop_gadget_info(RZ_NONNULL RzCore *core, RZ_NONNULL RZ_OWN RzRopSearchContext *context);
|
||||
RZ_API bool rz_core_rop_analyze_constraint(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *str,
|
||||
RZ_NULLABLE RZ_OUT RzRopConstraint *rop_constraint);
|
||||
RZ_API RZ_OWN RzPVector /*<RzRopConstraint *>*/ *rz_core_rop_constraint_map_parse(const RZ_NONNULL RzCore *core, int argc, const char **argv);
|
||||
RZ_API bool rz_core_handle_rop_request_type(RZ_NONNULL RzCore *core, RZ_NONNULL RzRopSearchContext *context, RZ_NONNULL RzList /*<RzCoreAsmHit *>*/ *hitlist);
|
||||
RZ_API RZ_NULLABLE RZ_OWN RzList /*<char *>*/ *rz_core_rop_handle_grep_args(RZ_NULLABLE const char *greparg, const bool regexp);
|
||||
|
||||
// ROP Search Context APIs
|
||||
RZ_API RZ_OWN RzRopSearchContext *rz_core_rop_search_context_new(RZ_NONNULL const RzCore *core, RZ_NULLABLE const char *greparg, bool regexp,
|
||||
RzRopRequestMask mask, RzRopDetailSearchMask detail_mask, RZ_NULLABLE RZ_BORROW RzCmdStateOutput *state);
|
||||
RZ_API void rz_core_rop_search_context_free(RZ_NULLABLE RzRopSearchContext *context);
|
||||
|
||||
// ROP Constraint APIs
|
||||
RZ_API void rz_core_rop_constraint_free(RZ_NULLABLE void *data);
|
||||
RZ_API RZ_OWN RzRopConstraint *rz_core_rop_constraint_parse_args(const RZ_NONNULL RzCore *core, const RZ_NONNULL char *token);
|
||||
|
||||
// ROP Gadget Info APIs
|
||||
RZ_API void rz_core_rop_gadget_info_free(RZ_NULLABLE RzRopGadgetInfo *gadget_info);
|
||||
RZ_API void rz_core_rop_gadget_info_add_register(const RZ_NONNULL RZ_OUT RzRopGadgetInfo *gadget_info,
|
||||
RZ_NONNULL RzRopRegInfo *reg_info, bool is_dependency);
|
||||
RZ_API void rz_core_rop_gadget_info_update_register(const RZ_INOUT RzRopGadgetInfo *gadget_info, RZ_INOUT RZ_NONNULL RzRopRegInfo *new_reg_info);
|
||||
RZ_API RZ_OWN RzRopGadgetInfo *rz_core_rop_gadget_info_new(ut64 address);
|
||||
RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_dup(RZ_BORROW RZ_NONNULL RzRopRegInfo *src);
|
||||
RZ_API void rz_core_rop_reg_info_free(RZ_NULLABLE RzRopRegInfo *reg_info);
|
||||
RZ_API RZ_OWN RzRopRegInfo *rz_core_rop_reg_info_new(RZ_NONNULL const RzCore *core, RZ_NONNULL const RzILEvent *evt,
|
||||
ut64 init_val, ut64 new_val);
|
||||
RZ_API RZ_BORROW RzRopRegInfo *rz_core_rop_gadget_info_get_modified_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info,
|
||||
const RZ_NONNULL char *name);
|
||||
RZ_API bool rz_core_rop_gadget_info_has_register(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name);
|
||||
RZ_API RZ_OWN RzPVector /*<RzRopRegInfo *>*/ *rz_core_rop_gadget_get_reg_info_by_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RzRopEvent event);
|
||||
RZ_API RZ_OWN RzPVector /*<RzRopRegInfo *>*/ *rz_core_rop_get_reg_info_by_reg_names(const RZ_NONNULL RzRopGadgetInfo *gadget_info, RZ_NONNULL const RzPVector /*<char *>*/ *registers);
|
||||
RZ_API bool rz_core_rop_gadget_reg_info_has_event(const RZ_NONNULL RzRopGadgetInfo *gadget_info,
|
||||
RzRopEvent event, const RZ_NULLABLE char *reg_name);
|
||||
RZ_API RZ_OWN RzPVector /*<RzRopRegInfo *>*/ *rz_core_rop_reg_info_find(const RZ_NONNULL RzRopGadgetInfo *gadget_info, const RZ_NONNULL char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // RZ_ROP_H
|
||||
|
|
@ -318,7 +318,7 @@ NAME=search rop gadgets with another end gadget as part of it.
|
|||
FILE=bins/elf/analysis/unoriginal
|
||||
CMDS=<<EOF
|
||||
e asm.bits=32
|
||||
e rop.len=15
|
||||
e gadget.len=15
|
||||
e search.from=0x08048340
|
||||
e search.to=0x08048400
|
||||
/R push esp
|
||||
|
|
@ -3526,3 +3526,90 @@ Gadget 0x8048692 (size 4 bytes)
|
|||
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=subchains test
|
||||
FILE==
|
||||
CMDS=<<EOF
|
||||
e asm.arch=x86
|
||||
e asm.bits=64
|
||||
wa "pop r12; pop r13; pop r14; pop r15; ret"
|
||||
e gadget.subchains=false
|
||||
/Rq
|
||||
echo "===================================================="
|
||||
e gadget.subchains=true
|
||||
/Rq
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00000000: pop r12; pop r13; pop r14; pop r15; ret;
|
||||
0x00000001: pop rsp; pop r13; pop r14; pop r15; ret;
|
||||
0x00000002: pop r13; pop r14; pop r15; ret;
|
||||
0x00000003: pop rbp; pop r14; pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000005: pop rsi; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000007: pop rdi; ret;
|
||||
0x00000008: ret;
|
||||
====================================================
|
||||
0x00000000: pop r12; pop r13; pop r14; pop r15; ret;
|
||||
0x00000002: pop r13; pop r14; pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000001: pop rsp; pop r13; pop r14; pop r15; ret;
|
||||
0x00000002: pop r13; pop r14; pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000002: pop r13; pop r14; pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000003: pop rbp; pop r14; pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000004: pop r14; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000005: pop rsi; pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000006: pop r15; ret;
|
||||
0x00000007: pop rdi; ret;
|
||||
0x00000008: ret;
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=search rop gadgets with comments
|
||||
FILE==
|
||||
CMDS=<<EOF
|
||||
e asm.arch=x86
|
||||
e asm.bits=64
|
||||
wa "pop r12; ret"
|
||||
CC Rizin is Cool! @ 0
|
||||
CC Its elegant! @ 2
|
||||
/R
|
||||
echo "========================================================="
|
||||
e gadget.comments=true
|
||||
/R
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00000000 415c pop r12
|
||||
0x00000002 c3 ret
|
||||
Gadget size: 3
|
||||
|
||||
0x00000001 5c pop rsp
|
||||
0x00000002 c3 ret
|
||||
Gadget size: 2
|
||||
|
||||
0x00000002 c3 ret
|
||||
Gadget size: 1
|
||||
|
||||
=========================================================
|
||||
0x00000000 415c pop r12 ; Rizin is Cool!
|
||||
0x00000002 c3 ret ; Its elegant!
|
||||
Gadget size: 3
|
||||
|
||||
0x00000001 5c pop rsp
|
||||
0x00000002 c3 ret ; Its elegant!
|
||||
Gadget size: 2
|
||||
|
||||
0x00000002 c3 ret ; Its elegant!
|
||||
Gadget size: 1
|
||||
|
||||
EOF
|
||||
RUN
|
||||
|
|
@ -400,7 +400,7 @@ CMDS=<<EOF
|
|||
e asm.bits=32
|
||||
e asm.arch=mips
|
||||
e scr.color=false
|
||||
e rop.len=8
|
||||
e gadget.len=8
|
||||
wx 1b000000040000001a0000004c08410018000000040000000800000000000070
|
||||
/R
|
||||
q
|
||||
|
|
|
|||
|
|
@ -379,6 +379,7 @@ Detailed project load info:
|
|||
project migrated from version 18 to 19.
|
||||
project migrated from version 19 to 20.
|
||||
project migrated from version 20 to 21.
|
||||
project migrated from version 21 to 22.
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -655,6 +655,42 @@ static bool test_migrate_v17_v18_rop_config() {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_migrate_v21_v22_gadget_config() {
|
||||
RzProject *prj = rz_project_load_file_raw("prj/v20-debase64.rzdb");
|
||||
mu_assert_notnull(prj, "load raw project");
|
||||
RzSerializeResultInfo *res = rz_serialize_result_info_new();
|
||||
|
||||
// get to v21 state
|
||||
bool s_20_21 = rz_project_migrate_v20_v21(prj, res);
|
||||
mu_assert_true(s_20_21, "v20->v21 migrate success");
|
||||
|
||||
// actual test
|
||||
bool s_21_22 = rz_project_migrate_v21_v22(prj, res);
|
||||
mu_assert_true(s_21_22, "v21->v22 migrate success");
|
||||
|
||||
Sdb *core_db = sdb_ns(prj, "core", false);
|
||||
Sdb *config_db = sdb_ns(core_db, "config", false);
|
||||
|
||||
mu_assert_null(sdb_get(config_db, "rop.len"), "old rop.len deleted");
|
||||
mu_assert_streq_free(sdb_get(config_db, "gadget.len"), "5", "new gadget.len added");
|
||||
|
||||
mu_assert_null(sdb_get(config_db, "rop.cache"), "old rop.cache deleted");
|
||||
mu_assert_streq_free(sdb_get(config_db, "gadget.cache"), "false", "new gadget.cache added");
|
||||
|
||||
mu_assert_null(sdb_get(config_db, "rop.subchains"), "old rop.subchains deleted");
|
||||
mu_assert_streq_free(sdb_get(config_db, "gadget.subchains"), "false", "new gadget.subchains added");
|
||||
|
||||
mu_assert_null(sdb_get(config_db, "rop.conditional"), "old rop.conditional deleted");
|
||||
mu_assert_streq_free(sdb_get(config_db, "gadget.conditional"), "false", "new gadget.conditional added");
|
||||
|
||||
mu_assert_null(sdb_get(config_db, "rop.comments"), "old rop.comments deleted");
|
||||
mu_assert_streq_free(sdb_get(config_db, "gadget.comments"), "false", "new gadget.comments added");
|
||||
|
||||
rz_serialize_result_info_free(res);
|
||||
rz_project_free(prj);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
/// Load project of given version from file into core and check the log for migration success messages
|
||||
#define BEGIN_LOAD_TEST(core, version, file) \
|
||||
do { \
|
||||
|
|
@ -1055,6 +1091,18 @@ static bool test_load_v17() {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_load_v22_gadget_config() {
|
||||
RzCore *core = rz_core_new();
|
||||
BEGIN_LOAD_TEST(core, 17, "prj/v17-rop-config.rzdb");
|
||||
mu_assert_eq(rz_config_get_i(core->config, "gadget.len"), 5, "gadget.len");
|
||||
mu_assert_eq(rz_config_get_b(core->config, "gadget.cache"), false, "gadget.cache");
|
||||
mu_assert_eq(rz_config_get_b(core->config, "gadget.subchains"), false, "gadget.subchains");
|
||||
mu_assert_eq(rz_config_get_b(core->config, "gadget.conditional"), false, "gadget.conditional");
|
||||
mu_assert_eq(rz_config_get_b(core->config, "gadget.comments"), false, "gadget.comments");
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
int all_tests() {
|
||||
mu_run_test(test_migrate_v1_v2_noreturn);
|
||||
mu_run_test(test_migrate_v1_v2_noreturn_empty);
|
||||
|
|
@ -1078,6 +1126,7 @@ int all_tests() {
|
|||
mu_run_test(test_migrate_v17_v18_rop_config);
|
||||
mu_run_test(test_migrate_v18_v19_str_config);
|
||||
mu_run_test(test_migrate_v20_v21_debase64);
|
||||
mu_run_test(test_migrate_v21_v22_gadget_config);
|
||||
mu_run_test(test_load_v1_noreturn);
|
||||
mu_run_test(test_load_v1_noreturn_empty);
|
||||
mu_run_test(test_load_v1_unknown_type);
|
||||
|
|
@ -1101,6 +1150,7 @@ int all_tests() {
|
|||
mu_run_test(test_load_v15_19_str_config);
|
||||
mu_run_test(test_load_v16);
|
||||
mu_run_test(test_load_v17);
|
||||
mu_run_test(test_load_v22_gadget_config);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "minunit.h"
|
||||
#include <rz_core.h>
|
||||
#include "analysis_private.h"
|
||||
#include <rz_rop.h>
|
||||
#include <rz_gadget.h>
|
||||
|
||||
// Only one gadget is added once for each test case.
|
||||
#define ROP_GADGET_MAX_SIZE 16
|
||||
|
|
@ -34,7 +34,7 @@ static RzCoreAsmHit *setup_rop_hitasm(RzCore *core, int addr, ut8 *buf_str, int
|
|||
return hit;
|
||||
}
|
||||
|
||||
static RzList /*<RzCoreAsmHit *>*/ *
|
||||
static RzPVector /*<RzCoreAsmHit *>*/ *
|
||||
setup_rop_hitlist(RzCore *core, ut8 *buf_str, int addr, int len, HtUP *ht_rop_analysis) {
|
||||
RzAnalysisOp aop = { 0 };
|
||||
rz_analysis_op_init(&aop);
|
||||
|
|
@ -47,23 +47,23 @@ setup_rop_hitlist(RzCore *core, ut8 *buf_str, int addr, int len, HtUP *ht_rop_an
|
|||
return NULL;
|
||||
}
|
||||
|
||||
RzList /*<RzCoreAsmHit *>*/ *hitlist = rz_list_newf(rz_core_asm_hit_free);
|
||||
RzPVector /*<RzCoreAsmHit *>*/ *hitlist = rz_pvector_new(rz_core_asm_hit_free);
|
||||
if (!hitlist) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RzCoreAsmHit *hit = setup_rop_hitasm(core, addr, buf_str, len - 1, ht_rop_analysis);
|
||||
if (!hit) {
|
||||
rz_list_free(hitlist);
|
||||
rz_pvector_free(hitlist);
|
||||
return NULL;
|
||||
}
|
||||
rz_list_append(hitlist, hit);
|
||||
rz_pvector_push(hitlist, hit);
|
||||
hit = setup_rop_hitasm(core, addr + len - 1, buf_str, 1, ht_rop_analysis);
|
||||
if (!hit) {
|
||||
rz_list_free(hitlist);
|
||||
rz_pvector_free(hitlist);
|
||||
return NULL;
|
||||
}
|
||||
rz_list_append(hitlist, hit);
|
||||
rz_pvector_push(hitlist, hit);
|
||||
rz_analysis_op_fini(&aop);
|
||||
return hitlist;
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ static void cleanup_test(RzCore *core, HtUP *ht_rop_analysis) {
|
|||
|
||||
static bool rop_gadget_info_cb(void *user, const ut64 k, const void *v) {
|
||||
HtUP *ht_rop_analysis = (HtUP *)user;
|
||||
RzRopGadgetInfo *gadget_info = (RzRopGadgetInfo *)v;
|
||||
RzGadgetInfo *gadget_info = (RzGadgetInfo *)v;
|
||||
mu_assert_eq(k, gadget_info->address, "ROP gadget address mismatch");
|
||||
RzAnalysisOp *aop = ht_up_find(ht_rop_analysis, k, NULL);
|
||||
mu_assert_notnull(aop, "ROP gadget analysis op is NULL");
|
||||
|
|
@ -95,16 +95,16 @@ static bool rop_gadget_info_cb(void *user, const ut64 k, const void *v) {
|
|||
mu_assert_notnull(src, "ROP gadget analysis op src is NULL");
|
||||
RzRegItem *reg_item = aop->dst->reg;
|
||||
mu_assert_notnull(reg_item, "ROP gadget register item is NULL");
|
||||
RzRopRegInfo *reg_info = rz_core_rop_gadget_info_get_modified_register(gadget_info, aop->dst->reg->name);
|
||||
RzGadgetRegInfo *reg_info = rz_core_gadget_info_get_modified_register(gadget_info, aop->dst->reg->name);
|
||||
mu_assert_notnull(reg_info, "ROP gadget modified register is NULL");
|
||||
mu_assert_streq(reg_info->name, reg_item->name, "ROP gadget modified register name mismatch");
|
||||
if (src[0].type == RZ_ANALYSIS_VAL_IMM) {
|
||||
mu_assert_eq(src->imm, reg_info->new_val - reg_info->init_val, "ROP gadget modified register value mismatch");
|
||||
} else if (src[0].type == RZ_ANALYSIS_VAL_REG) {
|
||||
RzPVector /*<RzRopRegInfo *>*/ *reg_info_vector = rz_core_rop_gadget_get_reg_info_by_event(gadget_info, RZ_ROP_EVENT_VAR_READ);
|
||||
RzPVector /*<RzGadgetRegInfo *>*/ *reg_info_vector = rz_core_gadget_get_reg_info_by_event(gadget_info, RZ_GADGET_EVENT_VAR_READ);
|
||||
mu_assert_notnull(reg_info_vector, "ROP gadget register item is NULL");
|
||||
mu_assert_eq(rz_pvector_len(reg_info_vector), 2, "ROP gadget register item count mismatch");
|
||||
RzRopRegInfo *reg_info_analysis_reg = rz_pvector_at(reg_info_vector, 0);
|
||||
RzGadgetRegInfo *reg_info_analysis_reg = rz_pvector_at(reg_info_vector, 0);
|
||||
mu_assert_streq(src->reg->name, reg_info_analysis_reg->name, "ROP gadget modified register value mismatch");
|
||||
rz_pvector_free(reg_info_vector);
|
||||
}
|
||||
|
|
@ -117,28 +117,28 @@ bool test_rz_direct_solver() {
|
|||
mu_assert_notnull(core, "setup_rz_core failed");
|
||||
int size = sizeof(x86_64_buf_str) / sizeof(x86_64_buf_str[0]);
|
||||
int addr = 0;
|
||||
RzRopSearchContext *context = rz_core_rop_search_context_new(
|
||||
core, NULL, false, RZ_ROP_GADGET_PRINT_DETAIL | RZ_ROP_GADGET_ANALYZE, RZ_ROP_DETAIL_SEARCH_NON,
|
||||
RzGadgetSearchContext *context = rz_core_gadget_search_context_new(
|
||||
core, RZ_GADGET_TYPE_ROP, NULL, false, RZ_GADGET_PRINT_DETAIL | RZ_GADGET_ANALYZE, RZ_GADGET_DETAIL_SEARCH_NON,
|
||||
NULL);
|
||||
mu_assert_notnull(context, "rz_core_rop_search_context_new failed");
|
||||
mu_assert_notnull(context, "rz_core_gadget_search_context_new failed");
|
||||
HtUP *ht_rop_analysis = ht_up_new(NULL, (HtUPFreeValue)rz_analysis_op_free);
|
||||
for (int i = 0; i < size; i++) {
|
||||
ut8 buf[ROP_GADGET_MAX_SIZE] = { 0 };
|
||||
int len = rz_hex_str2bin(x86_64_buf_str[i], buf);
|
||||
rz_io_write_at(core->io, addr, buf, len);
|
||||
RzList /*<RzCoreAsmHit *>*/ *hitlist =
|
||||
RzPVector /*<RzCoreAsmHit *>*/ *hitlist =
|
||||
setup_rop_hitlist(core, buf, addr, len, ht_rop_analysis);
|
||||
mu_assert_notnull(hitlist, "setup_rop_hitlist failed");
|
||||
rz_core_handle_rop_request_type(core, context, hitlist);
|
||||
rz_core_handle_gadget_request_type(core, context, hitlist);
|
||||
addr += len + 1;
|
||||
rz_list_free(hitlist);
|
||||
rz_pvector_free(hitlist);
|
||||
}
|
||||
|
||||
HtUP *rop_semantics = core->analysis->ht_rop_semantics;
|
||||
HtUP *rop_semantics = rz_analysis_get_gadget_semantics(core->analysis);
|
||||
mu_assert_notnull(rop_semantics, "ROP semantics hashtable is NULL");
|
||||
mu_assert_eq(ht_up_size(rop_semantics), 2, "ROP semantics hashtable count is not 2");
|
||||
ht_up_foreach(rop_semantics, rop_gadget_info_cb, ht_rop_analysis);
|
||||
rz_core_rop_search_context_free(context);
|
||||
rz_core_gadget_search_context_free(context);
|
||||
cleanup_test(core, ht_rop_analysis);
|
||||
mu_end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2026 MrQuantum1915 <darshanpatelgdh@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2024 z3phyr <giridh1337@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_core.h>
|
||||
#include "minunit.h"
|
||||
#include <rz_rop.h>
|
||||
#include "analysis_private.h"
|
||||
#include <rz_gadget.h>
|
||||
|
||||
// Define the register profile string for your architecture
|
||||
#define REGISTER_PROFILE_STRING \
|
||||
|
|
@ -35,7 +35,8 @@
|
|||
static void setup_rz_core(RzCore *core) {
|
||||
rz_config_set(core->config, "analysis.arch", "x86");
|
||||
rz_analysis_set_bits(core->analysis, 64);
|
||||
rz_reg_set_profile_string(core->analysis->reg, REGISTER_PROFILE_STRING);
|
||||
RzReg *reg = rz_analysis_get_reg(core->analysis);
|
||||
rz_reg_set_profile_string(reg, REGISTER_PROFILE_STRING);
|
||||
}
|
||||
|
||||
bool test_parse_reg_to_const(void) {
|
||||
|
|
@ -45,19 +46,19 @@ bool test_parse_reg_to_const(void) {
|
|||
|
||||
// Test case 1: Valid register to constant
|
||||
char str1[] = " eax = 123 ";
|
||||
RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1);
|
||||
RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_CONST, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_null(rop_constraint->args[SRC_REG], "Source register should be NULL");
|
||||
mu_assert_streq(rop_constraint->args[SRC_CONST], "123", "Invalid constant value");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 2: Invalid format
|
||||
char str2[] = "eax =";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str2);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str2);
|
||||
mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
|
|
@ -70,18 +71,18 @@ bool test_parse_reg_to_reg(void) {
|
|||
|
||||
// Test case 1: Valid register to register
|
||||
char str1[] = "eax = ebx ";
|
||||
RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1);
|
||||
RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_REG, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "ebx", "Invalid source register");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 2: Invalid format
|
||||
char str2[] = "eax =";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str2);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str2);
|
||||
mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
|
|
@ -94,53 +95,53 @@ bool test_parse_reg_op_const(void) {
|
|||
|
||||
// Test case 1: Valid register operation with constant
|
||||
char str1[] = "eax=eax+3";
|
||||
RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1);
|
||||
RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator");
|
||||
mu_assert_streq(rop_constraint->args[SRC_CONST], "3", "Invalid constant value");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 2: Invalid format
|
||||
char str2[] = "eax=eax+";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str2);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str2);
|
||||
mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 3: Valid register operation with increment operator
|
||||
char str3[] = "eax++";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str3);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str3);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator");
|
||||
mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 4: Valid register operation with decrement operator
|
||||
char str4[] = "eax--";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str4);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str4);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "sub", "Invalid operator");
|
||||
mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 5: Valid register operation with compound operator
|
||||
char str5[] = "eax *= 1";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str5);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str5);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_CONST, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "mul", "Invalid operator");
|
||||
mu_assert_streq(rop_constraint->args[SRC_CONST], "1", "Invalid constant value");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
|
|
@ -153,31 +154,31 @@ bool test_parse_reg_op_reg(void) {
|
|||
|
||||
// Test case 1: Valid register operation with register
|
||||
char str1[] = "eax=ebx-ecx";
|
||||
RzRopConstraint *rop_constraint = rz_core_rop_constraint_parse_args(core, str1);
|
||||
RzGadgetConstraint *rop_constraint = rz_core_gadget_constraint_parse_args(core, str1);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_REG, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "ebx", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "sub", "Invalid operator");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG_SECOND], "ecx", "Invalid destination constant register");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 2: Invalid format
|
||||
char str2[] = "eax = eax+ ";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str2);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str2);
|
||||
mu_assert_null(rop_constraint, "parse_reg_constraints failed on invalid input");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
// Test case 3: Valid register operation with register
|
||||
char str3[] = "eax += ebx";
|
||||
rop_constraint = rz_core_rop_constraint_parse_args(core, str3);
|
||||
rop_constraint = rz_core_gadget_constraint_parse_args(core, str3);
|
||||
mu_assert_notnull(rop_constraint, "parse_reg_constraints failed on valid input");
|
||||
mu_assert_eq(rop_constraint->type, MOV_OP_REG, "Invalid constraint type");
|
||||
mu_assert_streq(rop_constraint->args[DST_REG], "eax", "Invalid destination register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG], "eax", "Invalid source register");
|
||||
mu_assert_streq(rop_constraint->args[SRC_REG_SECOND], "ebx", "Invalid destination constant register");
|
||||
mu_assert_streq(rop_constraint->args[OP], "add", "Invalid operator");
|
||||
rz_core_rop_constraint_free(rop_constraint);
|
||||
rz_core_gadget_constraint_free(rop_constraint);
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
|
|
|
|||
Loading…
Reference in a new issue