Files
rizin/librz/bin/format/pyc/marshal.c
T

1372 lines
29 KiB
C

// SPDX-FileCopyrightText: 2016-2020 c0riolis
// SPDX-FileCopyrightText: 2016-2020 Tardy
// SPDX-FileCopyrightText: 2016-2020 l0stb1t
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_io.h>
#include <rz_bin.h>
#include "marshal.h"
#include "pyc_magic.h"
// avoiding using rizin internals asserts
#define if_true_return(cond, ret) \
if (cond) { \
return (ret); \
}
static pyc_object *get_object(RzBinPycObj *pyc, RzBuffer *buffer);
static pyc_object *copy_object(pyc_object *object);
static void free_object(pyc_object *object);
static ut8 get_ut8(RzBuffer *buffer, bool *error) {
ut8 ret = 0;
int size = rz_buf_read(buffer, &ret, sizeof(ret));
if (size < sizeof(ret)) {
*error = true;
}
return ret;
}
static ut16 get_ut16(RzBuffer *buffer, bool *error) {
ut16 ret = 0;
if (!rz_buf_read_le16(buffer, &ret)) {
*error = true;
}
return ret;
}
static ut32 get_ut32(RzBuffer *buffer, bool *error) {
ut32 ret = 0;
if (!rz_buf_read_le32(buffer, &ret)) {
*error = true;
}
return ret;
}
static st32 get_st32(RzBuffer *buffer, bool *error) {
st32 ret = 0;
if (!rz_buf_read_le32(buffer, (ut32 *)&ret)) {
*error = true;
}
return ret;
}
static st64 get_st64(RzBuffer *buffer, bool *error) {
st64 ret = 0;
if (!rz_buf_read_le64(buffer, (ut64 *)&ret)) {
*error = true;
}
return ret;
}
static double get_float64(RzBuffer *buffer, bool *error) {
double ret = 0;
if (!rz_buf_read_le64(buffer, (ut64 *)&ret)) {
*error = true;
}
return ret;
}
static ut8 *get_bytes(RzBuffer *buffer, ut32 size) {
rz_return_val_if_fail(size < ST32_MAX && buffer, NULL);
ut8 *ret = RZ_NEWS0(ut8, size + 1);
if (!ret) {
return NULL;
}
if (rz_buf_read(buffer, ret, size) < size) {
free(ret);
return NULL;
}
return ret;
}
static pyc_object *get_none_object(void) {
pyc_object *ret;
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_NONE;
ret->data = rz_str_dup("None");
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_false_object(void) {
pyc_object *ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_FALSE;
ret->data = rz_str_dup("False");
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_true_object(void) {
pyc_object *ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_TRUE;
ret->data = rz_str_dup("True");
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_int_object(RzBuffer *buffer) {
bool error = false;
pyc_object *ret = NULL;
st32 i = get_st32(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_INT;
ret->data = rz_str_newf("%d", i);
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_int64_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
st64 i;
i = get_st64(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_INT64;
ret->data = rz_str_newf("%" PFMT64d, i);
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
/* long is used when the number is > MAX_INT64 */
static pyc_object *get_long_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
bool neg = false;
ut32 tmp = 0;
size_t size;
size_t i, j = 0, left = 0;
ut32 n;
char *hexstr;
char digist2hex[] = "0123456789abcdef";
st32 ndigits = get_st32(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_LONG;
if (ndigits < 0) {
ndigits = -ndigits;
neg = true;
}
if (ndigits == 0) {
ret->data = rz_str_dup("0x0");
} else {
// the explicit cast is safe since ndigits is positive
size = (size_t)ndigits * 15;
size = (size - 1) / 4 + 1;
size += 4 + (neg ? 1 : 0);
hexstr = malloc(size);
if (!hexstr) {
free(ret);
return NULL;
}
memset(hexstr, 0x20, size);
j = size - 1;
hexstr[j] = 0;
for (i = 0; i < ndigits; i++) {
n = get_ut16(buffer, &error);
tmp |= n << left;
left += 15;
while (left >= 4 && j > 0) {
hexstr[--j] = digist2hex[tmp & 0xf];
tmp >>= 4;
left -= 4;
}
}
if (tmp && j > 0) {
hexstr[--j] = digist2hex[tmp & 0xf];
}
hexstr[--j] = 'x';
hexstr[--j] = '0';
if (neg) {
hexstr[--j] = '-';
}
rz_str_trim(hexstr);
ret->data = hexstr;
}
return ret;
}
static pyc_object *get_stringref_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_st32(buffer, &error);
if (n >= rz_list_length(pyc->interned_table)) {
RZ_LOG_ERROR("bad marshal data (string ref out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_STRINGREF;
ret->data = rz_list_get_n(pyc->interned_table, n);
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_float_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 size = 0;
ut8 n = 0;
n = get_ut8(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ut8 *s = malloc(n + 1);
if (!s) {
free(ret);
return NULL;
}
/* object contain string representation of the number */
size = rz_buf_read(buffer, s, n);
if (size != n) {
RZ_FREE(s);
RZ_FREE(ret);
return NULL;
}
s[n] = '\0';
ret->type = TYPE_FLOAT;
ret->data = s;
return ret;
}
static pyc_object *get_binary_float_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
double f;
f = get_float64(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_FLOAT;
ret->data = rz_str_newf("%.15g", f);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static pyc_object *get_complex_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n1 = 0;
ut32 n2 = 0;
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
if ((pyc->magic_int & 0xffff) <= 62061) {
n1 = get_ut8(buffer, &error);
} else {
n1 = get_st32(buffer, &error);
}
if (error || UT32_ADD_OVFCHK(n1, 1)) {
free(ret);
return NULL;
}
ut8 *s1 = malloc(n1 + 1);
if (!s1) {
return NULL;
}
/* object contain string representation of the number */
if (rz_buf_read(buffer, s1, n1) != n1) {
RZ_FREE(s1);
RZ_FREE(ret);
return NULL;
}
s1[n1] = '\0';
if ((pyc->magic_int & 0xffff) <= 62061) {
n2 = get_ut8(buffer, &error);
} else {
n2 = get_st32(buffer, &error);
}
if (error || UT32_ADD_OVFCHK(n2, 1)) {
return NULL;
}
ut8 *s2 = malloc(n2 + 1);
if (!s2) {
return NULL;
}
/* object contain string representation of the number */
if (rz_buf_read(buffer, s2, n2) != n2) {
RZ_FREE(s1);
RZ_FREE(s2);
RZ_FREE(ret);
return NULL;
}
s2[n2] = '\0';
ret->type = TYPE_COMPLEX;
ret->data = rz_str_newf("%s+%sj", s1, s2);
RZ_FREE(s1);
RZ_FREE(s2);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static pyc_object *get_binary_complex_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
double a, b;
// a + bj
a = get_float64(buffer, &error);
b = get_float64(buffer, &error);
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_BINARY_COMPLEX;
ret->data = rz_str_newf("%.15g+%.15gj", a, b);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static pyc_object *get_string_object(RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (string size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_STRING;
ret->data = get_bytes(buffer, n);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static bool add_string_to_cache(RzBinPycObj *pyc, ut64 addr, const char *data, ut32 size, ut32 length, RzStrEnc type) {
if (size == 0) {
return true;
}
RzBinString *string = RZ_NEW0(RzBinString);
if (!string) {
return false;
}
string->paddr = string->vaddr = addr;
string->size = size;
string->length = length;
string->type = type;
string->string = rz_str_dup(data);
if (!rz_pvector_push(pyc->strings_cache, string)) {
return false;
}
return true;
}
static pyc_object *get_unicode_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (unicode size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ut64 addr = rz_buf_tell(buffer);
ret = RZ_NEW0(pyc_object);
ret->type = TYPE_UNICODE;
ret->data = get_bytes(buffer, n);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
if (!add_string_to_cache(pyc, addr, ret->data, n, (ut32)rz_utf8_strlen(ret->data), RZ_STRING_ENC_UTF8)) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static pyc_object *get_interned_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (string size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->type = TYPE_INTERNED;
ret->data = get_bytes(buffer, n);
/* add data pointer to interned table */
rz_list_append(pyc->interned_table, ret->data);
if (!ret->data) {
RZ_FREE(ret);
}
return ret;
}
static pyc_object *get_array_object_generic(RzBinPycObj *pyc, RzBuffer *buffer, ut32 size) {
pyc_object *tmp = NULL;
pyc_object *ret = NULL;
ut32 i = 0;
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->data = rz_list_newf((RzListFree)free_object);
if (!ret->data) {
free(ret);
return NULL;
}
for (i = 0; i < size; i++) {
tmp = get_object(pyc, buffer);
if (!tmp) {
rz_list_free(ret->data);
RZ_FREE(ret);
return NULL;
}
if (!rz_list_append(ret->data, tmp)) {
free_object(tmp);
rz_list_free(ret->data);
free(ret);
return NULL;
}
}
return ret;
}
/* small TYPE_SMALL_TUPLE doesn't exist in python2 */
/* */
static pyc_object *get_small_tuple_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut8 n = 0;
n = get_ut8(buffer, &error);
if (error) {
return NULL;
}
ret = get_array_object_generic(pyc, buffer, n);
if (ret) {
ret->type = TYPE_SMALL_TUPLE;
return ret;
}
return NULL;
}
static pyc_object *get_tuple_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (tuple size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = get_array_object_generic(pyc, buffer, n);
if (ret) {
ret->type = TYPE_TUPLE;
return ret;
}
return NULL;
}
static pyc_object *get_list_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (list size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = get_array_object_generic(pyc, buffer, n);
if (ret) {
ret->type = TYPE_LIST;
return ret;
}
return NULL;
}
static pyc_object *get_dict_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL,
*key = NULL,
*val = NULL;
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ret->data = rz_list_newf((RzListFree)free_object);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
for (;;) {
key = get_object(pyc, buffer);
if (!key) {
break;
}
if (!rz_list_append(ret->data, key)) {
rz_list_free(ret->data);
RZ_FREE(ret);
free_object(key);
return NULL;
}
val = get_object(pyc, buffer);
if (!val) {
break;
}
if (!rz_list_append(ret->data, val)) {
rz_list_free(ret->data);
RZ_FREE(ret);
free_object(val);
return NULL;
}
}
ret->type = TYPE_DICT;
return ret;
}
static pyc_object *get_set_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 0;
n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (set size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = get_array_object_generic(pyc, buffer, n);
if (!ret) {
return NULL;
}
ret->type = TYPE_SET;
return ret;
}
static pyc_object *get_slice_object(RzBinPycObj *pyc, RzBuffer *buffer) {
pyc_object *ret = NULL;
bool error = false;
ut32 n = 3; // start, stop, step
// n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (list size out of range)\n");
return NULL;
}
if (error) {
return NULL;
}
ret = get_array_object_generic(pyc, buffer, n);
if (ret) {
ret->type = TYPE_SLICE;
return ret;
}
return NULL;
}
static pyc_object *get_ascii_object_generic(RzBinPycObj *pyc, RzBuffer *buffer, ut32 size, bool interned) {
pyc_object *ret = NULL;
ret = RZ_NEW0(pyc_object);
if (!ret) {
return NULL;
}
ut64 addr = rz_buf_tell(buffer);
ret->type = TYPE_ASCII;
ret->data = get_bytes(buffer, size);
if (!ret->data) {
RZ_FREE(ret);
return NULL;
}
if (!add_string_to_cache(pyc, addr, ret->data, size, size, RZ_STRING_ENC_8BIT)) {
RZ_FREE(ret);
return NULL;
}
return ret;
}
static pyc_object *get_ascii_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
ut32 n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (string size out of range)\n");
return NULL;
} else if (error) {
return NULL;
}
return get_ascii_object_generic(pyc, buffer, n, true);
}
static pyc_object *get_ascii_interned_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
ut32 n = get_ut32(buffer, &error);
if (n > ST32_MAX) {
RZ_LOG_ERROR("bad marshal data (string size out of range)\n");
return NULL;
} else if (error) {
return NULL;
}
return get_ascii_object_generic(pyc, buffer, n, true);
}
static pyc_object *get_short_ascii_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
ut8 n;
n = get_ut8(buffer, &error);
if (error) {
return NULL;
}
return get_ascii_object_generic(pyc, buffer, n, false);
}
static pyc_object *get_short_ascii_interned_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
ut8 n;
n = get_ut8(buffer, &error);
if (error) {
return NULL;
}
return get_ascii_object_generic(pyc, buffer, n, true);
}
static pyc_object *get_ref_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
pyc_object *ret;
pyc_object *obj;
ut32 index;
index = get_ut32(buffer, &error);
if (error) {
return NULL;
}
if (index >= rz_list_length(pyc->refs)) {
return NULL;
}
obj = rz_list_get_n(pyc->refs, index);
if (!obj) {
return NULL;
}
ret = copy_object(obj);
return ret;
}
static void free_object(pyc_object *object) {
if (!object) {
return;
}
switch (object->type) {
case TYPE_SMALL_TUPLE:
case TYPE_TUPLE:
rz_list_free(object->data);
break;
case TYPE_STRING:
case TYPE_TRUE:
case TYPE_FALSE:
case TYPE_INT:
case TYPE_NONE:
case TYPE_NULL:
case TYPE_ASCII_INTERNED:
case TYPE_SHORT_ASCII:
case TYPE_ASCII:
case TYPE_SHORT_ASCII_INTERNED:
free(object->data);
break;
case TYPE_CODE_v0:
case TYPE_CODE_v1: {
pyc_code_object *cobj = object->data;
free_object(cobj->code);
free_object(cobj->consts);
free_object(cobj->names);
free_object(cobj->varnames);
free_object(cobj->freevars);
free_object(cobj->cellvars);
free_object(cobj->filename);
free_object(cobj->name);
free_object(cobj->lnotab);
free(object->data);
} break;
case TYPE_REF:
free_object(object->data);
break;
case TYPE_SET:
case TYPE_FROZENSET:
case TYPE_ELLIPSIS:
case TYPE_STOPITER:
case TYPE_BINARY_COMPLEX:
case TYPE_BINARY_FLOAT:
case TYPE_COMPLEX:
case TYPE_STRINGREF:
case TYPE_DICT:
case TYPE_FLOAT:
case TYPE_INT64:
case TYPE_INTERNED:
case TYPE_LIST:
case TYPE_LONG:
case TYPE_UNICODE:
case TYPE_UNKNOWN:
RZ_LOG_ERROR("Free not implemented for type %x\n", object->type);
break;
default:
RZ_LOG_ERROR("Undefined type in free_object (%x)\n", object->type);
break;
}
free(object);
}
static pyc_object *copy_object(pyc_object *object) {
pyc_object *copy = RZ_NEW0(pyc_object);
if (!copy || !object) {
free(copy);
return NULL;
}
copy->type = object->type;
switch (object->type) {
case TYPE_NULL:
break;
case TYPE_TUPLE:
case TYPE_SMALL_TUPLE:
copy->data = rz_list_clone(object->data);
break;
case TYPE_INT:
case TYPE_INT64:
case TYPE_NONE:
case TYPE_TRUE:
case TYPE_FALSE:
case TYPE_STRING:
case TYPE_ASCII:
case TYPE_SHORT_ASCII:
case TYPE_ASCII_INTERNED:
case TYPE_SHORT_ASCII_INTERNED:
copy->data = rz_str_dup(object->data);
break;
case TYPE_CODE_v0:
case TYPE_CODE_v1: {
pyc_code_object *src = object->data;
pyc_code_object *dst = RZ_NEW0(pyc_code_object);
if (!dst) {
break;
}
memcpy(dst, src, sizeof(*dst));
dst->code = copy_object(src->code);
dst->consts = copy_object(src->consts);
dst->names = copy_object(src->names);
dst->localsplusnames = copy_object(src->localsplusnames);
dst->localspluskinds = copy_object(src->localspluskinds);
if (src->varnames) {
dst->varnames = copy_object(src->varnames);
}
if (src->freevars) {
dst->freevars = copy_object(src->freevars);
}
if (src->cellvars) {
dst->cellvars = copy_object(src->cellvars);
}
dst->filename = copy_object(src->filename);
dst->name = copy_object(src->name);
dst->lnotab = copy_object(src->lnotab);
dst->qualname = copy_object(src->qualname);
dst->exceptiontable = copy_object(src->exceptiontable);
copy->data = dst;
} break;
case TYPE_REF:
copy->data = copy_object(object->data);
break;
case TYPE_ELLIPSIS:
case TYPE_STOPITER:
case TYPE_BINARY_COMPLEX:
case TYPE_BINARY_FLOAT:
case TYPE_COMPLEX:
case TYPE_STRINGREF:
case TYPE_DICT:
case TYPE_FLOAT:
case TYPE_FROZENSET:
case TYPE_INTERNED:
case TYPE_LIST:
case TYPE_LONG:
case TYPE_SET:
case TYPE_UNICODE:
case TYPE_UNKNOWN:
RZ_LOG_ERROR("Copy not implemented for type %x\n", object->type);
break;
default:
RZ_LOG_ERROR("Undefined type in copy_object (%x)\n", object->type);
break;
}
if (!copy->data) {
RZ_FREE(copy);
}
return copy;
}
// populate varnames, freevars, cellvars version >=3.11.0
static void extract_variables_from_localplus(
pyc_object *localplusnames,
pyc_object *localpluskinds,
pyc_object **varnames,
pyc_object **freevars,
pyc_object **cellvars,
bool *error) {
if (!localplusnames || !localpluskinds) {
*error = true;
return;
}
RzList *names_list = (RzList *)localplusnames->data;
ut8 *kinds_list = (ut8 *)localpluskinds->data;
*varnames = RZ_NEW0(pyc_object);
*freevars = RZ_NEW0(pyc_object);
*cellvars = RZ_NEW0(pyc_object);
if (!*varnames || !*cellvars || !*freevars) {
free(*varnames);
free(*cellvars);
free(*freevars);
*error = true;
return;
}
(*varnames)->data = rz_list_new();
(*freevars)->data = rz_list_new();
(*cellvars)->data = rz_list_new();
(*varnames)->type = localplusnames->type;
(*freevars)->type = localplusnames->type;
(*cellvars)->type = localplusnames->type;
RzListIter *iter;
pyc_object *name;
int offset = 0;
rz_list_foreach (names_list, iter, name) {
ut8 kind = kinds_list[offset];
if (kind & RZ_PYC_CO_FAST_LOCAL) {
rz_list_append((*varnames)->data, name);
}
if (kind & RZ_PYC_CO_FAST_CELL) {
rz_list_append((*cellvars)->data, name);
}
if (kind & RZ_PYC_CO_FAST_FREE) {
rz_list_append((*freevars)->data, name);
}
offset++;
}
}
static pyc_object *get_code_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
pyc_object *ret = RZ_NEW0(pyc_object);
pyc_code_object *cobj = RZ_NEW0(pyc_code_object);
if (!ret || !cobj) {
free(ret);
free(cobj);
return NULL;
}
// ret->type = TYPE_CODE_v1;
// support start from v1.0
ret->data = cobj;
bool v10_to_12 = magic_int_within(pyc->magic_int, 39170, 16679, &error); // 1.0.1 - 1.2
bool v13_to_22 = magic_int_within(pyc->magic_int, 11913, 60718, &error); // 1.3b1 - 2.2a1
bool v11_to_14 = magic_int_within(pyc->magic_int, 39170, 20117, &error); // 1.0.1 - 1.4
bool v15_to_22 = magic_int_within(pyc->magic_int, 20121, 60718, &error); // 1.5a1 - 2.2a1
bool v13_to_20 = magic_int_within(pyc->magic_int, 11913, 50824, &error); // 1.3b1 - 2.0b1
bool v311_to_latest = magic_int_within(pyc->magic_int, 3495, 3627, &error); // 3.11a1 - latest;
// bool v21_to_27 = (!v13_to_20) && magic_int_within (magic_int, 60124, 62212, &error);
bool has_posonlyargcount = magic_int_within(pyc->magic_int, 3410, 3627, &error); // v3.8.0a4 - latest
if (error) {
free(ret);
free(cobj);
return NULL;
}
if (v13_to_22) {
cobj->argcount = get_ut16(buffer, &error);
} else if (v10_to_12) {
cobj->argcount = 0;
} else {
cobj->argcount = get_ut32(buffer, &error);
}
if (has_posonlyargcount) {
cobj->posonlyargcount = get_ut32(buffer, &error); // Included in argcount
} else {
cobj->posonlyargcount = 0; // None
}
if (((3020 < (pyc->magic_int & 0xffff)) && ((pyc->magic_int & 0xffff) < 20121)) && (!v11_to_14)) {
cobj->kwonlyargcount = get_ut32(buffer, &error); // Not included in argcount
} else {
cobj->kwonlyargcount = 0;
}
if (v13_to_22) {
cobj->nlocals = get_ut16(buffer, &error);
} else if (v10_to_12) {
cobj->nlocals = 0;
} else if (v311_to_latest) {
cobj->nlocals = 0;
} else {
cobj->nlocals = get_ut32(buffer, &error);
}
if (v15_to_22) {
cobj->stacksize = get_ut16(buffer, &error);
} else if (v11_to_14 || v10_to_12) {
cobj->stacksize = 0;
} else {
cobj->stacksize = get_ut32(buffer, &error);
}
if (v13_to_22) {
cobj->flags = get_ut16(buffer, &error);
} else if (v10_to_12) {
cobj->flags = 0;
} else {
cobj->flags = get_ut32(buffer, &error);
}
// to help disassemble the code
cobj->start_offset = rz_buf_tell(buffer) + 5; // 1 from get_object() and 4 from get_string_object()
if (!pyc->refs) {
return ret; // return for entried part to get the root object of this file
}
cobj->code = get_object(pyc, buffer);
cobj->end_offset = rz_buf_tell(buffer);
cobj->consts = get_object(pyc, buffer);
cobj->names = get_object(pyc, buffer);
if (v10_to_12 || v311_to_latest) {
cobj->varnames = NULL;
} else {
cobj->varnames = get_object(pyc, buffer);
}
if (v311_to_latest) {
cobj->localsplusnames = get_object(pyc, buffer);
cobj->localspluskinds = get_object(pyc, buffer);
} else {
cobj->localsplusnames = NULL;
cobj->localspluskinds = NULL;
}
if (!(v10_to_12 || v13_to_20 || v311_to_latest)) {
cobj->freevars = get_object(pyc, buffer);
cobj->cellvars = get_object(pyc, buffer);
} else {
cobj->freevars = NULL;
cobj->cellvars = NULL;
}
cobj->filename = get_object(pyc, buffer);
cobj->name = get_object(pyc, buffer);
if (v311_to_latest) {
cobj->qualname = get_object(pyc, buffer);
} else {
cobj->qualname = NULL;
}
if (v15_to_22) {
cobj->firstlineno = get_ut16(buffer, &error);
} else if (v11_to_14) {
cobj->firstlineno = 0;
} else {
cobj->firstlineno = get_ut32(buffer, &error);
}
if (v11_to_14) {
cobj->lnotab = NULL;
} else {
cobj->lnotab = get_object(pyc, buffer);
}
if (v311_to_latest) {
cobj->exceptiontable = get_object(pyc, buffer);
} else {
cobj->exceptiontable = NULL;
}
if (v311_to_latest) {
extract_variables_from_localplus(
cobj->localsplusnames,
cobj->localspluskinds,
&cobj->varnames,
&cobj->freevars,
&cobj->cellvars,
&error);
}
if (error) {
free_object(cobj->code);
free_object(cobj->consts);
free_object(cobj->names);
free_object(cobj->varnames);
free_object(cobj->freevars);
free_object(cobj->cellvars);
free_object(cobj->filename);
free_object(cobj->name);
free_object(cobj->lnotab);
free_object(cobj->localsplusnames);
free_object(cobj->localspluskinds);
free_object(cobj->qualname);
free_object(cobj->exceptiontable);
free(cobj);
RZ_FREE(ret);
return NULL;
}
return ret;
}
ut64 get_code_object_addr(RzBinPycObj *pyc, RzBuffer *buffer, ut32 magic) {
pyc->magic_int = magic;
pyc_object *co = get_code_object(pyc, buffer);
ut64 result = 0;
if (!co) {
return 0;
}
pyc_code_object *cobj = co->data;
result = cobj->start_offset;
free_object(co);
return result;
}
static pyc_object *get_object(RzBinPycObj *pyc, RzBuffer *buffer) {
bool error = false;
pyc_object *ret = NULL;
ut8 code = get_ut8(buffer, &error);
ut8 flag = code & FLAG_REF;
RzListIter *ref_idx = NULL;
ut8 type = code & ~FLAG_REF;
if (error) {
return NULL;
}
if (flag) {
ret = get_none_object();
if (!ret) {
return NULL;
}
ref_idx = rz_list_append(pyc->refs, ret);
if (!ref_idx) {
free_object(ret);
return NULL;
}
}
switch (type) {
case TYPE_NULL:
return NULL;
case TYPE_TRUE:
return get_true_object();
case TYPE_FALSE:
return get_false_object();
case TYPE_NONE:
return get_none_object();
case TYPE_REF:
return get_ref_object(pyc, buffer);
case TYPE_SMALL_TUPLE:
ret = get_small_tuple_object(pyc, buffer);
break;
case TYPE_TUPLE:
ret = get_tuple_object(pyc, buffer);
break;
case TYPE_STRING:
ret = get_string_object(buffer);
break;
case TYPE_CODE_v0:
ret = get_code_object(pyc, buffer);
if (ret) {
ret->type = TYPE_CODE_v0;
}
break;
case TYPE_CODE_v1:
ret = get_code_object(pyc, buffer);
if (ret) {
ret->type = TYPE_CODE_v1;
}
break;
case TYPE_INT:
ret = get_int_object(buffer);
break;
case TYPE_ASCII_INTERNED:
ret = get_ascii_interned_object(pyc, buffer);
break;
case TYPE_SHORT_ASCII:
ret = get_short_ascii_object(pyc, buffer);
break;
case TYPE_ASCII:
ret = get_ascii_object(pyc, buffer);
break;
case TYPE_SHORT_ASCII_INTERNED:
ret = get_short_ascii_interned_object(pyc, buffer);
break;
case TYPE_INT64:
ret = get_int64_object(buffer);
break;
case TYPE_INTERNED:
ret = get_interned_object(pyc, buffer);
break;
case TYPE_STRINGREF:
ret = get_stringref_object(pyc, buffer);
break;
case TYPE_FLOAT:
ret = get_float_object(buffer);
break;
case TYPE_BINARY_FLOAT:
ret = get_binary_float_object(buffer);
break;
case TYPE_COMPLEX:
ret = get_complex_object(pyc, buffer); // behaviour depends on Python version
break;
case TYPE_BINARY_COMPLEX:
ret = get_binary_complex_object(buffer);
break;
case TYPE_LIST:
ret = get_list_object(pyc, buffer);
break;
case TYPE_LONG:
ret = get_long_object(buffer);
break;
case TYPE_UNICODE:
ret = get_unicode_object(pyc, buffer);
break;
case TYPE_DICT:
ret = get_dict_object(pyc, buffer);
break;
case TYPE_FROZENSET:
case TYPE_SET:
ret = get_set_object(pyc, buffer);
break;
case TYPE_STOPITER:
ret = RZ_NEW0(pyc_object);
break;
case TYPE_ELLIPSIS:
ret = RZ_NEW0(pyc_object);
break;
case TYPE_SLICE:
ret = get_slice_object(pyc, buffer);
break;
case TYPE_UNKNOWN:
RZ_LOG_ERROR("Get not implemented for type 0x%x\n", type);
return NULL;
default:
RZ_LOG_ERROR("Undefined type in get_object (0x%x)\n", type);
return NULL;
}
if (flag && ref_idx) {
void *p = rz_list_val(ref_idx);
free_object(p);
p = copy_object(ret);
rz_list_set_val(ref_idx, p);
}
return ret;
}
static bool extract_sections_symbols(RzBinPycObj *pyc, pyc_object *obj, RzPVector /*<RzBinSection *>*/ *sections, RzPVector /*<RzBinSymbol *>*/ *symbols, RzList /*<pyc_code_object *>*/ *cobjs, char *prefix) {
pyc_code_object *cobj = NULL;
RzBinSection *section = NULL;
RzBinSymbol *symbol = NULL;
RzListIter *i = NULL;
// each code object is a section
if_true_return(!obj || (obj->type != TYPE_CODE_v1 && obj->type != TYPE_CODE_v0), false);
cobj = obj->data;
if_true_return(!cobj || !cobj->name, false);
if_true_return(cobj->name->type != TYPE_ASCII && cobj->name->type != TYPE_STRING && cobj->name->type != TYPE_INTERNED, false);
if_true_return(!cobj->name->data, false);
if_true_return(!cobj->consts, false);
// add the cobj to objs list
if (!rz_list_append(cobjs, cobj)) {
goto fail;
}
section = RZ_NEW0(RzBinSection);
symbol = RZ_NEW0(RzBinSymbol);
prefix = rz_str_newf("%s%s%s", prefix ? prefix : "",
prefix ? "." : "", (const char *)cobj->name->data);
if (!prefix || !section || !symbol) {
goto fail;
}
section->name = rz_str_dup(prefix);
if (!section->name) {
goto fail;
}
section->has_strings = false;
section->paddr = cobj->start_offset;
section->vaddr = cobj->start_offset;
section->size = cobj->end_offset - cobj->start_offset;
section->vsize = cobj->end_offset - cobj->start_offset;
if (!rz_pvector_push(sections, section)) {
goto fail;
}
section = NULL;
// start building symbol
symbol->name = rz_str_dup(prefix);
// symbol->bind;
symbol->type = RZ_BIN_TYPE_FUNC_STR;
symbol->size = cobj->end_offset - cobj->start_offset;
symbol->vaddr = cobj->start_offset;
symbol->paddr = cobj->start_offset;
symbol->ordinal = pyc->symbols_ordinal++;
if (cobj->consts->type != TYPE_TUPLE && cobj->consts->type != TYPE_SMALL_TUPLE) {
goto fail;
}
if (!rz_pvector_push(symbols, symbol)) {
goto fail;
}
rz_list_foreach (((RzList *)(cobj->consts->data)), i, obj)
extract_sections_symbols(pyc, obj, sections, symbols, cobjs, prefix);
free(prefix);
return true;
fail:
free(section);
free(prefix);
free(symbol);
return false;
}
bool get_sections_symbols_from_code_objects(RzBinPycObj *pyc, RzBuffer *buffer, RzPVector /*<RzBinSection *>*/ *sections, RzPVector /*<RzBinSymbol *>*/ *symbols, RzList /*<pyc_code_object *>*/ *cobjs, ut32 magic) {
bool ret;
pyc->magic_int = magic;
pyc->refs = rz_list_newf((RzListFree)free_object);
if (!pyc->refs) {
return false;
}
ret = extract_sections_symbols(pyc, get_object(pyc, buffer), sections, symbols, cobjs, NULL);
rz_list_free(pyc->refs);
return ret;
}