* Fix UB access of NULL context. During the tests the global RzCons is accessed. Because it was never initialized all members were 0. Leading to undefined behavior and breaking the test with ASAN enabled. * Use correct yaml example for the command described. * Remove old shell compatibility code. * Remove dependency tree of rz_core_cmd_subst() and rz_core_cmd_subst_i(). * Remove rz_core_cmd_pipe_old() * Remove unused rz_core_hack_help() * Regenerate grammar after removal of legacy_quoted_stmt.
6514 lines
198 KiB
C
6514 lines
198 KiB
C
// SPDX-FileCopyrightText: 2009-2021 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_asm.h>
|
|
#include <rz_cmd.h>
|
|
#include <rz_core.h>
|
|
#include <rz_config.h>
|
|
#include <rz_util.h>
|
|
#include <rz_type.h>
|
|
#include <rz_types.h>
|
|
|
|
#include "../core_private.h"
|
|
|
|
#define PF_USAGE_STR "pf[.k[.f[=v]]|[v]]|[n]|[0|cnt][fmt] [a0 a1 ...]"
|
|
|
|
static const ut32 colormap[256] = {
|
|
0x000000,
|
|
0x560000,
|
|
0x640000,
|
|
0x750000,
|
|
0x870000,
|
|
0x9b0000,
|
|
0xb00000,
|
|
0xc60000,
|
|
0xdd0000,
|
|
0xf50000,
|
|
0xff0f0f,
|
|
0xff2828,
|
|
0xff4343,
|
|
0xff5e5e,
|
|
0xff7979,
|
|
0xfe9595,
|
|
0x4c1600,
|
|
0x561900,
|
|
0x641e00,
|
|
0x752300,
|
|
0x872800,
|
|
0x9b2e00,
|
|
0xb03400,
|
|
0xc63b00,
|
|
0xdd4200,
|
|
0xf54900,
|
|
0xff570f,
|
|
0xff6928,
|
|
0xff7b43,
|
|
0xff8e5e,
|
|
0xffa179,
|
|
0xfeb595,
|
|
0x4c3900,
|
|
0x564000,
|
|
0x644b00,
|
|
0x755700,
|
|
0x876500,
|
|
0x9b7400,
|
|
0xb08400,
|
|
0xc69400,
|
|
0xdda600,
|
|
0xf5b800,
|
|
0xffc30f,
|
|
0xffc928,
|
|
0xffd043,
|
|
0xffd65e,
|
|
0xffdd79,
|
|
0xfee495,
|
|
0x4c4c00,
|
|
0x565600,
|
|
0x646400,
|
|
0x757500,
|
|
0x878700,
|
|
0x9b9b00,
|
|
0xb0b000,
|
|
0xc6c600,
|
|
0xdddd00,
|
|
0xf5f500,
|
|
0xffff0f,
|
|
0xffff28,
|
|
0xffff43,
|
|
0xffff5e,
|
|
0xffff79,
|
|
0xfffe95,
|
|
0x324c00,
|
|
0x395600,
|
|
0x426400,
|
|
0x4e7500,
|
|
0x5a8700,
|
|
0x679b00,
|
|
0x75b000,
|
|
0x84c600,
|
|
0x93dd00,
|
|
0xa3f500,
|
|
0xafff0f,
|
|
0xb7ff28,
|
|
0xc0ff43,
|
|
0xc9ff5e,
|
|
0xd2ff79,
|
|
0xdbfe95,
|
|
0x1f4c00,
|
|
0x235600,
|
|
0x296400,
|
|
0x307500,
|
|
0x388700,
|
|
0x409b00,
|
|
0x49b000,
|
|
0x52c600,
|
|
0x5cdd00,
|
|
0x66f500,
|
|
0x73ff0f,
|
|
0x82ff28,
|
|
0x91ff43,
|
|
0xa1ff5e,
|
|
0xb1ff79,
|
|
0xc1fe95,
|
|
0x004c00,
|
|
0x005600,
|
|
0x006400,
|
|
0x007500,
|
|
0x008700,
|
|
0x009b00,
|
|
0x00b000,
|
|
0x00c600,
|
|
0x00dd00,
|
|
0x00f500,
|
|
0x0fff0f,
|
|
0x28ff28,
|
|
0x43ff43,
|
|
0x5eff5e,
|
|
0x79ff79,
|
|
0x95fe95,
|
|
0x004c19,
|
|
0x00561c,
|
|
0x006421,
|
|
0x007527,
|
|
0x00872d,
|
|
0x009b33,
|
|
0x00b03a,
|
|
0x00c642,
|
|
0x00dd49,
|
|
0x00f551,
|
|
0x0fff5f,
|
|
0x28ff70,
|
|
0x43ff81,
|
|
0x5eff93,
|
|
0x79ffa6,
|
|
0x95feb8,
|
|
0x004c4c,
|
|
0x005656,
|
|
0x006464,
|
|
0x007575,
|
|
0x008787,
|
|
0x009b9b,
|
|
0x00b0b0,
|
|
0x00c6c6,
|
|
0x00dddd,
|
|
0x00f5f5,
|
|
0x0ffffe,
|
|
0x28fffe,
|
|
0x43fffe,
|
|
0x5efffe,
|
|
0x79ffff,
|
|
0x95fffe,
|
|
0x00394c,
|
|
0x004056,
|
|
0x004b64,
|
|
0x005775,
|
|
0x006587,
|
|
0x00749b,
|
|
0x0084b0,
|
|
0x0094c6,
|
|
0x00a6dd,
|
|
0x00b8f5,
|
|
0x0fc3ff,
|
|
0x28c9ff,
|
|
0x43d0ff,
|
|
0x5ed6ff,
|
|
0x79ddff,
|
|
0x95e4fe,
|
|
0x00264c,
|
|
0x002b56,
|
|
0x003264,
|
|
0x003a75,
|
|
0x004387,
|
|
0x004d9b,
|
|
0x0058b0,
|
|
0x0063c6,
|
|
0x006edd,
|
|
0x007af5,
|
|
0x0f87ff,
|
|
0x2893ff,
|
|
0x43a1ff,
|
|
0x5eaeff,
|
|
0x79bcff,
|
|
0x95cafe,
|
|
0x00134c,
|
|
0x001556,
|
|
0x001964,
|
|
0x001d75,
|
|
0x002187,
|
|
0x00269b,
|
|
0x002cb0,
|
|
0x0031c6,
|
|
0x0037dd,
|
|
0x003df5,
|
|
0x0f4bff,
|
|
0x285eff,
|
|
0x4372ff,
|
|
0x5e86ff,
|
|
0x799aff,
|
|
0x95b0fe,
|
|
0x19004c,
|
|
0x1c0056,
|
|
0x210064,
|
|
0x270075,
|
|
0x2d0087,
|
|
0x33009b,
|
|
0x3a00b0,
|
|
0x4200c6,
|
|
0x4900dd,
|
|
0x5100f5,
|
|
0x5f0fff,
|
|
0x7028ff,
|
|
0x8143ff,
|
|
0x935eff,
|
|
0xa679ff,
|
|
0xb895fe,
|
|
0x33004c,
|
|
0x390056,
|
|
0x420064,
|
|
0x4e0075,
|
|
0x5a0087,
|
|
0x67009b,
|
|
0x7500b0,
|
|
0x8400c6,
|
|
0x9300dd,
|
|
0xa300f5,
|
|
0xaf0fff,
|
|
0xb728ff,
|
|
0xc043ff,
|
|
0xc95eff,
|
|
0xd279ff,
|
|
0xdb95fe,
|
|
0x4c004c,
|
|
0x560056,
|
|
0x640064,
|
|
0x750075,
|
|
0x870087,
|
|
0x9b009b,
|
|
0xb000b0,
|
|
0xc600c6,
|
|
0xdd00dd,
|
|
0xf500f5,
|
|
0xfe0fff,
|
|
0xfe28ff,
|
|
0xfe43ff,
|
|
0xfe5eff,
|
|
0xfe79ff,
|
|
0xfe95fe,
|
|
0x4c0032,
|
|
0x560039,
|
|
0x640042,
|
|
0x75004e,
|
|
0x87005a,
|
|
0x9b0067,
|
|
0xb00075,
|
|
0xc60084,
|
|
0xdd0093,
|
|
0xf500a3,
|
|
0xff0faf,
|
|
0xff28b7,
|
|
0xff43c0,
|
|
0xff5ec9,
|
|
0xff79d2,
|
|
0xffffff,
|
|
};
|
|
|
|
static inline char *get_section_name(RzCore *core, ut64 offset) {
|
|
char *csection = rz_core_get_section_name(core, offset);
|
|
if (RZ_STR_ISEMPTY(csection)) {
|
|
free(csection);
|
|
return rz_str_dup("unknown");
|
|
}
|
|
rz_str_trim(csection);
|
|
if (RZ_STR_ISEMPTY(csection)) {
|
|
free(csection);
|
|
return rz_str_dup("unknown");
|
|
}
|
|
return csection;
|
|
}
|
|
|
|
static void colordump(RzCore *core, const ut8 *block, int len) {
|
|
const char *chars = " .,:;!O@#";
|
|
bool square = rz_config_get_i(core->config, "scr.square");
|
|
int i, j;
|
|
char ch, ch2, *color;
|
|
int cols = rz_config_get_i(core->config, "hex.cols");
|
|
bool show_color = rz_config_get_i(core->config, "scr.color");
|
|
bool show_flags = rz_config_get_i(core->config, "asm.flags");
|
|
bool show_section = rz_config_get_i(core->config, "hex.section");
|
|
bool show_offset = rz_config_get_i(core->config, "hex.offset");
|
|
bool show_cursor = core->print->cur_enabled;
|
|
bool show_unalloc = core->print->flags & RZ_PRINT_FLAGS_UNALLOC;
|
|
if (cols < 1 || cols > 0xfffff) {
|
|
cols = 32;
|
|
}
|
|
for (i = 0; i < len; i += cols) {
|
|
if (show_section) {
|
|
char *name = get_section_name(core, core->offset + i);
|
|
rz_cons_printf("%20s ", name ? name : "");
|
|
free(name);
|
|
}
|
|
if (show_offset) {
|
|
rz_print_addr(core->print, core->offset + i);
|
|
}
|
|
for (j = i; j < i + cols; j++) {
|
|
if (j >= len) {
|
|
break;
|
|
}
|
|
if (show_color) {
|
|
ut32 color_val = colormap[block[j]];
|
|
// Brightness weights are based on
|
|
// https://twitter.com/DanHollick/status/1417895189239123968
|
|
// (normalized to red). I'm aware that max
|
|
// brightness is greater than 255 * 3.
|
|
int brightness = ((color_val & 0xff0000) >> 16) + 2 * ((color_val & 0xff00) >> 8) + (color_val & 0xff) / 3;
|
|
char *str = rz_str_newf("rgb:%s rgb:%06x",
|
|
brightness <= 0x7f * 3 ? "fff" : "000", color_val);
|
|
color = rz_cons_pal_parse(str, NULL);
|
|
free(str);
|
|
if (show_cursor && core->print->cur == j) {
|
|
ch = '_';
|
|
} else {
|
|
ch = ' ';
|
|
}
|
|
} else {
|
|
color = rz_str_dup("");
|
|
if (show_cursor && core->print->cur == j) {
|
|
ch = '_';
|
|
} else {
|
|
const int idx = ((float)block[j] / 255) * (strlen(chars) - 1);
|
|
ch = chars[idx];
|
|
}
|
|
}
|
|
if (show_unalloc &&
|
|
!core->print->iob.is_valid_offset(core->print->iob.io, core->offset + j, false)) {
|
|
ch = core->print->io_unalloc_ch;
|
|
if (show_color) {
|
|
free(color);
|
|
color = rz_str_dup(Color_RESET);
|
|
if (ch == ' ') {
|
|
ch = '.';
|
|
}
|
|
} else {
|
|
ch = strchr(chars, ch) ? '?' : ch;
|
|
}
|
|
}
|
|
if (square) {
|
|
if (show_flags) {
|
|
RzFlagItem *fi = rz_flag_get_i(core->flags, core->offset + j);
|
|
if (fi) {
|
|
if (fi->name[1]) {
|
|
ch = fi->name[0];
|
|
ch2 = fi->name[1];
|
|
} else {
|
|
ch = ' ';
|
|
ch2 = fi->name[0];
|
|
}
|
|
} else {
|
|
ch2 = ch;
|
|
}
|
|
} else {
|
|
ch2 = ch;
|
|
}
|
|
rz_cons_printf("%s%c%c", color, ch, ch2);
|
|
} else {
|
|
rz_cons_printf("%s%c", color, ch);
|
|
}
|
|
free(color);
|
|
}
|
|
if (show_color) {
|
|
rz_cons_printf(Color_RESET);
|
|
}
|
|
rz_cons_newline();
|
|
}
|
|
}
|
|
|
|
static void findMethodBounds(RzList /*<RzBinSymbol *>*/ *methods, ut64 *min, ut64 *max) {
|
|
RzBinSymbol *sym;
|
|
RzListIter *iter;
|
|
ut64 at_min = UT64_MAX;
|
|
ut64 at_max = 0LL;
|
|
|
|
rz_list_foreach (methods, iter, sym) {
|
|
if (sym->vaddr) {
|
|
if (sym->vaddr < at_min) {
|
|
at_min = sym->vaddr;
|
|
}
|
|
if (sym->vaddr + sym->size > at_max) {
|
|
at_max = sym->vaddr + sym->size;
|
|
}
|
|
}
|
|
}
|
|
*min = at_min;
|
|
*max = at_max;
|
|
}
|
|
|
|
static ut64 findClassBounds(RzCore *core, int *len) {
|
|
ut64 min = 0, max = 0;
|
|
void **iter;
|
|
RzBinClass *c;
|
|
|
|
RzBinObject *bin_obj = rz_bin_cur_object(core->bin);
|
|
const RzPVector *cs = rz_bin_object_get_classes(bin_obj);
|
|
if (cs) {
|
|
rz_pvector_foreach (cs, iter) {
|
|
c = *iter;
|
|
if (!c || !c->name || !c->name[0]) {
|
|
continue;
|
|
}
|
|
findMethodBounds(c->methods, &min, &max);
|
|
if (len) {
|
|
*len = (max - min);
|
|
}
|
|
return min;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
RZ_API void rz_core_set_asm_configs(RzCore *core, char *arch, ut32 bits, int segoff) {
|
|
rz_config_set(core->config, "asm.arch", arch);
|
|
rz_config_set_i(core->config, "asm.bits", bits);
|
|
// XXX - this needs to be done here, because
|
|
// if arch == x86 and bits == 16, segoff automatically changes
|
|
rz_config_set_i(core->config, "asm.segoff", segoff);
|
|
}
|
|
|
|
/**
|
|
* \brief Frees a visual print gadget
|
|
*
|
|
* \param g reference to RzCoreGadget
|
|
*/
|
|
RZ_API void rz_core_gadget_free(RzCoreGadget *g) {
|
|
free(g->cmd);
|
|
free(g);
|
|
}
|
|
|
|
/**
|
|
* \brief Prints or displays the print gadgets while in
|
|
* visual mode
|
|
*
|
|
* \param core reference to RzCore
|
|
*/
|
|
RZ_API void rz_core_gadget_print(RzCore *core) {
|
|
RzCoreGadget *g;
|
|
RzListIter *iter;
|
|
rz_list_foreach (core->gadgets, iter, g) {
|
|
char *res = rz_core_cmd_str(core, g->cmd);
|
|
if (res) {
|
|
rz_cons_strcat_at(res, g->x, g->y, g->w, g->h);
|
|
free(res);
|
|
}
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_gadget_print_as_rizin_handler(RzCore *core, int argc, const char **argv) {
|
|
RzCoreGadget *g;
|
|
RzListIter *iter;
|
|
rz_list_foreach (core->gadgets, iter, g) {
|
|
rz_cons_printf("\"pg %d %d %d %d %s\"\n", g->x, g->y, g->w, g->h, g->cmd);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
RZ_IPI RzCmdStatus rz_cmd_print_gadget_remove_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_list_free(core->gadgets);
|
|
core->gadgets = rz_list_newf((RzListFree)rz_core_gadget_free);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
RZ_IPI RzCmdStatus rz_cmd_print_gadget_move_handler(RzCore *core, int argc, const char **argv) {
|
|
int n = rz_num_math(core->num, argv[1]);
|
|
int x = rz_num_math(core->num, argv[2]);
|
|
int y = rz_num_math(core->num, argv[3]);
|
|
int w = rz_num_math(core->num, argv[4]);
|
|
int h = rz_num_math(core->num, argv[5]);
|
|
RzCoreGadget *g = rz_list_get_n(core->gadgets, n);
|
|
if (x && y && w && h) {
|
|
g->x = x;
|
|
g->y = y;
|
|
g->w = w;
|
|
g->h = h;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_gadget_add_handler(RzCore *core, int argc, const char **argv) {
|
|
char *cmd = NULL;
|
|
if (argc == 1) {
|
|
rz_core_gadget_print(core);
|
|
} else {
|
|
int x = argc > 2 ? rz_num_math(core->num, argv[1]) : 1;
|
|
int y = argc > 3 ? rz_num_math(core->num, argv[2]) : 1;
|
|
int w = argc > 4 ? rz_num_math(core->num, argv[3]) : 1;
|
|
int h = argc > 5 ? rz_num_math(core->num, argv[4]) : 1;
|
|
if (x && y && w && h) {
|
|
char *tmp = rz_str_dup(argv[argc - 1]);
|
|
free(cmd);
|
|
cmd = tmp;
|
|
if (cmd) {
|
|
RzCoreGadget *g = RZ_NEW0(RzCoreGadget);
|
|
g->x = x;
|
|
g->y = y;
|
|
g->w = w;
|
|
g->h = h;
|
|
g->cmd = cmd;
|
|
rz_list_append(core->gadgets, g);
|
|
}
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_unix_handler(RzCore *core, int argc, const char **argv) {
|
|
char *date = NULL;
|
|
const ut8 *block = core->block;
|
|
ut32 len = core->blocksize;
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
int timezone = (int)rz_config_get_i(core->config, "time.zone");
|
|
if (len < sizeof(ut32)) {
|
|
RZ_LOG_ERROR("The block size is less than 4.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
|
|
ut32 dt = rz_read_ble32(block + i, big_endian);
|
|
// add timezone
|
|
dt += timezone * (60 * 60);
|
|
date = rz_time_date_unix_to_string(dt);
|
|
rz_cons_printf("%s\n", date);
|
|
free(date);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_current_handler(RzCore *core, int argc, const char **argv) {
|
|
char *now = rz_time_date_now_to_string();
|
|
rz_cons_printf("%s\n", now);
|
|
free(now);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_dos_handler(RzCore *core, int argc, const char **argv) {
|
|
char *date = NULL;
|
|
const ut8 *block = core->block;
|
|
ut32 len = core->blocksize;
|
|
if (len < sizeof(ut32)) {
|
|
RZ_LOG_ERROR("The block size is less than 4.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
|
|
ut32 dt = rz_read_le32(block + i);
|
|
date = rz_time_date_dos_to_string(dt);
|
|
rz_cons_printf("%s\n", date);
|
|
free(date);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_hfs_handler(RzCore *core, int argc, const char **argv) {
|
|
char *date = NULL;
|
|
const ut8 *block = core->block;
|
|
ut32 len = core->blocksize;
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
int timezone = (int)rz_config_get_i(core->config, "time.zone");
|
|
if (len < sizeof(ut32)) {
|
|
RZ_LOG_ERROR("The block size is less than 4.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
for (ut64 i = 0; i < len; i += sizeof(ut32)) {
|
|
ut32 dt = rz_read_ble32(block + i, big_endian);
|
|
// add timezone
|
|
dt += timezone * (60 * 60);
|
|
date = rz_time_date_hfs_to_string(dt);
|
|
rz_cons_printf("%s\n", date);
|
|
free(date);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_timestamp_ntfs_handler(RzCore *core, int argc, const char **argv) {
|
|
char *date = NULL;
|
|
const ut8 *block = core->block;
|
|
ut32 len = core->blocksize;
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
if (len < sizeof(ut64)) {
|
|
RZ_LOG_ERROR("The block size is less than 8.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
for (ut64 i = 0; i < len; i += sizeof(ut64)) {
|
|
ut64 dt = rz_read_ble64(block + i, big_endian);
|
|
date = rz_time_date_w32_to_string(dt);
|
|
rz_cons_printf("%s\n", date);
|
|
free(date);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// > pxa
|
|
/* In this function, most of the buffers have 4 times
|
|
* the required length. This is because we supports colours,
|
|
* that are 4 chars long. */
|
|
#define append(x, y) \
|
|
{ \
|
|
strcat(x, y); \
|
|
x += strlen(y); \
|
|
}
|
|
|
|
#define Pal(x, y) (x->cons && x->cons->context->pal.y) ? x->cons->context->pal.y
|
|
|
|
static void annotated_hexdump(RzCore *core, int len) {
|
|
if (!len) {
|
|
return;
|
|
}
|
|
const int usecolor = rz_config_get_i(core->config, "scr.color");
|
|
int nb_cols = rz_config_get_i(core->config, "hex.cols");
|
|
core->print->use_comments = rz_config_get_i(core->config, "hex.comments");
|
|
int flagsz = rz_config_get_i(core->config, "hex.flagsz");
|
|
bool showSection = rz_config_get_i(core->config, "hex.section");
|
|
const ut8 *buf = core->block;
|
|
ut64 addr = core->offset;
|
|
int color_idx = 0;
|
|
char *bytes, *chars;
|
|
char *ebytes, *echars; // They'll walk over the vars above
|
|
ut64 fend = UT64_MAX;
|
|
int i, j, low, max, here, rows;
|
|
bool marks = false, setcolor = true, hascolor = false;
|
|
ut8 ch = 0;
|
|
char tmpbuf[20] = { 0 };
|
|
char *colors[10] = { NULL };
|
|
for (i = 0; i < 10; i++) {
|
|
colors[i] = rz_cons_rainbow_get(i, 10, false);
|
|
}
|
|
const int col = core->print->col;
|
|
RzFlagItem *flag, *current_flag = NULL;
|
|
char **note;
|
|
int html = rz_config_get_i(core->config, "scr.html");
|
|
int nb_cons_cols;
|
|
bool compact = false;
|
|
|
|
if (core->print) {
|
|
compact = core->print->flags & RZ_PRINT_FLAGS_COMPACT;
|
|
}
|
|
char *format = compact ? " %X %X" : " %X %X ";
|
|
int step = compact ? 4 : 5;
|
|
|
|
// Adjust the number of columns
|
|
if (nb_cols < 1) {
|
|
nb_cols = 16;
|
|
}
|
|
nb_cols -= (nb_cols % 2); // nb_cols should be even
|
|
if (nb_cols < 1) {
|
|
return;
|
|
}
|
|
|
|
nb_cons_cols = 12 + nb_cols * 2 + (nb_cols / 2);
|
|
nb_cons_cols += 17;
|
|
rows = len / nb_cols;
|
|
|
|
chars = calloc(nb_cols * 40, sizeof(char));
|
|
if (!chars)
|
|
goto err_chars;
|
|
note = calloc(nb_cols, sizeof(char *));
|
|
if (!note)
|
|
goto err_note;
|
|
bytes = calloc(nb_cons_cols * 40, sizeof(char));
|
|
if (!bytes)
|
|
goto err_bytes;
|
|
int addrpadlen = strlen(rz_strf(tmpbuf, "%08" PFMT64x, addr)) - 8;
|
|
char addrpad[32];
|
|
if (addrpadlen > 0) {
|
|
memset(addrpad, ' ', addrpadlen);
|
|
addrpad[addrpadlen] = 0;
|
|
// Compute, then show the legend
|
|
strcpy(bytes, addrpad);
|
|
} else {
|
|
*addrpad = 0;
|
|
addrpadlen = 0;
|
|
}
|
|
strcpy(bytes + addrpadlen, "- offset - ");
|
|
j = strlen(bytes);
|
|
for (i = 0; i < nb_cols; i += 2) {
|
|
sprintf(bytes + j, format, (i & 0xf), (i + 1) & 0xf);
|
|
j += step;
|
|
}
|
|
j--;
|
|
strcpy(bytes + j, " ");
|
|
j += 2;
|
|
for (i = 0; i < nb_cols; i++) {
|
|
sprintf(bytes + j + i, "%0X", i % 17);
|
|
}
|
|
if (usecolor) {
|
|
const char *color_title = Pal(core, offset)
|
|
: Color_MAGENTA;
|
|
rz_cons_strcat(color_title);
|
|
rz_cons_strcat(bytes);
|
|
rz_cons_strcat(Color_RESET);
|
|
} else {
|
|
rz_cons_strcat(bytes);
|
|
}
|
|
rz_cons_newline();
|
|
|
|
// hexdump
|
|
for (i = 0; i < rows; i++) {
|
|
bytes[0] = '\0';
|
|
chars[0] = '\0';
|
|
ebytes = bytes;
|
|
echars = chars;
|
|
hascolor = false;
|
|
ut64 ea = addr;
|
|
if (core->print->pava) {
|
|
ut64 va = rz_io_p2v(core->io, addr);
|
|
if (va != UT64_MAX) {
|
|
ea = va;
|
|
}
|
|
}
|
|
|
|
if (usecolor) {
|
|
append(ebytes, core->cons->context->pal.offset);
|
|
}
|
|
if (showSection) {
|
|
char *name = get_section_name(core, ea);
|
|
char *s = rz_str_newf("%20s ", name);
|
|
append(ebytes, s);
|
|
free(s);
|
|
free(name);
|
|
}
|
|
ebytes += sprintf(ebytes, "0x%08" PFMT64x, ea);
|
|
if (usecolor) {
|
|
append(ebytes, Color_RESET);
|
|
}
|
|
append(ebytes, (col == 1) ? " |" : " ");
|
|
bool hadflag = false;
|
|
for (j = 0; j < nb_cols; j++) {
|
|
setcolor = true;
|
|
RZ_FREE(note[j]);
|
|
|
|
// TODO: in pava mode we should read addr or ea? // imho ea. but wat about hdrs and such
|
|
RzIntervalNode *meta_node = rz_meta_get_in(core->analysis, ea + j, RZ_META_TYPE_FORMAT);
|
|
RzAnalysisMetaItem *meta = meta_node ? meta_node->data : NULL;
|
|
if (meta && meta->type == RZ_META_TYPE_FORMAT && meta_node->start == addr + j) {
|
|
rz_cons_printf(".format %s ; size=", meta->str);
|
|
// TODO: Convert to the API
|
|
rz_core_cmdf(core, "pfs %s", meta->str);
|
|
char *r = rz_core_print_format(core, meta->str, RZ_PRINT_MUSTSEE, meta_node->start);
|
|
rz_cons_print(r);
|
|
free(r);
|
|
if (usecolor) {
|
|
append(ebytes, Color_INVERT);
|
|
append(echars, Color_INVERT);
|
|
}
|
|
hadflag = true;
|
|
}
|
|
if (meta) {
|
|
meta = NULL;
|
|
}
|
|
// collect comments
|
|
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, addr + j);
|
|
if (comment) {
|
|
note[j] = rz_str_newf(";%s", comment);
|
|
marks = true;
|
|
}
|
|
|
|
// collect flags
|
|
flag = rz_flag_get_i(core->flags, addr + j);
|
|
if (flag) { // Beginning of a flag
|
|
if (flagsz) {
|
|
fend = addr + flagsz; // core->blocksize;
|
|
} else {
|
|
fend = addr + j + flag->size;
|
|
}
|
|
free(note[j]);
|
|
note[j] = rz_str_prepend(rz_str_dup(flag->name), "/");
|
|
marks = true;
|
|
color_idx++;
|
|
color_idx %= 10;
|
|
current_flag = flag;
|
|
if (showSection) {
|
|
rz_cons_printf("%20s ", "");
|
|
}
|
|
if (flag->offset == addr + j) {
|
|
if (usecolor) {
|
|
append(ebytes, Color_INVERT);
|
|
append(echars, Color_INVERT);
|
|
}
|
|
hadflag = true;
|
|
}
|
|
} else {
|
|
// Are we past the current flag?
|
|
if (current_flag && addr + j > (current_flag->offset + current_flag->size)) {
|
|
setcolor = false;
|
|
current_flag = NULL;
|
|
}
|
|
// Turn colour off if we're at the end of the current flag
|
|
if (fend == UT64_MAX || fend <= addr + j) {
|
|
setcolor = false;
|
|
}
|
|
}
|
|
if (usecolor) {
|
|
if (!setcolor) {
|
|
const char *bytecolor = rz_print_byte_color(core->print, ch);
|
|
if (bytecolor) {
|
|
append(ebytes, bytecolor);
|
|
append(echars, bytecolor);
|
|
hascolor = true;
|
|
}
|
|
} else if (!hascolor) {
|
|
hascolor = true;
|
|
if (current_flag && current_flag->color) {
|
|
char *ansicolor = rz_cons_pal_parse(current_flag->color, NULL);
|
|
if (ansicolor) {
|
|
append(ebytes, ansicolor);
|
|
append(echars, ansicolor);
|
|
free(ansicolor);
|
|
}
|
|
} else { // Use "random" colours
|
|
append(ebytes, colors[color_idx]);
|
|
append(echars, colors[color_idx]);
|
|
}
|
|
}
|
|
}
|
|
here = RZ_MIN((i * nb_cols) + j, core->blocksize);
|
|
ch = buf[here];
|
|
if (core->print->ocur != -1) {
|
|
low = RZ_MIN(core->print->cur, core->print->ocur);
|
|
max = RZ_MAX(core->print->cur, core->print->ocur);
|
|
} else {
|
|
low = max = core->print->cur;
|
|
}
|
|
if (core->print->cur_enabled) {
|
|
if (low == max) {
|
|
if (low == here) {
|
|
if (html || !usecolor) {
|
|
append(ebytes, "[");
|
|
append(echars, "[");
|
|
} else {
|
|
append(echars, Color_INVERT);
|
|
append(ebytes, Color_INVERT);
|
|
}
|
|
}
|
|
} else {
|
|
if (here >= low && here < max) {
|
|
if (html || !usecolor) {
|
|
append(ebytes, "[");
|
|
append(echars, "[");
|
|
} else {
|
|
if (usecolor) {
|
|
append(ebytes, Color_INVERT);
|
|
append(echars, Color_INVERT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!ebytes) { // this check is just to silence the compiler
|
|
goto err_ebytes;
|
|
}
|
|
sprintf(ebytes, "%02x", ch);
|
|
// rz_print_byte (core->print, "%02x ", j, ch);
|
|
ebytes += strlen(ebytes);
|
|
if (hadflag) {
|
|
if (usecolor) {
|
|
append(ebytes, Color_INVERT_RESET);
|
|
append(echars, Color_INVERT_RESET);
|
|
}
|
|
hadflag = false;
|
|
}
|
|
sprintf(echars, "%c", IS_PRINTABLE(ch) ? ch : '.');
|
|
echars++;
|
|
if (core->print->cur_enabled && max == here) {
|
|
if (!html && usecolor) {
|
|
append(ebytes, Color_RESET);
|
|
append(echars, Color_RESET);
|
|
}
|
|
hascolor = false;
|
|
}
|
|
|
|
if (j < (nb_cols - 1) && (j % 2) && !compact) {
|
|
append(ebytes, " ");
|
|
}
|
|
|
|
if (fend != UT64_MAX && fend == addr + j + 1) {
|
|
if (!html && usecolor) {
|
|
append(ebytes, Color_RESET);
|
|
append(echars, Color_RESET);
|
|
}
|
|
fend = UT64_MAX;
|
|
hascolor = false;
|
|
}
|
|
}
|
|
if (!html && usecolor) {
|
|
append(ebytes, Color_RESET);
|
|
append(echars, Color_RESET);
|
|
}
|
|
append(ebytes, (col == 1) ? "| " : (col == 2) ? " |"
|
|
: " ");
|
|
if (col == 2) {
|
|
append(echars, "|");
|
|
}
|
|
|
|
if (marks) { // show comments and flags
|
|
int hasline = 0;
|
|
int out_sz = nb_cons_cols + 20;
|
|
char *out = calloc(out_sz, sizeof(char));
|
|
memset(out, ' ', nb_cons_cols - 1);
|
|
for (j = 0; j < nb_cols; j++) {
|
|
if (note[j]) {
|
|
int off = (j * 3) - (j / 2) + 13;
|
|
int notej_len = strlen(note[j]);
|
|
int sz = RZ_MIN(notej_len, nb_cons_cols - off);
|
|
if (compact) {
|
|
off -= (j / 2);
|
|
} else {
|
|
if (j % 2) {
|
|
off--;
|
|
}
|
|
}
|
|
memcpy(out + off, note[j], sz);
|
|
if (sz < notej_len) {
|
|
out[off + sz - 2] = '.';
|
|
out[off + sz - 1] = '.';
|
|
}
|
|
hasline = (out[off] != ' ');
|
|
RZ_FREE(note[j]);
|
|
}
|
|
}
|
|
out[out_sz - 1] = 0;
|
|
if (hasline) {
|
|
rz_cons_strcat(addrpad);
|
|
rz_cons_strcat(out);
|
|
rz_cons_newline();
|
|
}
|
|
marks = false;
|
|
free(out);
|
|
}
|
|
rz_cons_strcat(bytes);
|
|
rz_cons_strcat(chars);
|
|
|
|
if (core->print->use_comments) {
|
|
for (j = 0; j < nb_cols; j++) {
|
|
const char *comment = core->print->get_comments(core->print->user, addr + j);
|
|
if (comment) {
|
|
rz_cons_printf(" ; %s", comment);
|
|
}
|
|
}
|
|
}
|
|
|
|
rz_cons_newline();
|
|
addr += nb_cols;
|
|
}
|
|
|
|
err_ebytes:
|
|
free(bytes);
|
|
err_bytes:
|
|
free(note);
|
|
err_note:
|
|
free(chars);
|
|
err_chars:
|
|
for (i = 0; i < RZ_ARRAY_SIZE(colors); i++) {
|
|
free(colors[i]);
|
|
}
|
|
}
|
|
|
|
RZ_API void rz_core_print_examine(RzCore *core, const char *str) {
|
|
char cmd[128], *p;
|
|
ut64 addr = core->offset;
|
|
int size = (core->analysis->bits / 4);
|
|
int count = atoi(str);
|
|
int i, n;
|
|
if (count < 1) {
|
|
count = 1;
|
|
}
|
|
// skipspaces
|
|
while (*str >= '0' && *str <= '9') {
|
|
str++;
|
|
}
|
|
// "px/" alone isn't a full command.
|
|
if (!str[0]) {
|
|
return;
|
|
}
|
|
switch (str[1]) {
|
|
case 'b': size = 1; break;
|
|
case 'h': size = 2; break;
|
|
case 'd': size = 4; break;
|
|
case 'w': size = 4; break;
|
|
case 'g': size = 8; break;
|
|
}
|
|
if ((p = strchr(str, ' '))) {
|
|
*p++ = 0;
|
|
addr = rz_num_math(core->num, p);
|
|
}
|
|
switch (*str) {
|
|
case '?':
|
|
eprintf(
|
|
"Format is x/[num][format][size]\n"
|
|
"Num specifies the number of format elements to display\n"
|
|
"Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n"
|
|
" t(binary), f(float), a(address), i(instruction), c(char) and s(string),\n"
|
|
" T(OSType), A(floating point values in hex).\n"
|
|
"Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n");
|
|
break;
|
|
case 's': // "x/s"
|
|
rz_core_cmdf(core, "psb @! %d @ 0x%" PFMT64x, count * size, addr);
|
|
break;
|
|
case 'o': // "x/o"
|
|
rz_core_cmdf(core, "pxo %d @ 0x%" PFMT64x, count * size, addr);
|
|
break;
|
|
case 'f':
|
|
case 'A': // XXX (float in hex)
|
|
n = 3;
|
|
snprintf(cmd, sizeof(cmd), "pxo %d @ 0x%" PFMT64x,
|
|
count * size, addr);
|
|
strcpy(cmd, "pf ");
|
|
for (i = 0; i < count && n < sizeof(cmd); i++) {
|
|
cmd[n++] = 'f';
|
|
}
|
|
cmd[n] = 0;
|
|
rz_core_cmd0(core, cmd);
|
|
break;
|
|
case 'x':
|
|
switch (size) {
|
|
default:
|
|
case 1:
|
|
rz_core_cmdf(core, "px %d @ 0x%" PFMT64x, count, addr);
|
|
break;
|
|
case 2:
|
|
rz_core_cmdf(core, "px%c %d @ 0x%" PFMT64x,
|
|
'h', count * 2, addr);
|
|
break;
|
|
case 4:
|
|
rz_core_cmdf(core, "px%c %d @ 0x%" PFMT64x,
|
|
'w', count * 4, addr);
|
|
break;
|
|
case 8:
|
|
rz_core_cmdf(core, "px%c %d @ 0x%" PFMT64x,
|
|
'q', count * 8, addr);
|
|
break;
|
|
}
|
|
break;
|
|
case 'a':
|
|
case 'd':
|
|
rz_core_cmdf(core, "pxw %d @ 0x%" PFMT64x, count * size, addr);
|
|
break;
|
|
case 'i':
|
|
rz_core_cmdf(core, "pdq %d @ 0x%" PFMT64x, count, addr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool cmd_print_pxA(RzCore *core, int len, RzOutputMode mode) {
|
|
if (!len) {
|
|
return false;
|
|
}
|
|
RzConsPrintablePalette *pal = &core->cons->context->pal;
|
|
int show_offset = true;
|
|
int cols = rz_config_get_i(core->config, "hex.cols");
|
|
int show_color = rz_config_get_i(core->config, "scr.color");
|
|
int onechar = rz_config_get_i(core->config, "hex.onechar");
|
|
bool hex_offset = rz_config_get_i(core->config, "hex.offset");
|
|
int bgcolor_in_heap = false;
|
|
bool show_cursor = core->print->cur_enabled;
|
|
char buf[2];
|
|
char *bgcolor, *fgcolor, *text;
|
|
ut64 i, c, oi;
|
|
RzAnalysisOp op = { 0 };
|
|
ut8 *data;
|
|
int datalen;
|
|
switch (mode) {
|
|
case RZ_OUTPUT_MODE_LONG:
|
|
datalen = cols * 8 * core->cons->rows;
|
|
data = malloc(datalen);
|
|
rz_io_read_at(core->io, core->offset, data, datalen);
|
|
len = datalen;
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
data = core->block;
|
|
datalen = core->blocksize;
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
return false;
|
|
}
|
|
if (len < 1) {
|
|
len = datalen;
|
|
}
|
|
if (len < 0 || len > datalen) {
|
|
RZ_LOG_ERROR("core: Invalid length\n");
|
|
return false;
|
|
}
|
|
if (onechar) {
|
|
cols *= 4;
|
|
} else {
|
|
cols *= 2;
|
|
}
|
|
if (show_offset) {
|
|
char offstr[128];
|
|
snprintf(offstr, sizeof(offstr),
|
|
"0x%08" PFMT64x " ", core->offset);
|
|
if (strlen(offstr) > 12) {
|
|
cols -= ((strlen(offstr) - 12) * 2);
|
|
}
|
|
}
|
|
for (oi = i = c = 0; i < len; c++) {
|
|
if (i && (cols != 0) && !(c % cols)) {
|
|
show_offset = true;
|
|
rz_cons_printf(" %" PFMT64u "\n", i - oi);
|
|
oi = i;
|
|
}
|
|
if (show_offset && hex_offset) {
|
|
rz_cons_printf("0x%08" PFMT64x " ", core->offset + i);
|
|
show_offset = false;
|
|
}
|
|
if (bgcolor_in_heap) {
|
|
free(bgcolor);
|
|
bgcolor_in_heap = false;
|
|
}
|
|
bgcolor = Color_BGBLACK;
|
|
fgcolor = Color_WHITE;
|
|
text = NULL;
|
|
rz_analysis_op_init(&op);
|
|
if (rz_analysis_op(core->analysis, &op, core->offset + i, data + i, len - i, RZ_ANALYSIS_OP_MASK_BASIC) <= 0) {
|
|
op.type = 0;
|
|
bgcolor = Color_BGRED;
|
|
op.size = 1;
|
|
}
|
|
switch (op.type) {
|
|
case RZ_ANALYSIS_OP_TYPE_LEA:
|
|
case RZ_ANALYSIS_OP_TYPE_MOV:
|
|
case RZ_ANALYSIS_OP_TYPE_CAST:
|
|
case RZ_ANALYSIS_OP_TYPE_LENGTH:
|
|
case RZ_ANALYSIS_OP_TYPE_CMOV:
|
|
text = "mv";
|
|
bgcolor = pal->mov;
|
|
fgcolor = Color_YELLOW;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_PUSH:
|
|
case RZ_ANALYSIS_OP_TYPE_UPUSH:
|
|
case RZ_ANALYSIS_OP_TYPE_RPUSH:
|
|
bgcolor = pal->push;
|
|
fgcolor = Color_WHITE;
|
|
text = "->";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_IO:
|
|
bgcolor = pal->swi;
|
|
fgcolor = Color_WHITE;
|
|
text = "io";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_TRAP:
|
|
case RZ_ANALYSIS_OP_TYPE_SWI:
|
|
case RZ_ANALYSIS_OP_TYPE_NEW:
|
|
// bgcolor = Color_BGRED;
|
|
bgcolor = pal->trap; // rz_cons_swap_ground (pal->trap);
|
|
fgcolor = Color_WHITE;
|
|
text = "$$";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_POP:
|
|
text = "<-";
|
|
bgcolor = rz_cons_swap_ground(pal->pop);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_NOP:
|
|
fgcolor = Color_WHITE;
|
|
bgcolor = rz_cons_swap_ground(pal->nop);
|
|
bgcolor_in_heap = true;
|
|
text = "..";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_MUL:
|
|
fgcolor = Color_BLACK;
|
|
bgcolor = rz_cons_swap_ground(pal->math);
|
|
bgcolor_in_heap = true;
|
|
text = "_*";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_DIV:
|
|
bgcolor = rz_cons_swap_ground(pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_/";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_AND:
|
|
bgcolor = rz_cons_swap_ground(pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_&";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_XOR:
|
|
bgcolor = rz_cons_swap_ground(pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_^";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_OR:
|
|
bgcolor = rz_cons_swap_ground(pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_|";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SHR:
|
|
bgcolor = rz_cons_swap_ground(pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = ">>";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SHL:
|
|
bgcolor = rz_cons_swap_ground(pal->bin);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "<<";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_SUB:
|
|
bgcolor = rz_cons_swap_ground(pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "--";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ADD:
|
|
bgcolor = rz_cons_swap_ground(pal->math);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "++";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_JMP:
|
|
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_IJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_RJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_IRJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_MJMP:
|
|
bgcolor = rz_cons_swap_ground(pal->jmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "_J";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_UCJMP:
|
|
bgcolor = rz_cons_swap_ground(pal->cjmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "cJ";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_CALL:
|
|
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_ICALL:
|
|
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_IRCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_UCCALL:
|
|
bgcolor = rz_cons_swap_ground(pal->call);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "_C";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_ACMP:
|
|
case RZ_ANALYSIS_OP_TYPE_CMP:
|
|
bgcolor = rz_cons_swap_ground(pal->cmp);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_BLACK;
|
|
text = "==";
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_RET:
|
|
bgcolor = rz_cons_swap_ground(pal->ret);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "_R";
|
|
break;
|
|
case -1:
|
|
case RZ_ANALYSIS_OP_TYPE_ILL:
|
|
case RZ_ANALYSIS_OP_TYPE_UNK:
|
|
bgcolor = rz_cons_swap_ground(pal->invalid);
|
|
bgcolor_in_heap = true;
|
|
fgcolor = Color_WHITE;
|
|
text = "XX";
|
|
break;
|
|
}
|
|
int opsz = RZ_MAX(op.size, 1);
|
|
if (show_cursor) {
|
|
if (core->print->cur >= i && core->print->cur < i + opsz) {
|
|
rz_cons_invert(1, 1);
|
|
}
|
|
}
|
|
if (onechar) {
|
|
if (text) {
|
|
if (text[0] == '_' || text[0] == '.') {
|
|
buf[0] = text[1];
|
|
} else {
|
|
buf[0] = text[0];
|
|
}
|
|
} else {
|
|
buf[0] = '.';
|
|
}
|
|
buf[1] = 0;
|
|
text = buf;
|
|
}
|
|
if (show_color) {
|
|
if (!text) {
|
|
text = " ";
|
|
}
|
|
rz_cons_printf("%s%s%s\x1b[0m", bgcolor, fgcolor, text);
|
|
} else {
|
|
if (text) {
|
|
rz_cons_print(text);
|
|
} else {
|
|
rz_cons_print(" ");
|
|
}
|
|
}
|
|
if (show_cursor) {
|
|
if (core->print->cur >= i && core->print->cur < i + opsz) {
|
|
rz_cons_invert(0, 1);
|
|
}
|
|
}
|
|
i += opsz;
|
|
rz_analysis_op_fini(&op);
|
|
}
|
|
rz_cons_printf(" %" PFMT64d "\n", i - oi);
|
|
if (bgcolor_in_heap) {
|
|
free(bgcolor);
|
|
}
|
|
if (data != core->block) {
|
|
free(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Uses data from clipboard if value is NULL */
|
|
static bool print_operation_transform(RzCore *core, RzCoreWriteOp op, RZ_NULLABLE const char *val) {
|
|
ut8 *hex = NULL;
|
|
size_t hexlen = 0, buflen = 0;
|
|
if (val) {
|
|
hex = RZ_NEWS(ut8, (strlen(val) + 1) / 2);
|
|
if (!hex) {
|
|
return false;
|
|
}
|
|
hexlen = rz_hex_str2bin(val, hex);
|
|
}
|
|
ut8 *buf = rz_core_transform_op(core, core->offset, op, hex, hexlen, &buflen);
|
|
free(hex);
|
|
rz_core_print_hexdump(core, core->offset, buf, buflen, 16, 1, 1);
|
|
free(buf);
|
|
return true;
|
|
}
|
|
|
|
static void handle_entropy(RzCore *core, const char *name, const ut8 *block, int len) {
|
|
RzHashSize digest_size = 0;
|
|
ut8 *digest = rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
|
|
if (!digest) {
|
|
return;
|
|
}
|
|
double entropy = rz_read_be_double(digest);
|
|
rz_cons_printf("%f\n", entropy);
|
|
free(digest);
|
|
}
|
|
|
|
static void handle_ssdeep(RzCore *core, const char *name, const ut8 *block, int len) {
|
|
RzHashSize digest_size = 0;
|
|
char *digest = (char *)rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
|
|
if (!digest) {
|
|
return;
|
|
}
|
|
rz_cons_printf("%s\n", digest);
|
|
free(digest);
|
|
}
|
|
|
|
static inline void hexprint(const ut8 *data, int len) {
|
|
if (!data || len < 1) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < len; i++) {
|
|
rz_cons_printf("%02x", data[i]);
|
|
}
|
|
rz_cons_newline();
|
|
}
|
|
|
|
static void handle_hash_cfg(RzCore *core, const char *name, const ut8 *block, int len) {
|
|
RzHashSize digest_size = 0;
|
|
ut8 *digest = rz_hash_cfg_calculate_small_block(core->hash, name, block, len, &digest_size);
|
|
hexprint(digest, digest_size);
|
|
free(digest);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_hash_cfg_handler(RzCore *core, int argc, const char **argv) {
|
|
const RzHashPlugin *plugin = rz_hash_plugin_by_name(core->hash, argv[1]);
|
|
|
|
if (!plugin) {
|
|
RZ_LOG_ERROR("algorithm '%s' does not exists\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
if (!strncmp(plugin->name, "entropy", strlen("entropy"))) {
|
|
handle_entropy(core, plugin->name, core->block, core->blocksize);
|
|
} else if (!strcmp(plugin->name, "ssdeep")) {
|
|
handle_ssdeep(core, plugin->name, core->block, core->blocksize);
|
|
} else {
|
|
handle_hash_cfg(core, plugin->name, core->block, core->blocksize);
|
|
}
|
|
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_hash_cfg_algo_list_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_core_hash_plugins_print(core->hash, state);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_magic_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzList *hits = rz_core_search_magic(core, NULL, argc > 1 ? argv[1] : NULL);
|
|
if (!hits) {
|
|
RZ_LOG_ERROR("Searching for magics failed.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzListIter *it;
|
|
RzSearchHit *hit;
|
|
if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
PJ *pj = pj_new();
|
|
pj_a(pj);
|
|
rz_list_foreach (hits, it, hit) {
|
|
pj_o(pj);
|
|
pj_kn(pj, "address", hit->address);
|
|
pj_ks(pj, "magic", hit->comment);
|
|
pj_end(pj);
|
|
}
|
|
pj_end(pj);
|
|
rz_cons_println(pj_string(pj));
|
|
pj_free(pj);
|
|
} else {
|
|
rz_list_foreach (hits, it, hit) {
|
|
rz_cons_printf("0x%08" PFMT64x " %s\n", hit->address, hit->comment);
|
|
}
|
|
}
|
|
rz_list_free(hits);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static int bbcmp(RzAnalysisBlock *a, RzAnalysisBlock *b, void *user) {
|
|
return a->addr - b->addr;
|
|
}
|
|
|
|
/* TODO: integrate this into rz_analysis */
|
|
static void _pointer_table(RzCore *core, ut64 origin, ut64 offset, const ut8 *buf, int len, int step, RzOutputMode mode) {
|
|
if (step < 1) {
|
|
step = 4;
|
|
}
|
|
if (!rz_io_is_valid_offset(core->io, origin, 0) ||
|
|
!rz_io_is_valid_offset(core->io, offset, 0)) {
|
|
return;
|
|
}
|
|
if (origin != offset) {
|
|
if (mode == RZ_OUTPUT_MODE_RIZIN) {
|
|
rz_cons_printf("CC-@ 0x%08" PFMT64x "\n", origin);
|
|
rz_cons_printf("CC switch table @ 0x%08" PFMT64x "\n", origin);
|
|
rz_cons_printf("axd 0x%" PFMT64x " @ 0x%08" PFMT64x "\n", origin, offset);
|
|
}
|
|
}
|
|
for (size_t i = 0, n = 0; (i + sizeof(st32)) <= len; i += step, n++) {
|
|
st32 delta = rz_read_le32(buf + i);
|
|
ut64 addr = offset + delta;
|
|
if (!rz_io_is_valid_offset(core->io, addr, 0)) {
|
|
// Lets check for jmptbl with not relative addresses
|
|
// Like: jmp dword [eax*4 + jmptbl.0x5435345]
|
|
if (!rz_io_is_valid_offset(core->io, delta, 0)) {
|
|
break;
|
|
}
|
|
addr = delta;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_RIZIN) {
|
|
rz_cons_printf("af case.%zu.0x%" PFMT64x " 0x%08" PFMT64x "\n", n, offset, addr);
|
|
rz_cons_printf("ax 0x%" PFMT64x " @ 0x%08" PFMT64x "\n", offset, addr);
|
|
rz_cons_printf("ax 0x%" PFMT64x " @ 0x%08" PFMT64x "\n", addr, offset); // wrong, but useful because forward xrefs dont work :?
|
|
// FIXME: "aho" doesn't accept anything here after the "case" word
|
|
rz_cons_printf("aho case 0x%" PFMT64x " 0x%08" PFMT64x " @ 0x%08" PFMT64x "\n", (ut64)i, addr, offset + i); // wrong, but useful because forward xrefs dont work :?
|
|
rz_cons_printf("ahs %d @ 0x%08" PFMT64x "\n", step, offset + i);
|
|
} else {
|
|
rz_cons_printf("0x%08" PFMT64x " -> 0x%08" PFMT64x "\n", offset + i, addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pr_bb(RzCore *core, RzAnalysisFunction *fcn, RzAnalysisBlock *b, bool emu, ut64 saved_gp, ut8 *saved_arena, char p_type, bool fromHere) {
|
|
bool show_flags = rz_config_get_i(core->config, "asm.flags");
|
|
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
|
|
core->analysis->gp = saved_gp;
|
|
if (fromHere) {
|
|
if (b->addr < core->offset) {
|
|
core->cons->null = true;
|
|
} else {
|
|
core->cons->null = false;
|
|
}
|
|
}
|
|
if (emu) {
|
|
if (b->parent_reg_arena) {
|
|
ut64 gp;
|
|
rz_reg_arena_poke(core->analysis->reg, b->parent_reg_arena);
|
|
RZ_FREE(b->parent_reg_arena);
|
|
gp = rz_reg_getv(core->analysis->reg, "gp");
|
|
if (gp) {
|
|
core->analysis->gp = gp;
|
|
}
|
|
} else {
|
|
rz_reg_arena_poke(core->analysis->reg, saved_arena);
|
|
}
|
|
}
|
|
rz_config_set_b(core->config, "asm.bb.middle", false);
|
|
p_type == 'D'
|
|
? rz_core_cmdf(core, "pD %" PFMT64u " @ 0x%" PFMT64x, b->size, b->addr)
|
|
: rz_core_cmdf(core, "pI %" PFMT64u " @ 0x%" PFMT64x, b->size, b->addr);
|
|
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
|
|
|
|
if (b->jump != UT64_MAX) {
|
|
if (b->jump > b->addr) {
|
|
RzAnalysisBlock *jumpbb = rz_analysis_get_block_at(b->analysis, b->jump);
|
|
if (jumpbb && rz_list_contains(jumpbb->fcns, fcn)) {
|
|
if (emu && core->analysis->last_disasm_reg && !jumpbb->parent_reg_arena) {
|
|
jumpbb->parent_reg_arena = rz_reg_arena_dup(core->analysis->reg, core->analysis->last_disasm_reg);
|
|
}
|
|
}
|
|
}
|
|
if (p_type == 'D' && show_flags) {
|
|
rz_cons_printf("| ----------- true: 0x%08" PFMT64x, b->jump);
|
|
}
|
|
}
|
|
if (b->fail != UT64_MAX) {
|
|
if (b->fail > b->addr) {
|
|
RzAnalysisBlock *failbb = rz_analysis_get_block_at(b->analysis, b->fail);
|
|
if (failbb && rz_list_contains(failbb->fcns, fcn)) {
|
|
if (emu && core->analysis->last_disasm_reg && !failbb->parent_reg_arena) {
|
|
failbb->parent_reg_arena = rz_reg_arena_dup(core->analysis->reg, core->analysis->last_disasm_reg);
|
|
}
|
|
}
|
|
}
|
|
if (p_type == 'D' && show_flags) {
|
|
rz_cons_printf(" false: 0x%08" PFMT64x, b->fail);
|
|
}
|
|
}
|
|
if (p_type == 'D' && show_flags) {
|
|
rz_cons_newline();
|
|
}
|
|
}
|
|
|
|
static void handle_default_disasm_print_mode(const RzCore *core, const ut64 addr, const bool ret_val,
|
|
const char *m_intr, RzStrBuf *buf) {
|
|
const bool show_color = rz_config_get_i(core->config, "scr.color");
|
|
|
|
if (show_color) {
|
|
const char *offsetColor = rz_cons_singleton()->context->pal.offset;
|
|
if (!ret_val) {
|
|
rz_cons_printf("%s0x%08" PFMT64x "" Color_RESET " %10s %s\n",
|
|
offsetColor, addr, "", m_intr);
|
|
} else {
|
|
rz_strbuf_appendf(buf, "%s0x%08" PFMT64x "" Color_RESET " %10s %s\n",
|
|
offsetColor, addr, "", m_intr);
|
|
}
|
|
} else {
|
|
if (!ret_val) {
|
|
rz_cons_printf("0x%08" PFMT64x " %10s %s\n", addr, "", m_intr);
|
|
} else {
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x " %10s %s\n", addr, "", m_intr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void disasm_print_ret(const RzCore *core, const RzOutputMode mode, const char *m_intr, const ut64 addr,
|
|
const bool ret_val, RzStrBuf *buf) {
|
|
if (!buf && ret_val) {
|
|
return;
|
|
}
|
|
switch (mode) {
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
if (!ret_val) {
|
|
rz_cons_printf("%s\n", m_intr);
|
|
} else {
|
|
rz_strbuf_append(buf, m_intr);
|
|
}
|
|
break;
|
|
default:
|
|
handle_default_disasm_print_mode(core, addr, ret_val, m_intr, buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Disassemble from \p addr until \p limit no of instructions and
|
|
* prints or returns the disassembled string in \p buf
|
|
*
|
|
* \param core Pointer to the RzCore
|
|
* \param addr Address to start disassembling
|
|
* \param limit Maximum number of instructions to disassemble
|
|
* \param mode The mode in which data has to be printed/crafted
|
|
* \param ret_val If true, the disassembled string is stored in \p buf. Otherwise it is streamed to stdout
|
|
* \param buf Pointer to the RzStrBuf to store the disassembled string
|
|
*
|
|
* \return True if there are no errors during disassembling and crafting the response. False otherwise.
|
|
*/
|
|
RZ_API bool rz_core_disasm_until_ret(RZ_NONNULL RzCore *core, ut64 addr, const int limit,
|
|
const RzOutputMode mode, const bool ret_val, RZ_NULLABLE RZ_OUT RzStrBuf *buf) {
|
|
rz_return_val_if_fail(core, false);
|
|
if (!buf && ret_val) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < limit; i++) {
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, addr, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_DISASM);
|
|
if (!op) {
|
|
RZ_LOG_ERROR("Cannot get op at 0x%08" PFMT64x "\n", addr);
|
|
rz_analysis_op_free(op);
|
|
break;
|
|
}
|
|
const char *mnem = op->mnemonic;
|
|
disasm_print_ret(core, mode, mnem, addr, ret_val, buf);
|
|
switch (op->type & RZ_ANALYSIS_OP_MASK_WILDCARD) {
|
|
case RZ_ANALYSIS_OP_TYPE_RET:
|
|
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
|
rz_analysis_op_free(op);
|
|
goto beach;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (op->type == RZ_ANALYSIS_OP_TYPE_JMP) {
|
|
addr = op->jump;
|
|
} else {
|
|
addr += op->size;
|
|
}
|
|
if (ret_val) {
|
|
rz_strbuf_append(buf, "\n");
|
|
}
|
|
rz_analysis_op_free(op);
|
|
}
|
|
beach:
|
|
return true;
|
|
}
|
|
|
|
static void func_walk_blocks(RzCore *core, RzAnalysisFunction *f, bool fromHere, RzCmdStateOutput *state) {
|
|
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
|
|
rz_config_set_b(core->config, "asm.bb.middle", false);
|
|
|
|
rz_pvector_sort(f->bbs, (RzPVectorComparator)bbcmp, NULL);
|
|
|
|
RzAnalysisBlock *b;
|
|
void **iter;
|
|
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
rz_cmd_state_output_array_start(state);
|
|
|
|
rz_pvector_foreach (f->bbs, iter) {
|
|
b = (RzAnalysisBlock *)*iter;
|
|
if (fromHere) {
|
|
if (b->addr < core->offset) {
|
|
core->cons->null = true;
|
|
} else {
|
|
core->cons->null = false;
|
|
}
|
|
}
|
|
ut8 *buf = malloc(b->size);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: cannot allocate %" PFMT64u " byte(s)\n", b->size);
|
|
return;
|
|
}
|
|
rz_io_read_at(core->io, b->addr, buf, b->size);
|
|
rz_core_print_disasm_json(core, b->addr, buf, b->size, 0, state->d.pj);
|
|
free(buf);
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
} else {
|
|
bool asm_lines = rz_config_get_i(core->config, "asm.lines.bb");
|
|
bool emu = rz_config_get_i(core->config, "asm.emu");
|
|
ut64 saved_gp = 0;
|
|
ut8 *saved_arena = NULL;
|
|
if (emu) {
|
|
saved_gp = core->analysis->gp;
|
|
saved_arena = rz_reg_arena_peek(core->analysis->reg);
|
|
}
|
|
rz_config_set_i(core->config, "asm.lines.bb", 0);
|
|
|
|
rz_pvector_foreach (f->bbs, iter) {
|
|
b = (RzAnalysisBlock *)*iter;
|
|
pr_bb(core, f, b, emu, saved_gp, saved_arena, 'I', fromHere);
|
|
}
|
|
if (emu) {
|
|
core->analysis->gp = saved_gp;
|
|
if (saved_arena) {
|
|
rz_reg_arena_poke(core->analysis->reg, saved_arena);
|
|
RZ_FREE(saved_arena);
|
|
}
|
|
}
|
|
rz_config_set_i(core->config, "asm.lines.bb", asm_lines);
|
|
}
|
|
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
|
|
}
|
|
|
|
static inline char cmd_pxb_p(char input) {
|
|
return IS_PRINTABLE(input) ? input : '.';
|
|
}
|
|
|
|
static inline ut32 cmd_pxb_k(const ut8 *buffer, int x) {
|
|
return ((ut32)buffer[3 - x]) << (8 * x);
|
|
}
|
|
|
|
static void print_json_string(RzCore *core, const ut8 *block, ut32 len, RzStrEnc encoding, bool stop_at_nil, bool stop_at_unprintable) {
|
|
char *section = get_section_name(core, core->offset);
|
|
if (!section) {
|
|
return;
|
|
}
|
|
ut32 dlength = 0;
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = block;
|
|
opt.length = len;
|
|
opt.encoding = encoding;
|
|
opt.json = true;
|
|
opt.stop_at_nil = stop_at_nil;
|
|
opt.stop_at_unprintable = stop_at_unprintable;
|
|
char *dstring = rz_str_stringify_raw_buffer(&opt, &dlength);
|
|
if (!dstring) {
|
|
free(section);
|
|
return;
|
|
}
|
|
|
|
PJ *pj = pj_new();
|
|
if (!pj) {
|
|
free(section);
|
|
free(dstring);
|
|
return;
|
|
}
|
|
|
|
const char *enc_name = rz_str_enc_as_string(encoding);
|
|
pj_o(pj);
|
|
pj_k(pj, "string");
|
|
pj_raw(pj, "\"");
|
|
pj_raw(pj, dstring);
|
|
pj_raw(pj, "\"");
|
|
pj_kn(pj, "offset", core->offset);
|
|
pj_ks(pj, "section", section);
|
|
pj_kn(pj, "length", dlength);
|
|
pj_ks(pj, "type", enc_name);
|
|
pj_end(pj);
|
|
rz_cons_println(pj_string(pj));
|
|
pj_free(pj);
|
|
free(section);
|
|
free(dstring);
|
|
}
|
|
|
|
static char *__op_refs(RzCore *core, RzAnalysisOp *op, int n) {
|
|
RzStrBuf *sb = rz_strbuf_new("");
|
|
if (n) {
|
|
// RzList *list = rz_analysis_xrefs_get_from (core->analysis, op->addr);
|
|
RzList *list = rz_analysis_xrefs_get_to(core->analysis, op->addr);
|
|
RzAnalysisXRef *xref;
|
|
RzListIter *iter;
|
|
rz_list_foreach (list, iter, xref) {
|
|
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", xref->to);
|
|
}
|
|
} else {
|
|
if (op->jump != UT64_MAX) {
|
|
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->jump);
|
|
}
|
|
if (op->fail != UT64_MAX) {
|
|
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->fail);
|
|
}
|
|
if (op->ptr != UT64_MAX) {
|
|
if (rz_io_is_valid_offset(core->io, op->ptr, false)) {
|
|
rz_strbuf_appendf(sb, "0x%08" PFMT64x " ", op->ptr);
|
|
}
|
|
}
|
|
}
|
|
char *res = rz_strbuf_drain(sb);
|
|
rz_str_trim(res);
|
|
return res;
|
|
}
|
|
|
|
static inline char *__refs(RzCore *core, ut64 x) {
|
|
if (!core->print->hasrefs) {
|
|
return NULL;
|
|
}
|
|
|
|
char *refs = core->print->hasrefs(core->print->user, x, true);
|
|
if (RZ_STR_ISNOTEMPTY(refs)) {
|
|
rz_str_trim(refs);
|
|
} else {
|
|
RZ_FREE(refs);
|
|
}
|
|
return refs;
|
|
}
|
|
|
|
static bool cmd_pxr(RzCore *core, ut64 at, int len, RzCmdStateOutput *state, int wordsize, const char *query) {
|
|
if (!len) {
|
|
return true;
|
|
}
|
|
RzStrBuf *sb = rz_strbuf_new(NULL);
|
|
if (!sb) {
|
|
return false;
|
|
}
|
|
|
|
const ut8 *buf = core->block;
|
|
|
|
bool be = core->analysis->big_endian;
|
|
int end = RZ_MIN(core->blocksize, len);
|
|
int bitsize = wordsize * 8;
|
|
RzOutputMode mode = state->mode;
|
|
if (mode == RZ_OUTPUT_MODE_TABLE) {
|
|
RzTable *t = state->d.t;
|
|
RzTableColumnType *n = rz_table_type("number");
|
|
RzTableColumnType *s = rz_table_type("string");
|
|
rz_table_add_column(t, n, "addr", 0);
|
|
rz_table_add_column(t, n, "value", 0);
|
|
rz_table_add_column(t, s, "refs", 0);
|
|
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
|
|
ut64 addr = at + i;
|
|
ut64 val = rz_read_ble(buf + i, be, bitsize);
|
|
char *refs = __refs(core, val);
|
|
rz_table_add_rowf(t, "xxs", addr, val, refs);
|
|
RZ_FREE(refs);
|
|
}
|
|
rz_table_query(t, query);
|
|
} else if (mode == RZ_OUTPUT_MODE_JSON) {
|
|
PJ *pj = state->d.pj;
|
|
const int hex_depth = (int)rz_config_get_i(core->config, "hex.depth");
|
|
pj_a(pj);
|
|
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
|
|
ut64 addr = at + i;
|
|
ut64 val = rz_read_ble(buf + i, be, bitsize);
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", addr);
|
|
pj_kn(pj, "value", val);
|
|
char *refs = __refs(core, val);
|
|
if (refs) {
|
|
char *refstr = rz_str_escape(refs);
|
|
pj_ks(pj, "refstr", rz_str_trim_head_ro(refstr));
|
|
free(refstr);
|
|
|
|
pj_k(pj, "ref");
|
|
free(rz_core_analysis_hasrefs_to_depth(core, val, pj, hex_depth));
|
|
}
|
|
pj_end(pj);
|
|
}
|
|
pj_end(pj);
|
|
} else if (mode == RZ_OUTPUT_MODE_QUIET) {
|
|
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
|
|
ut64 val = rz_read_ble(buf + i, be, bitsize);
|
|
char *refs = __refs(core, val);
|
|
rz_strbuf_appendf(sb, "%s\n", refs);
|
|
}
|
|
} else if (mode == RZ_OUTPUT_MODE_RIZIN) {
|
|
for (ut64 i = 0; i + wordsize < end; i += wordsize) {
|
|
ut64 addr = at + i;
|
|
ut64 val = rz_read_ble(buf + i, be, bitsize);
|
|
rz_strbuf_appendf(sb, "f pxr.%" PFMT64x " @ 0x%" PFMT64x "\n", val, addr);
|
|
}
|
|
} else if (mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
char *hexdump_str = rz_core_print_hexdump_refs(core, core->offset, len, wordsize);
|
|
rz_strbuf_append(sb, hexdump_str);
|
|
free(hexdump_str);
|
|
} else {
|
|
rz_warn_if_reached();
|
|
rz_strbuf_free(sb);
|
|
return false;
|
|
}
|
|
if (mode == RZ_OUTPUT_MODE_RIZIN || mode == RZ_OUTPUT_MODE_STANDARD || mode == RZ_OUTPUT_MODE_QUIET) {
|
|
char *res = rz_strbuf_drain(sb);
|
|
rz_cons_print(res);
|
|
free(res);
|
|
} else {
|
|
rz_strbuf_free(sb);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void core_print_2bpp_row(const ut8 *buf, bool useColor) {
|
|
const char *symbols = "#=-.";
|
|
for (ut32 i = 0, c = 0; i < 8; i++) {
|
|
if (buf[1] & ((1 << 7) >> i)) {
|
|
c = 2;
|
|
}
|
|
if (buf[0] & ((1 << 7) >> i)) {
|
|
c++;
|
|
}
|
|
if (useColor) {
|
|
char *color = "";
|
|
switch (c) {
|
|
case 0:
|
|
color = Color_BGWHITE;
|
|
break;
|
|
case 1:
|
|
color = Color_BGRED;
|
|
break;
|
|
case 2:
|
|
color = Color_BGBLUE;
|
|
break;
|
|
case 3:
|
|
color = Color_BGBLACK;
|
|
break;
|
|
}
|
|
rz_cons_printf("%s ", color);
|
|
} else {
|
|
const char ch = symbols[c % 4];
|
|
rz_cons_printf("%c%c", ch, ch);
|
|
}
|
|
c = 0;
|
|
}
|
|
}
|
|
|
|
static void core_print_2bpp_tiles(RzCore *core, ut32 tiles) {
|
|
const ut8 *buf = core->block;
|
|
bool useColor = rz_config_get_i(core->config, "scr.color") > 0;
|
|
for (ut32 i = 0; i < 8; i++) {
|
|
for (ut32 r = 0; r < tiles; r++) {
|
|
core_print_2bpp_row(buf + 2 * i + r * 16, useColor);
|
|
}
|
|
if (useColor) {
|
|
rz_cons_printf(Color_RESET "\n");
|
|
} else {
|
|
rz_cons_printf("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void core_print_raw_buffer(RzStrStringifyOpt *opt) {
|
|
char *str = rz_str_stringify_raw_buffer(opt, NULL);
|
|
if (str) {
|
|
rz_cons_strcat(str);
|
|
free(str);
|
|
}
|
|
}
|
|
|
|
static RzCmdStatus core_print_string_in_block(RzCore *core, bool stop_at_nil, bool stop_at_unprintable, ut32 offset, RzOutputMode mode, RzStrEnc str_encoding) {
|
|
const ut8 *buffer = core->block + offset;
|
|
const ut32 length = core->blocksize - offset;
|
|
RzStrEnc encoding = str_encoding == RZ_STRING_ENC_SETTINGS ? core->bin->str_search_cfg.string_encoding : str_encoding;
|
|
RzStrStringifyOpt opt = { 0 };
|
|
|
|
if (encoding == RZ_STRING_ENC_GUESS) {
|
|
encoding = rz_str_guess_encoding_from_buffer(buffer, length);
|
|
}
|
|
|
|
switch (mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
opt.buffer = buffer;
|
|
opt.length = length;
|
|
opt.encoding = encoding;
|
|
opt.stop_at_nil = stop_at_nil;
|
|
opt.stop_at_unprintable = stop_at_unprintable;
|
|
core_print_raw_buffer(&opt);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
print_json_string(core, buffer, length, encoding, stop_at_nil, stop_at_nil);
|
|
break;
|
|
default:
|
|
RZ_LOG_ERROR("core: unsupported output mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// "ps"
|
|
RZ_IPI RzCmdStatus rz_print_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
bool stop_at_nil = !strcmp(argv[2], "null");
|
|
bool stop_at_unprintable = !strcmp(argv[2], "unprintable");
|
|
RzStrEnc enc = rz_str_enc_string_as_type(argv[1]);
|
|
return core_print_string_in_block(core, stop_at_nil, stop_at_unprintable, 0, mode, enc);
|
|
}
|
|
|
|
// "ps+"
|
|
RZ_IPI RzCmdStatus rz_print_string_as_libcpp_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
ut32 bitness = (ut32)rz_config_get_i(core->config, "asm.bits");
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
|
|
switch (bitness) {
|
|
case 32:
|
|
/* fall-thru */
|
|
case 64:
|
|
break;
|
|
default:
|
|
RZ_LOG_ERROR("core: %u bits are not supported by %s\n", bitness, argv[0]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut32 min_size = (bitness / 8) * 3;
|
|
if (core->blocksize < 2 || core->blocksize < min_size) {
|
|
RZ_LOG_ERROR("core: the block size is too small to read string (expected at least %u but got %u bytes).\n", core->blocksize, min_size);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RzCmdStatus status = RZ_CMD_STATUS_ERROR;
|
|
if (*core->block & 0x1) { // "long" string
|
|
const ut8 *ptr = core->block + (bitness / 8) * 2;
|
|
ut64 old_offset = core->offset;
|
|
ut64 new_offset = rz_read_ble(ptr, big_endian, bitness);
|
|
|
|
rz_core_seek(core, new_offset, SEEK_SET);
|
|
rz_core_block_read(core);
|
|
|
|
status = core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_SETTINGS);
|
|
|
|
rz_core_seek(core, old_offset, SEEK_SET);
|
|
rz_core_block_read(core);
|
|
} else {
|
|
status = core_print_string_in_block(core, true, false, 1, mode, RZ_STRING_ENC_SETTINGS);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// "psb"
|
|
RZ_IPI RzCmdStatus rz_print_strings_current_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzListIter *it = NULL;
|
|
RzDetectedString *detected = NULL;
|
|
RzBin *bin = core->bin;
|
|
RzUtilStrScanOptions scan_opt = {
|
|
.max_str_length = core->blocksize,
|
|
.min_str_length = bin->str_search_cfg.min_length,
|
|
.prefer_big_endian = false,
|
|
.check_ascii_freq = bin->str_search_cfg.check_ascii_freq,
|
|
};
|
|
|
|
RzList *found = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
if (!found) {
|
|
RZ_LOG_ERROR("core: failed to allocate RzList\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
if (rz_scan_strings_raw(core->block, found, &scan_opt, 0, core->blocksize, RZ_STRING_ENC_GUESS) < 0) {
|
|
rz_list_free(found);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_list_foreach (found, it, detected) {
|
|
ut64 address = core->offset + detected->addr;
|
|
if (mode != RZ_OUTPUT_MODE_QUIET) {
|
|
rz_print_offset(core->print, address, 0, 0, 0, 0, NULL);
|
|
}
|
|
RzStrEscOptions eopts = { 0 };
|
|
eopts.keep_printable = true;
|
|
char *escaped = rz_str_escape_utf8(detected->string, &eopts);
|
|
rz_cons_printf("%s", escaped);
|
|
free(escaped);
|
|
rz_cons_newline();
|
|
}
|
|
|
|
rz_list_free(found);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_first_string_current_block_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzDetectedString *detected = NULL;
|
|
RzBin *bin = core->bin;
|
|
RzUtilStrScanOptions scan_opt = {
|
|
.max_str_length = core->blocksize,
|
|
.min_str_length = bin->str_search_cfg.min_length,
|
|
.prefer_big_endian = false,
|
|
.check_ascii_freq = bin->str_search_cfg.check_ascii_freq,
|
|
};
|
|
|
|
RzList *found = rz_list_newf((RzListFree)rz_detected_string_free);
|
|
if (!found) {
|
|
RZ_LOG_ERROR("core: failed to allocate RzList\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
if (rz_scan_strings_raw(core->block, found, &scan_opt, 0, core->blocksize, RZ_STRING_ENC_GUESS) < 0) {
|
|
rz_list_free(found);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
detected = rz_list_first(found);
|
|
if (detected) {
|
|
rz_cons_memcat(detected->string, detected->size);
|
|
rz_cons_newline();
|
|
}
|
|
|
|
rz_list_free(found);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pascal_string_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzStrStringifyOpt opt = { 0 };
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
ut64 string_len = 0;
|
|
ut32 offset = 0;
|
|
|
|
if (!strcmp(argv[1], "8")) {
|
|
string_len = (ut64)core->block[0];
|
|
offset = 1;
|
|
} else if (!strcmp(argv[1], "16")) {
|
|
string_len = rz_read_ble16(core->block, big_endian);
|
|
offset = 2;
|
|
} else if (!strcmp(argv[1], "32")) {
|
|
string_len = rz_read_ble32(core->block, big_endian);
|
|
offset = 4;
|
|
} else {
|
|
string_len = rz_read_ble64(core->block, big_endian);
|
|
offset = 8;
|
|
}
|
|
|
|
if (string_len < 1) {
|
|
RZ_LOG_ERROR("core: string length is zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
if ((string_len + offset) > core->blocksize) {
|
|
RZ_LOG_ERROR("core: string length exceeds block size\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
switch (mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
opt.buffer = core->block + offset;
|
|
opt.length = string_len;
|
|
opt.encoding = RZ_STRING_ENC_8BIT;
|
|
opt.stop_at_nil = true;
|
|
opt.stop_at_unprintable = true;
|
|
core_print_raw_buffer(&opt);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
print_json_string(core, core->block + offset, string_len, RZ_STRING_ENC_8BIT, true, true);
|
|
break;
|
|
default:
|
|
RZ_LOG_ERROR("core: unsupported output mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_string_wrap_width_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
int h, w = rz_cons_get_size(&h);
|
|
int colwidth = rz_config_get_i(core->config, "hex.cols") * 2;
|
|
int width = (colwidth == 32) ? w : colwidth; // w;
|
|
ut64 blocksize = core->blocksize;
|
|
|
|
ut64 len = (h * w) / 3;
|
|
rz_core_block_size(core, len);
|
|
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = core->block;
|
|
opt.length = len;
|
|
opt.encoding = RZ_STRING_ENC_8BIT;
|
|
opt.wrap_at = width;
|
|
core_print_raw_buffer(&opt);
|
|
rz_core_block_size(core, blocksize);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_string_escaped_newlines_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = core->block;
|
|
opt.length = core->blocksize;
|
|
opt.encoding = RZ_STRING_ENC_8BIT;
|
|
opt.escape_nl = true;
|
|
core_print_raw_buffer(&opt);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_string_c_cpp_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
char *str = rz_core_print_string_c_cpp(core);
|
|
if (!str) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println(str);
|
|
free(str);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_hex_of_assembly_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
char *buf = rz_core_hex_of_assembly(core, argv[1]);
|
|
if (!buf) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println(buf);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_esil_of_assembly_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
char *buf = rz_core_esil_of_assembly(core, argv[1]);
|
|
if (!buf) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(buf);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_assembly_of_hex_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
ut8 *hex = calloc(1, strlen(argv[1]) + 1);
|
|
if (!hex) {
|
|
RZ_LOG_ERROR("Fail to allocate memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int len = rz_hex_str2bin(argv[1], hex);
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("rz_hex_str2bin: invalid hexstr\n");
|
|
free(hex);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *buf = rz_core_assembly_of_hex(core, hex, len);
|
|
free(hex);
|
|
if (!buf) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(buf);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_assembly_of_hex_alias_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return rz_assembly_of_hex_handler(core, argc, argv, mode);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instructions_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc <= 1) {
|
|
RZ_LOG_ERROR("Invalid arguments\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 len = rz_num_math(core->num, argv[1]);
|
|
if (len == 0) {
|
|
RZ_LOG_ERROR("The argument cannot be zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_print_disasm_instructions(core, len, 0);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instructions_function_handler(RzCore *core, int argc, const char **argv) {
|
|
const RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!f) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 fcn_size = rz_analysis_function_linear_size((RzAnalysisFunction *)f);
|
|
if (fcn_size == 0) {
|
|
RZ_LOG_ERROR("The function size is zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_print_disasm_instructions(core, fcn_size, 0);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_esil_of_hex_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
ut8 *hex = calloc(1, strlen(argv[1]) + 1);
|
|
if (!hex) {
|
|
RZ_LOG_ERROR("Fail to allocate memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int len = rz_hex_str2bin(argv[1], hex);
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("rz_hex_str2bin: invalid hexstr\n");
|
|
free(hex);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *buf = rz_core_esil_of_hex(core, hex, len);
|
|
if (!buf) {
|
|
// rz_core_esil_of_hex outputs the error message
|
|
free(hex);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(buf);
|
|
free(buf);
|
|
free(hex);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static int lenof(ut64 off, int two) {
|
|
char buf[64];
|
|
buf[0] = 0;
|
|
if (two) {
|
|
snprintf(buf, sizeof(buf), "+0x%" PFMT64x, off);
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "0x%08" PFMT64x, off);
|
|
}
|
|
return strlen(buf);
|
|
}
|
|
|
|
RZ_API void rz_print_offset_sg(RzPrint *p, ut64 off, int invert, int offseg, int seggrn, int offdec, int delta, const char *label) {
|
|
char space[32] = {
|
|
0
|
|
};
|
|
const char *reset = p->resetbg ? Color_RESET : Color_RESET_NOBG;
|
|
bool show_color = p->flags & RZ_PRINT_FLAGS_COLOR;
|
|
if (show_color) {
|
|
const char *k = rz_cons_singleton()->context->pal.offset; // TODO etooslow. must cache
|
|
const char *inv = invert ? RZ_CONS_INVERT(true, true) : "";
|
|
if (offseg) {
|
|
ut32 s, a;
|
|
a = off & 0xffff;
|
|
s = ((off - a) >> seggrn) & 0xffff;
|
|
if (offdec) {
|
|
snprintf(space, sizeof(space), "%d:%d", s, a);
|
|
rz_cons_printf("%s%s%9s%s", k, inv, space, reset);
|
|
} else {
|
|
rz_cons_printf("%s%s%04x:%04x%s", k, inv, s, a, reset);
|
|
}
|
|
} else {
|
|
int sz = lenof(off, 0);
|
|
int sz2 = lenof(delta, 1);
|
|
if (delta > 0 || label) {
|
|
if (label) {
|
|
const int label_padding = 10;
|
|
if (delta > 0) {
|
|
char *pad = rz_str_pad(' ', sz - sz2 + label_padding);
|
|
if (offdec) {
|
|
rz_cons_printf("%s%s%s%s+%d%s", k, inv, label, reset, delta, pad);
|
|
} else {
|
|
rz_cons_printf("%s%s%s%s+0x%x%s", k, inv, label, reset, delta, pad);
|
|
}
|
|
free(pad);
|
|
} else {
|
|
char *pad = rz_str_pad(' ', sz + label_padding);
|
|
rz_cons_printf("%s%s%s%s%s", k, inv, label, reset, pad);
|
|
free(pad);
|
|
}
|
|
} else {
|
|
char *pad = rz_str_pad(' ', sz - sz2);
|
|
if (offdec) {
|
|
rz_cons_printf("%s+%d%s", pad, delta, reset);
|
|
} else {
|
|
rz_cons_printf("%s+0x%x%s", pad, delta, reset);
|
|
}
|
|
free(pad);
|
|
}
|
|
} else {
|
|
if (offdec) {
|
|
snprintf(space, sizeof(space), "%" PFMT64u, off);
|
|
rz_cons_printf("%s%s%10s%s", k, inv, space, reset);
|
|
} else {
|
|
if (p->wide_offsets) {
|
|
rz_cons_printf("%s%s0x%016" PFMT64x "%s", k, inv, off, reset);
|
|
} else {
|
|
rz_cons_printf("%s%s0x%08" PFMT64x "%s", k, inv, off, reset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rz_cons_print(" ");
|
|
} else {
|
|
if (offseg) {
|
|
ut32 s, a;
|
|
a = off & 0xffff;
|
|
s = (off - a) >> seggrn;
|
|
if (offdec) {
|
|
snprintf(space, sizeof(space), "%d:%d", s & 0xffff, a & 0xffff);
|
|
rz_cons_printf("%9s%s", space, reset);
|
|
} else {
|
|
rz_cons_printf("%04x:%04x", s & 0xFFFF, a & 0xFFFF);
|
|
}
|
|
} else {
|
|
int sz = lenof(off, 0);
|
|
int sz2 = lenof(delta, 1);
|
|
if (delta > 0) {
|
|
char *pad = rz_str_pad(' ', sz - 5 - sz2 - 3);
|
|
if (offdec) {
|
|
rz_cons_printf("%s+%d%s", pad, delta, reset);
|
|
} else {
|
|
rz_cons_printf("%s+0x%x%s", pad, delta, reset);
|
|
}
|
|
free(pad);
|
|
} else {
|
|
if (offdec) {
|
|
snprintf(space, sizeof(space), "%" PFMT64u, off);
|
|
rz_cons_printf("%10s", space);
|
|
} else {
|
|
rz_cons_printf("0x%08" PFMT64x " ", off);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO : move to rz_util? .. depends on rz_cons...
|
|
// XXX: dupe of rz_print_addr
|
|
RZ_API void rz_print_offset(RzPrint *p, ut64 off, int invert, int offseg, int offdec, int delta, const char *label) {
|
|
rz_print_offset_sg(p, off, invert, offseg, 4, offdec, delta, label);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_utf8_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_utf16le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16LE);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_utf32le_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32LE);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_utf16be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF16BE);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_utf32be_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
return core_print_string_in_block(core, true, false, 0, mode, RZ_STRING_ENC_UTF32BE);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_annotated_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (len % 16) {
|
|
len += 16 - (len % 16);
|
|
}
|
|
annotated_hexdump(core, len);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_op_analysis_color_map_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(cmd_print_pxA(core, len, state->mode));
|
|
}
|
|
|
|
void print_cursor(RzPrint *p, int cur, int len, int set) {
|
|
if (rz_print_have_cursor(p, cur, len)) {
|
|
rz_cons_printf("%s", RZ_CONS_INVERT(set, 1));
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_bits_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
char buf[32];
|
|
for (int i = 0, c = 0; i < len; i++, c++) {
|
|
if (c == 0) {
|
|
ut64 ea = core->offset + i;
|
|
if (core->print->pava) {
|
|
ut64 va = rz_io_p2v(core->io, ea);
|
|
if (va != UT64_MAX) {
|
|
ea = va;
|
|
}
|
|
}
|
|
char *string = rz_print_section_str(core->print, ea);
|
|
rz_cons_print(string);
|
|
free(string);
|
|
rz_print_offset(core->print, ea, 0, 0, 0, 0, NULL);
|
|
}
|
|
rz_str_bits(buf, core->block + i, 8, NULL);
|
|
|
|
// split bits
|
|
memmove(buf + 5, buf + 4, 5);
|
|
buf[4] = 0;
|
|
|
|
print_cursor(core->print, i, 1, 1);
|
|
rz_cons_printf("%s.%s ", buf, buf + 5);
|
|
print_cursor(core->print, i, 1, 0);
|
|
if (c == 3) {
|
|
const ut8 *b = core->block + i - 3;
|
|
ut32 (*k)(const ut8 *, int) = cmd_pxb_k;
|
|
char (*p)(char) = cmd_pxb_p;
|
|
|
|
ut32 n = k(b, 0) | k(b, 1) | k(b, 2) | k(b, 3);
|
|
rz_cons_printf("0x%08x %c%c%c%c\n",
|
|
n, p(b[0]), p(b[1]), p(b[2]), p(b[3]));
|
|
c = -1;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_comments_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_hexdump_or_hexdiff(core, RZ_OUTPUT_MODE_STANDARD, core->offset, len, true));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer_common_handler(RzCore *core, int argc, const char **argv,
|
|
RzCmdStateOutput *state, ut8 n) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_dump(core, state->mode, core->offset, n, len, RZ_CORE_PRINT_FORMAT_TYPE_INTEGER));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 1);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 2);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 4);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_signed_integer8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_signed_integer_common_handler(core, argc, argv, state, 8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_emoji_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
static const char emoji[] = {
|
|
'\x8c', '\x80', '\x8c', '\x82', '\x8c', '\x85', '\x8c', '\x88',
|
|
'\x8c', '\x99', '\x8c', '\x9e', '\x8c', '\x9f', '\x8c', '\xa0',
|
|
'\x8c', '\xb0', '\x8c', '\xb1', '\x8c', '\xb2', '\x8c', '\xb3',
|
|
'\x8c', '\xb4', '\x8c', '\xb5', '\x8c', '\xb7', '\x8c', '\xb8',
|
|
'\x8c', '\xb9', '\x8c', '\xba', '\x8c', '\xbb', '\x8c', '\xbc',
|
|
'\x8c', '\xbd', '\x8c', '\xbe', '\x8c', '\xbf', '\x8d', '\x80',
|
|
'\x8d', '\x81', '\x8d', '\x82', '\x8d', '\x83', '\x8d', '\x84',
|
|
'\x8d', '\x85', '\x8d', '\x86', '\x8d', '\x87', '\x8d', '\x88',
|
|
'\x8d', '\x89', '\x8d', '\x8a', '\x8d', '\x8b', '\x8d', '\x8c',
|
|
'\x8d', '\x8d', '\x8d', '\x8e', '\x8d', '\x8f', '\x8d', '\x90',
|
|
'\x8d', '\x91', '\x8d', '\x92', '\x8d', '\x93', '\x8d', '\x94',
|
|
'\x8d', '\x95', '\x8d', '\x96', '\x8d', '\x97', '\x8d', '\x98',
|
|
'\x8d', '\x9c', '\x8d', '\x9d', '\x8d', '\x9e', '\x8d', '\x9f',
|
|
'\x8d', '\xa0', '\x8d', '\xa1', '\x8d', '\xa2', '\x8d', '\xa3',
|
|
'\x8d', '\xa4', '\x8d', '\xa5', '\x8d', '\xa6', '\x8d', '\xa7',
|
|
'\x8d', '\xa8', '\x8d', '\xa9', '\x8d', '\xaa', '\x8d', '\xab',
|
|
'\x8d', '\xac', '\x8d', '\xad', '\x8d', '\xae', '\x8d', '\xaf',
|
|
'\x8d', '\xb0', '\x8d', '\xb1', '\x8d', '\xb2', '\x8d', '\xb3',
|
|
'\x8d', '\xb4', '\x8d', '\xb5', '\x8d', '\xb6', '\x8d', '\xb7',
|
|
'\x8d', '\xb8', '\x8d', '\xb9', '\x8d', '\xba', '\x8d', '\xbb',
|
|
'\x8d', '\xbc', '\x8e', '\x80', '\x8e', '\x81', '\x8e', '\x82',
|
|
'\x8e', '\x83', '\x8e', '\x84', '\x8e', '\x85', '\x8e', '\x88',
|
|
'\x8e', '\x89', '\x8e', '\x8a', '\x8e', '\x8b', '\x8e', '\x8c',
|
|
'\x8e', '\x8d', '\x8e', '\x8e', '\x8e', '\x8f', '\x8e', '\x92',
|
|
'\x8e', '\x93', '\x8e', '\xa0', '\x8e', '\xa1', '\x8e', '\xa2',
|
|
'\x8e', '\xa3', '\x8e', '\xa4', '\x8e', '\xa5', '\x8e', '\xa6',
|
|
'\x8e', '\xa7', '\x8e', '\xa8', '\x8e', '\xa9', '\x8e', '\xaa',
|
|
'\x8e', '\xab', '\x8e', '\xac', '\x8e', '\xad', '\x8e', '\xae',
|
|
'\x8e', '\xaf', '\x8e', '\xb0', '\x8e', '\xb1', '\x8e', '\xb2',
|
|
'\x8e', '\xb3', '\x8e', '\xb4', '\x8e', '\xb5', '\x8e', '\xb7',
|
|
'\x8e', '\xb8', '\x8e', '\xb9', '\x8e', '\xba', '\x8e', '\xbb',
|
|
'\x8e', '\xbd', '\x8e', '\xbe', '\x8e', '\xbf', '\x8f', '\x80',
|
|
'\x8f', '\x81', '\x8f', '\x82', '\x8f', '\x83', '\x8f', '\x84',
|
|
'\x8f', '\x86', '\x8f', '\x87', '\x8f', '\x88', '\x8f', '\x89',
|
|
'\x8f', '\x8a', '\x90', '\x80', '\x90', '\x81', '\x90', '\x82',
|
|
'\x90', '\x83', '\x90', '\x84', '\x90', '\x85', '\x90', '\x86',
|
|
'\x90', '\x87', '\x90', '\x88', '\x90', '\x89', '\x90', '\x8a',
|
|
'\x90', '\x8b', '\x90', '\x8c', '\x90', '\x8d', '\x90', '\x8e',
|
|
'\x90', '\x8f', '\x90', '\x90', '\x90', '\x91', '\x90', '\x92',
|
|
'\x90', '\x93', '\x90', '\x94', '\x90', '\x95', '\x90', '\x96',
|
|
'\x90', '\x97', '\x90', '\x98', '\x90', '\x99', '\x90', '\x9a',
|
|
'\x90', '\x9b', '\x90', '\x9c', '\x90', '\x9d', '\x90', '\x9e',
|
|
'\x90', '\x9f', '\x90', '\xa0', '\x90', '\xa1', '\x90', '\xa2',
|
|
'\x90', '\xa3', '\x90', '\xa4', '\x90', '\xa5', '\x90', '\xa6',
|
|
'\x90', '\xa7', '\x90', '\xa8', '\x90', '\xa9', '\x90', '\xaa',
|
|
'\x90', '\xab', '\x90', '\xac', '\x90', '\xad', '\x90', '\xae',
|
|
'\x90', '\xaf', '\x90', '\xb0', '\x90', '\xb1', '\x90', '\xb2',
|
|
'\x90', '\xb3', '\x90', '\xb4', '\x90', '\xb5', '\x90', '\xb6',
|
|
'\x90', '\xb7', '\x90', '\xb8', '\x90', '\xb9', '\x90', '\xba',
|
|
'\x90', '\xbb', '\x90', '\xbc', '\x90', '\xbd', '\x90', '\xbe',
|
|
'\x91', '\x80', '\x91', '\x82', '\x91', '\x83', '\x91', '\x84',
|
|
'\x91', '\x85', '\x91', '\x86', '\x91', '\x87', '\x91', '\x88',
|
|
'\x91', '\x89', '\x91', '\x8a', '\x91', '\x8b', '\x91', '\x8c',
|
|
'\x91', '\x8d', '\x91', '\x8e', '\x91', '\x8f', '\x91', '\x90',
|
|
'\x91', '\x91', '\x91', '\x92', '\x91', '\x93', '\x91', '\x94',
|
|
'\x91', '\x95', '\x91', '\x96', '\x91', '\x97', '\x91', '\x98',
|
|
'\x91', '\x99', '\x91', '\x9a', '\x91', '\x9b', '\x91', '\x9c',
|
|
'\x91', '\x9d', '\x91', '\x9e', '\x91', '\x9f', '\x91', '\xa0',
|
|
'\x91', '\xa1', '\x91', '\xa2', '\x91', '\xa3', '\x91', '\xa4',
|
|
'\x91', '\xa5', '\x91', '\xa6', '\x91', '\xa7', '\x91', '\xa8',
|
|
'\x91', '\xa9', '\x91', '\xaa', '\x91', '\xae', '\x91', '\xaf',
|
|
'\x91', '\xba', '\x91', '\xbb', '\x91', '\xbc', '\x91', '\xbd',
|
|
'\x91', '\xbe', '\x91', '\xbf', '\x92', '\x80', '\x92', '\x81',
|
|
'\x92', '\x82', '\x92', '\x83', '\x92', '\x84', '\x92', '\x85'
|
|
};
|
|
int cols = core->print->cols;
|
|
if (cols < 1) {
|
|
cols = 1;
|
|
}
|
|
for (int i = 0; i < len; i += cols) {
|
|
rz_print_addr(core->print, core->offset + i);
|
|
for (int j = i; j < i + cols; j += 1) {
|
|
ut8 *p = (ut8 *)core->block + j;
|
|
if (j < len) {
|
|
rz_cons_printf("\xf0\x9f%c%c ", emoji[*p * 2], emoji[*p * 2 + 1]);
|
|
} else {
|
|
rz_cons_print(" ");
|
|
}
|
|
}
|
|
rz_cons_print(" ");
|
|
for (int j = i; j < len && j < i + cols; j += 1) {
|
|
ut8 *p = (ut8 *)core->block + j;
|
|
rz_print_byte(core->print, "%c", j, *p);
|
|
}
|
|
rz_cons_newline();
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_function_handler(RzCore *core, int argc, const char **argv) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hexii_handler(RzCore *core, int argc, const char **argv) {
|
|
core->print->show_offset = rz_config_get_i(core->config, "hex.offset");
|
|
rz_print_hexii(core->print, core->offset, core->block,
|
|
(int)core->blocksize, rz_config_get_i(core->config, "hex.cols"));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, int wordsize) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
const char *query = argc > 2 ? argv[2] : NULL;
|
|
switch (wordsize) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
cmd_pxr(core, core->offset, len, state, wordsize, query);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int wordsize = rz_analysis_get_address_bits(core->analysis) / 8;
|
|
return rz_print_hexword_references_common_handler(core, argc, argv, state, wordsize);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_1_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexword_references_common_handler(core, argc, argv, state, 1);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexword_references_common_handler(core, argc, argv, state, 2);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexword_references_common_handler(core, argc, argv, state, 4);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexword_references_8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexword_references_common_handler(core, argc, argv, state, 8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_sparse_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
core->print->flags |= RZ_PRINT_FLAGS_SPARSE;
|
|
rz_core_print_hexdump(core, core->offset, core->block, len, 16, 1, 1);
|
|
core->print->flags &= (int)(((ut32)-1) & (~RZ_PRINT_FLAGS_SPARSE));
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_delta_pointer_table_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
ut64 origin = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset;
|
|
// _pointer_table does rz_core_cmd with @, so it modifies core->block
|
|
// and this results in an UAF access when iterating over the jmptable
|
|
// so we do a new allocation to avoid that issue
|
|
ut8 *block = calloc(len, 1);
|
|
if (!block) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
memcpy(block, core->block, len);
|
|
_pointer_table(core, origin, core->offset, block, len, 4, state->mode);
|
|
free(block);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hexless_bytes_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
core->print->flags |= RZ_PRINT_FLAGS_NONHEX;
|
|
rz_core_print_hexdump(core, core->offset,
|
|
core->block, len, 8, 1, 1);
|
|
core->print->flags &= ~RZ_PRINT_FLAGS_NONHEX;
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hexless_words_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
ut8 *buf = calloc(len, 4);
|
|
if (!buf) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_read_at(core->io, core->offset, buf, len * 4);
|
|
core->print->flags |= RZ_PRINT_FLAGS_NONHEX;
|
|
rz_core_print_hexdump(core, core->offset, buf, len * 4, 8, 1, 1);
|
|
core->print->flags &= ~RZ_PRINT_FLAGS_NONHEX;
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hexpair_bytes_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = (int)rz_str_nlen((const char *)core->block, core->blocksize);
|
|
if (!len) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
rz_print_bytes(core->print, core->block, len, "%02x");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_hexdump_or_hexdiff(core, state->mode, core->offset, len, false));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_n_lines_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_hexdump_or_hexdiff(core, state->mode, core->offset, core->print->cols * len, false));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, ut8 n) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_dump(core, state->mode, core->offset, n, len, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 2);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 4);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hex_common_handler(core, argc, argv, state, 8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hexl_common_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state, ut8 n) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
bool hex_offset = rz_config_get_b(core->config, "hex.offset");
|
|
bool quiet = state->mode == RZ_OUTPUT_MODE_QUIET || state->mode == RZ_OUTPUT_MODE_QUIETEST;
|
|
return bool2status(rz_core_print_hexdump_byline(core, !quiet && hex_offset, core->offset, len, n));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex2l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 2);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex4l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 4);
|
|
}
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_hex8l_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_hexl_common_handler(core, argc, argv, state, 8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_oct_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)core->blocksize;
|
|
return bool2status(rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, core->offset, 1, len, RZ_CORE_PRINT_FORMAT_TYPE_OCTAL));
|
|
}
|
|
|
|
#define CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(name, type) \
|
|
RZ_IPI RzCmdStatus name(RzCore *core, int argc, const char **argv) { \
|
|
const int size = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize; \
|
|
if (size > core->blocksize_max) { \
|
|
RZ_LOG_ERROR("Size exceeds max size (%u)\n", core->blocksize_max); \
|
|
return RZ_CMD_STATUS_ERROR; \
|
|
} \
|
|
if (size <= 0) { \
|
|
RZ_LOG_ERROR("Size must be greater than 0\n"); \
|
|
return RZ_CMD_STATUS_ERROR; \
|
|
} \
|
|
char *code = rz_lang_byte_array(core->block, size, type); \
|
|
if (RZ_STR_ISNOTEMPTY(code)) { \
|
|
rz_cons_println(code); \
|
|
} \
|
|
RzCmdStatus result = code ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; \
|
|
free(code); \
|
|
return result; \
|
|
}
|
|
|
|
#define CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(name, type) \
|
|
RZ_IPI RzCmdStatus name(RzCore *core, int argc, const char **argv) { \
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian"); \
|
|
char *code = rz_lang_byte_array(core->block, core->blocksize, big_endian ? type##_BE : type##_LE); \
|
|
if (RZ_STR_ISNOTEMPTY(code)) { \
|
|
rz_cons_println(code); \
|
|
} \
|
|
RzCmdStatus result = code ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR; \
|
|
free(code); \
|
|
return result; \
|
|
}
|
|
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_rizin_handler, RZ_LANG_BYTE_ARRAY_RIZIN);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_asm_handler, RZ_LANG_BYTE_ARRAY_ASM);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_bash_handler, RZ_LANG_BYTE_ARRAY_BASH);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_c_cpp_bytes_handler, RZ_LANG_BYTE_ARRAY_C_CPP_BYTES);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_half_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_HALFWORDS);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_WORDS);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN(rz_cmd_print_byte_array_c_cpp_double_word_handler, RZ_LANG_BYTE_ARRAY_C_CPP_DOUBLEWORDS);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_golang_handler, RZ_LANG_BYTE_ARRAY_GOLANG);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_java_handler, RZ_LANG_BYTE_ARRAY_JAVA);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_json_handler, RZ_LANG_BYTE_ARRAY_JSON);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_kotlin_handler, RZ_LANG_BYTE_ARRAY_KOTLIN);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_nodejs_handler, RZ_LANG_BYTE_ARRAY_NODEJS);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_objc_handler, RZ_LANG_BYTE_ARRAY_OBJECTIVE_C);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_python_handler, RZ_LANG_BYTE_ARRAY_PYTHON);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_rust_handler, RZ_LANG_BYTE_ARRAY_RUST);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_swift_handler, RZ_LANG_BYTE_ARRAY_SWIFT);
|
|
CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL(rz_cmd_print_byte_array_yara_handler, RZ_LANG_BYTE_ARRAY_YARA);
|
|
#undef CMD_PRINT_BYTE_ARRAY_HANDLER_NORMAL
|
|
#undef CMD_PRINT_BYTE_ARRAY_HANDLER_ENDIAN
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_byte_array_with_inst_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_core_block_read(core);
|
|
const int size = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (size > core->blocksize_max) {
|
|
RZ_LOG_ERROR("Size exceeds max size (%u)\n", core->blocksize_max);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (size <= 0) {
|
|
RZ_LOG_ERROR("Size must be greater 0\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *code = rz_core_print_bytes_with_inst(core, core->block, core->offset, size);
|
|
if (!code) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println(code);
|
|
free(code);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void disassembly_as_table(RzTable *t, RzCore *core, ut64 addr, int n_instrs, int n_bytes) {
|
|
ut8 buffer[256];
|
|
rz_table_set_columnsf(t, "snssssss", "name", "addr", "bytes", "disasm", "comment", "esil", "refs", "xrefs");
|
|
const int minopsz = 1;
|
|
const int options = RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_HINT | RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_ESIL;
|
|
const int addrbytes = core->io->addrbytes;
|
|
ut64 offset = addr;
|
|
ut64 inc = 0;
|
|
for (int i = 0, j = 0; rz_disasm_check_end(n_instrs, i, n_bytes, j * addrbytes); i++, offset += inc, j += inc) {
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, offset, options);
|
|
if (!op || op->size < 1) {
|
|
i += minopsz;
|
|
inc = minopsz;
|
|
continue;
|
|
}
|
|
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, offset);
|
|
if (!comment) {
|
|
comment = "";
|
|
}
|
|
rz_io_read_at(core->io, offset, buffer, RZ_MIN(op->size, sizeof(buffer)));
|
|
char *bytes = rz_hex_bin2strdup(buffer, op->size);
|
|
RzFlagItem *flag = rz_flag_get_i(core->flags, offset);
|
|
char *function_name = flag ? flag->name : "";
|
|
const char *esil = RZ_STRBUF_SAFEGET(&op->esil);
|
|
char *refs = __op_refs(core, op, 0);
|
|
char *xrefs = __op_refs(core, op, 1);
|
|
rz_table_add_rowf(t, "sXssssss", function_name, offset, bytes, op->mnemonic, comment, esil, refs, xrefs);
|
|
free(bytes);
|
|
free(xrefs);
|
|
free(refs);
|
|
inc = op->size;
|
|
rz_analysis_op_free(op);
|
|
}
|
|
}
|
|
|
|
static bool core_disassembly(RzCore *core, int n_bytes, int n_instrs, RzCmdStateOutput *state, bool cbytes) {
|
|
ut64 offset = rz_core_backward_offset(core, core->offset, &n_instrs, &n_bytes);
|
|
|
|
if (n_bytes == 0) {
|
|
const int max_op_size = rz_analysis_archinfo(core->analysis, RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE);
|
|
n_bytes = max_op_size * n_instrs;
|
|
}
|
|
|
|
RZ_LOG_VERBOSE("disassembly at: 0x%" PFMT64x " "
|
|
"blocksize: %" PFMT32d " "
|
|
"n_bytes: %" PFMT32d " "
|
|
"n_instrs: %" PFMT32d "\n",
|
|
core->offset, core->blocksize, n_bytes, n_instrs);
|
|
RzCoreDisasmOptions disasm_options = {
|
|
.cbytes = cbytes,
|
|
};
|
|
|
|
ut8 *buf = RZ_NEWS0(ut8, n_bytes + 1);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("Failed to allocate memory\n");
|
|
return false;
|
|
}
|
|
bool ret = true;
|
|
if (!rz_io_read_at_mapped(core->io, offset, buf, n_bytes + 1)) {
|
|
// Even with an error, keep on disassembling as at least some data may be read successfully
|
|
RZ_LOG_ERROR("Failed to read chunk of size 0x%" PFMT64x " at 0x%" PFMT64x " for disassembly.\n", (ut64)(n_bytes + 1), offset);
|
|
ret = false;
|
|
}
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_core_print_disasm(core, offset, buf, n_bytes,
|
|
n_bytes > 0 && !n_instrs ? n_bytes : n_instrs, state, &disasm_options);
|
|
break;
|
|
case RZ_OUTPUT_MODE_TABLE:
|
|
disassembly_as_table(state->d.t, core, offset, n_instrs, n_bytes);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_core_print_disasm_json(core, offset, buf, n_bytes, n_instrs, state->d.pj);
|
|
rz_cmd_state_output_array_end(state);
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_core_disasm_pdi(core, n_instrs, n_bytes, 0);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
free(buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_bytes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut64 n_bytes = argc > 1 ? (ut64)rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (n_bytes == 0) {
|
|
RZ_LOG_ERROR("The argument cannot be zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return bool2status(core_disassembly(core, n_bytes, 0, state, true));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instructions_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int n_instrs = 0;
|
|
if (argc <= 1) {
|
|
// when no arg, we always use the rows number of the terminal
|
|
// no args must be always positive, if is not we use 16
|
|
n_instrs = rz_num_get(core->num, "$r");
|
|
if (n_instrs < 1) {
|
|
n_instrs = 16;
|
|
}
|
|
} else {
|
|
n_instrs = (int)rz_num_math(core->num, argv[1]);
|
|
if (n_instrs == 0) {
|
|
RZ_LOG_ERROR("The argument cannot be zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
return bool2status(core_disassembly(core, argc > 1 ? (int)core->blocksize : 0, n_instrs, state, false));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_possible_opcodes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut64 n_bytes = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
ut8 *buffer = RZ_NEWS0(ut8, n_bytes);
|
|
RzPVector *vec = NULL;
|
|
RzCmdStatus res = RZ_CMD_STATUS_OK;
|
|
if (!buffer) {
|
|
goto fail;
|
|
}
|
|
if (!rz_io_read_at(core->io, core->offset, buffer, n_bytes)) {
|
|
goto fail;
|
|
}
|
|
vec = rz_core_disasm_all_possible_opcodes(core, buffer, core->offset, n_bytes);
|
|
if (!vec) {
|
|
goto fail;
|
|
}
|
|
|
|
bool color = rz_config_get_i(core->config, "scr.color") > 0;
|
|
void **p;
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cons_break_push(NULL, NULL);
|
|
rz_pvector_foreach (vec, p) {
|
|
RzCoreDisasmOp *op = *p;
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("0x%08" PFMT64x " %20s %s\n", op->offset, op->hex, color ? op->assembly_colored : op->assembly);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(state->d.pj);
|
|
pj_kn(state->d.pj, "addr", op->offset);
|
|
pj_ks(state->d.pj, "bytes", op->hex);
|
|
pj_ks(state->d.pj, "inst", op->assembly);
|
|
pj_end(state->d.pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_cons_printf("%s\n", color ? op->assembly_colored : op->assembly);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
rz_cons_break_pop();
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
ret:
|
|
free(buffer);
|
|
rz_pvector_free(vec);
|
|
return res;
|
|
fail:
|
|
res = RZ_CMD_STATUS_ERROR;
|
|
goto ret;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_possible_opcodes_treeview_handler(RzCore *core, int argc, const char **argv) {
|
|
#define TREEVIEW_N_BYTES 28
|
|
ut8 buffer[TREEVIEW_N_BYTES];
|
|
RzPVector *vec = NULL;
|
|
RzCmdStatus res = RZ_CMD_STATUS_OK;
|
|
if (!rz_io_read_at(core->io, core->offset, buffer, TREEVIEW_N_BYTES)) {
|
|
goto fail;
|
|
}
|
|
vec = rz_core_disasm_all_possible_opcodes(core, buffer, core->offset, TREEVIEW_N_BYTES);
|
|
if (!vec) {
|
|
goto fail;
|
|
}
|
|
|
|
bool color = rz_config_get_i(core->config, "scr.color") > 0;
|
|
void **p;
|
|
int position = 0;
|
|
rz_pvector_foreach (vec, p) {
|
|
RzCoreDisasmOp *op = *p;
|
|
if (op->size < 1) {
|
|
continue;
|
|
}
|
|
int padding = position * 2;
|
|
int space = 60 - padding;
|
|
if ((position + op->size) >= 30) {
|
|
ut32 last = (30 - position) * 2;
|
|
op->hex[last - 1] = '.';
|
|
op->hex[last] = 0;
|
|
}
|
|
rz_cons_printf("0x%08" PFMT64x " %*s%*s %s\n", op->offset, padding, "", -space, op->hex, color ? op->assembly_colored : op->assembly);
|
|
position++;
|
|
}
|
|
|
|
ret:
|
|
rz_pvector_free(vec);
|
|
return res;
|
|
fail:
|
|
res = RZ_CMD_STATUS_ERROR;
|
|
goto ret;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_basic_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
|
|
core->num->value = 0;
|
|
if (!b) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut8 *block = malloc(b->size + 1);
|
|
if (!block) {
|
|
RZ_LOG_ERROR("Cannot allocate buffer\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_read_at(core->io, b->addr, block, b->size);
|
|
RzCoreDisasmOptions disasm_options = {
|
|
.cbytes = 2,
|
|
};
|
|
rz_cmd_state_output_array_start(state);
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
core->num->value = rz_core_print_disasm(core, b->addr, block, b->size, 9999, state, &disasm_options);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
core->num->value = 1;
|
|
rz_core_print_disasm_json(core, b->addr, block, b->size, 0, state->d.pj);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
free(block);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_basic_block_as_text_json_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
|
|
core->num->value = 0;
|
|
if (!b) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut8 *block = malloc(b->size + 1);
|
|
if (!block) {
|
|
RZ_LOG_ERROR("Cannot allocate buffer\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_read_at(core->io, b->addr, block, b->size);
|
|
RzCoreDisasmOptions disasm_options = {
|
|
.cbytes = 2,
|
|
};
|
|
core->num->value = rz_core_print_disasm(core, b->addr, block, b->size, 9999, state, &disasm_options);
|
|
|
|
free(block);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_comments_in_n_instructions_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (parsed > ST16_MAX || parsed < ST16_MIN) {
|
|
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int n_instrs = parsed;
|
|
if (rz_core_disasm_pdi(core, n_instrs, 0, 'C') < 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instructions_with_flow_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : (core->blocksize / 4);
|
|
if (parsed > ST16_MAX || parsed < ST16_MIN) {
|
|
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int n_instrs = parsed;
|
|
// this command is going to be removed when esil will be removed.
|
|
rz_core_disasm_pde(core, n_instrs, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
core->num->value = 0;
|
|
ut32 old_blocksize = core->blocksize;
|
|
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_ROOT);
|
|
if (!function) {
|
|
function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
}
|
|
if (!function) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
bool ret = rz_core_print_function_disasm_json(core, function, state->d.pj);
|
|
rz_core_block_size(core, old_blocksize);
|
|
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut64 linear_size = rz_analysis_function_linear_size(function);
|
|
ut64 max_real_size = rz_analysis_function_realsize(function) + 4096;
|
|
if (max_real_size < linear_size) {
|
|
RZ_LOG_ERROR("Linear size differs too much from the bbsum, please use pdr instead.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut64 start = function->addr; // For pdf, start disassembling at the entrypoint
|
|
ut64 end = rz_analysis_function_max_addr(function);
|
|
if (end <= start) {
|
|
RZ_LOG_ERROR("Cannot print function because the end offset is less or equal to the start offset\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut64 size = end - start;
|
|
ut8 *bytes = malloc(size);
|
|
if (!bytes) {
|
|
RZ_LOG_ERROR("Cannot allocate buffer\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
(void)rz_io_read_at(core->io, start, bytes, size);
|
|
RzCoreDisasmOptions disasm_options = {
|
|
.cbytes = 1,
|
|
.function = function,
|
|
};
|
|
core->num->value = rz_core_print_disasm(core, start, bytes, size, size, state, &disasm_options);
|
|
free(bytes);
|
|
|
|
rz_core_block_size(core, old_blocksize);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_current_block_json_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_return_val_if_fail(core, RZ_CMD_STATUS_ERROR);
|
|
bool enable_color = rz_config_get_i(core->config, "escr.color") != 0;
|
|
char *res = rz_print_json_indent((const char *)core->block, enable_color, " ", NULL);
|
|
if (RZ_STR_ISEMPTY(res)) {
|
|
free(res);
|
|
RZ_LOG_ERROR("Couldn't find a JSON string.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
} else {
|
|
rz_cons_printf("%s\n", res);
|
|
}
|
|
free(res);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_function_rzil_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAnalysisFunction *f = rz_analysis_first_function_in(core->analysis, core->offset);
|
|
if (!f) {
|
|
goto exit;
|
|
}
|
|
|
|
RzIterator *ops = rz_core_analysis_op_function_iter(core, f, RZ_ANALYSIS_OP_MASK_IL);
|
|
if (!ops) {
|
|
goto exit;
|
|
}
|
|
|
|
rz_core_il_cons_print(core, ops, false);
|
|
rz_iterator_free(ops);
|
|
return RZ_CMD_STATUS_OK;
|
|
exit:
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_function_summary_handler(RzCore *core, int argc, const char **argv) {
|
|
ut32 old_blocksize = core->blocksize;
|
|
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!function) {
|
|
RZ_LOG_ERROR("cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut32 rs = rz_analysis_function_realsize(function);
|
|
ut32 fs = rz_analysis_function_linear_size(function);
|
|
rz_core_block_size(core, RZ_MAX(rs, fs));
|
|
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_INST, 0, function);
|
|
rz_core_block_size(core, old_blocksize);
|
|
if (!string) {
|
|
RZ_LOG_ERROR("failed summarize %" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(string);
|
|
free(string);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_n_instrs_as_text_json_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut32 old_blocksize = core->blocksize;
|
|
ut64 old_offset = core->offset;
|
|
core->num->value = 0;
|
|
|
|
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : 0;
|
|
if (parsed > ST16_MAX || parsed < ST16_MIN) {
|
|
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int n_instrs = parsed;
|
|
if (n_instrs < 0) {
|
|
ut64 new_offset = old_offset;
|
|
if (!rz_core_prevop_addr(core, old_offset, -n_instrs, &new_offset)) {
|
|
new_offset = rz_core_prevop_addr_force(core, old_offset, -n_instrs);
|
|
}
|
|
ut32 new_blocksize = new_offset - old_blocksize;
|
|
if (new_blocksize > old_blocksize) {
|
|
rz_core_block_size(core, new_blocksize);
|
|
}
|
|
rz_core_seek(core, new_offset, true);
|
|
} else {
|
|
rz_core_block_read(core);
|
|
}
|
|
|
|
state->mode = RZ_OUTPUT_MODE_JSON;
|
|
|
|
if (rz_cons_singleton()->is_html) {
|
|
rz_cons_singleton()->is_html = false;
|
|
rz_cons_singleton()->was_html = true;
|
|
}
|
|
RzCoreDisasmOptions disasm_options = {
|
|
.cbytes = 1,
|
|
};
|
|
core->num->value = rz_core_print_disasm(core, core->offset, core->block, core->blocksize, RZ_ABS(n_instrs), state, &disasm_options);
|
|
|
|
if (n_instrs < 0) {
|
|
rz_core_block_size(core, old_blocksize);
|
|
rz_core_seek(core, old_offset, true);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassembly_all_methods_class_handler(RzCore *core, int argc, const char **argv) {
|
|
ut32 old_blocksize = core->blocksize;
|
|
ut64 old_offset = core->offset;
|
|
|
|
int len = 0;
|
|
ut64 at = findClassBounds(core, &len);
|
|
if (!at) {
|
|
RZ_LOG_ERROR("Cannot find class at 0x%" PFMT64x ".\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_core_seek(core, at, true);
|
|
|
|
// TODO: remove this and use C api.
|
|
// on success returns 0 else negative
|
|
int ret = rz_core_cmdf(core, "pD %d", len);
|
|
|
|
rz_core_block_size(core, old_blocksize);
|
|
rz_core_seek(core, old_offset, true);
|
|
return ret >= 0 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_sizes_of_n_instructions_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut32 old_blocksize = core->blocksize;
|
|
ut64 old_offset = core->offset;
|
|
st64 ret = 0;
|
|
|
|
st64 parsed = argc > 1 ? (st64)rz_num_math(core->num, argv[1]) : (core->blocksize / 4);
|
|
if (parsed > ST16_MAX || parsed < ST16_MIN) {
|
|
RZ_LOG_ERROR("the number of instructions is too big (%d < n_instrs < %d).\n", ST16_MAX, ST16_MIN);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int n_instrs = parsed;
|
|
if (n_instrs < 0) {
|
|
ut64 new_offset = old_offset;
|
|
if (!rz_core_prevop_addr(core, old_offset, -n_instrs, &new_offset)) {
|
|
new_offset = rz_core_prevop_addr_force(core, old_offset, -n_instrs);
|
|
}
|
|
ut32 new_blocksize = new_offset - old_blocksize;
|
|
if (new_blocksize > old_blocksize) {
|
|
rz_core_block_size(core, new_blocksize);
|
|
}
|
|
rz_core_seek(core, new_offset, true);
|
|
} else {
|
|
rz_core_block_read(core);
|
|
}
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cons_break_push(NULL, NULL);
|
|
for (ut32 i = 0, j = 0; i < core->blocksize && j < RZ_ABS(n_instrs); i += ret, j++) {
|
|
RzAsmOp asm_op = { 0 };
|
|
ret = rz_asm_disassemble(core->rasm, &asm_op, core->block + i, core->blocksize - i);
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
// be sure to return 0 when it fails to disassemble the
|
|
// instruction to uniform the output across all disassemblers.
|
|
int op_size = ret < 1 ? 0 : ret;
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("%d\n", op_size);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_N(state->d.pj, op_size);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (ret < 1) {
|
|
ret = 1;
|
|
}
|
|
}
|
|
rz_cons_break_pop();
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
if (n_instrs < 0) {
|
|
rz_core_block_size(core, old_blocksize);
|
|
rz_core_seek(core, old_offset, true);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void disassemble_till_return_is_found(RzCore *core, ut64 offset, ut64 limit, RzCmdStateOutput *state) {
|
|
bool src_color = rz_config_get_i(core->config, "scr.color") > 0;
|
|
const char *off_color = src_color ? rz_cons_singleton()->context->pal.b0x00 : "";
|
|
const char *ret_color = src_color ? rz_cons_singleton()->context->pal.jmp : "";
|
|
const char *end_color = src_color ? Color_RESET : "";
|
|
|
|
for (ut64 i = 0; i < limit; i++) {
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, offset, RZ_ANALYSIS_OP_MASK_BASIC | RZ_ANALYSIS_OP_MASK_DISASM);
|
|
if (!op) {
|
|
return;
|
|
}
|
|
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_cons_printf("%s%s%s\n", ret_color, op->mnemonic, end_color);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("%s0x%08" PFMT64x "%s %-11s%s\n", off_color, core->offset + i, ret_color, op->mnemonic, end_color);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(state->d.pj);
|
|
pj_ks(state->d.pj, "mnemonic", op->mnemonic);
|
|
pj_kn(state->d.pj, "address", core->offset + i);
|
|
pj_end(state->d.pj);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
|
|
if (!(op->type & (RZ_ANALYSIS_OP_TYPE_RET | RZ_ANALYSIS_OP_TYPE_UJMP))) {
|
|
rz_analysis_op_free(op);
|
|
return;
|
|
}
|
|
|
|
if (op->type == RZ_ANALYSIS_OP_TYPE_JMP) {
|
|
offset = op->jump;
|
|
} else {
|
|
offset += op->size;
|
|
}
|
|
|
|
rz_analysis_op_free(op);
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_ropchain_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut64 limit = argc > 1 ? rz_num_math(core->num, argv[1]) : 1024;
|
|
if (limit > 1024) {
|
|
RZ_LOG_ERROR("the limit value exceeds the max value (1024).\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 asm_bits = core->rasm->bits;
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
bool src_color = rz_config_get_i(core->config, "scr.color") > 0;
|
|
|
|
const char *off_color = src_color ? rz_cons_singleton()->context->pal.offset : "";
|
|
const char *num_color = src_color ? rz_cons_singleton()->context->pal.num : "";
|
|
const char *end_color = src_color ? Color_RESET : "";
|
|
|
|
if (asm_bits < 64) {
|
|
asm_bits = 32;
|
|
}
|
|
|
|
ut32 asm_bytes = asm_bits / 8;
|
|
if (core->blocksize < asm_bytes) {
|
|
RZ_LOG_ERROR("block size is not enough big to host a word (needs to be >= %u bytes).\n", asm_bytes);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut8 *bytes = RZ_NEWS0(ut8, core->blocksize);
|
|
if (!bytes) {
|
|
RZ_LOG_ERROR("cannot allocate buffer.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
(void)rz_io_read_at(core->io, core->offset, bytes, core->blocksize);
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
for (ut32 i = 0; i < core->blocksize - asm_bytes; i += asm_bytes) {
|
|
ut64 number = rz_read_ble(bytes + i, big_endian, asm_bits);
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
rz_cons_printf("%s0x%08" PFMT64x "%s %s0x%08" PFMT64x "%s\n", off_color, core->offset + i, end_color, num_color, number, end_color);
|
|
disassemble_till_return_is_found(core, core->offset + i, limit, state);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("[%s0x%08" PFMT64x "%s] %s0x%08" PFMT64x "%s\n", off_color, core->offset + i, end_color, num_color, number, end_color);
|
|
disassemble_till_return_is_found(core, core->offset + i, limit, state);
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(state->d.pj);
|
|
pj_kn(state->d.pj, "address", core->offset + i);
|
|
pj_kn(state->d.pj, "bits", asm_bits);
|
|
pj_kn(state->d.pj, "word", number);
|
|
pj_ka(state->d.pj, "opcodes");
|
|
disassemble_till_return_is_found(core, core->offset + i, limit, state);
|
|
pj_end(state->d.pj);
|
|
pj_end(state->d.pj);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static bool core_walk_function_blocks(RzCore *core, RzAnalysisFunction *f, RzCmdStateOutput *state, char type_print, bool fromHere) {
|
|
void **iter;
|
|
RzAnalysisBlock *b = NULL;
|
|
const bool orig_bb_middle = rz_config_get_b(core->config, "asm.bb.middle");
|
|
rz_config_set_b(core->config, "asm.bb.middle", false);
|
|
|
|
if (rz_pvector_len(f->bbs) >= 1) {
|
|
ut32 fcn_size = rz_analysis_function_realsize(f);
|
|
b = rz_pvector_tail(f->bbs);
|
|
if (b->size > fcn_size) {
|
|
b->size = fcn_size;
|
|
}
|
|
}
|
|
|
|
rz_pvector_sort(f->bbs, (RzPVectorComparator)bbcmp, NULL);
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
rz_pvector_foreach (f->bbs, iter) {
|
|
b = (RzAnalysisBlock *)*iter;
|
|
ut8 *buf = malloc(b->size);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("cannot allocate %" PFMT64u " byte(s)\n", b->size);
|
|
return false;
|
|
}
|
|
(void)rz_io_read_at(core->io, b->addr, buf, b->size);
|
|
rz_core_print_disasm_json(core, b->addr, buf, b->size, 0, state->d.pj);
|
|
free(buf);
|
|
}
|
|
} else {
|
|
bool asm_lines = rz_config_get_i(core->config, "asm.lines.bb");
|
|
bool emu = rz_config_get_i(core->config, "asm.emu");
|
|
ut64 saved_gp = 0;
|
|
ut8 *saved_arena = NULL;
|
|
if (emu) {
|
|
saved_gp = core->analysis->gp;
|
|
saved_arena = rz_reg_arena_peek(core->analysis->reg);
|
|
}
|
|
rz_config_set_i(core->config, "asm.lines.bb", 0);
|
|
rz_pvector_foreach (f->bbs, iter) {
|
|
b = (RzAnalysisBlock *)*iter;
|
|
pr_bb(core, f, b, emu, saved_gp, saved_arena, type_print, fromHere);
|
|
}
|
|
if (emu) {
|
|
core->analysis->gp = saved_gp;
|
|
if (saved_arena) {
|
|
rz_reg_arena_poke(core->analysis->reg, saved_arena);
|
|
RZ_FREE(saved_arena);
|
|
}
|
|
}
|
|
rz_config_set_i(core->config, "asm.lines.bb", asm_lines);
|
|
}
|
|
rz_config_set_b(core->config, "asm.bb.middle", orig_bb_middle);
|
|
return true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
// RZ_ANALYSIS_FCN_TYPE_FCN|RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!function) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
bool ret = core_walk_function_blocks(core, function, state, 'D', false);
|
|
rz_cmd_state_output_array_end(state);
|
|
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_from_current_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *function = rz_analysis_get_fcn_in(core->analysis, core->offset, 0);
|
|
// RZ_ANALYSIS_FCN_TYPE_FCN|RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!function) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
bool ret = core_walk_function_blocks(core, function, state, 'D', true);
|
|
rz_cmd_state_output_array_end(state);
|
|
return ret ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_recursively_no_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut64 old_offset = core->offset;
|
|
RzAnalysisOp aop = { 0 };
|
|
ut32 aop_type;
|
|
ut64 aop_jump;
|
|
int aop_size;
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
for (ut64 count = core->blocksize, offset = core->offset; count > 0; count--) {
|
|
rz_core_seek(core, offset, true);
|
|
|
|
rz_analysis_op_init(&aop);
|
|
int ret = rz_analysis_op(core->analysis, &aop, offset, core->block, core->blocksize, RZ_ANALYSIS_OP_MASK_BASIC);
|
|
if (ret > 0) {
|
|
aop_type = aop.type;
|
|
aop_jump = aop.jump;
|
|
aop_size = aop.size;
|
|
}
|
|
rz_analysis_op_fini(&aop);
|
|
|
|
if (ret < 1 || aop_size < 1) {
|
|
offset++;
|
|
continue;
|
|
}
|
|
|
|
core_disassembly(core, core->blocksize, 1, state, false);
|
|
|
|
switch (aop_type) {
|
|
case RZ_ANALYSIS_OP_TYPE_JMP:
|
|
offset = aop_jump;
|
|
continue;
|
|
case RZ_ANALYSIS_OP_TYPE_UCJMP:
|
|
break;
|
|
case RZ_ANALYSIS_OP_TYPE_RET:
|
|
count = 1; // stop disassembling when hitting RET
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
offset += aop_size;
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
|
|
rz_core_seek(core, old_offset, true);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_n_bytes_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc <= 1) {
|
|
RZ_LOG_ERROR("Invalid argument.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut64 n_bytes = rz_num_math(core->num, argv[1]);
|
|
// small patch to reuse rz_core_print_disasm_strings which
|
|
// needs to be rewritten entirely
|
|
char *string = rz_core_print_disasm_strings(core, argc > 1 ? RZ_CORE_DISASM_STRINGS_MODE_BYTES : RZ_CORE_DISASM_STRINGS_MODE_INST, n_bytes, NULL);
|
|
if (!string) {
|
|
RZ_LOG_ERROR("failed summarize bytes %" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(string);
|
|
free(string);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_function_handler(RzCore *core, int argc, const char **argv) {
|
|
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_FUNCTION, 0, NULL);
|
|
if (!string) {
|
|
RZ_LOG_ERROR("failed summarize function %" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(string);
|
|
free(string);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_disassemble_summarize_block_handler(RzCore *core, int argc, const char **argv) {
|
|
// small patch to reuse rz_core_print_disasm_strings which
|
|
// needs to be rewritten entirely
|
|
char *string = rz_core_print_disasm_strings(core, RZ_CORE_DISASM_STRINGS_MODE_BLOCK, 0, NULL);
|
|
if (!string) {
|
|
RZ_LOG_ERROR("failed summarize block %" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(string);
|
|
free(string);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_base64_encode_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
char *buf = rz_base64_encode_dyn((const unsigned char *)core->block, core->blocksize);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("rz_base64_encode_dyn: error\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println((const char *)buf);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_base64_decode_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
ut8 *buf = rz_base64_decode_dyn((const char *)core->block, core->blocksize);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("rz_base64_decode_dyn: error\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_println((const char *)buf);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_bitstream_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
int len = (int)rz_num_math(core->num, argv[1]);
|
|
int skip = (int)rz_num_math(core->num, argv[2]);
|
|
if (len < 0 || skip < 0) {
|
|
RZ_LOG_ERROR("len and skip should be positive numbers\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
// `pb len skip` means skip <skip> bits then print <len> bits
|
|
char *buf = RZ_NEWS0(char, len + skip + 1);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("Fail to allocate memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_str_bits(buf, core->block, len + skip, NULL);
|
|
rz_cons_println(buf + skip);
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_byte_bitstream_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
ut64 start = core->offset;
|
|
int len = (int)rz_num_math(core->num, argv[1]);
|
|
if (len < 0) {
|
|
start = core->offset + len;
|
|
len *= -1;
|
|
}
|
|
ut8 *bit_buf = RZ_NEWS0(ut8, len);
|
|
char *str_buf = RZ_NEWS0(char, len * 8 + 1);
|
|
if (!bit_buf || !str_buf) {
|
|
RZ_LOG_ERROR("Fail to allocate memory\n");
|
|
free(bit_buf);
|
|
free(str_buf);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_read_at(core->io, start, bit_buf, len);
|
|
rz_str_bits(str_buf, (const ut8 *)bit_buf, len * 8, NULL);
|
|
rz_cons_println(str_buf);
|
|
free(bit_buf);
|
|
free(str_buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_asn1_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
|
RzASN1Object *asn1 = rz_asn1_object_parse(core->block, core->blocksize);
|
|
if (!asn1) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
char *res = rz_asn1_to_string(asn1, 0, mode == RZ_OUTPUT_MODE_STANDARD);
|
|
rz_asn1_object_free(asn1);
|
|
if (!res) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%s", res);
|
|
free(res);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_protobuf_standard_handler(RzCore *core, int argc, const char **argv) {
|
|
char *s = rz_protobuf_decode(core->block, core->blocksize, false);
|
|
if (!s) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%s", s);
|
|
free(s);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_protobuf_verbose_handler(RzCore *core, int argc, const char **argv) {
|
|
char *s = rz_protobuf_decode(core->block, core->blocksize, true);
|
|
if (!s) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%s", s);
|
|
free(s);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_pkcs7_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
char *res = NULL;
|
|
RzCMS *cms = rz_pkcs7_cms_parse(core->block, core->blocksize);
|
|
if (!cms) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
}
|
|
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
rz_pkcs7_cms_json(cms, state->d.pj);
|
|
break;
|
|
default:
|
|
res = rz_pkcs7_cms_to_string(cms);
|
|
if (res) {
|
|
rz_cons_printf("%s", res);
|
|
free(res);
|
|
}
|
|
break;
|
|
}
|
|
rz_pkcs7_cms_free(cms);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_x509_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
char *res = NULL;
|
|
RzStrBuf *sb = NULL;
|
|
RzX509Certificate *x509 = rz_x509_certificate_parse2(core->block, core->blocksize);
|
|
if (!x509) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
rz_x509_certificate_json(state->d.pj, x509);
|
|
break;
|
|
default:
|
|
sb = rz_strbuf_new(NULL);
|
|
if (!sb) {
|
|
RZ_LOG_ERROR("core: failed to allocate RzStrBuf\n");
|
|
rz_x509_certificate_free(x509);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_x509_certificate_dump(x509, NULL, sb);
|
|
res = rz_strbuf_drain(sb);
|
|
if (res) {
|
|
rz_cons_printf("%s", res);
|
|
free(res);
|
|
}
|
|
break;
|
|
}
|
|
rz_x509_certificate_free(x509);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_axml_handler(RzCore *core, int argc, const char **argv) {
|
|
char *s = rz_axml_decode(core->block, core->blocksize);
|
|
if (!s) {
|
|
RZ_LOG_ERROR("core: Malformed object: did you supply enough data?\ntry to change the block size (see b? or @!<size>)\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%s", s);
|
|
free(s);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
typedef struct {
|
|
ut64 size;
|
|
ut64 repeat;
|
|
bool useBytes;
|
|
} PrintValueOptions;
|
|
|
|
static void print_value_single(RzCore *core, PrintValueOptions *opts, ut64 address, ut64 value, RzCmdStateOutput *state) {
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_RIZIN:
|
|
rz_cons_printf("f pval.0x%08" PFMT64x " @ %" PFMT64d "\n", address, value);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
switch (opts->size) {
|
|
case 1:
|
|
rz_cons_printf("0x%02" PFMT64x "\n", value);
|
|
break;
|
|
case 2:
|
|
rz_cons_printf("0x%04" PFMT64x "\n", value);
|
|
break;
|
|
case 4:
|
|
rz_cons_printf("0x%08" PFMT64x "\n", value);
|
|
break;
|
|
case 8:
|
|
rz_cons_printf("0x%016" PFMT64x "\n", value);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON: {
|
|
// TODO: Use API instead of the command
|
|
char *str = rz_core_cmd_str(core, "ps");
|
|
rz_str_trim(str);
|
|
char *p = str;
|
|
if (p) {
|
|
while (*p) {
|
|
if (*p == '\\' && p[1] == 'x') {
|
|
memmove(p, p + 4, strlen(p + 4) + 1);
|
|
}
|
|
p++;
|
|
}
|
|
}
|
|
pj_o(state->d.pj);
|
|
pj_k(state->d.pj, "value");
|
|
switch (opts->size) {
|
|
case 1:
|
|
case 2:
|
|
pj_i(state->d.pj, value);
|
|
break;
|
|
case 4:
|
|
case 8:
|
|
pj_n(state->d.pj, value);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
pj_ks(state->d.pj, "string", str);
|
|
free(str);
|
|
pj_end(state->d.pj);
|
|
break;
|
|
}
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool print_value(RzCore *core, PrintValueOptions *opts, RzCmdStateOutput *state) {
|
|
ut64 old_at = core->offset;
|
|
ut8 *block = core->block;
|
|
int blocksize = core->blocksize;
|
|
ut8 *block_end = core->block + blocksize;
|
|
|
|
bool big_endian = rz_config_get_b(core->config, "cfg.bigendian");
|
|
if (block + 8 >= block_end) {
|
|
RZ_LOG_ERROR("core: block is truncated.\n");
|
|
return false;
|
|
}
|
|
ut64 repeat = opts->repeat;
|
|
if (opts->useBytes && opts->size > 0 && repeat > 0) {
|
|
repeat /= opts->size;
|
|
}
|
|
ut64 at = old_at;
|
|
rz_cmd_state_output_array_start(state);
|
|
do {
|
|
rz_core_seek(core, at, false);
|
|
|
|
ut64 v = 0;
|
|
switch (opts->size) {
|
|
case 1:
|
|
v = rz_read_ble8(block);
|
|
block += opts->size;
|
|
break;
|
|
case 2:
|
|
v = rz_read_ble16(block, big_endian);
|
|
block += opts->size;
|
|
break;
|
|
case 4:
|
|
v = rz_read_ble32(block, big_endian);
|
|
block += opts->size;
|
|
break;
|
|
case 8:
|
|
v = rz_read_ble64(block, big_endian);
|
|
block += opts->size;
|
|
break;
|
|
case 0:
|
|
v = rz_read_ble64(block, big_endian);
|
|
opts->size = core->rasm->bits / 8;
|
|
switch (core->rasm->bits / 8) {
|
|
case 1: v &= UT8_MAX; break;
|
|
case 2: v &= UT16_MAX; break;
|
|
case 4: v &= UT32_MAX; break;
|
|
case 8: v &= UT64_MAX; break;
|
|
default: break;
|
|
}
|
|
block += core->rasm->bits / 8;
|
|
break;
|
|
}
|
|
print_value_single(core, opts, at, v, state);
|
|
repeat--;
|
|
at += opts->size;
|
|
} while (repeat > 0);
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_core_seek(core, old_at, false);
|
|
return true;
|
|
}
|
|
|
|
static RzCmdStatus print_value_size(RzCore *core, RzCmdStateOutput *state, int argc, const char **argv, ut64 size) {
|
|
int repeat = argc > 1 ? rz_num_math(NULL, argv[1]) : 1;
|
|
if (repeat <= 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
PrintValueOptions opts = {
|
|
.size = size,
|
|
.repeat = repeat,
|
|
.useBytes = false
|
|
};
|
|
return bool2status(print_value(core, &opts, state));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_value_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_value_size(core, state, argc, argv, 0);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_value1_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_value_size(core, state, argc, argv, 1);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_value2_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_value_size(core, state, argc, argv, 2);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_value4_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_value_size(core, state, argc, argv, 4);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_value8_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_value_size(core, state, argc, argv, 8);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_url_encode_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = core->block;
|
|
opt.length = len;
|
|
opt.encoding = RZ_STRING_ENC_8BIT;
|
|
opt.urlencode = true;
|
|
core_print_raw_buffer(&opt);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_url_encode_wide_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = core->block;
|
|
opt.length = len;
|
|
opt.encoding = RZ_STRING_ENC_UTF16LE;
|
|
opt.urlencode = true;
|
|
core_print_raw_buffer(&opt);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_url_encode_zero_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
RzStrStringifyOpt opt = { 0 };
|
|
opt.buffer = core->block;
|
|
opt.length = len;
|
|
opt.stop_at_nil = true;
|
|
opt.stop_at_unprintable = true;
|
|
opt.encoding = RZ_STRING_ENC_8BIT;
|
|
opt.urlencode = true;
|
|
core_print_raw_buffer(&opt);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern0_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (st64 i = 0; i < len; i++) {
|
|
rz_cons_print("00");
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern1_handler(RzCore *core, int argc, const char **argv) {
|
|
st8 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 min = (core->offset & 0xff);
|
|
for (ut8 i = 0; i < len; i++) {
|
|
rz_cons_printf("%02x", i + min);
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern2_handler(RzCore *core, int argc, const char **argv) {
|
|
st16 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
// TODO: honor cfg.bigendian
|
|
ut16 min = (core->offset & 0xffff);
|
|
for (ut16 i = 0; i < len; i++) {
|
|
rz_cons_printf("%04x", i + min);
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern4_handler(RzCore *core, int argc, const char **argv) {
|
|
st32 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
// TODO: honor cfg.bigendian
|
|
ut32 min = (core->offset & UT32_MAX);
|
|
for (ut32 i = 0; i < len; i++) {
|
|
rz_cons_printf("%08" PFMT32x, i + min);
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern8_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
// TODO: honor cfg.bigendian
|
|
ut64 min = (core->offset);
|
|
for (ut64 i = 0; i < len; i++) {
|
|
rz_cons_printf("%016" PFMT64x, i + min);
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern_latin_alphabet_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
size_t bs = 4;
|
|
ut8 *buf = calloc(bs, 1);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("Cannot allocate buffer\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (st64 i = 0; i < len; i++) {
|
|
incAlphaBuffer(buf, bs);
|
|
for (st64 j = 0; j < bs; j++) {
|
|
rz_cons_printf("%c", buf[j] ? buf[j] : 'A');
|
|
}
|
|
rz_cons_printf(" ");
|
|
}
|
|
rz_cons_newline();
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern_debrujin_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *buf = (ut8 *)rz_debruijn_pattern(len, 0, NULL);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("Cannot generate De Brujin pattern\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (st64 i = 0; i < len; i++) {
|
|
rz_cons_printf("%02x", buf[i]);
|
|
}
|
|
rz_cons_newline();
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern_oxff_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (st64 i = 0; i < len; i++) {
|
|
rz_cons_print("ff");
|
|
}
|
|
rz_cons_newline();
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_pattern_num_handler(RzCore *core, int argc, const char **argv) {
|
|
st64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 1) {
|
|
RZ_LOG_ERROR("Invalid pattern length\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
size_t bs = 4;
|
|
ut8 *buf = calloc(bs, 1);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("Cannot allocate buffer\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (st64 i = 0; i < len; i++) {
|
|
incDigitBuffer(buf, bs);
|
|
for (st64 j = 0; j < bs; j++) {
|
|
rz_cons_printf("%c", buf[j] ? buf[j] : '0');
|
|
}
|
|
rz_cons_printf(" ");
|
|
}
|
|
rz_cons_newline();
|
|
free(buf);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_2swap_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP2, NULL));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_4swap_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP4, NULL));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_8swap_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_BYTESWAP8, NULL));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_add_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_ADD, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_and_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_AND, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_div_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_DIV, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_shl_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SHIFT_LEFT, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_mul_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_MUL, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_or_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_OR, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_shr_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SHIFT_RIGHT, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_sub_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_SUB, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_operation_xor_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(print_operation_transform(core, RZ_CORE_WRITE_OP_XOR, argv[1]));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_key_randomart_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len == 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
len = len > core->blocksize ? core->blocksize : len;
|
|
char *s = rz_hash_cfg_randomart(core->block, len, core->offset);
|
|
rz_cons_println(s);
|
|
free(s);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_key_mosaic_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len == 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
len = len > core->blocksize ? core->blocksize : len;
|
|
int w, h;
|
|
RzConsCanvas *c;
|
|
w = rz_cons_get_size(&h);
|
|
ut64 offset0 = core->offset;
|
|
int cols = (w / 20);
|
|
int rows = (h / 12);
|
|
int i, j;
|
|
char *s;
|
|
if (rows < 1) {
|
|
rows = 1;
|
|
}
|
|
c = rz_cons_canvas_new(w, rows * 11);
|
|
for (i = 0; i < rows; i++) {
|
|
for (j = 0; j < cols; j++) {
|
|
rz_cons_canvas_gotoxy(c, j * 20, i * 11);
|
|
core->offset += len;
|
|
rz_io_read_at(core->io, core->offset, core->block, len);
|
|
s = rz_hash_cfg_randomart(core->block, len, core->offset);
|
|
rz_cons_canvas_write(c, s);
|
|
free(s);
|
|
}
|
|
}
|
|
rz_cons_canvas_print(c);
|
|
rz_cons_canvas_free(c);
|
|
rz_io_read_at(core->io, offset0, core->block, len);
|
|
core->offset = offset0;
|
|
rz_cons_printf("\n");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc <= 1) {
|
|
RZ_LOG_ERROR("Invalid arguments\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut64 N = rz_num_math(core->num, argv[1]);
|
|
if (N == 0) {
|
|
RZ_LOG_ERROR("The argument cannot be zero\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_print_disasm_instructions(core, 0, N);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_opcodes_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 N = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (N == 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_print_disasm_all(core, core->offset, N, N, 'i');
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_block_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAnalysisBlock *b = rz_analysis_find_most_relevant_block_in(core->analysis, core->offset);
|
|
if (!b) {
|
|
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
core->num->value = 0;
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_print_disasm_instructions(core, b->size - (core->offset - b->addr), 0);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_esil_handler(RzCore *core, int argc, const char **argv) {
|
|
ut64 N = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (N == 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_core_disasm_pdi(core, N, 0, 'e');
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
return rz_cmd_disassembly_function_handler(core, argc, argv, state);
|
|
}
|
|
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!f) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
ut32 bsz = core->blocksize;
|
|
// int fsz = rz_analysis_function_realsize (f);
|
|
int fsz = rz_analysis_function_linear_size(f); // we want max-min here
|
|
rz_core_block_size(core, fsz);
|
|
rz_core_print_disasm_instructions(core, fsz, 0);
|
|
rz_core_block_size(core, bsz);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_calls_function_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzListIter *iter;
|
|
RzAnalysisXRef *xrefi;
|
|
RzList *refs = NULL;
|
|
|
|
rz_cmd_state_output_array_start(state);
|
|
// get function in current offset
|
|
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
|
|
if (!f) {
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
// get all the calls of the function
|
|
refs = rz_core_analysis_fcn_get_calls(core, f);
|
|
if (rz_list_empty(refs)) {
|
|
rz_cmd_state_output_array_end(state);
|
|
rz_list_free(refs);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
// store current configurations
|
|
RzConfigHold *hc = rz_config_hold_new(core->config);
|
|
rz_config_hold_i(hc, "asm.offset", NULL);
|
|
rz_config_hold_i(hc, "asm.comments", NULL);
|
|
rz_config_hold_i(hc, "asm.tabs", NULL);
|
|
rz_config_hold_i(hc, "asm.bytes", NULL);
|
|
rz_config_hold_i(hc, "emu.str", NULL);
|
|
|
|
// temporarily replace configurations
|
|
rz_config_set_i(core->config, "asm.offset", false);
|
|
rz_config_set_i(core->config, "asm.comments", false);
|
|
rz_config_set_i(core->config, "asm.tabs", 0);
|
|
rz_config_set_i(core->config, "asm.bytes", false);
|
|
rz_config_set_i(core->config, "emu.str", false);
|
|
|
|
// iterate over all call references
|
|
rz_list_foreach (refs, iter, xrefi) {
|
|
if (state->mode == RZ_OUTPUT_MODE_JSON) {
|
|
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, xrefi->to,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
char *dst = rz_str_newf((f ? f->name : "0x%08" PFMT64x), xrefi->to);
|
|
char *dst2 = NULL;
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, xrefi->to, RZ_ANALYSIS_OP_MASK_BASIC);
|
|
RzBinReloc *rel = rz_core_getreloc(core, xrefi->to, op->size);
|
|
if (rel) {
|
|
if (rel && rel->import && rel->import->name) {
|
|
dst2 = rel->import->name;
|
|
} else if (rel && rel->symbol && rel->symbol->name) {
|
|
dst2 = rel->symbol->name;
|
|
}
|
|
} else {
|
|
dst2 = dst;
|
|
}
|
|
pj_o(state->d.pj);
|
|
pj_ks(state->d.pj, "dest", dst2);
|
|
pj_kn(state->d.pj, "addr", xrefi->to);
|
|
pj_kn(state->d.pj, "at", xrefi->from);
|
|
pj_end(state->d.pj);
|
|
rz_analysis_op_free(op);
|
|
free(dst);
|
|
} else {
|
|
ut64 off = core->offset;
|
|
rz_core_seek(core, xrefi->from, true);
|
|
core_disassembly(core, 1, 1, state, false);
|
|
rz_core_seek(core, off, true);
|
|
}
|
|
}
|
|
|
|
rz_list_free(refs);
|
|
|
|
// restore saved configuration
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
|
|
rz_cmd_state_output_array_end(state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_recursive_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!f) {
|
|
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
core->num->value = 0;
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
func_walk_blocks(core, f, false, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_recursive_at_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
RzAnalysisFunction *f = rz_analysis_get_fcn_in(core->analysis, core->offset,
|
|
RZ_ANALYSIS_FCN_TYPE_FCN | RZ_ANALYSIS_FCN_TYPE_SYM);
|
|
if (!f) {
|
|
RZ_LOG_ERROR("core: Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
core->num->value = 0;
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
func_walk_blocks(core, f, true, state);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_instr_until_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
const ut64 limit = argc > 1 ? rz_num_math(core->num, argv[1]) : 1024;
|
|
if (!rz_core_disasm_until_ret(core, core->offset, limit, state->mode, false, NULL)) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
typedef struct rz_core_analysis_stats_range_t {
|
|
RzCoreAnalysisStats *as;
|
|
ut64 from;
|
|
ut64 to;
|
|
ut64 piece;
|
|
} RzCoreAnalysisStatsRange;
|
|
|
|
static RzCoreAnalysisStatsRange *analysis_stats_range(RzCore *core, int width) {
|
|
int cols = rz_config_get_i(core->config, "hex.cols");
|
|
int w = RZ_MAX(cols, width);
|
|
|
|
ut64 from = UT64_MAX;
|
|
ut64 to = 0;
|
|
|
|
RzList *list = rz_core_get_boundaries_select(core, "search.from", "search.to", "search.in");
|
|
if (rz_list_empty(list)) {
|
|
RZ_LOG_ERROR("No range to calculate stats for.\n");
|
|
rz_list_free(list);
|
|
return NULL;
|
|
}
|
|
RzCoreAnalysisStatsRange *srange = RZ_NEW0(RzCoreAnalysisStatsRange);
|
|
if (!srange) {
|
|
rz_list_free(list);
|
|
return NULL;
|
|
}
|
|
RzListIter *iter;
|
|
RzIOMap *map;
|
|
rz_list_foreach (list, iter, map) {
|
|
ut64 f = rz_itv_begin(map->itv);
|
|
ut64 t = rz_itv_end(map->itv);
|
|
if (f < from) {
|
|
from = f;
|
|
}
|
|
if (t > to) {
|
|
to = t;
|
|
}
|
|
}
|
|
rz_list_free(list);
|
|
srange->from = from;
|
|
srange->to = to;
|
|
|
|
ut64 piece = RZ_MAX((to - from) / w, 1);
|
|
if (piece * w != to - from) {
|
|
// add 1 to compute `piece = ceil((to - from) / w)` instead
|
|
piece++;
|
|
}
|
|
srange->piece = piece;
|
|
|
|
srange->as = rz_core_analysis_get_stats(core, from, to - 1, piece);
|
|
return srange;
|
|
}
|
|
|
|
static void analysis_stats_range_free(RzCoreAnalysisStatsRange *srange) {
|
|
if (!srange) {
|
|
return;
|
|
}
|
|
rz_core_analysis_stats_free(srange->as);
|
|
free(srange);
|
|
}
|
|
|
|
static void analysis_stats_standard_info(RzCore *core, RzCoreAnalysisStatsRange *srange, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, bool use_color) {
|
|
ut64 at = rz_core_analysis_stats_get_block_from(srange->as, blockidx);
|
|
ut64 ate = rz_core_analysis_stats_get_block_to(srange->as, blockidx) + 1;
|
|
if (core->offset >= at && core->offset < ate) {
|
|
rz_cons_memcat("^", 1);
|
|
} else {
|
|
RzIOMap *s = rz_io_map_get(core->io, at);
|
|
if (use_color) {
|
|
if (s) {
|
|
if (s->perm & RZ_PERM_X) {
|
|
rz_cons_print(rz_cons_singleton()->context->pal.graph_ujump);
|
|
} else {
|
|
rz_cons_print(rz_cons_singleton()->context->pal.graph_true);
|
|
}
|
|
} else {
|
|
rz_cons_print(rz_cons_singleton()->context->pal.graph_false);
|
|
}
|
|
}
|
|
if (sitem->strings > 0) {
|
|
rz_cons_memcat("z", 1);
|
|
} else if (sitem->symbols > 0) {
|
|
rz_cons_memcat("s", 1);
|
|
} else if (sitem->functions > 0) {
|
|
rz_cons_memcat("F", 1);
|
|
} else if (sitem->comments > 0) {
|
|
rz_cons_memcat("c", 1);
|
|
} else if (sitem->flags > 0) {
|
|
rz_cons_memcat(".", 1);
|
|
} else if (sitem->in_functions > 0) {
|
|
rz_cons_memcat("f", 1);
|
|
} else {
|
|
rz_cons_memcat("_", 1);
|
|
}
|
|
}
|
|
if (use_color) {
|
|
rz_cons_print(Color_RESET);
|
|
}
|
|
}
|
|
|
|
static void analysis_stats_json_info(RzCore *core, RzCoreAnalysisStats *as, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, RzCmdStateOutput *state) {
|
|
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
|
|
ut64 ate = rz_core_analysis_stats_get_block_to(as, blockidx) + 1;
|
|
pj_o(state->d.pj);
|
|
if ((sitem->flags) || (sitem->functions) || (sitem->comments) || (sitem->symbols) || (sitem->perm) || (sitem->strings)) {
|
|
pj_kn(state->d.pj, "offset", at);
|
|
pj_kn(state->d.pj, "size", ate - at);
|
|
}
|
|
if (sitem->flags) {
|
|
pj_ki(state->d.pj, "flags", sitem->flags);
|
|
}
|
|
if (sitem->functions) {
|
|
pj_ki(state->d.pj, "functions", sitem->functions);
|
|
}
|
|
if (sitem->in_functions) {
|
|
pj_ki(state->d.pj, "in_functions", sitem->in_functions);
|
|
}
|
|
if (sitem->comments) {
|
|
pj_ki(state->d.pj, "comments", sitem->comments);
|
|
}
|
|
if (sitem->symbols) {
|
|
pj_ki(state->d.pj, "symbols", sitem->symbols);
|
|
}
|
|
if (sitem->strings) {
|
|
pj_ki(state->d.pj, "strings", sitem->strings);
|
|
}
|
|
if (sitem->perm) {
|
|
pj_ks(state->d.pj, "perm", rz_str_rwx_i(sitem->perm));
|
|
}
|
|
pj_end(state->d.pj);
|
|
}
|
|
|
|
static void analysis_stats_table_info(RzCore *core, RzCoreAnalysisStats *as, RzCoreAnalysisStatsItem *sitem, ut64 blockidx, RzCmdStateOutput *state) {
|
|
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
|
|
if ((sitem->flags) || (sitem->functions) || (sitem->comments) || (sitem->symbols) || (sitem->strings)) {
|
|
rz_table_add_rowf(state->d.t, "xddddd", at, sitem->flags,
|
|
sitem->functions, sitem->comments, sitem->symbols, sitem->strings);
|
|
}
|
|
}
|
|
|
|
static void analysis_stats_entropy_info(RzCore *core, RzCoreAnalysisStats *as, ut64 blockidx, bool use_color) {
|
|
ut64 at = rz_core_analysis_stats_get_block_from(as, blockidx);
|
|
ut64 ate = rz_core_analysis_stats_get_block_to(as, blockidx) + 1;
|
|
ut8 *blockptr = malloc(ate - at);
|
|
if (!blockptr) {
|
|
return;
|
|
}
|
|
if (rz_io_read_at(core->io, at, blockptr, (ate - at))) {
|
|
ut8 entropy = (ut8)(rz_hash_entropy_fraction(blockptr, (ate - at)) * 255);
|
|
entropy = 9 * entropy / 200; // normalize entropy from 0 to 9
|
|
if (use_color) {
|
|
const char *color =
|
|
(entropy > 6) ? Color_BGRED : (entropy > 3) ? Color_BGGREEN
|
|
: Color_BGBLUE;
|
|
rz_cons_printf("%s%d" Color_RESET, color, entropy);
|
|
} else {
|
|
rz_cons_printf("%d", entropy);
|
|
}
|
|
}
|
|
free(blockptr);
|
|
if (use_color) {
|
|
rz_cons_print(Color_RESET);
|
|
}
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_minus_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
|
|
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
|
|
if (!srange) {
|
|
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bool use_color = rz_config_get_i(core->config, "scr.color");
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
pj_o(state->d.pj);
|
|
pj_kn(state->d.pj, "from", srange->from);
|
|
pj_kn(state->d.pj, "to", srange->to);
|
|
pj_ki(state->d.pj, "blocksize", srange->piece);
|
|
pj_ka(state->d.pj, "blocks");
|
|
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
|
|
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
|
|
analysis_stats_json_info(core, srange->as, sitem, i, state);
|
|
}
|
|
pj_end(state->d.pj);
|
|
pj_end(state->d.pj);
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
rz_cons_printf("0x%08" PFMT64x " [", srange->from);
|
|
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
|
|
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
|
|
analysis_stats_standard_info(core, srange, sitem, i, use_color);
|
|
}
|
|
rz_cons_printf("] 0x%08" PFMT64x "\n", srange->to);
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
break;
|
|
}
|
|
analysis_stats_range_free(srange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_minus_entropy_handler(RzCore *core, int argc, const char **argv) {
|
|
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
|
|
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
|
|
if (!srange) {
|
|
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
bool use_color = rz_config_get_i(core->config, "scr.color");
|
|
rz_cons_printf("0x%08" PFMT64x " [", srange->from);
|
|
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
|
|
analysis_stats_entropy_info(core, srange->as, i, use_color);
|
|
}
|
|
rz_cons_printf("] 0x%08" PFMT64x "\n", srange->to);
|
|
analysis_stats_range_free(srange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_minus_table_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int width = argc > 1 ? (int)rz_num_math(core->num, argv[1]) : (int)(core->print->cols * 2.7);
|
|
RzCoreAnalysisStatsRange *srange = analysis_stats_range(core, width);
|
|
if (!srange) {
|
|
RZ_LOG_ERROR("Cannot find valid range for calculating the analysis information\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cmd_state_output_array_start(state);
|
|
rz_cmd_state_output_set_columnsf(state, "xddddd", "offset", "flags", "funcs", "cmts", "syms", "str");
|
|
state->d.t->showSum = true;
|
|
state->d.t->showFancy = true;
|
|
for (size_t i = 0; i < rz_vector_len(&srange->as->blocks); i++) {
|
|
RzCoreAnalysisStatsItem *sitem = rz_vector_index_ptr(&srange->as->blocks, i);
|
|
analysis_stats_table_info(core, srange->as, sitem, i, state);
|
|
}
|
|
rz_cmd_state_output_array_end(state);
|
|
analysis_stats_range_free(srange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_disassembly_handler(RzCore *core, int argc, const char **argv) {
|
|
int h, w = rz_cons_get_size(&h);
|
|
int colwidth = rz_config_get_i(core->config, "hex.cols") * 2.5;
|
|
if (colwidth < 1) {
|
|
colwidth = 16;
|
|
}
|
|
int i, columns = w / colwidth;
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
int rows = user_rows > 0 ? user_rows : h - 2;
|
|
|
|
RzConfigHold *ch = rz_config_hold_new(core->config);
|
|
rz_config_hold_i(ch, "asm.offset", "asm.bytes", NULL);
|
|
if (rz_config_get_i(core->config, "asm.minicols")) {
|
|
rz_config_set_b(core->config, "asm.offset", false);
|
|
}
|
|
rz_config_set_b(core->config, "asm.bytes", false);
|
|
|
|
RzConsCanvas *c = rz_cons_canvas_new(w, rows);
|
|
ut64 osek = core->offset;
|
|
int pos_i = 0;
|
|
c->color = rz_config_get_i(core->config, "scr.color");
|
|
for (i = 0; i < columns; i++) {
|
|
(void)rz_cons_canvas_gotoxy(c, i * (w / columns), 0);
|
|
// TODO: Use the API directly
|
|
char *cmd = rz_str_newf("pdq %d @i:%d", rows, pos_i);
|
|
char *dis = rz_core_cmd_str(core, cmd);
|
|
if (dis) {
|
|
RzList *dis_lines = rz_str_split_duplist_n(dis, "\n", 0, false);
|
|
ut32 n_lines = rz_list_length(dis_lines);
|
|
rz_list_free(dis_lines);
|
|
|
|
// If the output contains more lines than expected, do not move
|
|
// forward the whole chunk as some data will be hidden.
|
|
if (n_lines > rows) {
|
|
pos_i -= (n_lines - rows - 1);
|
|
}
|
|
|
|
rz_cons_canvas_write(c, dis);
|
|
}
|
|
free(cmd);
|
|
free(dis);
|
|
|
|
pos_i += rows;
|
|
}
|
|
rz_core_seek(core, osek, true);
|
|
|
|
rz_cons_canvas_print(c);
|
|
rz_cons_canvas_free(c);
|
|
rz_cons_printf("\n");
|
|
|
|
rz_config_hold_restore(ch);
|
|
rz_config_hold_free(ch);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void print_stack(RzCore *core) {
|
|
RzCmdStateOutput so;
|
|
ut64 sp_addr = rz_core_reg_getv_by_role_or_name(core, "SP");
|
|
if (rz_config_get_b(core->config, "dbg.slow")) {
|
|
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD);
|
|
int wordsize = rz_analysis_get_address_bits(core->analysis) / 8;
|
|
cmd_pxr(core, sp_addr, 128, &so, wordsize, NULL);
|
|
rz_cmd_state_output_print(&so);
|
|
rz_cmd_state_output_fini(&so);
|
|
} else if (rz_config_get_b(core->config, "stack.bytes")) {
|
|
char *string = rz_core_print_hexdump_or_hexdiff_str(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 128, false);
|
|
if (!string) {
|
|
RZ_LOG_ERROR("fail to print hexdump at 0x%" PFMT64x "\n", sp_addr);
|
|
return; // TODO: free stuff
|
|
}
|
|
rz_cons_print(string);
|
|
} else if (core->rasm->bits == 64) {
|
|
rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 8, 128, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL);
|
|
} else if (core->rasm->bits == 32) {
|
|
rz_core_print_dump(core, RZ_OUTPUT_MODE_STANDARD, sp_addr, 4, 128, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL);
|
|
}
|
|
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD);
|
|
core_disassembly(core, core->blocksize, 0, &so, false);
|
|
rz_cmd_state_output_fini(&so);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_debug_handler(RzCore *core, int argc, const char **argv) {
|
|
if (!rz_config_get_b(core->config, "cfg.debug")) {
|
|
RZ_LOG_ERROR("Command works only in debug mode\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int h, w = rz_cons_get_size(&h);
|
|
int rows = h - 2;
|
|
int obsz = core->blocksize;
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
if (user_rows > 0) {
|
|
rows = user_rows;
|
|
}
|
|
bool asm_minicols = rz_config_get_i(core->config, "asm.minicols");
|
|
char *o_ao = rz_str_dup(rz_config_get(core->config, "asm.offset"));
|
|
char *o_ab = rz_str_dup(rz_config_get(core->config, "asm.bytes"));
|
|
if (asm_minicols) {
|
|
// Set asm.offset and asm.bytes configs to false to avoid printing them
|
|
rz_config_set_b(core->config, "asm.offset", false);
|
|
rz_config_set_b(core->config, "asm.bytes", false);
|
|
}
|
|
rz_config_set_b(core->config, "asm.bytes", false);
|
|
RzConsCanvas *c = rz_cons_canvas_new(w, rows);
|
|
ut64 osek = core->offset;
|
|
c->color = rz_config_get_i(core->config, "scr.color");
|
|
rz_core_block_size(core, rows * 32);
|
|
|
|
// Left column
|
|
RzCmdStateOutput so;
|
|
(void)rz_cons_canvas_gotoxy(c, 0, 0);
|
|
rz_cons_push();
|
|
rz_debug_regs_args_handler(core, 0, NULL, RZ_OUTPUT_MODE_STANDARD);
|
|
rz_cons_print("\nbacktrace:\n");
|
|
rz_cmd_state_output_init(&so, RZ_OUTPUT_MODE_STANDARD);
|
|
rz_cmd_debug_display_bt_handler(core, 0, NULL, &so);
|
|
rz_cmd_state_output_print(&so);
|
|
rz_cmd_state_output_fini(&so);
|
|
rz_cons_canvas_write(c, rz_cons_get_buffer());
|
|
rz_cons_pop();
|
|
|
|
// Right column
|
|
(void)rz_cons_canvas_gotoxy(c, RZ_MAX(w / 3, 28), 0);
|
|
rz_cons_push();
|
|
print_stack(core);
|
|
rz_cons_canvas_write(c, rz_cons_get_buffer());
|
|
rz_cons_pop();
|
|
|
|
rz_core_block_size(core, obsz);
|
|
rz_core_seek(core, osek, true);
|
|
rz_cons_canvas_print(c);
|
|
rz_cons_canvas_free(c);
|
|
|
|
if (asm_minicols) {
|
|
rz_config_set(core->config, "asm.offset", o_ao);
|
|
rz_config_set(core->config, "asm.bytes", o_ab);
|
|
}
|
|
rz_config_set(core->config, "asm.bytes", o_ab);
|
|
free(o_ao);
|
|
free(o_ab);
|
|
rz_cons_printf("\n");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static bool print_hexdump_columns(RzCore *core, int user_rows, bool has_header, const char *xcmd) {
|
|
int h, w = rz_cons_get_size(&h);
|
|
int hex_cols = rz_config_get_i(core->config, "hex.cols");
|
|
int colwidth = hex_cols * 5;
|
|
int i, columns = w / (colwidth * 0.9);
|
|
int rows = user_rows > 0 ? user_rows : h - 2;
|
|
|
|
RzConfigHold *ch = rz_config_hold_new(core->config);
|
|
rz_config_hold_i(ch, "hex.cols", NULL);
|
|
rz_config_set_i(core->config, "hex.cols", colwidth / 5);
|
|
|
|
// Add one more line for the hexdump header
|
|
int canvas_rows = rows + (has_header ? 1 : 0);
|
|
RzConsCanvas *c = rz_cons_canvas_new(w, canvas_rows);
|
|
if (!c) {
|
|
RZ_LOG_ERROR("core: Couldn't allocate a canvas with %d rows\n", rows);
|
|
rz_config_set_i(core->config, "hex.cols", hex_cols);
|
|
return false;
|
|
}
|
|
|
|
ut64 tsek = core->offset;
|
|
c->color = rz_config_get_i(core->config, "scr.color");
|
|
int bsize = hex_cols * rows;
|
|
if (!strcmp(xcmd, "pxAl")) {
|
|
bsize *= 12;
|
|
}
|
|
for (i = 0; i < columns; i++) {
|
|
(void)rz_cons_canvas_gotoxy(c, i * (w / columns), 0);
|
|
char *cmd = rz_str_newf("%s %d @ %" PFMT64u, xcmd, bsize, tsek);
|
|
char *dis = rz_core_cmd_str(core, cmd);
|
|
if (dis) {
|
|
RzList *dis_lines = rz_str_split_duplist_n(dis, "\n", 0, false);
|
|
// Count the lines do not contain actual data and handle them for
|
|
// the next column
|
|
RzListIter *it;
|
|
char *line;
|
|
int i = 0, diff_lines = 0;
|
|
rz_list_foreach (dis_lines, it, line) {
|
|
if (line[0] == ' ' && i < canvas_rows) {
|
|
diff_lines++;
|
|
}
|
|
i++;
|
|
}
|
|
rz_list_free(dis_lines);
|
|
if (!UT64_MUL_OVFCHK(diff_lines, hex_cols)) {
|
|
tsek -= diff_lines * hex_cols;
|
|
}
|
|
|
|
rz_cons_canvas_write(c, dis);
|
|
free(dis);
|
|
}
|
|
free(cmd);
|
|
tsek += bsize;
|
|
}
|
|
|
|
rz_cons_canvas_print(c);
|
|
rz_cons_canvas_free(c);
|
|
rz_cons_printf("\n");
|
|
|
|
rz_config_hold_restore(ch);
|
|
rz_config_hold_free(ch);
|
|
return true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_hex_annotated_handler(RzCore *core, int argc, const char **argv) {
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
return bool2status(print_hexdump_columns(core, user_rows, true, "pxa"));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_hex_op_colored_handler(RzCore *core, int argc, const char **argv) {
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
return bool2status(print_hexdump_columns(core, user_rows, false, "pxAl"));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_hex_handler(RzCore *core, int argc, const char **argv) {
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
return bool2status(print_hexdump_columns(core, user_rows, true, "px"));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_columns_hex_words_handler(RzCore *core, int argc, const char **argv) {
|
|
int user_rows = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
return bool2status(print_hexdump_columns(core, user_rows, false, "pxw"));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_d_handler(RzCore *core, int argc, const char **argv) {
|
|
int min = -1, max = 0, dict = 0, range = 0;
|
|
bool histogram[256] = { 0 };
|
|
const ut8 *block = core->block;
|
|
ut32 bsz = core->blocksize;
|
|
for (size_t i = 0; i < bsz; i++) {
|
|
histogram[block[i]] = true;
|
|
}
|
|
for (size_t i = 0; i < 256; i++) {
|
|
if (histogram[i]) {
|
|
if (min == -1) {
|
|
min = i;
|
|
}
|
|
max = i;
|
|
dict++;
|
|
}
|
|
}
|
|
range = max - min;
|
|
rz_cons_printf("min: %d 0x%x\n", min, min);
|
|
rz_cons_printf("max: %d 0x%x\n", max, max);
|
|
rz_cons_printf("unique (count): %d 0x%x\n", dict, dict);
|
|
rz_cons_printf("range (max-min): %d 0x%x\n", range, range);
|
|
rz_cons_printf("size (of block): %d 0x%x\n", bsz, bsz);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
typedef struct core_block_range_t {
|
|
ut64 from;
|
|
ut64 to;
|
|
ut64 totalsize;
|
|
int nblocks;
|
|
st64 blocksize;
|
|
int skipblocks;
|
|
} CoreBlockRange;
|
|
|
|
static CoreBlockRange *calculate_blocks_range(RzCore *core, ut64 from, ut64 to, ut64 totalsize, int nblocks, int skipblocks) {
|
|
if (nblocks == 0) {
|
|
return NULL;
|
|
}
|
|
CoreBlockRange *brange = RZ_NEW0(CoreBlockRange);
|
|
if (!brange) {
|
|
return NULL;
|
|
}
|
|
|
|
if (totalsize == UT64_MAX) {
|
|
if (rz_config_get_b(core->config, "cfg.debug")) {
|
|
RzDebugMap *map = rz_debug_map_get(core->dbg, core->offset);
|
|
if (map) {
|
|
brange->totalsize = map->addr_end - map->addr;
|
|
brange->from = map->addr;
|
|
}
|
|
} else {
|
|
if (core->file && core->io) {
|
|
brange->totalsize = rz_io_fd_size(core->io, core->file->fd);
|
|
if ((st64)brange->totalsize < 1) {
|
|
brange->totalsize = UT64_MAX;
|
|
}
|
|
}
|
|
if (brange->totalsize == UT64_MAX) {
|
|
RZ_LOG_ERROR("core: Cannot determine file size\n");
|
|
free(brange);
|
|
return NULL;
|
|
}
|
|
}
|
|
} else {
|
|
brange->totalsize = totalsize;
|
|
}
|
|
st64 blocksize = core->blocksize;
|
|
// If we are not in the debug mode - use only current mapped ranges
|
|
if (!rz_config_get_b(core->config, "cfg.debug")) {
|
|
RzList *boundaries = rz_core_get_boundaries_select(core, "zoom.from", "zoom.to", "zoom.in");
|
|
if (!boundaries) {
|
|
free(brange);
|
|
return NULL;
|
|
}
|
|
RzIOMap *map = rz_list_first(boundaries);
|
|
if (map) {
|
|
brange->from = map->itv.addr;
|
|
RzIOMap *m;
|
|
RzListIter *iter;
|
|
rz_list_foreach (boundaries, iter, m) {
|
|
brange->to = rz_itv_end(m->itv);
|
|
}
|
|
brange->totalsize = brange->to - brange->from;
|
|
} else {
|
|
brange->from = core->offset;
|
|
}
|
|
rz_list_free(boundaries);
|
|
}
|
|
if (nblocks < 1) {
|
|
brange->nblocks = brange->totalsize / blocksize;
|
|
} else {
|
|
blocksize = brange->totalsize / nblocks;
|
|
brange->nblocks = nblocks;
|
|
}
|
|
if (skipblocks > 0) {
|
|
brange->skipblocks = skipblocks;
|
|
}
|
|
brange->blocksize = blocksize;
|
|
return brange;
|
|
}
|
|
|
|
typedef enum {
|
|
HISTOGRAM_ANALYSIS_BASIC_BLOCKS,
|
|
HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS,
|
|
HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS,
|
|
HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS,
|
|
HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS,
|
|
} CoreAnalysisHistogramType;
|
|
|
|
static inline void data_array_increment_element(ut8 *data, int i) {
|
|
if (data[i] < 0xff) {
|
|
data[i]++;
|
|
}
|
|
}
|
|
|
|
static bool if_aop_match_hist_type(RzAnalysisOp *op, CoreAnalysisHistogramType t) {
|
|
switch (t) {
|
|
case HISTOGRAM_ANALYSIS_BASIC_BLOCKS:
|
|
/* We do not need to check the op type in this case */
|
|
return false;
|
|
case HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS: {
|
|
switch (op->type) {
|
|
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
|
case RZ_ANALYSIS_OP_TYPE_CALL:
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS: {
|
|
if (op->family == RZ_ANALYSIS_OP_FAMILY_PRIV) {
|
|
return true;
|
|
}
|
|
switch (op->type) {
|
|
case RZ_ANALYSIS_OP_TYPE_SWI:
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS: {
|
|
switch (op->type) {
|
|
case RZ_ANALYSIS_OP_TYPE_TRAP:
|
|
case RZ_ANALYSIS_OP_TYPE_ILL:
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS: {
|
|
switch (op->type) {
|
|
case RZ_ANALYSIS_OP_TYPE_JMP:
|
|
// case RZ_ANALYSIS_OP_TYPE_RJMP:
|
|
// case RZ_ANALYSIS_OP_TYPE_UJMP:
|
|
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Counts all analysis metainformation units per block
|
|
static ut8 *analysis_stats_histogram_data(RzCore *core, CoreBlockRange *brange) {
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
if (!data) {
|
|
RZ_LOG_ERROR("core: Failed to allocate memory\n");
|
|
return NULL;
|
|
}
|
|
// FIXME: Should we just use the value from brange instead?
|
|
ut64 to = brange->from + (brange->blocksize * brange->nblocks) - 1;
|
|
if (to < brange->from) {
|
|
free(data);
|
|
return NULL;
|
|
}
|
|
RzCoreAnalysisStats *as = rz_core_analysis_get_stats(core, brange->from, to, brange->blocksize);
|
|
if (!as) {
|
|
free(data);
|
|
return NULL;
|
|
}
|
|
for (size_t i = 0; i < RZ_MIN(brange->nblocks, rz_vector_len(&as->blocks)); i++) {
|
|
int value = 0;
|
|
RzCoreAnalysisStatsItem *block = rz_vector_index_ptr(&as->blocks, i);
|
|
value += block->functions;
|
|
value += block->in_functions;
|
|
value += block->comments;
|
|
value += block->symbols;
|
|
value += block->flags;
|
|
value += block->strings;
|
|
value += block->blocks;
|
|
data[i] = RZ_MIN(255, value);
|
|
}
|
|
rz_core_analysis_stats_free(as);
|
|
return data;
|
|
}
|
|
|
|
static ut8 *analysis_histogram_data(RzCore *core, CoreBlockRange *brange, CoreAnalysisHistogramType hist_type) {
|
|
size_t j, i = 0;
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
if (!data) {
|
|
RZ_LOG_ERROR("core: Failed to allocate memory\n");
|
|
return NULL;
|
|
}
|
|
for (i = 0; i < brange->nblocks; i++) {
|
|
if (rz_cons_is_breaked()) {
|
|
break;
|
|
}
|
|
ut64 off = brange->from + (i + brange->skipblocks) * brange->blocksize;
|
|
for (j = 0; j < brange->blocksize; j++) {
|
|
if (hist_type == HISTOGRAM_ANALYSIS_BASIC_BLOCKS) {
|
|
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, off + j, 0);
|
|
if (fcn) {
|
|
data[i] = rz_pvector_len(fcn->bbs);
|
|
}
|
|
continue;
|
|
}
|
|
RzAnalysisOp *op = rz_core_analysis_op(core, off + j, RZ_ANALYSIS_OP_MASK_BASIC);
|
|
if (op) {
|
|
if (op->size < 1) {
|
|
// do nothing
|
|
if (hist_type == HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS) {
|
|
data_array_increment_element(data, i);
|
|
}
|
|
} else {
|
|
if (if_aop_match_hist_type(op, hist_type)) {
|
|
data_array_increment_element(data, i);
|
|
}
|
|
}
|
|
if (op->size > 0) {
|
|
j += op->size - 1;
|
|
}
|
|
rz_analysis_op_free(op);
|
|
} else {
|
|
if (hist_type == HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS) {
|
|
data_array_increment_element(data, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static bool print_histogram(RzCore *core, RZ_NULLABLE RzHistogramOptions *opts, const ut8 *data, ut64 offset, int width, int step, bool vertical) {
|
|
RzStrBuf *strbuf = NULL;
|
|
bool hex_offset = rz_config_get_i(core->config, "hex.offset");
|
|
core->print->num = core->num;
|
|
if (hex_offset) {
|
|
// TODO: Currently this option doesn't affect horizontal histograms
|
|
core->print->flags |= RZ_PRINT_FLAGS_OFFSET;
|
|
} else {
|
|
core->print->flags &= ~RZ_PRINT_FLAGS_OFFSET;
|
|
}
|
|
if (opts) {
|
|
strbuf = vertical ? rz_histogram_vertical(opts, data, width, step) : rz_histogram_horizontal(opts, data, width, 14);
|
|
} else {
|
|
RzHistogramOptions default_opts = {
|
|
.unicode = rz_config_get_b(core->config, "scr.utf8"),
|
|
.thinline = !rz_config_get_b(core->config, "scr.hist.block"),
|
|
.legend = false,
|
|
.offset = rz_config_get_b(core->config, "hex.offset"),
|
|
.offpos = offset,
|
|
.cursor = false,
|
|
.curpos = 0,
|
|
.color = rz_config_get_i(core->config, "scr.color"),
|
|
.pal = &core->cons->context->pal
|
|
};
|
|
strbuf = vertical ? rz_histogram_vertical(&default_opts, data, width, step) : rz_histogram_horizontal(&default_opts, data, width, 14);
|
|
}
|
|
if (!strbuf) {
|
|
return false;
|
|
} else {
|
|
char *histogram = rz_strbuf_drain(strbuf);
|
|
rz_cons_print(histogram);
|
|
free(histogram);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void showcursor(RzCore *core, int x) {
|
|
if (!x) {
|
|
int wheel = rz_config_get_i(core->config, "scr.wheel");
|
|
if (wheel) {
|
|
rz_cons_enable_mouse(true);
|
|
}
|
|
} else {
|
|
rz_cons_enable_mouse(false);
|
|
}
|
|
rz_cons_show_cursor(x);
|
|
}
|
|
|
|
static RzCmdStatus print_visual_bytes(RzCore *core, RZ_NONNULL const unsigned char *data, RZ_NONNULL CoreBlockRange *brange) {
|
|
if (!rz_cons_is_interactive()) {
|
|
RZ_LOG_ERROR("core: visual mode requires scr.interactive=true.\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
RzConsCanvas *can;
|
|
bool exit_histogram = false, is_error = false;
|
|
RzConfigHold *hc = rz_config_hold_new(core->config);
|
|
if (!hc) {
|
|
return false;
|
|
}
|
|
rz_config_hold_i(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
|
|
|
|
int h, w = rz_cons_get_size(&h);
|
|
can = rz_cons_canvas_new(w, h);
|
|
if (!can) {
|
|
w = 80;
|
|
h = 25;
|
|
can = rz_cons_canvas_new(w, h);
|
|
if (!can) {
|
|
RZ_LOG_ERROR("core: cannot create RzCons.canvas context. Invalid screen "
|
|
"size? See scr.columns + scr.rows\n");
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
return false;
|
|
}
|
|
}
|
|
can->color = rz_config_get_i(core->config, "scr.color");
|
|
|
|
RzHistogramOptions *opts = rz_histogram_options_new();
|
|
if (!opts) {
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
rz_cons_canvas_free(can);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
opts->unicode = rz_config_get_b(core->config, "scr.utf8");
|
|
opts->thinline = !rz_config_get_b(core->config, "scr.hist.block");
|
|
opts->legend = false;
|
|
opts->offset = rz_config_get_b(core->config, "hex.offset");
|
|
opts->offpos = brange->from;
|
|
opts->cursor = false;
|
|
opts->curpos = 0;
|
|
opts->color = rz_config_get_i(core->config, "scr.color");
|
|
opts->pal = &core->cons->context->pal;
|
|
RzHistogramInteractive *hist = rz_histogram_interactive_new(can, opts);
|
|
hist->size = brange->nblocks;
|
|
if (!hist) {
|
|
rz_histogram_options_free(hist->opts);
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
rz_cons_canvas_free(can);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
|
|
int okey, key;
|
|
while (!exit_histogram && !is_error && !rz_cons_is_breaked()) {
|
|
showcursor(core, false);
|
|
w = rz_cons_get_size(&h);
|
|
if (!rz_cons_canvas_resize(hist->can, w, h)) {
|
|
rz_histogram_options_free(hist->opts);
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
rz_cons_canvas_free(can);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
hist->w = w;
|
|
hist->h = h;
|
|
RzStrBuf *str = rz_histogram_interactive_horizontal(hist, data);
|
|
rz_cons_canvas_write(hist->can, str->ptr);
|
|
rz_cons_canvas_print_region(hist->can);
|
|
rz_cons_newline();
|
|
rz_cons_visual_flush();
|
|
okey = rz_cons_readchar();
|
|
key = rz_cons_arrow_to_hjkl(okey);
|
|
switch (key) {
|
|
case '?':
|
|
rz_cons_clear00();
|
|
rz_cons_printf("Visual ASCII Art graph keybindings:\n"
|
|
" +/- - zoom in/out\n"
|
|
" hl - move left and right\n"
|
|
" q - back to Visual mode\n");
|
|
rz_cons_less();
|
|
rz_cons_any_key(NULL);
|
|
break;
|
|
case 'h':
|
|
hist->barnumber = (hist->barnumber > 0) ? (hist->barnumber - 1) : (brange->nblocks - 1);
|
|
break;
|
|
case 'l':
|
|
hist->barnumber = (hist->barnumber == brange->nblocks - 1) ? (0) : (hist->barnumber + 1);
|
|
break;
|
|
case '+':
|
|
rz_histogram_interactive_zoom_in(hist);
|
|
break;
|
|
case '-':
|
|
rz_histogram_interactive_zoom_out(hist);
|
|
break;
|
|
case 'q':
|
|
case 'Q':
|
|
case ' ':
|
|
exit_histogram = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
rz_cons_clear00();
|
|
}
|
|
rz_cons_break_pop();
|
|
core->cons->event_resize = NULL;
|
|
core->cons->event_data = NULL;
|
|
core->keep_asmqjmps = false;
|
|
rz_config_hold_restore(hc);
|
|
rz_config_hold_free(hc);
|
|
rz_histogram_interactive_free(hist);
|
|
rz_cons_show_cursor(true);
|
|
rz_cons_enable_mouse(false);
|
|
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static CoreBlockRange *parse_args_calculate_range(RzCore *core, int argc, const char **argv) {
|
|
int nblocks = argc > 1 ? rz_num_math(core->num, argv[1]) : -1;
|
|
ut64 totalsize = argc > 2 ? rz_num_math(core->num, argv[2]) : UT64_MAX;
|
|
int skipblocks = argc > 3 ? rz_num_math(core->num, argv[3]) : -1;
|
|
CoreBlockRange *brange = calculate_blocks_range(core, 0, 0, totalsize, nblocks, skipblocks);
|
|
if (!brange) {
|
|
RZ_LOG_ERROR("Cannot calculate blocks range\n");
|
|
}
|
|
return brange;
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_bytes(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
rz_io_read_at(core->io, core->offset, data, brange->nblocks);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_bytes(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_bytes(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_bytes(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_entropy(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
rz_io_read_at(core->io, off, tmp, brange->blocksize);
|
|
data[i] = (ut8)(255 * rz_hash_entropy_fraction(tmp, brange->blocksize));
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static bool print_rising_and_falling_entropy_table(RzCore *core, RzCmdStateOutput *state, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
|
|
bool resetFlag = 1;
|
|
st8 lastEdge = 0;
|
|
RzTable *t = state->d.t;
|
|
RzTableColumnType *n = rz_table_type("number");
|
|
RzTableColumnType *s = rz_table_type("string");
|
|
rz_table_add_column(t, n, "addr", 0);
|
|
rz_table_add_column(t, n, "index", 0);
|
|
rz_table_add_column(t, s, "edge_type", 0);
|
|
rz_table_add_column(t, n, "entropy_value", 0);
|
|
for (int i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i));
|
|
if (!rz_io_read_at(core->io, off, tmp, brange->blocksize))
|
|
return false;
|
|
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
|
|
// reseting flag if goes above falling threshold and below rising threshold
|
|
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
|
|
resetFlag = 1;
|
|
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
|
|
resetFlag = 1;
|
|
}
|
|
// if reset flag is true
|
|
// than if entopy goes above threshold printing rising entropy edge
|
|
// and if entropy goes below threshold printing falling entropy edge
|
|
if (resetFlag == 1 && data >= risingthreshold) {
|
|
// rising edge print
|
|
resetFlag = 0;
|
|
lastEdge = 1;
|
|
rz_table_add_rowf(t, "xnsf", off, i, "rising entropy edge", data);
|
|
} else if (resetFlag == 1 && data <= fallingthreshold) {
|
|
// falling edge print
|
|
resetFlag = 0;
|
|
lastEdge = 0;
|
|
rz_table_add_rowf(t, "xnsf", off, i, "falling entropy edge", data);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool print_rising_and_falling_entropy_JSON(RzCore *core, RzCmdStateOutput *state, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
|
|
bool resetFlag = 1;
|
|
st8 lastEdge = 0;
|
|
PJ *pj = state->d.pj;
|
|
pj_a(pj);
|
|
for (int i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i));
|
|
if (!rz_io_read_at(core->io, off, tmp, brange->blocksize))
|
|
return false;
|
|
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
|
|
// reseting flag if goes above falling threshold and below rising threshold
|
|
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
|
|
resetFlag = 1;
|
|
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
|
|
resetFlag = 1;
|
|
}
|
|
// if reset flag is true
|
|
// than if entopy goes above threshold printing rising entropy edge
|
|
// and if entropy goes below threshold printing falling entropy edge
|
|
if (resetFlag == 1 && data >= risingthreshold) {
|
|
// rising edge print
|
|
resetFlag = 0;
|
|
lastEdge = 1;
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", off);
|
|
pj_kn(pj, "index", i);
|
|
pj_ks(pj, "edge_type", "rising entropy edge");
|
|
pj_kd(pj, "entropy_value", data);
|
|
pj_end(pj);
|
|
} else if (resetFlag == 1 && data <= fallingthreshold) {
|
|
// falling edge print
|
|
resetFlag = 0;
|
|
lastEdge = 0;
|
|
pj_o(pj);
|
|
pj_kn(pj, "addr", off);
|
|
pj_kn(pj, "index", i);
|
|
pj_ks(pj, "edge_type", "falling entropy edge");
|
|
pj_kd(pj, "entropy_value", data);
|
|
pj_end(pj);
|
|
}
|
|
}
|
|
pj_end(pj);
|
|
return true;
|
|
}
|
|
|
|
static bool print_rising_and_falling_entropy_quiet(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
|
|
RzStrBuf *buf = rz_strbuf_new("");
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return false;
|
|
}
|
|
bool resetFlag = 1;
|
|
st8 lastEdge = 0;
|
|
for (int i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i));
|
|
if (!rz_io_read_at(core->io, off, tmp, brange->blocksize)) {
|
|
rz_strbuf_free(buf);
|
|
return false;
|
|
}
|
|
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
|
|
// reseting flag if goes above falling threshold and below rising threshold
|
|
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
|
|
resetFlag = 1;
|
|
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
|
|
resetFlag = 1;
|
|
}
|
|
// if reset flag is true
|
|
// than if entopy goes above threshold printing rising entropy edge
|
|
// and if entropy goes below threshold printing falling entropy edge
|
|
if (resetFlag == 1 && data >= risingthreshold) {
|
|
// rising edge print
|
|
resetFlag = 0;
|
|
lastEdge = 1;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x "\n", off);
|
|
} else if (resetFlag == 1 && data <= fallingthreshold) {
|
|
// falling edge print
|
|
resetFlag = 0;
|
|
lastEdge = 0;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x "\n", off);
|
|
}
|
|
}
|
|
char *res = rz_strbuf_drain(buf);
|
|
rz_cons_print(res);
|
|
free(res);
|
|
return true;
|
|
}
|
|
|
|
static bool print_rising_and_falling_entropy_standard(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
|
|
RzStrBuf *buf = rz_strbuf_new("");
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return false;
|
|
}
|
|
bool resetFlag = 1;
|
|
st8 lastEdge = 0;
|
|
for (int i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i));
|
|
if (!rz_io_read_at(core->io, off, tmp, brange->blocksize)) {
|
|
rz_strbuf_free(buf);
|
|
return false;
|
|
}
|
|
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
|
|
// reseting flag if goes above falling threshold and below rising threshold
|
|
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
|
|
resetFlag = 1;
|
|
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
|
|
resetFlag = 1;
|
|
}
|
|
// if reset flag is true
|
|
// than if entopy goes above threshold printing rising entropy edge
|
|
// and if entropy goes below threshold printing falling entropy edge
|
|
if (resetFlag == 1 && data >= risingthreshold) {
|
|
// rising edge print
|
|
resetFlag = 0;
|
|
lastEdge = 1;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x " Rising entropy edge\n", off);
|
|
} else if (resetFlag == 1 && data <= fallingthreshold) {
|
|
// falling edge print
|
|
resetFlag = 0;
|
|
lastEdge = 0;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x " Falling entropy edge\n", off);
|
|
}
|
|
}
|
|
char *res = rz_strbuf_drain(buf);
|
|
rz_cons_print(res);
|
|
free(res);
|
|
return true;
|
|
}
|
|
|
|
static bool print_rising_and_falling_entropy_long(RzCore *core, CoreBlockRange *brange, ut8 *tmp, double fallingthreshold, double risingthreshold) {
|
|
RzStrBuf *buf = rz_strbuf_new("");
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return false;
|
|
}
|
|
bool resetFlag = 1;
|
|
st8 lastEdge = 0;
|
|
for (int i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i));
|
|
if (!rz_io_read_at(core->io, off, tmp, brange->blocksize)) {
|
|
rz_strbuf_free(buf);
|
|
return false;
|
|
}
|
|
double data = rz_hash_entropy_fraction(tmp, brange->blocksize);
|
|
// reseting flag if goes above falling threshold and below rising threshold
|
|
if (resetFlag == 0 && lastEdge == 0 && data > fallingthreshold) {
|
|
resetFlag = 1;
|
|
} else if (resetFlag == 0 && lastEdge == 1 && data < risingthreshold) {
|
|
resetFlag = 1;
|
|
}
|
|
// if reset flag is true
|
|
// than if entopy goes above threshold printing rising entropy edge
|
|
// and if entropy goes below threshold printing falling entropy edge
|
|
if (resetFlag == 1 && data >= risingthreshold) {
|
|
// rising edge print
|
|
resetFlag = 0;
|
|
lastEdge = 1;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x " ", off);
|
|
rz_strbuf_appendf(buf, "%03x Rising entropy edge (%8lf)\n", i, data);
|
|
} else if (resetFlag == 1 && data <= fallingthreshold) {
|
|
// falling edge print
|
|
resetFlag = 0;
|
|
lastEdge = 0;
|
|
rz_strbuf_appendf(buf, "0x%08" PFMT64x " ", off);
|
|
rz_strbuf_appendf(buf, "%03x Falling entropy edge (%8lf)\n", i, data);
|
|
}
|
|
}
|
|
char *res = rz_strbuf_drain(buf);
|
|
rz_cons_print(res);
|
|
free(res);
|
|
return true;
|
|
}
|
|
|
|
static RzCmdStatus print_rising_and_falling_entropy(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
double risingthreshold = 0.95;
|
|
double fallingthreshold = 0.85;
|
|
if (argc >= 3) {
|
|
risingthreshold = rz_num_get_float(core->num, argv[1]);
|
|
fallingthreshold = rz_num_get_float(core->num, argv[2]);
|
|
}
|
|
if (fallingthreshold > risingthreshold) {
|
|
RZ_LOG_ERROR("falling threshold is greater than rising threshold\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (risingthreshold > 1) {
|
|
RZ_LOG_ERROR("threshold can't be greater than 1\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int nblocks = -1;
|
|
ut64 totalsize = UT64_MAX;
|
|
int skipblocks = -1;
|
|
CoreBlockRange *brange = calculate_blocks_range(core, 0, 0, totalsize, nblocks, skipblocks);
|
|
if (!brange) {
|
|
RZ_LOG_ERROR("Cannot calculate blocks range\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_TABLE:
|
|
if (!print_rising_and_falling_entropy_table(core, state, brange, tmp, fallingthreshold, risingthreshold)) {
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
if (!print_rising_and_falling_entropy_JSON(core, state, brange, tmp, fallingthreshold, risingthreshold)) {
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
if (!print_rising_and_falling_entropy_quiet(core, brange, tmp, fallingthreshold, risingthreshold)) {
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_STANDARD:
|
|
if (!print_rising_and_falling_entropy_standard(core, brange, tmp, fallingthreshold, risingthreshold)) {
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
break;
|
|
case RZ_OUTPUT_MODE_LONG:
|
|
if (!print_rising_and_falling_entropy_long(core, brange, tmp, fallingthreshold, risingthreshold)) {
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
rz_warn_if_reached();
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
free(tmp);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_entropy_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_entropy(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_entropy_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_entropy(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_entropy_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_entropy(core, argc, argv, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_rising_and_falling_entropy_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return print_rising_and_falling_entropy(core, argc, argv, state);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_marks(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
for (size_t j = 0; j < brange->blocksize; j++) {
|
|
if (rz_flag_get_at(core->flags, off + j, false)) {
|
|
data_array_increment_element(data, i);
|
|
}
|
|
}
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_m_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_marks(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_m_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_marks(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_m_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_marks(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_0x00(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
int k = 0;
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
rz_io_read_at(core->io, off, tmp, brange->blocksize);
|
|
for (size_t j = k = 0; j < brange->blocksize; j++) {
|
|
if (!tmp[j]) {
|
|
k++;
|
|
}
|
|
}
|
|
data[i] = 256 * k / brange->blocksize;
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_0x00_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0x00(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_0x00_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0x00(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_0x00_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0x00(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_0xff(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
int k = 0;
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
rz_io_read_at(core->io, off, tmp, brange->blocksize);
|
|
for (size_t j = k = 0; j < brange->blocksize; j++) {
|
|
if (tmp[j] == 0xff) {
|
|
k++;
|
|
}
|
|
}
|
|
data[i] = 256 * k / brange->blocksize;
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_0xff_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0xff(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_0xff_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0xff(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_0xff_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_0xff(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_printable(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
int k = 0;
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
rz_io_read_at(core->io, off, tmp, brange->blocksize);
|
|
for (size_t j = k = 0; j < brange->blocksize; j++) {
|
|
if (IS_PRINTABLE(tmp[j])) {
|
|
k++;
|
|
}
|
|
}
|
|
data[i] = 256 * k / brange->blocksize;
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_printable_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_printable(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_printable_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_printable(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_printable_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_printable(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_z(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = calloc(1, brange->nblocks);
|
|
ut8 *tmp = malloc(brange->blocksize);
|
|
if (!tmp) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to malloc memory\n");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
size_t len = 0;
|
|
for (size_t i = 0; i < brange->nblocks; i++) {
|
|
int k = 0;
|
|
ut64 off = brange->from + (brange->blocksize * (i + brange->skipblocks));
|
|
rz_io_read_at(core->io, off, tmp, brange->blocksize);
|
|
for (size_t j = k = 0; j < brange->blocksize; j++) {
|
|
if (IS_PRINTABLE(tmp[j])) {
|
|
if ((j + 1) < brange->blocksize && tmp[j + 1] == 0) {
|
|
k++;
|
|
j++;
|
|
}
|
|
if (len++ > 8) {
|
|
k++;
|
|
}
|
|
} else {
|
|
len = 0;
|
|
}
|
|
}
|
|
data[i] = 256 * k / brange->blocksize;
|
|
}
|
|
free(tmp);
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
free(data);
|
|
free(brange);
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_z_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_z(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_z_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_z(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_z_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_z(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus print_histogram_stats(RzCore *core, int argc, const char **argv, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = analysis_stats_histogram_data(core, brange);
|
|
if (!data) {
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to access analysis stats");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_stats_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_stats(core, argc, argv, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_stats_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_stats(core, argc, argv, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_stats_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_histogram_stats(core, argc, argv, false, true);
|
|
}
|
|
|
|
static RzCmdStatus analysis_hist_handler(RzCore *core, int argc, const char **argv, CoreAnalysisHistogramType hist_type, bool vertical, bool isinteractive) {
|
|
CoreBlockRange *brange = parse_args_calculate_range(core, argc, argv);
|
|
if (!brange) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
ut8 *data = analysis_histogram_data(core, brange, hist_type);
|
|
if (!data) {
|
|
free(brange);
|
|
RZ_LOG_ERROR("core: failed to access analyzed instructions for specified range");
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (isinteractive) {
|
|
if (!print_visual_bytes(core, data, brange)) {
|
|
RZ_LOG_ERROR("Cannot generate interactive histogram\n");
|
|
free(brange);
|
|
free(data);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
} else {
|
|
if (!print_histogram(core, NULL, data, brange->from, brange->nblocks, brange->blocksize, vertical)) {
|
|
RZ_LOG_ERROR("Cannot generate %s histogram\n", vertical ? "vertical" : "horizontal");
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
}
|
|
free(data);
|
|
free(brange);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_bbs_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_call_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_jump_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_priv_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_invalid_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, true, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_bbs_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_call_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_jump_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_priv_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_invalid_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, false, false);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_bbs_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_BASIC_BLOCKS, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_call_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_CALL_INSTRUCTIONS, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_jump_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_JUMP_INSTRUCTIONS, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_priv_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_PRIV_INSTRUCTIONS, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_equal_invalid_visual_handler(RzCore *core, int argc, const char **argv) {
|
|
return analysis_hist_handler(core, argc, argv, HISTOGRAM_ANALYSIS_INVALID_INSTRUCTIONS, false, true);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_print_equal_two_handler(RzCore *core, int argc, const char **argv) {
|
|
short *word = (short *)core->block;
|
|
size_t i, words = core->blocksize / 2;
|
|
int step = rz_num_math(core->num, argv[1]);
|
|
ut64 oldword = 0;
|
|
for (i = 0; i < words; i++) {
|
|
ut64 word64 = word[i] + ST16_MAX;
|
|
rz_cons_printf("0x%08" PFMT64x " %8d ", core->offset + (i * 2), word[i]);
|
|
RzBarOptions baropts = {
|
|
.unicode = rz_config_get_b(core->config, "scr.utf8"),
|
|
.thinline = !rz_config_get_b(core->config, "scr.hist.block"),
|
|
.legend = false,
|
|
.offset = rz_config_get_b(core->config, "hex.offset"),
|
|
.offpos = 0,
|
|
.cursor = false,
|
|
.curpos = 0,
|
|
.color = rz_config_get_i(core->config, "scr.color")
|
|
};
|
|
RzStrBuf *strbuf = rz_progressbar(&baropts, word64 * 100 / UT16_MAX, 60);
|
|
if (!strbuf) {
|
|
RZ_LOG_ERROR("Cannot generate vertical histogram\n");
|
|
} else {
|
|
char *bar = rz_strbuf_drain(strbuf);
|
|
rz_cons_print(bar);
|
|
free(bar);
|
|
}
|
|
rz_cons_printf(" %" PFMT64d, word64 - oldword);
|
|
oldword = word64;
|
|
rz_cons_newline();
|
|
i += step;
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static void printraw(RzCore *core, int len, bool stop_at_null) {
|
|
ut8 *data = malloc(len);
|
|
if (!data) {
|
|
return;
|
|
}
|
|
if (rz_io_read_at(core->io, core->offset, data, len)) {
|
|
if (stop_at_null) {
|
|
len = rz_str_nlen((const char *)data, len);
|
|
}
|
|
rz_print_raw(core->print, core->offset, data, len);
|
|
}
|
|
free(data);
|
|
core->cons->newline = core->cmd_in_backticks ? false : true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
printraw(core, len, false);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_colors_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
colordump(core, core->block, len);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static bool gunzip_and_print_block(RzCore *core, bool verbose) {
|
|
int outlen = 0;
|
|
int inConsumed = 0;
|
|
ut8 *out;
|
|
out = rz_inflate(core->block, core->blocksize, &inConsumed, &outlen);
|
|
if (!out) {
|
|
return false;
|
|
}
|
|
if (verbose) {
|
|
rz_cons_printf("consumed: %d produced: %d\n", inConsumed, outlen);
|
|
}
|
|
rz_cons_memcat((const char *)out, outlen);
|
|
free(out);
|
|
return true;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_gunzip_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(gunzip_and_print_block(core, false));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_gunzip_verbose_handler(RzCore *core, int argc, const char **argv) {
|
|
return bool2status(gunzip_and_print_block(core, true));
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_printable_handler(RzCore *core, int argc, const char **argv) {
|
|
int a = rz_config_get_i(core->config, "hex.bytes");
|
|
rz_config_set_i(core->config, "hex.bytes", false);
|
|
// TODO: Use the API instead of commands
|
|
rz_core_cmd0(core, "pxx");
|
|
rz_config_set_i(core->config, "hex.bytes", a);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static RzCmdStatus print_format(RzCore *core, const char *fmt, int mode, RzCmdStateOutput *state) {
|
|
rz_return_val_if_fail(fmt, RZ_CMD_STATUS_ERROR);
|
|
|
|
if (state) {
|
|
switch (state->mode) {
|
|
case RZ_OUTPUT_MODE_JSON:
|
|
mode = RZ_PRINT_JSON;
|
|
break;
|
|
case RZ_OUTPUT_MODE_RIZIN:
|
|
mode = RZ_PRINT_SEEFLAGS;
|
|
break;
|
|
case RZ_OUTPUT_MODE_QUIET:
|
|
mode |= RZ_PRINT_QUIET | RZ_PRINT_MUSTSEE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// Temporary workaround until `librz/type/format.c` is rewritten properly
|
|
if (state->mode != RZ_OUTPUT_MODE_JSON) {
|
|
rz_cmd_state_output_array_start(state);
|
|
}
|
|
}
|
|
char *format = rz_core_print_format(core, fmt, mode, core->offset);
|
|
if (!format) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
if (state) {
|
|
// Temporary workaround until `librz/type/format.c` is rewritten properly
|
|
if (state->mode != RZ_OUTPUT_MODE_JSON) {
|
|
rz_cmd_state_output_array_end(state);
|
|
}
|
|
}
|
|
rz_cons_print(format);
|
|
free(format);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static RzCmdStatus print_format_write(RzCore *core, const char *fmt, const char *value) {
|
|
rz_return_val_if_fail(fmt, RZ_CMD_STATUS_ERROR);
|
|
char *format = rz_core_print_format_write(core, fmt, value, core->offset);
|
|
if (!format) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(format);
|
|
free(format);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_raw_string_handler(RzCore *core, int argc, const char **argv) {
|
|
int len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len < 0) {
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
printraw(core, len, true);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int mode = RZ_PRINT_MUSTSEE;
|
|
return print_format(core, argv[1], mode, state);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_type_db_format_delete(core->analysis->typedb, argv[1]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc, const char **argv) {
|
|
rz_type_db_format_purge(core->analysis->typedb);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_named_dot_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
int mode = RZ_PRINT_MUSTSEE;
|
|
return print_format(core, argv[1], mode, state);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_named_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc < 2) {
|
|
// List all named formats
|
|
RzListIter *iter;
|
|
RzTypeFormat *fmt = NULL;
|
|
RzList *formats = rz_type_db_format_all(core->analysis->typedb);
|
|
rz_list_foreach (formats, iter, fmt) {
|
|
rz_cons_printf("%s \"%s\"\n", fmt->name, fmt->body);
|
|
}
|
|
rz_list_free(formats);
|
|
return RZ_CMD_STATUS_OK;
|
|
} else if (argc < 3) {
|
|
// Show the format string for a named format
|
|
const char *fmt = rz_type_db_format_get(core->analysis->typedb, argv[1]);
|
|
if (RZ_STR_ISEMPTY(fmt)) {
|
|
RZ_LOG_ERROR("Format with \"%s\" name not found\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_printf("%s\n", fmt);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
rz_type_db_format_set(core->analysis->typedb, argv[1], argv[2]);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_c_handler(RzCore *core, int argc, const char **argv) {
|
|
int mode = RZ_PRINT_STRUCT;
|
|
return print_format(core, argv[1], mode, NULL);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_dot_handler(RzCore *core, int argc, const char **argv) {
|
|
int mode = RZ_PRINT_DOT;
|
|
return print_format(core, argv[1], mode, NULL);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_file_handler(RzCore *core, int argc, const char **argv) {
|
|
if (argc < 2) {
|
|
RzList *files;
|
|
RzListIter *iter;
|
|
const char *fn;
|
|
char *home = rz_path_home_prefix(RZ_SDB_FORMAT);
|
|
if (home) {
|
|
files = rz_sys_dir(home);
|
|
rz_list_foreach (files, iter, fn) {
|
|
if (*fn && *fn != '.') {
|
|
rz_cons_println(fn);
|
|
}
|
|
}
|
|
rz_list_free(files);
|
|
free(home);
|
|
}
|
|
char *path = rz_path_system(RZ_SDB_FORMAT);
|
|
if (path) {
|
|
files = rz_sys_dir(path);
|
|
rz_list_foreach (files, iter, fn) {
|
|
if (*fn && *fn != '.') {
|
|
rz_cons_println(fn);
|
|
}
|
|
}
|
|
rz_list_free(files);
|
|
free(path);
|
|
}
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
char *home_formats = rz_path_home_prefix(RZ_SDB_FORMAT);
|
|
char *home = rz_file_path_join(home_formats, argv[1]);
|
|
free(home_formats);
|
|
char *system_formats = rz_path_system(RZ_SDB_FORMAT);
|
|
char *path = rz_file_path_join(system_formats, argv[1]);
|
|
free(system_formats);
|
|
if (rz_str_endswith(argv[1], ".h")) {
|
|
char *error_msg = NULL;
|
|
const char *dir = rz_config_get(core->config, "dir.types");
|
|
int result = rz_type_parse_file(core->analysis->typedb, path, dir, &error_msg);
|
|
if (!result) {
|
|
// TODO: Use the API here
|
|
rz_core_cmd0(core, ".ts*");
|
|
} else {
|
|
RZ_LOG_ERROR("core: Parse error: %s\n", error_msg);
|
|
free(error_msg);
|
|
}
|
|
} else {
|
|
if (!rz_core_cmd_file(core, home) && !rz_core_cmd_file(core, path)) {
|
|
if (!rz_core_cmd_file(core, argv[1])) {
|
|
RZ_LOG_ERROR("core: pfo: cannot open format file at '%s'\n", path);
|
|
}
|
|
}
|
|
}
|
|
free(home);
|
|
free(path);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_size_handler(RzCore *core, int argc, const char **argv) {
|
|
const char *format = rz_type_db_format_get(core->analysis->typedb, argv[1]);
|
|
if (!format) {
|
|
RZ_LOG_ERROR("Format \"%s\" could not be found\n", argv[1]);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
int fmtsz = rz_type_format_struct_size(core->analysis->typedb, format, RZ_PRINT_MUSTSEE, 0);
|
|
rz_cons_printf("%d\n", fmtsz);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_value_handler(RzCore *core, int argc, const char **argv) {
|
|
int mode = RZ_PRINT_VALUE | RZ_PRINT_MUSTSEE;
|
|
return print_format(core, argv[1], mode, NULL);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_format_write_handler(RzCore *core, int argc, const char **argv) {
|
|
return print_format_write(core, argv[1], argv[2]);
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_2bpp_tiles_handler(RzCore *core, int argc, const char **argv) {
|
|
size_t len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len == 0) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
core_print_2bpp_tiles(core, len / 16);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
static RzCmdStatus print_8bit_hexpair(RzCore *core, ut64 addr, size_t len) {
|
|
ut8 *buf = malloc(len);
|
|
if (!buf) {
|
|
RZ_LOG_ERROR("core: cannot allocate %zu byte(s)\n", len);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_io_read_at(core->io, addr, buf, len);
|
|
rz_print_bytes(core->print, buf, len, "%02x");
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_8bit_hexpair_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
size_t len = argc > 1 ? rz_num_math(core->num, argv[1]) : core->blocksize;
|
|
if (len == 0) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
if (state->mode == RZ_OUTPUT_MODE_STANDARD) {
|
|
return print_8bit_hexpair(core, core->offset, len);
|
|
}
|
|
char *code = rz_lang_byte_array(core->block, len, RZ_LANG_BYTE_ARRAY_JSON);
|
|
if (RZ_STR_ISEMPTY(code)) {
|
|
free(code);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
rz_cons_print(code);
|
|
free(code);
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
|
|
RZ_IPI RzCmdStatus rz_cmd_print_8bit_hexpair_function_handler(RzCore *core, int argc, const char **argv) {
|
|
RzAnalysisFunction *f = rz_analysis_first_function_in(core->analysis, core->offset);
|
|
if (!f) {
|
|
RZ_LOG_ERROR("Cannot find function at 0x%08" PFMT64x "\n", core->offset);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
size_t len = rz_analysis_function_linear_size(f);
|
|
ut64 addr = rz_analysis_function_min_addr(f);
|
|
return print_8bit_hexpair(core, addr, len);
|
|
}
|
|
|
|
// "x"
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_alias_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
return rz_print_hexdump_handler(core, argc, argv, state);
|
|
}
|
|
|
|
// "xc"
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_comments_alias_handler(RzCore *core, int argc, const char **argv) {
|
|
return rz_print_hexdump_comments_handler(core, argc, argv);
|
|
}
|
|
|
|
static size_t format_width_to_num(size_t arch_bits, const char *width) {
|
|
rz_return_val_if_fail(width, 0);
|
|
switch (width[0]) {
|
|
default:
|
|
rz_warn_if_reached();
|
|
return 0;
|
|
case 'b': // # Byte = 1 bytes
|
|
return 1;
|
|
case 'h': // # Half word = 2 bytes
|
|
return 2;
|
|
case 'w': // # Word = 4 bytes
|
|
return 4;
|
|
case 'd': // # Double word = 8 bytes
|
|
return 8;
|
|
case 'a': // # Architecture width
|
|
return arch_bits > 0 ? arch_bits / 8 : 1;
|
|
}
|
|
}
|
|
|
|
// "pxF"
|
|
RZ_IPI RzCmdStatus rz_print_hexdump_format_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
|
|
ut64 num = rz_num_math(core->num, argv[1]);
|
|
if (!num) {
|
|
return RZ_CMD_STATUS_OK;
|
|
}
|
|
const char *format = argv[2];
|
|
size_t width = format_width_to_num(core->analysis ? core->analysis->bits : 0, argv[3]);
|
|
switch (format[0]) {
|
|
default:
|
|
RZ_LOG_ERROR("Invalid format: '%s'.\n", format);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
case 'x':
|
|
return bool2status(rz_core_print_dump(core, state->mode, core->offset, width, num * width, RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL));
|
|
case 'o':
|
|
// Parameter n must be 1 here. Don't ask me why :( The rabbit whole is deep and defuse.
|
|
return bool2status(rz_core_print_dump(core, state->mode, core->offset, 1, num * width, RZ_CORE_PRINT_FORMAT_TYPE_OCTAL));
|
|
case 'd':
|
|
return bool2status(rz_core_print_dump(core, state->mode, core->offset, width, num * width, RZ_CORE_PRINT_FORMAT_TYPE_INTEGER));
|
|
case 'f': {
|
|
char *format = RZ_NEWS0(char, num + 1);
|
|
for (size_t i = 0; i < num; ++i) {
|
|
format[i] = 'f';
|
|
}
|
|
RzCmdStatus status = print_format(core, format, RZ_PRINT_MUSTSEE, state);
|
|
free(format);
|
|
return status;
|
|
}
|
|
case 's': {
|
|
size_t block_size_bak = core->blocksize;
|
|
size_t new_block_size = num * width;
|
|
if (!rz_core_block_size(core, new_block_size)) {
|
|
RZ_LOG_ERROR("Failed to set block size to %" PFMTSZu " bytes.\n", new_block_size);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
const char *psb = "psb";
|
|
RzCmdStatus status = rz_print_strings_current_block_handler(core, 1, &psb, state->mode);
|
|
if (!rz_core_block_size(core, block_size_bak)) {
|
|
RZ_LOG_ERROR("Failed to reset block size to %" PFMTSZu " bytes.\n", block_size_bak);
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|
|
return status;
|
|
}
|
|
}
|
|
return RZ_CMD_STATUS_ERROR;
|
|
}
|