Refactor debruijn code and make it accessible from ragg2 -P
This commit is contained in:
parent
f930a97adc
commit
30acdbf50c
|
@ -1,4 +1,4 @@
|
|||
/* radare - LGPL - Copyright 2011-2013 - pancake */
|
||||
/* radare - LGPL - Copyright 2011-2014 - pancake */
|
||||
|
||||
#include <r_egg.h>
|
||||
#include <r_bin.h>
|
||||
|
@ -28,6 +28,7 @@ static int usage (int v) {
|
|||
" -p [padding] add padding after compilation (padding=n10s32)\n"
|
||||
" ntas : begin nop, trap, 'a', sequence\n"
|
||||
" NTAS : same as above, but at the end\n"
|
||||
" -P [size] prepend debrujn pattern\n"
|
||||
" -s show assembler\n"
|
||||
" -r show raw bytes instead of hexpairs\n"
|
||||
" -x execute\n"
|
||||
|
@ -87,6 +88,7 @@ static int openfile (const char *f, int x) {
|
|||
int main(int argc, char **argv) {
|
||||
const char *file = NULL;
|
||||
const char *padding = NULL;
|
||||
const char *pattern = NULL;
|
||||
char *bytes = NULL;
|
||||
const char *contents = NULL;
|
||||
const char *arch = R_SYS_ARCH;
|
||||
|
@ -106,7 +108,7 @@ int main(int argc, char **argv) {
|
|||
int c, i;
|
||||
REgg *egg = r_egg_new ();
|
||||
|
||||
while ((c = getopt (argc, argv, "he:a:b:f:o:sxrk:FOI:Li:c:p:B:C:vd:D:w:")) != -1) {
|
||||
while ((c = getopt (argc, argv, "he:a:b:f:o:sxrk:FOI:Li:c:p:P:B:C:vd:D:w:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
arch = optarg;
|
||||
|
@ -181,6 +183,9 @@ int main(int argc, char **argv) {
|
|||
case 'p':
|
||||
padding = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pattern = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
char *p = strchr (optarg, '=');
|
||||
|
@ -231,7 +236,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (optind == argc && !shellcode && !bytes && !contents && !encoder && !padding) {
|
||||
if (optind == argc && !shellcode && !bytes && !contents && !encoder && !padding && !pattern) {
|
||||
return usage (0);
|
||||
} else file = argv[optind];
|
||||
|
||||
|
@ -333,6 +338,9 @@ int main(int argc, char **argv) {
|
|||
if (padding)
|
||||
r_egg_padding (egg, padding);
|
||||
|
||||
if (pattern)
|
||||
r_egg_pattern (egg, r_num_math (NULL, pattern));
|
||||
|
||||
if (!(b = r_egg_get_bin (egg))) {
|
||||
eprintf ("r_egg_get_bin: invalid egg :(\n");
|
||||
goto fail;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/* radare - LGPL - Copyright 2009-2014 - pancake */
|
||||
|
||||
#include "../util/debruijn.c"
|
||||
|
||||
static void cmd_write_bits(RCore *core, int set, ut64 val) {
|
||||
ut64 ret, orig;
|
||||
// used to set/unset bit in current address
|
||||
|
@ -700,7 +698,7 @@ static int cmd_write(void *data, const char *input) {
|
|||
len = (int)(input[2]==' ')?
|
||||
r_num_math (core->num, input + 2): core->blocksize;
|
||||
if (len > 0) {
|
||||
buf = cyclic_pattern(len, 0, debruijn_charset);
|
||||
buf = (ut8*)r_debruijn_pattern (len, 0, NULL); //debruijn_charset);
|
||||
if (buf) {
|
||||
r_core_write_at (core, core->offset, buf, len);
|
||||
free (buf);
|
||||
|
@ -712,7 +710,7 @@ static int cmd_write(void *data, const char *input) {
|
|||
case 'O':
|
||||
len = (int)(input[2]==' ')?
|
||||
r_num_math (core->num, input + 2): core->blocksize;
|
||||
core->num->value = cyclic_pattern_offset (len, !core->assembler->big_endian);
|
||||
core->num->value = r_debruijn_offset (len, !core->assembler->big_endian);
|
||||
r_cons_printf ("%d\n", core->num->value);
|
||||
break;
|
||||
case '\0':
|
||||
|
|
|
@ -420,3 +420,9 @@ R_API void r_egg_finalize(REgg *egg) {
|
|||
memcpy (egg->bin->buf + b->cur, b->buf, b->length);
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_egg_pattern(REgg *egg, int size) {
|
||||
char *ret = r_debruijn_pattern ((int)size, 0, NULL);
|
||||
r_buf_prepend_bytes (egg->bin, ret, strlen (ret));
|
||||
free (ret);
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ R_API void r_egg_printf(REgg *egg, const char *fmt, ...);
|
|||
R_API int r_egg_compile(REgg *egg);
|
||||
R_API int r_egg_padding (REgg *egg, const char *pad);
|
||||
R_API int r_egg_assemble(REgg *egg);
|
||||
R_API void r_egg_pattern(REgg *egg, int size);
|
||||
R_API RBuffer *r_egg_get_bin(REgg *egg);
|
||||
//R_API int r_egg_dump (REgg *egg, const char *file) { }
|
||||
R_API char *r_egg_get_source(REgg *egg);
|
||||
|
|
|
@ -611,6 +611,10 @@ R_API int r_sandbox_chdir (const char *path);
|
|||
R_API int r_sandbox_check_path (const char *path);
|
||||
R_API int r_sandbox_kill(int pid, int sig);
|
||||
|
||||
/* derbuijn.c */
|
||||
R_API char* r_debruijn_pattern(int size, int start, const char* charset);
|
||||
R_API int r_debruijn_offset(ut64 value, int guest_endian);
|
||||
|
||||
/* strpool */
|
||||
#define R_STRPOOL_INC 1024
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* radare - LGPL - Copyright 2014 - crowell */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <r_util.h>
|
||||
|
||||
// For information about the algorithm, see Joe Sawada and Frank Ruskey, "An
|
||||
// Efficient Algorithm for Generating Necklaces with Fixed Density"
|
||||
|
@ -12,126 +11,128 @@
|
|||
// "A%sB$nC-(D;)Ea0Fb1Gc2Hd3Ie4Jf5Kg6Lh7Mi8Nj9OkPlQmRnSoTpUqVrWsXtYuZvwxyz";
|
||||
|
||||
//TODO(crowell): Make charset configurable, to allow banning characters.
|
||||
char* debruijn_charset =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
static const char* debruijn_charset = "ABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
|
||||
// Generate a De Bruijn sequence.
|
||||
void de_bruijn_seq(int prenecklace_len_t, int lyndon_prefix_len_p, int order,
|
||||
int maxlen, int size, int* prenecklace_a, char* sequence,
|
||||
char* charset) {
|
||||
if (strlen(sequence) == maxlen) {
|
||||
return;
|
||||
}
|
||||
int j;
|
||||
if (prenecklace_len_t > order) {
|
||||
if (order % lyndon_prefix_len_p == 0) {
|
||||
for (j = 1; j <= lyndon_prefix_len_p; ++j) {
|
||||
sequence[strlen(sequence)] = charset[prenecklace_a[j]];
|
||||
if (strlen(sequence) == maxlen) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prenecklace_a[prenecklace_len_t] =
|
||||
prenecklace_a[prenecklace_len_t - lyndon_prefix_len_p];
|
||||
de_bruijn_seq(prenecklace_len_t + 1, lyndon_prefix_len_p, order, maxlen,
|
||||
size, prenecklace_a, sequence, charset);
|
||||
for (j = prenecklace_a[prenecklace_len_t - lyndon_prefix_len_p] + 1;
|
||||
j < size; ++j) {
|
||||
prenecklace_a[prenecklace_len_t] = j;
|
||||
de_bruijn_seq(prenecklace_len_t + 1, prenecklace_len_t, order, maxlen,
|
||||
size, prenecklace_a, sequence, charset);
|
||||
}
|
||||
}
|
||||
static void de_bruijn_seq(int prenecklace_len_t, int lyndon_prefix_len_p, int order,
|
||||
int maxlen, int size, int* prenecklace_a, char* sequence,
|
||||
const char* charset) {
|
||||
int j;
|
||||
if (strlen(sequence) == maxlen) {
|
||||
return;
|
||||
}
|
||||
if (prenecklace_len_t > order) {
|
||||
if (order % lyndon_prefix_len_p == 0) {
|
||||
for (j = 1; j <= lyndon_prefix_len_p; ++j) {
|
||||
sequence[strlen(sequence)] = charset[prenecklace_a[j]];
|
||||
if (strlen(sequence) == maxlen) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prenecklace_a[prenecklace_len_t] =
|
||||
prenecklace_a[prenecklace_len_t - lyndon_prefix_len_p];
|
||||
de_bruijn_seq(prenecklace_len_t + 1, lyndon_prefix_len_p, order, maxlen,
|
||||
size, prenecklace_a, sequence, charset);
|
||||
for (j = prenecklace_a[prenecklace_len_t - lyndon_prefix_len_p] + 1;
|
||||
j < size; ++j) {
|
||||
prenecklace_a[prenecklace_len_t] = j;
|
||||
de_bruijn_seq(prenecklace_len_t + 1, prenecklace_len_t, order, maxlen,
|
||||
size, prenecklace_a, sequence, charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a De Bruijn sequence.
|
||||
// The returned string is malloced, and it is the responsibility of the caller
|
||||
// to free the memory.
|
||||
char* de_bruijn(char* charset, int order, int maxlen) {
|
||||
int size = strlen(charset);
|
||||
int* prenecklace_a = calloc(size * order, sizeof(int));
|
||||
char* sequence = calloc(maxlen + 1, sizeof(char));
|
||||
de_bruijn_seq(1, 1, order, maxlen, size, prenecklace_a, sequence, charset);
|
||||
free(prenecklace_a);
|
||||
return sequence;
|
||||
static char* de_bruijn(const char* charset, int order, int maxlen) {
|
||||
int size = strlen (charset);
|
||||
int* prenecklace_a = calloc(size * order, sizeof(int));
|
||||
char* sequence = calloc(maxlen + 1, sizeof(char));
|
||||
de_bruijn_seq(1, 1, order, maxlen, size, prenecklace_a, sequence, charset);
|
||||
free(prenecklace_a);
|
||||
return sequence;
|
||||
}
|
||||
|
||||
// Generate a cyclic pattern of desired size, and charset, return with starting
|
||||
// offset of start.
|
||||
// The returned string is malloced, and it is the responsibility of the caller
|
||||
// to free the memory.
|
||||
char* cyclic_pattern(int size, int start, char* charset) {
|
||||
if (start >= size) {
|
||||
return (char*)NULL;
|
||||
}
|
||||
char* pattern = de_bruijn(charset, 3 /*subsequence length*/, size);
|
||||
if (start == 0) {
|
||||
return pattern;
|
||||
} else {
|
||||
char* returned_pattern = calloc((size - start) + 1, sizeof(char));
|
||||
strncpy(returned_pattern, pattern + start, size - start);
|
||||
free(pattern);
|
||||
return returned_pattern;
|
||||
}
|
||||
R_API char* r_debruijn_pattern(int size, int start, const char* charset) {
|
||||
char *pat, *pat2;
|
||||
if (!charset)
|
||||
charset = debruijn_charset;
|
||||
if (start >= size) {
|
||||
return (char*)NULL;
|
||||
}
|
||||
pat = de_bruijn(charset, 3 /*subsequence length*/, size);
|
||||
if (start == 0)
|
||||
return pat;
|
||||
pat2 = calloc ((size - start) + 1, sizeof(char));
|
||||
strncpy (pat2, pat + start, size - start);
|
||||
pat2[size-start] = 0;
|
||||
free (pat);
|
||||
return pat2;
|
||||
}
|
||||
|
||||
// In-place reverse a string.
|
||||
void reverse_string(char* str) {
|
||||
// Skip null and empty strings.
|
||||
if (str == 0 || str[0] == 0) {
|
||||
return;
|
||||
}
|
||||
char* start = str;
|
||||
char* end = start + strlen(str) - 1;
|
||||
char temp;
|
||||
while (end > start) {
|
||||
temp = *start;
|
||||
*start = *end;
|
||||
*end = temp;
|
||||
++start;
|
||||
--end;
|
||||
}
|
||||
static void reverse_string(char* str) {
|
||||
char *start = str, *end, temp;
|
||||
// Skip null and empty strings.
|
||||
if (!str || !*str)
|
||||
return;
|
||||
end = start + strlen (str) - 1;
|
||||
while (end > start) {
|
||||
temp = *start;
|
||||
*start = *end;
|
||||
*end = temp;
|
||||
++start;
|
||||
--end;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a cyclic pattern of 0x10000 long.
|
||||
// The returned string is malloced, and it is the responsibility of the caller
|
||||
// to free the memory.
|
||||
char* cyclic_pattern_long() {
|
||||
// 0x10000 should be long enough. This is how peda works, and nobody
|
||||
// complains.
|
||||
return cyclic_pattern(0x10000, 0, debruijn_charset);
|
||||
static char* cyclic_pattern_long() {
|
||||
// 0x10000 should be long enough. This is how peda works, and nobody
|
||||
// complains.
|
||||
return r_debruijn_pattern (0x10000, 0, debruijn_charset);
|
||||
}
|
||||
|
||||
// Finds the offset of a given value in a cyclic pattern of an integer.
|
||||
// Guest endian = 1 if little, 0 if big.
|
||||
// Host endian = 1 if little, 0 if big.
|
||||
int cyclic_pattern_offset(unsigned long long value, int guest_endian) {
|
||||
if (value == 0) {
|
||||
return -1;
|
||||
}
|
||||
char* pattern = cyclic_pattern_long();
|
||||
unsigned long long needle_l[2]; // Hold the value as a string.
|
||||
needle_l[0] = value;
|
||||
needle_l[1] = 0;
|
||||
char* needle = (char*)&needle_l;
|
||||
// On little-endian systems with more bits than the binary being analyzed, we
|
||||
// may need to find the begin of this.
|
||||
while (needle[0] == 0) {
|
||||
++needle;
|
||||
}
|
||||
int n = 1;
|
||||
// little endian if true
|
||||
int host_endian = (*(char*)&n == 1) ? 1 : 0;
|
||||
if (host_endian != guest_endian) {
|
||||
reverse_string(needle);
|
||||
}
|
||||
char* pch = strstr(pattern, needle);
|
||||
int retval = -1;
|
||||
if (pch != NULL) {
|
||||
retval = (int)(pch - pattern);
|
||||
}
|
||||
free(pattern);
|
||||
return retval;
|
||||
R_API int r_debruijn_offset(ut64 value, int guest_endian) {
|
||||
ut64 needle_l[2]; // Hold the value as a string.
|
||||
char* needle, *pattern;
|
||||
|
||||
if (value == 0)
|
||||
return -1;
|
||||
pattern = cyclic_pattern_long();
|
||||
|
||||
needle_l[0] = value;
|
||||
needle_l[1] = 0;
|
||||
needle = (char*)&needle_l;
|
||||
// On little-endian systems with more bits than the binary being analyzed, we
|
||||
// may need to find the begin of this.
|
||||
while (!needle[0])
|
||||
needle++;
|
||||
|
||||
// we should not guess the endian. its already handled by other functions
|
||||
// and configure by the user in cfg.bigendian
|
||||
int n = 1;
|
||||
// little endian if true
|
||||
int host_endian = (*(char*)&n == 1) ? 1 : 0;
|
||||
if (host_endian != guest_endian)
|
||||
reverse_string (needle);
|
||||
|
||||
char* pch = strstr (pattern, needle);
|
||||
int retval = -1;
|
||||
if (pch != NULL)
|
||||
retval = (int)(pch - pattern);
|
||||
free (pattern);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ ragg2 \- radare2 utility to run programs in exotic environments
|
|||
.Op Fl D Ar off:qword
|
||||
.Op Fl w Ar off:hexpair
|
||||
.Op Fl p Ar padding
|
||||
.Op Fl P Ar pattern
|
||||
.Op Fl FOLsrxvh
|
||||
.Sh DESCRIPTION
|
||||
ragg2 is a frontend for r_egg, compile programs into tiny binaries for x86-32/64 and arm.
|
||||
|
@ -62,6 +63,8 @@ Patch final buffer with given qword at specified offset
|
|||
Patch final buffer with given hexpairs at specified offset
|
||||
.It Fl p Ar padding
|
||||
Specify generic paddings with a format string.
|
||||
.It Fl P Ar size
|
||||
Prepend debruijn sequence of given length.
|
||||
.It Fl F
|
||||
autodetect native file format (osx=mach0, linux=elf, ..)
|
||||
.It Fl O
|
||||
|
|
Loading…
Reference in New Issue