2022-04-09 12:07:07 +00:00
|
|
|
/* radare - LGPL - Copyright 2011-2022 - pancake */
|
2012-08-02 00:44:46 +00:00
|
|
|
|
2011-07-26 23:16:18 +00:00
|
|
|
#include <r_egg.h>
|
2017-05-26 00:43:26 +00:00
|
|
|
#include <config.h>
|
2011-07-26 23:16:18 +00:00
|
|
|
|
2013-06-15 00:56:25 +00:00
|
|
|
R_LIB_VERSION (r_egg);
|
|
|
|
|
2011-11-13 03:08:08 +00:00
|
|
|
// TODO: must be plugins
|
2011-07-26 23:16:18 +00:00
|
|
|
extern REggEmit emit_x86;
|
|
|
|
extern REggEmit emit_x64;
|
|
|
|
extern REggEmit emit_arm;
|
2022-04-09 12:07:07 +00:00
|
|
|
extern REggEmit emit_esil;
|
2011-09-19 00:39:33 +00:00
|
|
|
extern REggEmit emit_trace;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
2014-05-03 12:21:03 +00:00
|
|
|
static REggPlugin *egg_static_plugins[] =
|
2011-11-13 03:08:08 +00:00
|
|
|
{ R_EGG_STATIC_PLUGINS };
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
struct egg_patch_t {
|
|
|
|
RBuffer *b;
|
|
|
|
int off;
|
|
|
|
};
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
void egg_patch_free(void *p) {
|
2019-03-15 19:28:52 +00:00
|
|
|
struct egg_patch_t *ep = (struct egg_patch_t *)p;
|
2021-05-04 11:16:55 +00:00
|
|
|
if (ep) {
|
|
|
|
r_buf_free (ep->b);
|
|
|
|
free (ep);
|
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 14:08:32 +00:00
|
|
|
R_API REgg *r_egg_new(void) {
|
2011-11-13 03:08:08 +00:00
|
|
|
int i;
|
2011-07-26 23:16:18 +00:00
|
|
|
REgg *egg = R_NEW0 (REgg);
|
2018-01-16 10:13:21 +00:00
|
|
|
if (!egg) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->src = r_buf_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->src) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->buf = r_buf_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->buf) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->bin = r_buf_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->bin) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = &emit_x86;
|
2011-08-07 22:46:04 +00:00
|
|
|
egg->syscall = r_syscall_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->syscall) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->rasm = r_asm_new ();
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->rasm) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->bits = 0;
|
|
|
|
egg->endian = 0;
|
2014-03-07 00:26:11 +00:00
|
|
|
egg->db = sdb_new (NULL, NULL, 0);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->db) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
egg->patches = r_list_newf (egg_patch_free);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!egg->patches) {
|
|
|
|
goto beach;
|
|
|
|
}
|
2011-11-13 03:08:08 +00:00
|
|
|
egg->plugins = r_list_new ();
|
2022-08-18 11:58:40 +00:00
|
|
|
for (i = 0; egg_static_plugins[i]; i++) {
|
2016-04-03 21:52:36 +00:00
|
|
|
r_egg_add (egg, egg_static_plugins[i]);
|
2011-11-13 03:08:08 +00:00
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
return egg;
|
2016-05-24 20:22:15 +00:00
|
|
|
|
|
|
|
beach:
|
|
|
|
r_egg_free (egg);
|
|
|
|
return NULL;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_add(REgg *a, REggPlugin *foo) {
|
|
|
|
r_return_val_if_fail (a && foo, false);
|
2011-11-13 03:08:08 +00:00
|
|
|
RListIter *iter;
|
|
|
|
RAsmPlugin *h;
|
|
|
|
// TODO: cache foo->name length and use memcmp instead of strcmp
|
2018-03-14 11:41:39 +00:00
|
|
|
if (!foo->name) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2018-03-14 11:41:39 +00:00
|
|
|
}
|
2017-07-30 08:15:51 +00:00
|
|
|
r_list_foreach (a->plugins, iter, h) {
|
|
|
|
if (!strcmp (h->name, foo->name)) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2017-07-30 08:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-13 03:08:08 +00:00
|
|
|
r_list_append (a->plugins, foo);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-11-13 03:08:08 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
R_API char *r_egg_to_string(REgg *egg) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_val_if_fail (egg, NULL);
|
2019-03-26 19:32:53 +00:00
|
|
|
return r_buf_to_string (egg->buf);
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
R_API void r_egg_free(REgg *egg) {
|
2018-03-14 11:41:39 +00:00
|
|
|
if (egg) {
|
|
|
|
r_buf_free (egg->src);
|
|
|
|
r_buf_free (egg->buf);
|
|
|
|
r_buf_free (egg->bin);
|
|
|
|
r_list_free (egg->list);
|
|
|
|
r_asm_free (egg->rasm);
|
|
|
|
r_syscall_free (egg->syscall);
|
|
|
|
sdb_free (egg->db);
|
|
|
|
r_list_free (egg->plugins);
|
|
|
|
r_list_free (egg->patches);
|
|
|
|
r_egg_lang_free (egg);
|
|
|
|
free (egg);
|
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
R_API void r_egg_reset(REgg *egg) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_if_fail (egg);
|
2011-09-19 23:53:15 +00:00
|
|
|
r_egg_lang_include_init (egg);
|
2011-11-30 09:27:01 +00:00
|
|
|
// TODO: use r_list_purge instead of free/new here
|
2011-09-19 23:53:15 +00:00
|
|
|
r_buf_free (egg->src);
|
|
|
|
r_buf_free (egg->buf);
|
2011-11-14 09:10:55 +00:00
|
|
|
r_buf_free (egg->bin);
|
2011-09-19 23:53:15 +00:00
|
|
|
egg->src = r_buf_new ();
|
|
|
|
egg->buf = r_buf_new ();
|
2011-11-14 09:10:55 +00:00
|
|
|
egg->bin = r_buf_new ();
|
2011-11-30 09:27:01 +00:00
|
|
|
r_list_purge (egg->patches);
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_setup(REgg *egg, const char *arch, int bits, int endian, const char *os) {
|
|
|
|
r_return_val_if_fail (egg && arch, false);
|
2018-01-24 14:12:33 +00:00
|
|
|
const char *asmcpu = NULL; // TODO
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = NULL;
|
2011-12-01 02:28:12 +00:00
|
|
|
|
2011-08-09 00:03:12 +00:00
|
|
|
egg->os = os? r_str_hash (os): R_EGG_OS_DEFAULT;
|
2019-03-15 19:28:52 +00:00
|
|
|
//eprintf ("%s -> %x (linux=%x) (darwin=%x)\n", os, egg->os, R_EGG_OS_LINUX, R_EGG_OS_DARWIN);
|
2011-11-15 13:30:52 +00:00
|
|
|
// TODO: setup egg->arch for all archs
|
2011-07-26 23:16:18 +00:00
|
|
|
if (!strcmp (arch, "x86")) {
|
2011-11-15 13:30:52 +00:00
|
|
|
egg->arch = R_SYS_ARCH_X86;
|
2011-07-26 23:16:18 +00:00
|
|
|
switch (bits) {
|
|
|
|
case 32:
|
2018-01-24 14:12:33 +00:00
|
|
|
r_syscall_setup (egg->syscall, arch, bits, asmcpu, os);
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = &emit_x86;
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->bits = bits;
|
|
|
|
break;
|
|
|
|
case 64:
|
2018-01-24 14:12:33 +00:00
|
|
|
r_syscall_setup (egg->syscall, arch, bits, asmcpu, os);
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = &emit_x64;
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->bits = bits;
|
|
|
|
break;
|
|
|
|
}
|
2022-04-09 12:07:07 +00:00
|
|
|
} else if (!strcmp (arch, "esil")) {
|
|
|
|
egg->arch = R_SYS_ARCH_ESIL;
|
|
|
|
r_syscall_setup (egg->syscall, arch, bits, asmcpu, os);
|
|
|
|
egg->remit = &emit_esil;
|
2019-03-15 19:28:52 +00:00
|
|
|
} else if (!strcmp (arch, "arm")) {
|
2011-11-15 13:30:52 +00:00
|
|
|
egg->arch = R_SYS_ARCH_ARM;
|
2011-07-26 23:16:18 +00:00
|
|
|
switch (bits) {
|
|
|
|
case 16:
|
|
|
|
case 32:
|
2020-10-19 10:21:49 +00:00
|
|
|
case 64:
|
2018-01-24 14:12:33 +00:00
|
|
|
r_syscall_setup (egg->syscall, arch, bits, asmcpu, os);
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = &emit_arm;
|
2011-07-26 23:16:18 +00:00
|
|
|
egg->bits = bits;
|
|
|
|
egg->endian = endian;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
} else if (!strcmp (arch, "trace")) {
|
2011-09-19 00:39:33 +00:00
|
|
|
//r_syscall_setup (egg->syscall, arch, os, bits);
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit = &emit_trace;
|
2011-09-19 00:39:33 +00:00
|
|
|
egg->bits = bits;
|
|
|
|
egg->endian = endian;
|
|
|
|
}
|
2021-05-04 11:16:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API bool r_egg_include_str(REgg *egg, const char *arg) {
|
|
|
|
r_buf_append_bytes (egg->src, (const ut8*)arg, strlen (arg));
|
|
|
|
return true;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_include(REgg *egg, const char *file, int format) {
|
|
|
|
r_return_val_if_fail (egg && file, false);
|
2020-03-15 22:34:38 +00:00
|
|
|
size_t sz;
|
2019-03-15 19:28:52 +00:00
|
|
|
const ut8 *foo = (const ut8 *)r_file_slurp (file, &sz);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!foo) {
|
2021-05-04 11:16:55 +00:00
|
|
|
return false;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
|
|
|
// XXX: format breaks compiler layers
|
2011-07-26 23:16:18 +00:00
|
|
|
switch (format) {
|
|
|
|
case 'r': // raw
|
2020-03-15 22:34:38 +00:00
|
|
|
r_egg_raw (egg, foo, (int)sz);
|
2011-07-26 23:16:18 +00:00
|
|
|
break;
|
|
|
|
case 'a': // assembly
|
2020-03-15 22:34:38 +00:00
|
|
|
r_buf_append_bytes (egg->buf, foo, (ut64)sz);
|
2011-07-26 23:16:18 +00:00
|
|
|
break;
|
|
|
|
default:
|
2020-03-15 22:34:38 +00:00
|
|
|
r_buf_append_bytes (egg->src, foo, (ut64)sz);
|
2021-05-04 11:16:55 +00:00
|
|
|
break;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
2011-11-12 05:16:00 +00:00
|
|
|
free ((void *)foo);
|
2021-05-04 11:16:55 +00:00
|
|
|
return true;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_load(REgg *egg, const char *code, int format) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_if_fail (egg && code);
|
2011-07-26 23:16:18 +00:00
|
|
|
switch (format) {
|
|
|
|
case 'a': // assembly
|
2019-03-15 19:28:52 +00:00
|
|
|
r_buf_append_bytes (egg->buf, (const ut8 *)code, strlen (code));
|
2011-07-26 23:16:18 +00:00
|
|
|
break;
|
|
|
|
default:
|
2019-03-15 19:28:52 +00:00
|
|
|
r_buf_append_bytes (egg->src, (const ut8 *)code, strlen (code));
|
2011-07-26 23:16:18 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_syscall(REgg *egg, const char *arg, ...) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_if_fail (egg);
|
2011-08-07 22:46:04 +00:00
|
|
|
RSyscallItem *item = r_syscall_get (egg->syscall,
|
|
|
|
r_syscall_get_num (egg->syscall, arg), -1);
|
|
|
|
if (!strcmp (arg, "close")) {
|
2014-03-24 23:34:23 +00:00
|
|
|
//egg->remit->syscall_args ();
|
2011-08-07 22:46:04 +00:00
|
|
|
}
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!item) {
|
2015-04-19 01:27:16 +00:00
|
|
|
return;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2014-03-24 23:34:23 +00:00
|
|
|
egg->remit->syscall (egg, item->num);
|
2021-03-14 23:34:21 +00:00
|
|
|
r_syscall_item_free (item);
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_alloc(REgg *egg, int n) {
|
|
|
|
// add esp, n
|
|
|
|
}
|
|
|
|
|
2011-07-26 23:29:22 +00:00
|
|
|
R_API void r_egg_label(REgg *egg, const char *name) {
|
|
|
|
r_egg_printf (egg, "%s:\n", name);
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
R_API void r_egg_math(REgg *egg) { //, char eq, const char *vs, char type, const char *sr
|
2011-07-27 08:30:23 +00:00
|
|
|
// TODO
|
|
|
|
//e->mathop (egg, op, type, eq, p);
|
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_raw(REgg *egg, const ut8 *b, int len) {
|
|
|
|
r_return_val_if_fail (egg && b, false);
|
2019-02-02 04:33:43 +00:00
|
|
|
int outlen = len * 2; // two hexadecimal digits per byte
|
|
|
|
char *out = malloc (outlen + 1);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!out) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-02-02 05:47:13 +00:00
|
|
|
(void)r_hex_bin2str (b, len, out);
|
2019-03-15 19:28:52 +00:00
|
|
|
r_buf_append_bytes (egg->buf, (const ut8 *)".hex ", 5);
|
|
|
|
r_buf_append_bytes (egg->buf, (const ut8 *)out, outlen);
|
|
|
|
r_buf_append_bytes (egg->buf, (const ut8 *)"\n", 1);
|
2014-05-03 12:21:03 +00:00
|
|
|
free (out);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
static bool r_egg_raw_prepend(REgg *egg, const ut8 *b, int len) {
|
|
|
|
r_return_val_if_fail (egg && b, false);
|
2019-02-02 04:33:43 +00:00
|
|
|
int outlen = len * 2; // two hexadecimal digits per byte
|
|
|
|
char *out = malloc (outlen + 1);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!out) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-09 10:32:31 +00:00
|
|
|
r_hex_bin2str (b, len, out);
|
2019-03-15 19:28:52 +00:00
|
|
|
r_buf_prepend_bytes (egg->buf, (const ut8 *)"\n", 1);
|
|
|
|
r_buf_prepend_bytes (egg->buf, (const ut8 *)out, outlen);
|
|
|
|
r_buf_prepend_bytes (egg->buf, (const ut8 *)".hex ", 5);
|
2015-05-09 10:32:31 +00:00
|
|
|
free (out);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2015-05-09 10:32:31 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
static bool r_egg_prepend_bytes(REgg *egg, const ut8 *b, int len) {
|
|
|
|
r_return_val_if_fail (egg && b, false);
|
2019-02-02 04:33:43 +00:00
|
|
|
if (!r_egg_raw_prepend (egg, b, len)) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2016-10-02 21:46:57 +00:00
|
|
|
}
|
|
|
|
if (!r_buf_prepend_bytes (egg->bin, b, len)) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2016-10-02 21:46:57 +00:00
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2015-05-09 10:32:31 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
static bool r_egg_append_bytes(REgg *egg, const ut8 *b, int len) {
|
|
|
|
r_return_val_if_fail (egg && b, false);
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!r_egg_raw (egg, b, len)) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-05-09 10:32:31 +00:00
|
|
|
|
2018-09-13 08:17:26 +00:00
|
|
|
if (!r_buf_append_bytes (egg->bin, b, len)) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2015-05-09 10:32:31 +00:00
|
|
|
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2015-05-09 10:32:31 +00:00
|
|
|
}
|
|
|
|
|
2011-08-07 01:53:41 +00:00
|
|
|
// r_egg_block (egg, FRAME | IF | ELSE | ENDIF | FOR | WHILE, sz)
|
2011-07-26 23:16:18 +00:00
|
|
|
R_API void r_egg_if(REgg *egg, const char *reg, char cmp, int v) {
|
2019-03-15 19:28:52 +00:00
|
|
|
// egg->depth++;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_printf(REgg *egg, const char *fmt, ...) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_if_fail (egg && fmt);
|
2011-07-26 23:16:18 +00:00
|
|
|
va_list ap;
|
|
|
|
int len;
|
|
|
|
char buf[1024];
|
|
|
|
va_start (ap, fmt);
|
|
|
|
len = vsnprintf (buf, sizeof (buf), fmt, ap);
|
2019-03-15 19:28:52 +00:00
|
|
|
r_buf_append_bytes (egg->buf, (const ut8 *)buf, len);
|
2011-07-26 23:16:18 +00:00
|
|
|
va_end (ap);
|
|
|
|
}
|
|
|
|
|
2019-02-01 22:47:33 +00:00
|
|
|
R_API bool r_egg_assemble_asm(REgg *egg, char **asm_list) {
|
2014-01-15 00:56:28 +00:00
|
|
|
RAsmCode *asmcode = NULL;
|
|
|
|
char *code = NULL;
|
2017-09-27 09:29:15 +00:00
|
|
|
char *asm_name = NULL;
|
2011-07-26 23:16:18 +00:00
|
|
|
|
2017-09-27 09:29:15 +00:00
|
|
|
if (asm_list) {
|
|
|
|
char **asm_;
|
|
|
|
|
2019-03-15 19:28:52 +00:00
|
|
|
for (asm_ = asm_list; *asm_; asm_ += 2) {
|
2017-09-27 09:29:15 +00:00
|
|
|
if (!strcmp (egg->remit->arch, asm_[0])) {
|
|
|
|
asm_name = asm_[1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!asm_name) {
|
|
|
|
if (egg->remit == &emit_x86 || egg->remit == &emit_x64) {
|
|
|
|
asm_name = "x86.nz";
|
|
|
|
} else if (egg->remit == &emit_arm) {
|
|
|
|
asm_name = "arm";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (asm_name) {
|
|
|
|
r_asm_use (egg->rasm, asm_name);
|
2011-07-26 23:16:18 +00:00
|
|
|
r_asm_set_bits (egg->rasm, egg->bits);
|
2016-04-26 09:09:15 +00:00
|
|
|
r_asm_set_big_endian (egg->rasm, egg->endian);
|
2011-07-26 23:16:18 +00:00
|
|
|
r_asm_set_syntax (egg->rasm, R_ASM_SYNTAX_INTEL);
|
|
|
|
code = r_buf_to_string (egg->buf);
|
|
|
|
asmcode = r_asm_massemble (egg->rasm, code);
|
2011-07-26 23:29:22 +00:00
|
|
|
if (asmcode) {
|
2017-09-27 09:29:15 +00:00
|
|
|
if (asmcode->len > 0) {
|
2019-03-26 11:50:13 +00:00
|
|
|
r_buf_append_bytes (egg->bin, asmcode->bytes, asmcode->len);
|
2017-09-27 09:29:15 +00:00
|
|
|
}
|
2011-07-26 23:29:22 +00:00
|
|
|
// LEAK r_asm_code_free (asmcode);
|
2017-09-27 09:29:15 +00:00
|
|
|
} else {
|
2022-08-21 22:37:31 +00:00
|
|
|
R_LOG_ERROR ("fail assembling");
|
2011-07-26 23:29:22 +00:00
|
|
|
}
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
2014-01-15 00:56:28 +00:00
|
|
|
free (code);
|
2022-03-15 18:54:04 +00:00
|
|
|
bool ret = (asmcode);
|
2014-01-15 00:56:28 +00:00
|
|
|
r_asm_code_free (asmcode);
|
|
|
|
return ret;
|
2011-07-26 23:16:18 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 22:47:33 +00:00
|
|
|
R_API bool r_egg_assemble(REgg *egg) {
|
2017-09-27 09:29:15 +00:00
|
|
|
return r_egg_assemble_asm (egg, NULL);
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:51:09 +00:00
|
|
|
R_API bool r_egg_compile(REgg *egg) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_val_if_fail (egg, false);
|
2019-05-15 13:34:06 +00:00
|
|
|
r_buf_seek (egg->src, 0, R_BUF_SET);
|
2019-03-26 19:32:53 +00:00
|
|
|
char b;
|
|
|
|
int r = r_buf_read (egg->src, (ut8 *)&b, sizeof (b));
|
|
|
|
if (r != sizeof (b) || !egg->remit) {
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2014-03-28 14:57:50 +00:00
|
|
|
}
|
2011-11-13 03:08:08 +00:00
|
|
|
// only emit begin if code is found
|
2017-10-06 22:18:59 +00:00
|
|
|
r_egg_lang_init (egg);
|
2019-03-26 19:32:53 +00:00
|
|
|
for (; b; ) {
|
|
|
|
r_egg_lang_parsechar (egg, b);
|
2019-06-03 06:07:50 +00:00
|
|
|
if (egg->lang.elem_n >= sizeof (egg->lang.elem)) {
|
2022-07-04 15:42:25 +00:00
|
|
|
R_LOG_ERROR ("too large element");
|
2019-06-03 06:07:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-05-04 10:51:09 +00:00
|
|
|
size_t r = r_buf_read (egg->src, (ut8 *)&b, sizeof (b));
|
2019-03-26 19:32:53 +00:00
|
|
|
if (r != sizeof (b)) {
|
|
|
|
break;
|
2015-04-16 15:49:17 +00:00
|
|
|
}
|
2019-03-26 19:32:53 +00:00
|
|
|
// XXX: some parse fail errors are false positives :(
|
2011-08-09 00:03:12 +00:00
|
|
|
}
|
2021-05-04 10:51:09 +00:00
|
|
|
if (egg->context > 0) {
|
2022-07-04 15:42:25 +00:00
|
|
|
R_LOG_ERROR ("expected '}' at the end of the file. %d left", egg->context);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2013-10-23 22:51:26 +00:00
|
|
|
}
|
2011-08-08 00:07:26 +00:00
|
|
|
// TODO: handle errors here
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-08-08 00:07:26 +00:00
|
|
|
}
|
|
|
|
|
2011-07-26 23:16:18 +00:00
|
|
|
R_API RBuffer *r_egg_get_bin(REgg *egg) {
|
|
|
|
// TODO increment reference
|
|
|
|
return egg->bin;
|
|
|
|
}
|
|
|
|
|
|
|
|
//R_API int r_egg_dump (REgg *egg, const char *file) { }
|
|
|
|
|
|
|
|
R_API char *r_egg_get_source(REgg *egg) {
|
|
|
|
return r_buf_to_string (egg->src);
|
|
|
|
}
|
|
|
|
|
|
|
|
R_API char *r_egg_get_assembly(REgg *egg) {
|
|
|
|
return r_buf_to_string (egg->buf);
|
|
|
|
}
|
2011-07-27 08:30:23 +00:00
|
|
|
|
|
|
|
R_API void r_egg_append(REgg *egg, const char *src) {
|
|
|
|
r_buf_append_bytes (egg->src, (const ut8*)src, strlen (src));
|
|
|
|
}
|
2011-09-18 16:56:11 +00:00
|
|
|
|
2011-09-21 17:51:09 +00:00
|
|
|
/* JIT : TODO: accept arguments here */
|
2011-09-18 16:56:11 +00:00
|
|
|
R_API int r_egg_run(REgg *egg) {
|
2021-05-04 11:16:55 +00:00
|
|
|
r_return_val_if_fail (egg, -1);
|
2019-04-15 11:24:15 +00:00
|
|
|
ut64 tmpsz;
|
2019-05-15 13:34:06 +00:00
|
|
|
const ut8 *tmp = r_buf_data (egg->bin, &tmpsz);
|
2021-05-04 11:16:55 +00:00
|
|
|
return r_sys_run (tmp, tmpsz);
|
2011-09-18 16:56:11 +00:00
|
|
|
}
|
2011-11-12 05:16:00 +00:00
|
|
|
|
2019-08-17 23:55:38 +00:00
|
|
|
R_API int r_egg_run_rop(REgg *egg) {
|
|
|
|
ut64 sz;
|
|
|
|
const ut8 *tmp = r_buf_data (egg->bin, &sz);
|
|
|
|
return r_sys_run_rop (tmp, sz);
|
|
|
|
}
|
|
|
|
|
2011-11-13 03:08:08 +00:00
|
|
|
#define R_EGG_FILL_TYPE_TRAP
|
|
|
|
#define R_EGG_FILL_TYPE_NOP
|
|
|
|
#define R_EGG_FILL_TYPE_CHAR
|
|
|
|
#define R_EGG_FILL_TYPE_SEQ
|
|
|
|
#define R_EGG_FILL_TYPE_SEQ
|
|
|
|
|
2011-11-13 04:26:07 +00:00
|
|
|
static inline char *eon(char *n) {
|
2018-09-13 08:17:26 +00:00
|
|
|
while (*n && (*n >= '0' && *n <= '9')) {
|
|
|
|
n++;
|
|
|
|
}
|
2011-11-13 04:26:07 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2015-04-08 21:39:14 +00:00
|
|
|
/* padding looks like:
|
|
|
|
([snatSNAT][0-9]+)*
|
|
|
|
*/
|
2021-05-04 10:51:09 +00:00
|
|
|
R_API bool r_egg_padding(REgg *egg, const char *pad) {
|
2015-04-08 21:39:14 +00:00
|
|
|
int number;
|
2019-03-15 19:28:52 +00:00
|
|
|
ut8 *buf, padding_byte;
|
2015-04-08 21:39:14 +00:00
|
|
|
char *p, *o = strdup (pad);
|
|
|
|
|
2019-04-15 11:24:15 +00:00
|
|
|
for (p = o; *p;) { // parse pad string
|
2015-04-08 21:39:14 +00:00
|
|
|
const char f = *p++;
|
2019-03-15 19:28:52 +00:00
|
|
|
number = strtol (p, NULL, 10);
|
2015-04-08 21:39:14 +00:00
|
|
|
|
2016-10-02 21:46:57 +00:00
|
|
|
if (number < 1) {
|
2022-08-21 22:37:31 +00:00
|
|
|
R_LOG_ERROR ("Invalid padding length at %d", number);
|
2011-11-13 04:26:07 +00:00
|
|
|
free (o);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-13 04:26:07 +00:00
|
|
|
}
|
2015-04-08 21:39:14 +00:00
|
|
|
p = eon(p);
|
|
|
|
|
2011-11-13 04:26:07 +00:00
|
|
|
switch (f) {
|
2015-04-08 21:39:14 +00:00
|
|
|
case 's': case 'S': padding_byte = 0; break;
|
|
|
|
case 'n': case 'N': padding_byte = 0x90; break;
|
2019-03-15 19:28:52 +00:00
|
|
|
case 'a':
|
|
|
|
case 'A': padding_byte = 'A'; break;
|
|
|
|
case 't':
|
|
|
|
case 'T': padding_byte = 0xcc; break;
|
2011-11-13 04:26:07 +00:00
|
|
|
default:
|
2022-08-21 22:37:31 +00:00
|
|
|
R_LOG_ERROR ("Invalid padding format (%c)", *p);
|
2015-04-08 21:39:14 +00:00
|
|
|
eprintf ("Valid ones are:\n");
|
2022-05-05 10:46:01 +00:00
|
|
|
eprintf (" s S : NULL byte\n");
|
|
|
|
eprintf (" n N : nop\n");
|
|
|
|
eprintf (" a A : 0x41\n");
|
|
|
|
eprintf (" t T : trap (0xcc)\n");
|
2011-11-13 04:26:07 +00:00
|
|
|
free (o);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-13 04:26:07 +00:00
|
|
|
}
|
2014-05-03 12:21:03 +00:00
|
|
|
|
2015-04-08 21:39:14 +00:00
|
|
|
buf = malloc (number);
|
|
|
|
if (!buf) {
|
2011-11-30 09:27:01 +00:00
|
|
|
free (o);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-30 09:27:01 +00:00
|
|
|
}
|
2015-04-08 21:39:14 +00:00
|
|
|
|
|
|
|
memset (buf, padding_byte, number);
|
2016-10-02 21:46:57 +00:00
|
|
|
if (f >= 'a' && f <= 'z') {
|
2015-05-09 10:32:31 +00:00
|
|
|
r_egg_prepend_bytes(egg, buf, number);
|
2015-04-08 21:39:14 +00:00
|
|
|
} else {
|
2015-05-09 10:32:31 +00:00
|
|
|
r_egg_append_bytes(egg, buf, number);
|
2015-04-08 21:39:14 +00:00
|
|
|
}
|
|
|
|
free (buf);
|
2011-11-13 04:26:07 +00:00
|
|
|
}
|
|
|
|
free (o);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-11-13 04:26:07 +00:00
|
|
|
}
|
|
|
|
|
2011-11-13 03:08:08 +00:00
|
|
|
R_API void r_egg_fill(REgg *egg, int pos, int type, int argc, int length) {
|
2011-11-14 01:04:27 +00:00
|
|
|
// TODO
|
2011-11-12 05:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_option_set(REgg *egg, const char *key, const char *val) {
|
2014-03-07 00:26:11 +00:00
|
|
|
sdb_set (egg->db, key, val, 0);
|
2011-11-12 05:16:00 +00:00
|
|
|
}
|
|
|
|
|
2011-11-13 03:47:56 +00:00
|
|
|
R_API char *r_egg_option_get(REgg *egg, const char *key) {
|
2014-03-07 00:26:11 +00:00
|
|
|
return sdb_get (egg->db, key, NULL);
|
2011-11-12 05:16:00 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_shellcode(REgg *egg, const char *name) {
|
|
|
|
r_return_val_if_fail (egg && name, false);
|
2011-11-13 03:08:08 +00:00
|
|
|
REggPlugin *p;
|
|
|
|
RListIter *iter;
|
|
|
|
RBuffer *b;
|
|
|
|
r_list_foreach (egg->plugins, iter, p) {
|
2011-11-14 01:04:27 +00:00
|
|
|
if (p->type == R_EGG_PLUGIN_SHELLCODE && !strcmp (name, p->name)) {
|
2011-11-13 03:08:08 +00:00
|
|
|
b = p->build (egg);
|
2016-09-19 12:44:47 +00:00
|
|
|
if (!b) {
|
2022-08-21 22:37:31 +00:00
|
|
|
R_LOG_ERROR ("%s Shellcode has failed", p->name);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-12-01 02:28:12 +00:00
|
|
|
}
|
2019-04-15 11:24:15 +00:00
|
|
|
ut64 tmpsz;
|
2019-05-15 13:34:06 +00:00
|
|
|
const ut8 *tmp = r_buf_data (b, &tmpsz);
|
2019-04-15 11:24:15 +00:00
|
|
|
r_egg_raw (egg, tmp, tmpsz);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-11-13 03:08:08 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-12 05:16:00 +00:00
|
|
|
}
|
2011-11-14 01:04:27 +00:00
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_encode(REgg *egg, const char *name) {
|
2011-11-14 01:04:27 +00:00
|
|
|
REggPlugin *p;
|
|
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (egg->plugins, iter, p) {
|
|
|
|
if (p->type == R_EGG_PLUGIN_ENCODER && !strcmp (name, p->name)) {
|
2022-07-07 18:25:26 +00:00
|
|
|
RBuffer *b = p->build (egg);
|
|
|
|
if (b) {
|
|
|
|
r_buf_free (egg->bin);
|
|
|
|
egg->bin = b;
|
|
|
|
return true;
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2022-07-07 18:25:26 +00:00
|
|
|
return false;
|
2011-11-14 01:04:27 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-14 01:04:27 +00:00
|
|
|
}
|
2011-11-30 09:27:01 +00:00
|
|
|
|
2021-05-04 11:16:55 +00:00
|
|
|
R_API bool r_egg_patch(REgg *egg, int off, const ut8 *buf, int len) {
|
2019-03-15 19:28:52 +00:00
|
|
|
struct egg_patch_t *ep = R_NEW (struct egg_patch_t);
|
|
|
|
if (!ep) {
|
2018-09-13 08:17:26 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
ep->b = r_buf_new_with_bytes (buf, len);
|
|
|
|
if (!ep->b) {
|
|
|
|
egg_patch_free (ep);
|
2015-09-14 00:08:31 +00:00
|
|
|
return false;
|
2011-11-30 09:27:01 +00:00
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
ep->off = off;
|
|
|
|
r_list_append (egg->patches, ep);
|
2015-09-14 00:08:31 +00:00
|
|
|
return true;
|
2011-11-30 09:27:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
R_API void r_egg_finalize(REgg *egg) {
|
2019-03-15 19:28:52 +00:00
|
|
|
struct egg_patch_t *ep;
|
2011-11-30 09:27:01 +00:00
|
|
|
RListIter *iter;
|
2019-03-26 19:32:53 +00:00
|
|
|
if (!egg->bin) {
|
2018-10-12 10:18:22 +00:00
|
|
|
r_buf_free (egg->bin);
|
2014-10-29 01:44:21 +00:00
|
|
|
egg->bin = r_buf_new ();
|
2016-10-02 21:46:57 +00:00
|
|
|
}
|
2019-03-15 19:28:52 +00:00
|
|
|
r_list_foreach (egg->patches, iter, ep) {
|
|
|
|
if (ep->off < 0) {
|
2019-04-15 11:24:15 +00:00
|
|
|
ut64 sz;
|
2019-05-15 13:34:06 +00:00
|
|
|
const ut8 *buf = r_buf_data (ep->b, &sz);
|
2019-03-15 19:28:52 +00:00
|
|
|
r_egg_append_bytes (egg, buf, sz);
|
2019-05-15 13:34:06 +00:00
|
|
|
} else if (ep->off < r_buf_size (egg->bin)) {
|
2019-04-15 11:24:15 +00:00
|
|
|
ut64 sz;
|
2019-05-15 13:34:06 +00:00
|
|
|
const ut8 *buf = r_buf_data (ep->b, &sz);
|
2019-03-15 19:28:52 +00:00
|
|
|
int r = r_buf_write_at (egg->bin, ep->off, buf, sz);
|
|
|
|
if (r < sz) {
|
2022-07-07 18:25:26 +00:00
|
|
|
R_LOG_ERROR ("cannot write");
|
2014-10-29 01:44:21 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-05-15 13:34:06 +00:00
|
|
|
} else {
|
2022-07-07 18:25:26 +00:00
|
|
|
R_LOG_ERROR ("Cannot patch outside");
|
2019-05-15 13:34:06 +00:00
|
|
|
return;
|
2011-11-30 09:27:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-05 14:03:40 +00:00
|
|
|
|
|
|
|
R_API void r_egg_pattern(REgg *egg, int size) {
|
|
|
|
char *ret = r_debruijn_pattern ((int)size, 0, NULL);
|
2014-09-05 14:13:47 +00:00
|
|
|
if (ret) {
|
2015-05-09 10:32:31 +00:00
|
|
|
r_egg_prepend_bytes (egg, (const ut8*)ret, strlen(ret));
|
2014-09-05 14:13:47 +00:00
|
|
|
free (ret);
|
2018-09-13 08:17:26 +00:00
|
|
|
} else {
|
2022-07-07 18:25:26 +00:00
|
|
|
R_LOG_ERROR ("Invalid debruijn pattern length");
|
2018-09-13 08:17:26 +00:00
|
|
|
}
|
2014-09-05 14:03:40 +00:00
|
|
|
}
|