mirror of
https://github.com/radareorg/r2hermes.git
synced 2026-11-09 17:47:09 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5e0562f77 | ||
|
|
323c2ec730 | ||
|
|
447b05881a | ||
|
|
940512b8d8 | ||
|
|
e6d057bcaf | ||
|
|
0d360df678 | ||
|
|
8cfe3c6442 | ||
|
|
8b70c445f3 | ||
|
|
e906df6512 | ||
|
|
97e0fcb3ba | ||
|
|
dd2cd0274f | ||
|
|
9113341a4a |
No files matched your search
@@ -47,3 +47,35 @@ jobs:
|
||||
- name: Test if r2plugin is available
|
||||
run: |
|
||||
r2 -q -c La~hbc -c Lb~hbc -c Lc~hbc -- | grep -E "(core|arch|bin).*hbc"
|
||||
|
||||
meson-r2git:
|
||||
name: Test unified r2plugin with Meson
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install build dependencies
|
||||
run: sudo apt-get update -y && sudo apt-get install -y build-essential meson ninja-build pkg-config
|
||||
|
||||
- name: Build radare2 from git with Meson
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/radareorg/radare2.git
|
||||
cd radare2
|
||||
|
||||
# Clone r2hermes into the plugins directory and configure XPS
|
||||
cp -f ../r2plugin/config.mk libr/xps/config.mk
|
||||
git clone .. libr/xps/p/r2hermes
|
||||
make -C libr/xps/p/r2hermes include/hbc/version.h
|
||||
make -C libr/xps/p/r2hermes
|
||||
make -C libr/xps
|
||||
|
||||
# Build radare2 with meson
|
||||
meson setup b --prefix=/usr
|
||||
meson compile -C b
|
||||
sudo meson install -C b
|
||||
|
||||
- name: Test if r2plugin is available
|
||||
run: |
|
||||
r2 -q -c La~hbc -c Lb~hbc -c Lc~hbc -- | grep -E "(core|arch|bin).*hbc"
|
||||
@@ -4,13 +4,15 @@
|
||||

|
||||

