librz/core: Add ica, ics, pfa commands (#6039)

- `ica` applies the class flags at given address
- `ics` generates type definitions from classes (class as C struct)
- `pfa` applies format string at given address and define flags for each field
This commit is contained in:
Farhan Saiyed 2026-03-17 20:26:24 +05:30 committed by GitHub
parent 21d4084af0
commit 6e016eee9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 238 additions and 16 deletions

View file

@ -4109,6 +4109,95 @@ RZ_API bool rz_core_bin_class_methods_print(RZ_NONNULL RzCore *core, RZ_NONNULL
return true;
}
RZ_API RzCmdStatus rz_core_bin_class_apply_print(RZ_NONNULL RzCore *core, RZ_NONNULL const char *classname, ut64 addr) {
rz_return_val_if_fail(core && classname, RZ_CMD_STATUS_ERROR);
RzBinObject *o = rz_bin_cur_object(core->bin);
const RzPVector *classes = rz_bin_object_get_classes(o);
if (!classes) {
return RZ_CMD_STATUS_ERROR;
}
RzBinClass *klass = NULL;
void **iter;
rz_pvector_foreach (classes, iter) {
RzBinClass *c = *iter;
if (c && c->name && !strcmp(c->name, classname)) {
klass = c;
break;
}
}
if (!klass) {
RZ_LOG_ERROR("Class \"%s\" not found\n", classname);
return RZ_CMD_STATUS_ERROR;
}
RzListIter *it;
RzBinSymbol *sym;
ut64 min_vaddr = UT64_MAX;
rz_list_foreach (klass->methods, it, sym) {
if (sym->vaddr && sym->vaddr < min_vaddr) {
min_vaddr = sym->vaddr;
}
}
if (min_vaddr == UT64_MAX) {
min_vaddr = klass->addr;
}
rz_flag_space_push(core->flags, RZ_FLAGS_FS_CLASSES);
rz_list_foreach (klass->methods, it, sym) {
char *fn = rz_core_bin_method_build_flag_name(klass, sym);
if (fn) {
rz_flag_set(core->flags, fn, addr + (sym->vaddr - min_vaddr), sym->size);
free(fn);
}
}
rz_flag_space_pop(core->flags);
return RZ_CMD_STATUS_OK;
}
RZ_API bool rz_core_bin_classes_to_struct(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf) {
rz_return_val_if_fail(core && bf && bf->o, false);
const RzPVector *classes = rz_bin_object_get_classes(bf->o);
if (!classes) {
return false;
}
void **iter;
RzBinClass *c;
rz_pvector_foreach (classes, iter) {
c = *iter;
if (!c || !c->name || !c->name[0]) {
continue;
}
RzListIter *it;
RzBinClassField *f;
bool has_fields = false;
RzStrBuf *sb = rz_strbuf_new(NULL);
if (!sb) {
return false;
}
rz_strbuf_appendf(sb, "struct %s {", c->name);
rz_list_foreach (c->fields, it, f) {
if (!f->name) {
continue;
}
char *type = objc_type_toc(f->type);
char *name = objc_name_toc(f->name);
rz_strbuf_appendf(sb, " %s %s;", type, name);
free(type);
free(name);
has_fields = true;
}
if (has_fields) {
rz_strbuf_append(sb, " }");
rz_types_define(core, rz_strbuf_get(sb));
}
rz_strbuf_free(sb);
}
return true;
}
RZ_API bool rz_core_bin_classes_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state) {
rz_return_val_if_fail(core && bf && bf->o && state, false);

View file

@ -378,6 +378,19 @@ RZ_IPI RzCmdStatus rz_cmd_info_classes_handler(RzCore *core, int argc, const cha
return bool2status(rz_core_bin_classes_print(core, bf, state));
}
RZ_IPI RzCmdStatus rz_cmd_info_class_apply_handler(RzCore *core, int argc, const char **argv) {
ut64 addr = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset;
return rz_core_bin_class_apply_print(core, argv[1], addr);
}
RZ_IPI RzCmdStatus rz_cmd_info_classes_to_struct_handler(RzCore *core, int argc, const char **argv) {
RzBinFile *bf = rz_bin_cur(core->bin);
if (!bf) {
return RZ_CMD_STATUS_ERROR;
}
return bool2status(rz_core_bin_classes_to_struct(core, bf));
}
RZ_IPI RzCmdStatus rz_cmd_info_class_as_source_handler(RzCore *core, int argc, const char **argv) {
GET_CHECK_CUR_BINFILE(core);
return bool2status(rz_core_bin_class_as_source_print(core, bf, argv[1]));

View file

@ -6298,6 +6298,29 @@ RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_cmd_print_format_apply_handler(RzCore *core, int argc, const char **argv) {
if (argc < 2) {
return RZ_CMD_STATUS_WRONG_ARGS;
}
const char *typename = argv[1];
ut64 addr = argc > 2 ? rz_num_math(core->num, argv[2]) : core->offset;
const char *fmt = rz_type_db_format_get(core->analysis->typedb, typename);
if (RZ_STR_ISEMPTY(fmt)) {
RZ_LOG_ERROR("Format with \"%s\" name not found\n", typename);
return RZ_CMD_STATUS_ERROR;
}
ut64 old_offset = core->offset;
rz_core_seek(core, addr, true);
RzCmdStatus status = print_format(core, fmt, RZ_PRINT_MUSTSEE, NULL);
rz_core_seek(core, old_offset, true);
return status;
}
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);

View file

@ -613,6 +613,7 @@ static const RzCmdDescArg egg_type_args[2];
static const RzCmdDescArg egg_padding_args[2];
static const RzCmdDescArg egg_encoder_args[3];
static const RzCmdDescArg history_list_or_exec_args[2];
static const RzCmdDescArg cmd_info_class_apply_args[2];
static const RzCmdDescArg cmd_info_class_as_source_args[2];
static const RzCmdDescArg cmd_info_class_fields_args[2];
static const RzCmdDescArg cmd_info_class_methods_args[2];
@ -718,6 +719,7 @@ static const RzCmdDescArg cmd_disassemble_ropchain_args[2];
static const RzCmdDescArg cmd_disassemble_summarize_n_bytes_args[2];
static const RzCmdDescArg cmd_print_format_args[2];
static const RzCmdDescArg cmd_print_format_delete_args[2];
static const RzCmdDescArg cmd_print_format_apply_args[2];
static const RzCmdDescArg cmd_print_format_c_args[2];
static const RzCmdDescArg cmd_print_format_dot_args[2];
static const RzCmdDescArg cmd_print_format_named_dot_args[2];
@ -13197,6 +13199,20 @@ static const RzCmdDescHelp cmd_info_classes_help = {
.args = cmd_info_classes_args,
};
static const RzCmdDescArg cmd_info_class_apply_args[] = {
{
.name = "class name",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_LAST,
},
{ 0 },
};
static const RzCmdDescHelp cmd_info_class_apply_help = {
.summary = "Apply class flags at given address",
.args = cmd_info_class_apply_args,
};
static const RzCmdDescArg cmd_info_class_as_source_args[] = {
{
.name = "class name",
@ -13242,6 +13258,14 @@ static const RzCmdDescHelp cmd_info_class_methods_help = {
.args = cmd_info_class_methods_args,
};
static const RzCmdDescArg cmd_info_classes_to_struct_args[] = {
{ 0 },
};
static const RzCmdDescHelp cmd_info_classes_to_struct_help = {
.summary = "Generate type definitions from classes",
.args = cmd_info_classes_to_struct_args,
};
static const RzCmdDescArg cmd_info_signature_args[] = {
{ 0 },
};
@ -15681,6 +15705,20 @@ static const RzCmdDescHelp cmd_print_format_delete_all_help = {
.args = cmd_print_format_delete_all_args,
};
static const RzCmdDescArg cmd_print_format_apply_args[] = {
{
.name = "format",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_LAST,
},
{ 0 },
};
static const RzCmdDescHelp cmd_print_format_apply_help = {
.summary = "Apply format string at given address and define flags for each field",
.args = cmd_print_format_apply_args,
};
static const RzCmdDescArg cmd_print_format_c_args[] = {
{
.name = "format",
@ -23895,6 +23933,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *ic_cd = rz_cmd_desc_group_state_new(core->rcmd, i_cd, "ic", RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET | RZ_OUTPUT_MODE_QUIETEST, rz_cmd_info_classes_handler, &cmd_info_classes_help, &ic_help);
rz_warn_if_fail(ic_cd);
rz_cmd_desc_set_default_mode(ic_cd, RZ_OUTPUT_MODE_TABLE);
RzCmdDesc *cmd_info_class_apply_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "ica", rz_cmd_info_class_apply_handler, &cmd_info_class_apply_help);
rz_warn_if_fail(cmd_info_class_apply_cd);
RzCmdDesc *cmd_info_class_as_source_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "icc", rz_cmd_info_class_as_source_handler, &cmd_info_class_as_source_help);
rz_warn_if_fail(cmd_info_class_as_source_cd);
@ -23906,6 +23947,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
rz_warn_if_fail(cmd_info_class_methods_cd);
rz_cmd_desc_set_default_mode(cmd_info_class_methods_cd, RZ_OUTPUT_MODE_TABLE);
RzCmdDesc *cmd_info_classes_to_struct_cd = rz_cmd_desc_argv_new(core->rcmd, ic_cd, "ics", rz_cmd_info_classes_to_struct_handler, &cmd_info_classes_to_struct_help);
rz_warn_if_fail(cmd_info_classes_to_struct_cd);
RzCmdDesc *cmd_info_signature_cd = rz_cmd_desc_argv_state_new(core->rcmd, i_cd, "iC", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_info_signature_handler, &cmd_info_signature_help);
rz_warn_if_fail(cmd_info_signature_cd);
@ -24440,6 +24484,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *cmd_print_format_delete_all_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pf-*", rz_cmd_print_format_delete_all_handler, &cmd_print_format_delete_all_help);
rz_warn_if_fail(cmd_print_format_delete_all_cd);
RzCmdDesc *cmd_print_format_apply_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pfa", rz_cmd_print_format_apply_handler, &cmd_print_format_apply_help);
rz_warn_if_fail(cmd_print_format_apply_cd);
RzCmdDesc *cmd_print_format_c_cd = rz_cmd_desc_argv_new(core->rcmd, pf_cd, "pfc", rz_cmd_print_format_c_handler, &cmd_print_format_c_help);
rz_warn_if_fail(cmd_print_format_c_cd);

View file

@ -1686,12 +1686,16 @@ RZ_IPI RzCmdStatus rz_cmd_info_all_handler(RzCore *core, int argc, const char **
RZ_IPI RzCmdStatus rz_cmd_info_archs_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "ic"
RZ_IPI RzCmdStatus rz_cmd_info_classes_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "ica"
RZ_IPI RzCmdStatus rz_cmd_info_class_apply_handler(RzCore *core, int argc, const char **argv);
// "icc"
RZ_IPI RzCmdStatus rz_cmd_info_class_as_source_handler(RzCore *core, int argc, const char **argv);
// "icf"
RZ_IPI RzCmdStatus rz_cmd_info_class_fields_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "icm"
RZ_IPI RzCmdStatus rz_cmd_info_class_methods_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "ics"
RZ_IPI RzCmdStatus rz_cmd_info_classes_to_struct_handler(RzCore *core, int argc, const char **argv);
// "iC"
RZ_IPI RzCmdStatus rz_cmd_info_signature_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "id"
@ -2047,6 +2051,8 @@ RZ_IPI RzCmdStatus rz_cmd_print_format_handler(RzCore *core, int argc, const cha
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_handler(RzCore *core, int argc, const char **argv);
// "pf-*"
RZ_IPI RzCmdStatus rz_cmd_print_format_delete_all_handler(RzCore *core, int argc, const char **argv);
// "pfa"
RZ_IPI RzCmdStatus rz_cmd_print_format_apply_handler(RzCore *core, int argc, const char **argv);
// "pfc"
RZ_IPI RzCmdStatus rz_cmd_print_format_c_handler(RzCore *core, int argc, const char **argv);
// "pfd"

View file

@ -46,6 +46,12 @@ commands:
- RZ_OUTPUT_MODE_QUIET
- RZ_OUTPUT_MODE_QUIETEST
args: []
- name: ica
summary: Apply class flags at given address
cname: cmd_info_class_apply
args:
- name: class name
type: RZ_CMD_ARG_TYPE_STRING
- name: icc
summary: Prints class, fields and methods as source code
cname: cmd_info_class_as_source
@ -81,6 +87,10 @@ commands:
- name: class name
type: RZ_CMD_ARG_TYPE_STRING
optional: true
- name: ics
summary: Generate type definitions from classes
cname: cmd_info_classes_to_struct
args: []
- name: iC
cname: cmd_info_signature
summary: Show signature info (entitlements, ...)

View file

@ -484,6 +484,12 @@ commands:
summary: Remove all named formats
cname: cmd_print_format_delete_all
args: []
- name: pfa
summary: Apply format string at given address and define flags for each field
cname: cmd_print_format_apply
args:
- name: format
type: RZ_CMD_ARG_TYPE_STRING
- name: pfc
summary: Show data using given format string with C syntax
cname: cmd_print_format_c

View file

@ -1108,6 +1108,8 @@ RZ_API bool rz_core_bin_classes_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinF
RZ_API bool rz_core_bin_class_as_source_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, const char *class_name);
RZ_API bool rz_core_bin_class_fields_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state, const char *class_name);
RZ_API bool rz_core_bin_class_methods_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state, const char *class_name);
RZ_API RzCmdStatus rz_core_bin_class_apply_print(RZ_NONNULL RzCore *core, RZ_NONNULL const char *classname, ut64 addr);
RZ_API bool rz_core_bin_classes_to_struct(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf);
RZ_API bool rz_core_bin_signatures_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state);
RZ_API bool rz_core_bin_fields_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RZ_NONNULL RzCmdStateOutput *state);
RZ_API bool rz_core_bin_structured_data_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile *bf, RzOutputMode mode);

