rizin/test/unit/test_rop.c

151 lines
5.4 KiB
C

// 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 <rz_gadget.h>
// Only one gadget is added once for each test case.
#define ROP_GADGET_MAX_SIZE 16
static const char *x86_64_buf_str[] = {
// mov rbx, 1; ret;
"48C7C301000000C3",
// mov rbx, rax; ret;
"4889c3c3"
};
static RzCoreAsmHit *setup_rop_hitasm(RzCore *core, int addr, ut8 *buf_str, int len, HtUP *ht_rop_analysis) {
RzCoreAsmHit *hit = rz_core_asm_hit_new();
if (!hit) {
return NULL;
}
hit->addr = addr;
hit->len = len;
RzAnalysisOp *aop = rz_analysis_op_new();
if (rz_analysis_op(core->analysis, aop, addr, buf_str, len,
RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_VAL) < 0) {
rz_core_asm_hit_free(hit);
rz_analysis_op_free(aop);
return NULL;
}
ht_up_insert(ht_rop_analysis, addr, aop);
return hit;
}
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);
if (rz_analysis_op(core->analysis, &aop, addr + len - 1, buf_str + len - 1, 1,
RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_VAL) < 0) {
return NULL;
}
if (aop.type != RZ_ANALYSIS_OP_TYPE_RET) {
return NULL;
}
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_pvector_free(hitlist);
return NULL;
}
rz_pvector_push(hitlist, hit);
hit = setup_rop_hitasm(core, addr + len - 1, buf_str, 1, ht_rop_analysis);
if (!hit) {
rz_pvector_free(hitlist);
return NULL;
}
rz_pvector_push(hitlist, hit);
rz_analysis_op_fini(&aop);
return hitlist;
}
static RzCore *setup_rz_core(char *arch, int bits) {
RzCore *core = rz_core_new();
if (!core) {
return NULL;
}
rz_io_open_at(core->io, "malloc://0x100", RZ_PERM_RX, 0644, 0, NULL);
rz_core_arch_configure(core, "x86", 64, NULL, NULL, NULL);
rz_config_set_b(core->config, "asm.lines", false);
return core;
}
static void cleanup_test(RzCore *core, HtUP *ht_rop_analysis) {
ht_up_free(ht_rop_analysis);
rz_core_free(core);
}
static bool rop_gadget_info_cb(void *user, const ut64 k, const void *v) {
HtUP *ht_rop_analysis = (HtUP *)user;
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");
mu_assert_notnull(aop->dst, "ROP gadget analysis op dst is NULL");
RzAnalysisValue *src = aop->src[0];
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");
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 /*<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");
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);
}
return true;
}
bool test_rz_direct_solver() {
RzCore *core = setup_rz_core("x86", 64);
mu_assert_notnull(core, "setup_rz_core failed");
int size = sizeof(x86_64_buf_str) / sizeof(x86_64_buf_str[0]);
int addr = 0;
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_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);
RzPVector /*<RzCoreAsmHit *>*/ *hitlist =
setup_rop_hitlist(core, buf, addr, len, ht_rop_analysis);
mu_assert_notnull(hitlist, "setup_rop_hitlist failed");
rz_core_handle_gadget_request_type(core, context, hitlist);
addr += len + 1;
rz_pvector_free(hitlist);
}
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_gadget_search_context_free(context);
cleanup_test(core, ht_rop_analysis);
mu_end;
}
bool all_tests() {
mu_run_test(test_rz_direct_solver);
return tests_passed != tests_run;
}
mu_main(all_tests)