|
||||
|
||||
Hermes bytecode disassembler, decompiler, and radare2 plugins.
|
||||
Meta's React Native Hermes bytecode assembler, disassembler, decompiler, and compation radare2 plugins.
|
||||
|
||||
Supports Hermes bytecode **v51 - v96** (React Native / Meta).
|
||||
<p align="center">
|
||||
<img width="250px" height="500px" src="r2hermes500.png" />
|
||||
</p>
|
||||
|
||||
## Features
|
||||
|
||||
- Disassemble Hermes bytecode
|
||||
- Disassemble Hermes bytecode (v51 .. v96)
|
||||
- Decompile to JavaScript pseudocode
|
||||
- Assemble instructions
|
||||
- Parse binary headers
|
||||
|
||||
+1
-40
@@ -239,23 +239,6 @@ Result hbc_decomp_all(
|
||||
HBCDecompOptions options,
|
||||
char **out_str);
|
||||
|
||||
/**
|
||||
* Disassemble a specific function.
|
||||
*/
|
||||
Result hbc_disasm_fn(
|
||||
HBC *hbc,
|
||||
u32 function_id,
|
||||
HBCDisOptions options,
|
||||
char **out_str);
|
||||
|
||||
/**
|
||||
* Disassemble all functions.
|
||||
*/
|
||||
Result hbc_disasm_all(
|
||||
HBC *hbc,
|
||||
HBCDisOptions options,
|
||||
char **out_str);
|
||||
|
||||
/**
|
||||
* Single instruction decode output
|
||||
*/
|
||||
@@ -296,14 +279,6 @@ typedef struct {
|
||||
u32 count;
|
||||
} HBCInsns;
|
||||
|
||||
/**
|
||||
* Decode a function into an array of instructions.
|
||||
*/
|
||||
Result hbc_decode_fn(
|
||||
HBC *hbc,
|
||||
u32 function_id,
|
||||
HBCInsns *out);
|
||||
|
||||
/**
|
||||
* Free instruction array.
|
||||
*/
|
||||
@@ -339,6 +314,7 @@ typedef struct {
|
||||
|
||||
/* HBC context (optional, for object/array buffer resolution) */
|
||||
HBC *hbc;
|
||||
bool build_objects;
|
||||
} HBCDecodeCtx;
|
||||
|
||||
/**
|
||||
@@ -346,21 +322,6 @@ typedef struct {
|
||||
*/
|
||||
Result hbc_dec(const HBCDecodeCtx *ctx, HBCInsnInfo *out);
|
||||
|
||||
/**
|
||||
* Decode a single instruction from raw bytes.
|
||||
* @param hbc Optional HBC context for object/array buffer resolution (can be NULL)
|
||||
*/
|
||||
Result hbc_dec_insn(
|
||||
const u8 *bytes,
|
||||
size_t len,
|
||||
u32 bytecode_version,
|
||||
u64 pc,
|
||||
bool asm_syntax,
|
||||
bool resolve_string_ids,
|
||||
const HBCStrs *string_ctx,
|
||||
HBC *hbc,
|
||||
HBCInsnInfo *out);
|
||||
|
||||
/* ============================================================================
|
||||
* Instruction Encoding
|
||||
* ============================================================================ */
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
project(
|
||||
'r2hermes',
|
||||
'c',
|
||||
version: '1.0.0',
|
||||
version: '1.1.0',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="200mm"
|
||||
height="200mm"
|
||||
viewBox="0 0 200 200"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4.2 (ebf0e940, 2025-05-08)"
|
||||
sodipodi:docname="r2hermes.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape0="https://www.inkscape.org/namespaces/inkscape"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.65979082"
|
||||
inkscape:cx="365.26728"
|
||||
inkscape:cy="427.40819"
|
||||
inkscape:window-width="1544"
|
||||
inkscape:window-height="987"
|
||||
inkscape:window-x="222"
|
||||
inkscape:window-y="44"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><path
|
||||
style="fill:#000000;stroke-width:2.07237"
|
||||
d="m 65.405259,182.40488 c 8.08363,-1.31155 15.545839,-5.228 27.944365,-14.66619 3.105915,-2.36433 5.83115,-4.29879 6.0561,-4.29879 0.22491,0 3.287466,2.24953 6.805676,4.99895 12.97156,10.13707 22.71012,14.36051 32.02796,13.88998 8.20183,-0.41416 12.80798,-4.26906 16.08053,-13.45777 1.91346,-5.37259 2.29499,-20.84084 0.73918,-29.96811 -0.66776,-3.91748 -0.95174,-7.34867 -0.63106,-7.62487 0.32066,-0.27621 3.54393,-1.74852 7.1628,-3.27179 11.88898,-5.00441 18.05863,-8.46822 22.31527,-12.52834 11.35847,-10.83415 11.16153,-20.986376 -0.61644,-31.778748 -5.03438,-4.613098 -14.86053,-10.036823 -24.31596,-13.421646 l -5.54144,-1.98371 0.96825,-4.882283 c 1.5104,-7.615982 2.03694,-21.007379 1.05512,-26.834672 -2.53415,-15.040824 -11.30206,-22.001727 -24.07884,-19.116366 -8.57482,1.93644 -16.48902,6.477513 -30.57361,17.54278 -1.688876,1.326834 -1.718076,1.312777 -9.566219,-4.604651 -25.39237,-19.145631 -42.985514,-17.789987 -48.051634,3.702633 -1.43768,6.099251 -1.423548,17.269444 0.03345,26.433827 0.638137,4.013848 0.884878,7.536494 0.548313,7.828101 -0.336567,0.291609 -2.750361,1.28414 -5.363986,2.205627 -2.613629,0.921487 -7.054966,2.828803 -9.86964,4.238481 -26.2070036,13.125292 -29.8334427,29.994037 -9.54137,44.382647 5.359465,3.80026 11.124311,6.71237 19.47139,9.83592 l 6.274598,2.34801 -1.088676,5.24951 c -0.655525,3.16087 -1.115861,9.61263 -1.157005,16.21576 -0.05999,9.62896 0.135018,11.55446 1.599087,15.78953 3.105332,8.98262 7.427923,12.83351 16.244148,14.4715 0.20104,0.0374 2.482391,-0.27553 5.069643,-0.69532 z m -8.852167,-10.12344 c -3.751344,-2.97305 -6.085299,-14.77458 -4.985876,-25.21082 0.888267,-8.43185 1.555743,-12.11741 2.275049,-12.56197 0.34399,-0.21259 5.646833,0.46084 11.784093,1.49653 12.711453,2.14513 11.070753,1.1235 20.576734,12.81302 l 6.242461,7.6764 -2.71268,2.39074 c -9.130327,8.04677 -19.716332,13.76414 -26.838471,14.49514 -3.77633,0.38757 -4.658421,0.23469 -6.34131,-1.09904 z m 73.818708,0.0207 c -5.40534,-1.77815 -9.64358,-4.27951 -17.92297,-10.57797 l -6.73906,-5.12666 3.13901,-3.70679 c 1.72644,-2.03872 5.1939,-6.25609 7.70544,-9.37193 2.51155,-3.11585 5.28303,-5.82911 6.15887,-6.02949 1.94032,-0.44394 20.59258,-3.29257 21.55902,-3.29257 1.08625,0 2.65075,11.33101 2.67497,19.37373 0.0391,13.01979 -2.82778,19.24338 -9.12516,19.80859 -1.9941,0.17904 -4.91659,-0.24347 -7.45012,-1.07691 z m -36.172965,-28.07332 -4.518716,-5.28005 4.701481,-0.21618 c 2.585816,-0.11889 6.856,-0.11889 9.4893,0 l 4.7878,0.21618 -4.49901,5.30037 c -2.47443,2.91518 -4.711196,5.29121 -4.970576,5.28005 -0.25936,-0.011 -2.504992,-2.39635 -4.990279,-5.30037 z m -7.77842,-14.96041 -4.255191,-0.26532 -4.355269,-6.72452 c -5.439438,-8.39848 -11.625669,-20.34073 -11.625669,-22.442863 0,-2.105876 6.189501,-14.049411 11.650254,-22.480845 l 4.379853,-6.76253 h 16.819551 16.819506 l 3.5512,5.30036 c 4.06848,6.072519 10.45604,17.295145 12.14627,21.340435 l 1.14799,2.747513 -4.11174,8.03841 c -2.26146,4.42112 -6.00156,10.91641 -8.3113,14.43398 l -4.19957,6.39559 -6.12059,0.47639 c -6.08243,0.47343 -15.393643,0.45101 -23.535295,-0.0566 z m -23.660648,-3.01883 c -3.290834,-0.65524 -6.166359,-1.38013 -6.390062,-1.61089 -0.436965,-0.45069 3.070702,-11.61604 3.958794,-12.60133 0.40219,-0.4462 7.771942,11.34737 9.389357,15.02548 0.28811,0.6552 0.599983,0.69163 -6.958089,-0.81326 z m 65.732503,0.89746 c 6.64942,-11.94184 8.90852,-15.59436 9.3454,-15.10968 0.83096,0.92192 4.38345,12.05732 4.02936,12.63022 -0.17345,0.28066 -2.7153,0.91951 -5.64856,1.41968 -2.93327,0.50016 -5.95013,1.08422 -6.70417,1.2979 -0.75403,0.21368 -1.21393,0.10652 -1.02203,-0.23812 z M 40.005184,119.92199 C 29.137487,115.74039 18.735382,108.57757 16.083732,103.44985 13.899781,99.226547 14.580281,97.184361 19.943193,91.867578 25.253006,86.603437 33.09917,82.027199 41.911899,79.054431 l 4.850434,-1.636179 4.235148,11.284153 4.23515,11.284154 -4.136306,10.890761 c -2.99014,7.87294 -4.460892,10.88087 -5.30767,10.85503 -0.644249,-0.0186 -3.24681,-0.83432 -5.783471,-1.81036 z m 107.143396,-9.20743 -4.20703,-11.051106 4.13229,-10.880221 c 3.12305,-8.22283 4.44062,-10.880218 5.39457,-10.880218 2.21207,0 13.66146,4.960442 18.49426,8.012637 2.56597,1.620561 6.35959,4.737825 8.43028,6.927254 3.29211,3.480926 3.76485,4.362967 3.76485,7.024508 0,2.787706 -0.4151,3.454746 -4.93483,7.930046 -3.06936,3.03918 -6.92045,5.91803 -10.18754,7.61558 -5.43168,2.82227 -14.20922,6.35595 -15.78264,6.35383 -0.49344,-6.6e-4 -2.79033,-4.97421 -5.10421,-11.05231 z M 59.992728,87.32898 c -2.345369,-6.331151 -3.945993,-11.996043 -3.499922,-12.386837 0.600454,-0.526047 12.734475,-3.012835 13.068922,-2.678391 0.22244,0.222439 -7.925708,14.81773 -8.7104,15.602422 -0.264717,0.264716 -0.651086,0.02298 -0.8586,-0.537194 z m 72.901162,-7.023738 c -2.4819,-4.300108 -4.41643,-7.914508 -4.29895,-8.032001 0.33879,-0.338789 12.46534,2.131868 13.07301,2.663491 0.525,0.459308 -2.783,11.529369 -3.77888,12.645862 -0.26542,0.297565 -2.51325,-2.977245 -4.99518,-7.277352 z M 52.413642,60.17422 c -2Line truncated
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ssscsssssssscsssssssssssscssssssssssscsscsscsssssccsccccscsccssscccsscsscssssssscsssscsssscccscsscssssssssssssssssssssssscssssssscsssscsscssccc" /><path
|
||||
style="fill:#1a1a1a;stroke-width:0.116743"
|
||||
d="m 99.09343,86.984035 c -0.433378,0.01898 -1.279722,-0.04797 -1.166293,0.626811 -0.07594,1.725589 -0.01063,3.460018 -0.08505,5.180484 -1.583015,-2.272255 -3.661797,-4.374412 -6.38905,-5.173624 -1.820358,-0.634195 -3.799636,-0.502714 -5.687046,-0.337252 -2.578839,0.461946 -4.988,2.259769 -5.748925,4.831396 -1.044344,3.15068 0.554172,6.85477 3.396683,8.47144 2.819126,1.35582 6.537812,1.15347 8.845863,-1.10658 1.26105,-1.14881 1.988894,-2.83896 1.858987,-4.55045 0.04593,-1.18872 -0.0836,-2.39009 0.02806,-3.57187 0.739949,-0.12582 1.19556,0.73185 1.596618,1.21831 1.406494,1.95756 1.5765,4.4103 1.604586,6.73006 0.112076,5.45862 0.04861,10.93116 0.06875,16.39512 -1.50075,0.0423 -3.039804,-0.083 -4.517192,0.0616 0.07047,0.51904 -0.422063,1.8136 0.477918,1.66633 7.588321,0 15.176631,0 22.764951,0 0.22573,-0.34655 0.38535,-1.573 -0.11674,-1.7279 -0.9962,0 -1.99239,0 -2.98859,0 0,-8.80241 0,-17.60483 0,-26.407248 1.0731,-0.04054 2.18324,0.081 3.23302,-0.06156 -0.0571,-0.49214 0.39445,-1.669191 -0.46772,-1.548211 -5.0858,-0.237955 -10.17665,-0.369779 -15.25934,-0.677209 -0.48295,-0.01632 -0.96624,-0.02889 -1.44949,-0.01961 z"
|
||||
id="path68"
|
||||
inkscape0:connector-curvature="0" /></g></svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -22,10 +22,12 @@ configure_file(
|
||||
install: true,
|
||||
)
|
||||
|
||||
# Include directories
|
||||
# Register plugins in the static plugin lists
|
||||
core_plugins += ['r2hermes']
|
||||
|
||||
# Include directories (relative to this meson.build file location)
|
||||
include_dirs = include_directories(join_paths('..', 'include'))
|
||||
r_core_additional_inc += include_dirs
|
||||
r_core_additional_inc += ['../xps/p/r2hermes/include']
|
||||
|
||||
# Library source files
|
||||
lib_utils_src = files(
|
||||
@@ -56,7 +58,7 @@ lib_opcodes_src = files(
|
||||
lib_core_src = files(
|
||||
'../src/lib/hbc.c',
|
||||
'../src/lib/r2.c',
|
||||
'../src/r2/core_hbc.c',
|
||||
'../src/r2/core_hbc_one.c',
|
||||
)
|
||||
|
||||
lib_src = lib_utils_src + lib_parsers_src + lib_disasm_src + lib_decompile_src + lib_opcodes_src + lib_core_src
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifdef R2_CORE_H
|
||||
#include "core/deps.h"
|
||||
#endif
|
||||
#ifdef R2_ARCH_H
|
||||
#include "arch/deps.h"
|
||||
#endif
|
||||
|
||||
@@ -1133,7 +1133,7 @@ Result _hbc_translate_instruction_to_tokens(const ParsedInstruction *insn_c, Tok
|
||||
}
|
||||
case OP_DeclareGlobalVar:
|
||||
{
|
||||
RETURN_IF_ERROR (add (out, create_raw_token ("declare extern var ")));
|
||||
RETURN_IF_ERROR (add (out, create_raw_token ("declare extern var")));
|
||||
u32 sid = insn->arg1;
|
||||
RETURN_IF_ERROR (add (out, unquoted_string (insn->hbc_reader, sid)));
|
||||
break;
|
||||
|
||||
+59
-124
@@ -337,34 +337,6 @@ Result hbc_decomp_all(
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
Result hbc_disasm_fn(
|
||||
HBC *hbc,
|
||||
u32 function_id,
|
||||
HBCDisOptions options,
|
||||
char **out_str) {
|
||||
(void)function_id;
|
||||
(void)options;
|
||||
|
||||
if (!hbc || !out_str) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
|
||||
return ERROR_RESULT (RESULT_ERROR_NOT_IMPLEMENTED, "Disassembly via state not yet implemented");
|
||||
}
|
||||
|
||||
Result hbc_disasm_all(
|
||||
HBC *hbc,
|
||||
HBCDisOptions options,
|
||||
char **out_str) {
|
||||
(void)options;
|
||||
|
||||
if (!hbc || !out_str) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
|
||||
return ERROR_RESULT (RESULT_ERROR_NOT_IMPLEMENTED, "Disassembly via state not yet implemented");
|
||||
}
|
||||
|
||||
Result hbc_all_funcs(
|
||||
HBC *hbc,
|
||||
HBCFuncArray *out) {
|
||||
@@ -406,34 +378,40 @@ void hbc_free_funcs(HBCFuncArray *arr) {
|
||||
}
|
||||
}
|
||||
|
||||
Result hbc_decode_fn(
|
||||
HBC *hbc,
|
||||
u32 function_id,
|
||||
HBCInsns *out) {
|
||||
if (!hbc || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
|
||||
const u8 *bytecode = NULL;
|
||||
u32 bytecode_size = 0;
|
||||
Result res = hbc_get_function_bytecode (hbc, function_id, &bytecode, &bytecode_size);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
HBCStrs string_tables = { 0 };
|
||||
res = hbc_get_string_tables (hbc, &string_tables);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
out->instructions = NULL;
|
||||
out->count = 0;
|
||||
return ERROR_RESULT (RESULT_ERROR_NOT_IMPLEMENTED, "Instruction decoding via state not yet implemented");
|
||||
}
|
||||
|
||||
/* Single-instruction decode functions */
|
||||
|
||||
static char *build_literal_comment(HBCReader *reader, u8 opcode, const u32 *ovs, const char *base_text) {
|
||||
const bool is_obj = (opcode == OP_NewObjectWithBuffer || opcode == OP_NewObjectWithBufferLong);
|
||||
StringBuffer sb;
|
||||
if (_hbc_string_buffer_init (&sb, 256).code != RESULT_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
Result fmt_res;
|
||||
if (is_obj) {
|
||||
const u32 key_count = ovs[1];
|
||||
const u32 value_count = ovs[2];
|
||||
const u32 keys_id = ovs[3];
|
||||
const u32 values_id = ovs[4];
|
||||
fmt_res = _hbc_format_object_literal (reader, key_count, value_count, keys_id, values_id, &sb, LITERALS_PRETTY_NEVER, true);
|
||||
} else {
|
||||
const u32 value_count = ovs[2];
|
||||
const u32 array_id = ovs[3];
|
||||
fmt_res = _hbc_format_array_literal (reader, value_count, array_id, &sb, LITERALS_PRETTY_NEVER, true);
|
||||
}
|
||||
char *result = NULL;
|
||||
if (fmt_res.code == RESULT_SUCCESS && sb.length > 0) {
|
||||
size_t base_len = strlen (base_text);
|
||||
result = (char *)malloc (base_len + 4 + sb.length + 1);
|
||||
if (result) {
|
||||
memcpy (result, base_text, base_len);
|
||||
memcpy (result + base_len, " ; ", 4);
|
||||
memcpy (result + base_len + 4, sb.data, sb.length + 1);
|
||||
}
|
||||
}
|
||||
_hbc_string_buffer_free (&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result hbc_dec(const HBCDecodeCtx *ctx, HBCInsnInfo *out) {
|
||||
if (!ctx || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid context");
|
||||
@@ -445,30 +423,7 @@ Result hbc_dec(const HBCDecodeCtx *ctx, HBCInsnInfo *out) {
|
||||
hbc_debug_printf ("Warning: bytecode version not specified, defaulting to %u\n", bytecode_version);
|
||||
}
|
||||
|
||||
return hbc_dec_insn (
|
||||
ctx->bytes,
|
||||
ctx->len,
|
||||
bytecode_version,
|
||||
ctx->pc,
|
||||
ctx->asm_syntax,
|
||||
ctx->resolve_string_ids,
|
||||
ctx->string_tables,
|
||||
ctx->hbc,
|
||||
out);
|
||||
}
|
||||
|
||||
Result hbc_dec_insn(
|
||||
const u8 *bytes,
|
||||
size_t len,
|
||||
u32 bytecode_version,
|
||||
u64 pc,
|
||||
bool asm_syntax,
|
||||
bool resolve_string_ids,
|
||||
const HBCStrs *string_ctx,
|
||||
HBC *hbc,
|
||||
HBCInsnInfo *out) {
|
||||
|
||||
if (!bytes || !out || len == 0) {
|
||||
if (!ctx->bytes || !out || ctx->len == 0) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
|
||||
@@ -479,7 +434,7 @@ Result hbc_dec_insn(
|
||||
}
|
||||
|
||||
/* Read opcode */
|
||||
u8 opcode = bytes[0];
|
||||
u8 opcode = ctx->bytes[0];
|
||||
|
||||
/* Find instruction definition */
|
||||
const Instruction *inst = NULL;
|
||||
@@ -522,7 +477,7 @@ Result hbc_dec_insn(
|
||||
default: need = 0; break;
|
||||
}
|
||||
|
||||
if (pos + need > len) {
|
||||
if (pos + need > ctx->len) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -531,19 +486,19 @@ Result hbc_dec_insn(
|
||||
case OPERAND_TYPE_REG8:
|
||||
case OPERAND_TYPE_UINT8:
|
||||
case OPERAND_TYPE_ADDR8:
|
||||
operand_values[i] = bytes[pos];
|
||||
operand_values[i] = ctx->bytes[pos];
|
||||
pos += 1;
|
||||
break;
|
||||
case OPERAND_TYPE_UINT16:
|
||||
operand_values[i] = bytes[pos] | (bytes[pos + 1] << 8);
|
||||
operand_values[i] = ctx->bytes[pos] | (ctx->bytes[pos + 1] << 8);
|
||||
pos += 2;
|
||||
break;
|
||||
case OPERAND_TYPE_REG32:
|
||||
case OPERAND_TYPE_UINT32:
|
||||
case OPERAND_TYPE_IMM32:
|
||||
case OPERAND_TYPE_ADDR32:
|
||||
operand_values[i] = bytes[pos] | (bytes[pos + 1] << 8) |
|
||||
(bytes[pos + 2] << 16) | (bytes[pos + 3] << 24);
|
||||
operand_values[i] = ctx->bytes[pos] | (ctx->bytes[pos + 1] << 8) |
|
||||
(ctx->bytes[pos + 2] << 16) | (ctx->bytes[pos + 3] << 24);
|
||||
pos += 4;
|
||||
break;
|
||||
case OPERAND_TYPE_DOUBLE:
|
||||
@@ -563,7 +518,7 @@ Result hbc_dec_insn(
|
||||
/* Convert instruction name to snake_case */
|
||||
hbc_camel_to_snake (inst->name, mnemonic, sizeof (mnemonic));
|
||||
|
||||
if (asm_syntax) {
|
||||
if (ctx->asm_syntax) {
|
||||
/* ASM syntax: mnemonic operand1, operand2, ... */
|
||||
offset = snprintf (buf, sizeof (buf), "%s", mnemonic);
|
||||
|
||||
@@ -585,16 +540,16 @@ Result hbc_dec_insn(
|
||||
} else if (operand_meaning == OPERAND_MEANING_STRING_ID) {
|
||||
/* For string IDs, output the string storage offset (not the ID)
|
||||
* so r2 can replace it with flags */
|
||||
if (resolve_string_ids && string_ctx && string_ctx->string_storage_offset != 0) {
|
||||
if (ctx->resolve_string_ids && ctx->string_tables && ctx->string_tables->string_storage_offset != 0) {
|
||||
u32 str_offset = 0;
|
||||
bool found = false;
|
||||
|
||||
/* Cast to proper types for access */
|
||||
const StringTableEntry *small_table = (const StringTableEntry *)string_ctx->small_string_table;
|
||||
const OffsetLengthPair *overflow_table = (const OffsetLengthPair *)string_ctx->overflow_string_table;
|
||||
const StringTableEntry *small_table = (const StringTableEntry *)ctx->string_tables->small_string_table;
|
||||
const OffsetLengthPair *overflow_table = (const OffsetLengthPair *)ctx->string_tables->overflow_string_table;
|
||||
|
||||
/* Look up string storage offset from string tables */
|
||||
if (val < string_ctx->string_count && small_table) {
|
||||
if (val < ctx->string_tables->string_count && small_table) {
|
||||
if (small_table[val].length == 0xFF && overflow_table) {
|
||||
/* Overflow string */
|
||||
u32 overflow_idx = small_table[val].offset;
|
||||
@@ -608,7 +563,7 @@ Result hbc_dec_insn(
|
||||
|
||||
if (found) {
|
||||
/* Output the file-absolute string offset in hex - r2 will replace this with the string flag */
|
||||
u32 file_offset = string_ctx->string_storage_offset + str_offset;
|
||||
u32 file_offset = ctx->string_tables->string_storage_offset + str_offset;
|
||||
offset += snprintf (buf + offset, sizeof (buf) - offset, "0x%x", file_offset);
|
||||
} else {
|
||||
/* Fallback: just show the ID */
|
||||
@@ -631,41 +586,18 @@ Result hbc_dec_insn(
|
||||
}
|
||||
}
|
||||
|
||||
char *final_text = NULL;
|
||||
if (hbc && (opcode == OP_NewObjectWithBuffer || opcode == OP_NewObjectWithBufferLong ||
|
||||
opcode == OP_NewArrayWithBuffer || opcode == OP_NewArrayWithBufferLong)) {
|
||||
HBCReader *reader = &hbc->reader;
|
||||
StringBuffer sb;
|
||||
if (_hbc_string_buffer_init (&sb, 256).code == RESULT_SUCCESS) {
|
||||
Result fmt_res = { .code = RESULT_ERROR_PARSING_FAILED };
|
||||
if (opcode == OP_NewObjectWithBuffer || opcode == OP_NewObjectWithBufferLong) {
|
||||
u32 key_count = operand_values[1];
|
||||
u32 value_count = operand_values[2];
|
||||
u32 keys_id = operand_values[3];
|
||||
u32 values_id = operand_values[4];
|
||||
fmt_res = _hbc_format_object_literal (reader, key_count, value_count, keys_id, values_id,
|
||||
&sb, LITERALS_PRETTY_NEVER, true);
|
||||
} else {
|
||||
u32 value_count = operand_values[2];
|
||||
u32 array_id = operand_values[3];
|
||||
fmt_res = _hbc_format_array_literal (reader, value_count, array_id,
|
||||
&sb, LITERALS_PRETTY_NEVER, true);
|
||||
}
|
||||
if (fmt_res.code == RESULT_SUCCESS && sb.data && sb.data[0]) {
|
||||
size_t buf_len = strlen (buf);
|
||||
size_t sb_len = strlen (sb.data);
|
||||
final_text = (char *)malloc (buf_len + 4 + sb_len + 1);
|
||||
if (final_text) {
|
||||
memcpy (final_text, buf, buf_len);
|
||||
memcpy (final_text + buf_len, " ; ", 4);
|
||||
memcpy (final_text + buf_len + 4, sb.data, sb_len + 1);
|
||||
}
|
||||
}
|
||||
_hbc_string_buffer_free (&sb);
|
||||
if (ctx->build_objects && ctx->hbc) {
|
||||
const bool is_literal_op = (opcode == OP_NewObjectWithBuffer || opcode == OP_NewObjectWithBufferLong ||
|
||||
opcode == OP_NewArrayWithBuffer || opcode == OP_NewArrayWithBufferLong);
|
||||
if (is_literal_op) {
|
||||
char *with_comment = build_literal_comment (&ctx->hbc->reader, opcode, operand_values, buf);
|
||||
out->text = with_comment ? with_comment : strdup (buf);
|
||||
} else {
|
||||
out->text = strdup (buf);
|
||||
}
|
||||
} else {
|
||||
out->text = strdup (buf);
|
||||
}
|
||||
|
||||
out->text = final_text ? final_text : strdup (buf);
|
||||
out->size = (u32)pos;
|
||||
out->opcode = opcode;
|
||||
|
||||
@@ -674,9 +606,12 @@ Result hbc_dec_insn(
|
||||
out->is_call = (strncmp (mnemonic, "call", 4) == 0) || (strcmp (mnemonic, "construct") == 0);
|
||||
out->jump_target = 0;
|
||||
|
||||
if (!out->is_jump && !strncmp (mnemonic, "save_generator", strlen ("save_generator"))) {
|
||||
out->is_jump = true;
|
||||
}
|
||||
if (out->is_jump && operand_values[0] != 0) {
|
||||
/* Calculate jump target (relative offset) */
|
||||
out->jump_target = pc + (i32)operand_values[0];
|
||||
out->jump_target = ctx->pc + (i32)operand_values[0];
|
||||
}
|
||||
|
||||
return SUCCESS_RESULT ();
|
||||
|
||||
@@ -831,7 +831,7 @@ Result _hbc_reader_read_string_tables(HBCReader *reader) {
|
||||
u32 overflow_index = reader->small_string_table[i].offset;
|
||||
if (overflow_index >= reader->header.overflowStringCount) {
|
||||
/* Invalid overflow index */
|
||||
reader->strings[i] = strdup("");
|
||||
reader->strings[i] = strdup ("");
|
||||
if (!reader->strings[i]) {
|
||||
free (string_storage);
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "Failed to allocate empty string");
|
||||
@@ -851,7 +851,7 @@ Result _hbc_reader_read_string_tables(HBCReader *reader) {
|
||||
/* Check bounds */
|
||||
if (offset + (is_utf16? length * 2: length) > string_storage_size) {
|
||||
fprintf (stderr, "Warning: String %u offset/length out of bounds, treating as empty string\n", i);
|
||||
reader->strings[i] = strdup("");
|
||||
reader->strings[i] = strdup ("");
|
||||
if (!reader->strings[i]) {
|
||||
free (string_storage);
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "Failed to allocate empty string");
|
||||
|
||||
+18
-25
@@ -1,4 +1,4 @@
|
||||
/* radare2 - LGPL - Copyright 2025 - pancake */
|
||||
/* radare2 - LGPL - Copyright 2025-2026 - pancake */
|
||||
|
||||
#include <r_anal.h>
|
||||
#include <hbc/hbc.h>
|
||||
@@ -38,13 +38,6 @@ static ut32 detect_version_from_bin(RArchSession *s) {
|
||||
return 96;
|
||||
}
|
||||
|
||||
#define READ_REG8(b, pos) ((u8) (b)[(pos)])
|
||||
#define READ_UINT8(b, pos) ((u8) (b)[(pos)])
|
||||
#define READ_UINT16(b, pos) ((u16) ((b)[(pos)] | ((b)[(pos) + 1] << 8)))
|
||||
#define READ_UINT32(b, pos) ((u32) ((b)[(pos)] | ((b)[(pos) + 1] << 8) | ((b)[(pos) + 2] << 16) | ((b)[(pos) + 3] << 24)))
|
||||
#define READ_INT8(b, pos) ((i8) (b)[(pos)])
|
||||
#define READ_INT32(b, pos) ((i32)READ_UINT32 (b, pos))
|
||||
|
||||
#include "esil.inc.c"
|
||||
|
||||
static bool load_string_tables(HermesArchSession *hs, RArchSession *s) {
|
||||
@@ -98,6 +91,9 @@ static bool opcode_is_conditional(u8 opcode) {
|
||||
case OP_JmpUndefined:
|
||||
case OP_JmpUndefinedLong:
|
||||
return true;
|
||||
case OP_SaveGenerator:
|
||||
case OP_SaveGeneratorLong:
|
||||
return true;
|
||||
default:
|
||||
/* Relational and equality conditional jumps occupy 152..191 */
|
||||
if (opcode >= OP_JLess && opcode <= OP_JStrictNotEqualLong) {
|
||||
@@ -172,7 +168,7 @@ static void parse_operands_and_set_ptr(RAnalOp *op, const ut8 *bytes, ut32 size,
|
||||
if (meta_result.code == RESULT_SUCCESS) {
|
||||
/* Set op->ptr to the file offset of the string.
|
||||
* meta.offset already includes string_storage_file_offset */
|
||||
op->ptr = (st64) meta.offset;
|
||||
op->ptr = (st64)meta.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,6 +231,9 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
.string_tables = &string_tables,
|
||||
.hbc = hs->hbc
|
||||
};
|
||||
if (mask & R_ARCH_OP_MASK_ESIL && mask & R_ARCH_OP_MASK_DISASM) {
|
||||
ctx.build_objects = true;
|
||||
}
|
||||
|
||||
HBCInsnInfo sinfo;
|
||||
if (hbc_dec (&ctx, &sinfo).code != RESULT_SUCCESS) {
|
||||
@@ -249,20 +248,8 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
/* Parse operands and set ptr for string/function references */
|
||||
parse_operands_and_set_ptr (op, op->bytes, op->size, sinfo.opcode, hs);
|
||||
|
||||
if (sinfo.text) {
|
||||
char mnemonic_raw[64];
|
||||
const char *end = sinfo.text;
|
||||
while (*end && *end != ' ' && *end != '\t') {
|
||||
end++;
|
||||
}
|
||||
size_t len = end - sinfo.text;
|
||||
if (len > 0 && len < sizeof (mnemonic_raw)) {
|
||||
memcpy (mnemonic_raw, sinfo.text, len);
|
||||
mnemonic_raw[len] = '\0';
|
||||
char mnemonic[64];
|
||||
hbc_snake_to_camel (mnemonic_raw, mnemonic, sizeof (mnemonic));
|
||||
set_esil (op, mnemonic, op->bytes, op->addr);
|
||||
}
|
||||
if (mask & R_ARCH_OP_MASK_ESIL && sinfo.text) {
|
||||
set_esil (op, op->bytes, op->addr);
|
||||
}
|
||||
|
||||
if (sinfo.opcode == OP_Ret) {
|
||||
@@ -277,6 +264,14 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* SaveGenerator instructions are conditional branches, not calls */
|
||||
if (sinfo.opcode == OP_SaveGenerator || sinfo.opcode == OP_SaveGeneratorLong) {
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->jump = sinfo.jump_target;
|
||||
op->fail = op->addr + op->size;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sinfo.is_jump) {
|
||||
op->type = R_ANAL_OP_TYPE_JMP;
|
||||
}
|
||||
@@ -494,8 +489,6 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
case OP_StartGenerator:
|
||||
case OP_ResumeGenerator:
|
||||
case OP_CompleteGenerator:
|
||||
case OP_SaveGenerator:
|
||||
case OP_SaveGeneratorLong:
|
||||
case OP_DirectEval:
|
||||
op->type = R_ANAL_OP_TYPE_CALL;
|
||||
break;
|
||||
|
||||
+1
-1
@@ -300,7 +300,7 @@ static RList *strings(RBinFile *bf) {
|
||||
|
||||
ptr->paddr = meta.offset;
|
||||
ptr->vaddr = meta.offset;
|
||||
ptr->size = meta.isUTF16 ? (meta.length * 2) : meta.length;
|
||||
ptr->size = meta.isUTF16? (meta.length * 2): meta.length;
|
||||
ptr->length = meta.length;
|
||||
ptr->ordinal = i;
|
||||
r_list_append (ret, ptr);
|
||||
|
||||
+275
-276
File diff suppressed because it is too large.
Load diff
+86
-3
@@ -235,7 +235,20 @@ static Result cmd_dis(const CliContext *ctx, int argc, char **argv) {
|
||||
|
||||
HBCInsnInfo sinfo;
|
||||
memset (&sinfo, 0, sizeof (sinfo));
|
||||
Result r = hbc_dec_insn (bytes, bcount, 96, 0, asm_syntax, false, NULL, NULL, &sinfo);
|
||||
|
||||
HBCDecodeCtx dec_ctx = {
|
||||
.bytes = bytes,
|
||||
.len = bcount,
|
||||
.bytecode_version = 96,
|
||||
.pc = 0,
|
||||
.asm_syntax = asm_syntax,
|
||||
.resolve_string_ids = false,
|
||||
.string_tables = NULL,
|
||||
.hbc = NULL,
|
||||
.build_objects = true
|
||||
};
|
||||
|
||||
Result r = hbc_dec (&dec_ctx, &sinfo);
|
||||
if (r.code != RESULT_SUCCESS) {
|
||||
return r;
|
||||
}
|
||||
@@ -575,6 +588,77 @@ static Result cmd_cmp(const CliContext *ctx, int argc, char **argv) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static Result disasm_function(HBC *hbc, u32 function_id, char **out) {
|
||||
const u8 *bytecode = NULL;
|
||||
u32 bytecode_size = 0;
|
||||
Result res = hbc_get_function_bytecode (hbc, function_id, &bytecode, &bytecode_size);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
HBCHeader hdr;
|
||||
res = hbc_get_header (hbc, &hdr);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
HBCFunc fi;
|
||||
res = hbc_get_function_info (hbc, function_id, &fi);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t cap = 4096;
|
||||
size_t len = 0;
|
||||
char *buf = malloc (cap);
|
||||
if (!buf) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
u32 offset = 0;
|
||||
while (offset < bytecode_size) {
|
||||
HBCInsnInfo insn_info;
|
||||
memset (&insn_info, 0, sizeof (insn_info));
|
||||
HBCDecodeCtx dec_ctx = {
|
||||
.bytes = bytecode + offset,
|
||||
.len = bytecode_size - offset,
|
||||
.pc = fi.offset + offset,
|
||||
.bytecode_version = hdr.version,
|
||||
.asm_syntax = false,
|
||||
.resolve_string_ids = false,
|
||||
.string_tables = NULL,
|
||||
.hbc = hbc,
|
||||
.build_objects = false
|
||||
};
|
||||
res = hbc_dec (&dec_ctx, &insn_info);
|
||||
if (res.code != RESULT_SUCCESS || insn_info.size == 0) {
|
||||
free (insn_info.text);
|
||||
break;
|
||||
}
|
||||
const char *text = insn_info.text? insn_info.text: "";
|
||||
size_t text_len = strlen (text);
|
||||
if (len + text_len + 2 > cap) {
|
||||
cap *= 2;
|
||||
char *tmp = realloc (buf, cap);
|
||||
if (!tmp) {
|
||||
free (insn_info.text);
|
||||
free (buf);
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
}
|
||||
buf = tmp;
|
||||
}
|
||||
memcpy (buf + len, text, text_len);
|
||||
len += text_len;
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
free (insn_info.text);
|
||||
offset += insn_info.size;
|
||||
}
|
||||
*out = buf;
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static Result cmd_cf(const CliContext *ctx, int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
return errorf (RESULT_ERROR_INVALID_ARGUMENT, "Usage: %s cf <input_file> <python_dis_file> <function_id>", ctx->program_name);
|
||||
@@ -594,9 +678,8 @@ static Result cmd_cf(const CliContext *ctx, int argc, char **argv) {
|
||||
return errorf (RESULT_ERROR_INVALID_ARGUMENT, "Invalid function id %u", function_id);
|
||||
}
|
||||
|
||||
HBCDisOptions opt = (HBCDisOptions){ 0 };
|
||||
char *disasm_str = NULL;
|
||||
res = hbc_disasm_fn (hbc, function_id, opt, &disasm_str);
|
||||
res = disasm_function (hbc, function_id, &disasm_str);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_close (hbc);
|
||||
return res;
|
||||
|
||||
Reference in new issue
Block a user