175 lines
4 KiB
C
175 lines
4 KiB
C
// SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_types.h>
|
|
#include <rz_util.h>
|
|
#include <rz_lib.h>
|
|
#include <rz_asm.h>
|
|
#include <rz_core.h>
|
|
|
|
#include "../arch/java/jvm.h"
|
|
#include "../arch/java/assembler.h"
|
|
|
|
typedef struct java_analysis_context_t {
|
|
LookupSwitch ls;
|
|
TableSwitch ts;
|
|
ut16 switchop;
|
|
ut64 pc;
|
|
ut64 last;
|
|
ut32 count;
|
|
} JavaAsmContext;
|
|
|
|
static void update_context(JavaAsmContext *ctx) {
|
|
ctx->count++;
|
|
if (ctx->switchop == BYTECODE_AA_TABLESWITCH && ctx->count > ctx->ts.length) {
|
|
ctx->switchop = BYTECODE_00_NOP;
|
|
} else if (ctx->switchop == BYTECODE_AB_LOOKUPSWITCH && ctx->count > ctx->ls.npairs) {
|
|
ctx->switchop = BYTECODE_00_NOP;
|
|
}
|
|
}
|
|
|
|
static ut64 find_method(RzAsm *a) {
|
|
ut64 addr = a->pc;
|
|
if (!a->binb.bin) {
|
|
return addr;
|
|
}
|
|
|
|
RzBinSection *sec;
|
|
void **it;
|
|
RzBinObject *obj = rz_bin_cur_object(a->binb.bin);
|
|
const RzPVector *vec = obj ? a->binb.get_sections(obj) : NULL;
|
|
|
|
rz_pvector_foreach (vec, it) {
|
|
sec = *it;
|
|
ut64 from = sec->vaddr;
|
|
ut64 to = from + sec->vsize;
|
|
if (!(sec->perm & RZ_PERM_X) || addr < from || addr > to) {
|
|
continue;
|
|
}
|
|
return sec->paddr;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
static int java_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
|
|
JavaAsmContext *ctx = (JavaAsmContext *)a->plugin_data;
|
|
rz_strbuf_set(&op->buf_asm, "invalid");
|
|
|
|
if (a->pc < ctx->last) {
|
|
ctx->switchop = BYTECODE_00_NOP;
|
|
}
|
|
ctx->last = a->pc;
|
|
switch (ctx->switchop) {
|
|
case BYTECODE_AA_TABLESWITCH: {
|
|
if (len < 4) {
|
|
RZ_LOG_ERROR("[!] java_analysis: no enough data for lookupswitch case.\n");
|
|
return -1;
|
|
}
|
|
op->size = 4;
|
|
ut64 jump = ctx->pc + rz_read_be32(buf);
|
|
rz_strbuf_setf(&op->buf_asm, "case %d: goto 0x%" PFMT64x, ctx->count + ctx->ts.low, jump);
|
|
update_context(ctx);
|
|
return op->size;
|
|
}
|
|
case BYTECODE_AB_LOOKUPSWITCH: {
|
|
if (len < 8) {
|
|
RZ_LOG_ERROR("[!] java_analysis: no enough data for lookupswitch case.\n");
|
|
return -1;
|
|
}
|
|
op->size = 8;
|
|
st32 number = (st32)rz_read_be32(buf);
|
|
ut64 jump = ctx->pc + rz_read_at_be32(buf, 4);
|
|
rz_strbuf_setf(&op->buf_asm, "case %d: goto 0x%" PFMT64x, number, jump);
|
|
update_context(ctx);
|
|
return op->size;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
JavaVM vm = { 0 };
|
|
Bytecode bc = { 0 };
|
|
|
|
rz_strbuf_set(&op->buf_asm, "invalid");
|
|
|
|
ut64 section = find_method(a);
|
|
if (!jvm_init(&vm, buf, len, a->pc, section)) {
|
|
RZ_LOG_ERROR("[!] java_disassemble: bad or invalid data.\n");
|
|
return -1;
|
|
}
|
|
op->size = 1;
|
|
if (jvm_fetch(&vm, &bc)) {
|
|
op->size = bc.size;
|
|
bytecode_snprint(&op->buf_asm, &bc);
|
|
if (bc.opcode == BYTECODE_AA_TABLESWITCH) {
|
|
ctx->count = 0;
|
|
ctx->switchop = BYTECODE_AA_TABLESWITCH;
|
|
ctx->ts = *((TableSwitch *)bc.extra);
|
|
ctx->pc = a->pc;
|
|
} else if (bc.opcode == BYTECODE_AB_LOOKUPSWITCH) {
|
|
ctx->count = 0;
|
|
ctx->switchop = BYTECODE_AB_LOOKUPSWITCH;
|
|
ctx->ls = *((LookupSwitch *)bc.extra);
|
|
ctx->pc = a->pc;
|
|
}
|
|
bytecode_clean(&bc);
|
|
} else {
|
|
RZ_LOG_ERROR("[!] java_disassemble: jvm fetch failed.\n");
|
|
return -1;
|
|
}
|
|
return op->size;
|
|
}
|
|
|
|
static bool java_init(void **user) {
|
|
JavaAsmContext *ctx = RZ_NEW0(JavaAsmContext);
|
|
if (!ctx) {
|
|
return false;
|
|
}
|
|
*user = ctx;
|
|
return true;
|
|
}
|
|
|
|
static bool java_fini(void *user) {
|
|
if (!user) {
|
|
return false;
|
|
}
|
|
JavaAsmContext *ctx = (JavaAsmContext *)user;
|
|
free(ctx);
|
|
return true;
|
|
}
|
|
|
|
static int java_assemble(RzAsm *a, RzAsmOp *ao, const char *str) {
|
|
ut8 buffer[128];
|
|
st32 written = 0;
|
|
st32 slen = strlen(str);
|
|
|
|
if (!java_assembler(str, slen, buffer, sizeof(buffer), a->pc, &written)) {
|
|
return -1;
|
|
}
|
|
|
|
rz_strbuf_setbin(&ao->buf, (const ut8 *)&buffer, written);
|
|
return written;
|
|
}
|
|
|
|
RzAsmPlugin rz_asm_plugin_java = {
|
|
.name = "java",
|
|
.desc = "Java bytecode disassembler",
|
|
.arch = "java",
|
|
.license = "LGPL-3",
|
|
.author = "deroad",
|
|
.bits = 32,
|
|
.endian = RZ_SYS_ENDIAN_BIG,
|
|
.init = java_init,
|
|
.fini = java_fini,
|
|
.disassemble = &java_disassemble,
|
|
.assemble = &java_assemble,
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_ASM,
|
|
.data = &rz_asm_plugin_java,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|