/
analysis_pyc.c
162 lines (140 loc) · 3.78 KB
/
analysis_pyc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// 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 int archinfo(RzAnalysis *analysis, RzAnalysisInfoType query) {
if (!strcmp(analysis->cpu, "x86")) {
return -1;
}
bool is_16_bits = analysis && analysis->bits == 16;
switch (query) {
case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE:
return is_16_bits ? 1 : 2;
case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE:
return is_16_bits ? 3 : 2;
case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS:
return false;
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 /*<RzList<void *> *>*/ *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);
if (!is_pyc) {
return NULL;
}
return ((RzBinPycObj *)b->cur->o->bin_obj)->shared;
}
static int pyc_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) {
pyc_opcodes *ops = (pyc_opcodes *)a->plugin_data;
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 (!pyc_opcodes_equal(ops, a->cpu)) {
free_opcode(ops);
ops = NULL;
}
if (!ops) {
if (!(ops = get_opcode_by_version(a->cpu))) {
return -1;
}
a->plugin_data = ops;
}
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:
return op->size;
}
static bool finish(void *user) {
pyc_opcodes *ops = (user);
free_opcode(ops);
return true;
}
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