rizin/librz/analysis/p/analysis_pyc.c
Riccardo Schirone 53bf5c497f SPDX Copyright text for all files based on history
- Add LICENSES directory
- Download additional licenses used
- Add .reuse directory
- Add doc about SPDX/reuse

Co-authored-by: Florian Märkl <info@florianmaerkl.de>
2021-03-05 19:39:15 +08:00

153 lines
3.5 KiB
C

// SPDX-FileCopyrightText: 2016-2020 FXTi <zjxiang1998@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_lib.h>
#include <rz_util.h>
#include <rz_asm.h>
#include "../../asm/arch/pyc/pyc_dis.h"
static pyc_opcodes *ops = NULL;
static int archinfo(RzAnalysis *analysis, int query) {
if (!strcmp(analysis->cpu, "x86")) {
return -1;
}
switch (query) {
case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE:
return (analysis->bits == 16) ? 1 : 2;
case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE:
return (analysis->bits == 16) ? 3 : 2;
default:
return -1;
}
}
static char *get_reg_profile(RzAnalysis *analysis) {
return strdup(
"=PC pc\n"
"=BP bp\n"
"=SP sp\n"
"=A0 sp\n"
"gpr sp .32 0 0\n" // stack pointer
"gpr pc .32 4 0\n" // program counter
"gpr bp .32 8 0\n" // base pointer // unused
);
}
static RzList *get_pyc_code_obj(RzAnalysis *analysis) {
RzBin *b = analysis->binb.bin;
RzBinPlugin *plugin = b->cur && b->cur->o ? b->cur->o->plugin : NULL;
bool is_pyc = (plugin && strcmp(plugin->name, "pyc") == 0);
return is_pyc ? b->cur->o->bin_obj : NULL;
}
static int pyc_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) {
RzList *cobjs = rz_list_get_n(get_pyc_code_obj(a), 0);
RzListIter *iter = NULL;
pyc_code_object *func = NULL, *t = NULL;
rz_list_foreach (cobjs, iter, t) {
if (RZ_BETWEEN(t->start_offset, addr, t->end_offset - 1)) { // addr in [start_offset, end_offset)
func = t;
break;
}
}
if (!func) {
return -1;
}
ut64 func_base = func->start_offset;
ut32 extended_arg = 0, oparg = 0;
ut8 op_code = data[0];
op->addr = addr;
op->sign = true;
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
op->id = op_code;
if (!ops || !pyc_opcodes_equal(ops, a->cpu)) {
if (!(ops = get_opcode_by_version(a->cpu))) {
return -1;
}
}
bool is_python36 = a->bits == 8;
pyc_opcode_object *op_obj = &ops->opcodes[op_code];
if (!op_obj->op_name) {
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
op->size = 1;
goto analysis_end;
}
op->size = is_python36 ? 2 : ((op_code >= ops->have_argument) ? 3 : 1);
if (op_code >= ops->have_argument) {
if (!is_python36) {
oparg = data[1] + data[2] * 256 + extended_arg;
} else {
oparg = data[1] + extended_arg;
}
}
if (op_obj->type & HASJABS) {
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
op->jump = func_base + oparg;
if (op_obj->type & HASCONDITION) {
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
op->fail = addr + ((is_python36) ? 2 : 3);
}
goto analysis_end;
}
if (op_obj->type & HASJREL) {
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
op->jump = addr + oparg + ((is_python36) ? 2 : 3);
op->fail = addr + ((is_python36) ? 2 : 3);
if (op_obj->type & HASCONDITION) {
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
//op->fail = addr + ((is_python36)? 2: 3);
}
//goto analysis_end;
}
if (op_obj->type & HASCOMPARE) {
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
goto analysis_end;
}
analysis_pyc_op(op, op_obj, oparg);
analysis_end:
//free_opcode (ops);
return op->size;
}
static int finish(void *user) {
if (ops) {
free_opcode(ops);
ops = NULL;
}
return 0;
}
RzAnalysisPlugin rz_analysis_plugin_pyc = {
.name = "pyc",
.desc = "Python bytecode analysis plugin",
.license = "LGPL3",
.arch = "pyc",
.bits = 16 | 8, // Partially agree with this
.archinfo = archinfo,
.get_reg_profile = get_reg_profile,
.op = &pyc_op,
.esil = false,
.fini = &finish,
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ANALYSIS,
.data = &rz_analysis_plugin_pyc,
.version = RZ_VERSION
};
#endif