View file

@ -616,6 +616,30 @@ class std::type_info {
EOF
RUN
NAME=ica
FILE=bins/mach0/objc-employee
CMDS=<<EOF
ica Employee @ 0x100000000
fl@F:classes~method
EOF
EXPECT=<<EOF
0x100000000 0 method.Employee.helloWorld
0x100000030 0 method.Employee.sayHello
0x100000060 0 method.Employee.p0
0x100000080 0 method.Employee.p1
0x1000000a0 0 method.Employee.p2
0x1000000c0 0 method.Employee.p3
0x1000000e0 0 method.Employee.base
0x100000100 0 method.class.Employee.sayHello
0x100000130 0 method.Employee.username
0x100000160 0 method.Employee.setUsername:
0x1000001a0 0 method.Employee.firstName
0x1000001d0 0 method.Employee.setFirstName:
0x100000210 0 method.Employee.shortWord
0x100000230 0 method.Employee.wideWord
EOF
RUN
NAME=iq & iaq
FILE=bins/elf/libmagic.so
CMDS=iq;iaq

View file

@ -82,12 +82,20 @@ NAME=seteq
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pfn foo "xd foo bar"
pf. foo
pfn foo "xxd foo bar cow"
w hello happy world
w goodbye cruel world @ 0x20
s 0x20
pf. foo @ 0x00
pfa foo
EOF
EXPECT=<<EOF
foo : 0x00000000 = 0x00000000
bar : 0x00000004 = 0
foo : 0x00000000 = 0x6c6c6568
bar : 0x00000004 = 0x6168206f
cow : 0x00000008 = 544829552
foo : 0x00000020 = 0x646f6f67
bar : 0x00000024 = 0x20657962
cow : 0x00000028 = 1702195811
EOF
RUN

View file

@ -82,9 +82,8 @@ RUN
NAME=tc4
FILE=bins/mach0/objc-employee
BROKEN=1
CMDS=<<EOF
.ic*
ics
tc Employee
tc NSString
EOF
@ -111,9 +110,8 @@ RUN
NAME=tc iOS14 arm64
FILE=bins/mach0/objc-employee-ios14-arm64
BROKEN=1
CMDS=<<EOF
.ic*
ics
tsc Employee
tsc NSString
EOF
@ -209,9 +207,8 @@ RUN
NAME=tc4 iOS14 arm64
FILE=bins/mach0/objc-employee-ios14-arm64
BROKEN=1
CMDS=<<EOF
.ic*
ics
tc Employee
tc NSString
EOF
@ -238,9 +235,8 @@ RUN
NAME=tc iOS14 arm64e
FILE=bins/mach0/objc-employee-ios14-arm64e
BROKEN=1
CMDS=<<EOF
.ic*
ics
tsc Employee
tsc NSString
EOF
@ -336,9 +332,8 @@ RUN
NAME=tc4 iOS14 arm64e
FILE=bins/mach0/objc-employee-ios14-arm64e
BROKEN=1
CMDS=<<EOF
.ic*
ics
tc Employee
tc NSString
EOF
@ -387,9 +382,8 @@ RUN
NAME=test cmd tsc
FILE=bins/mach0/objc-employee
BROKEN=1
CMDS=<<EOF
.ic*
ics
tsc Employee
EOF
EXPECT=<<EOF