Refactor (once again) rsa-find.

This commit is contained in:
jvoisin 2014-06-28 15:16:04 +02:00
parent 0ebfd4c642
commit 2ddb3c90e9
2 changed files with 37 additions and 44 deletions

View file

@ -461,18 +461,20 @@ static int cmd_search(void *data, const char *input) {
dosearch = R_TRUE;
} break;
case 'C': {
dosearch = crypto_search = R_TRUE;
switch (input[1]) {
case 'a':
dosearch = aes_search = crypto_search = R_TRUE;
aes_search = R_TRUE;
break;
case 'r':
dosearch = rsa_search = crypto_search = R_TRUE;
rsa_search = R_TRUE;
break;
default:{
dosearch = crypto_search = R_FALSE;
const char* help_msg[] = {
"Usage: /C", "", "Search for crypto materials",
"/Ca", "" , "Search for AES keys",
"/Cr", "", "Search for RSA keys",
"/Cr", "", "Search for private RSA keys",
NULL};
r_core_cmd_help (core, help_msg);
}

View file

@ -1,13 +1,10 @@
// RSAKeyFinder 1.0 (2008-07-18)
// By Nadia Heninger and J. Alex Halderman
// Contribution to r2 by @santitox
// Integrated by jvoisin
// Integrated and refactored by jvoisin
#include <r_search.h>
#define NB_PRIVATES_FIELDS 10
#define NB_PUBLIC_FIELDS 3
/*Baby BER parser, just good enough for RSA keys.
This is not robust to errors in the memory image, but if we added
@ -17,68 +14,62 @@ Parses a single field of the key, beginning at start. Each field
consists of a type, a length, and a value. Puts the type of field
into type, the number of bytes into len, and returns a pointer to
the beginning of the value. */
static ut8* parse_next_rsa_field(const ut8* start, ut32 *type, ut32 *len) {
ut8 *val = malloc(1);
*type = start[0];
*len = 0;
if (!(start[1] & 0x80)) {
*len = start[1];
*val = start[2];
static const ut8* parse_next_rsa_field(const ut8* start, ut32 *type, ut32 *len) {
type = (ut32*) start;
*len = 0;
if (!(start[1] & 128)) {
len = (ut32*)(start + 1);
return start + 2;
} else {
int i;
const int lensize = start[1] & 0x7F;
const int lensize = start[1] & 127;
for (i=0; i < lensize; i++)
*len = (*len << 8) | start[2+i];
*val = start[2+lensize];
return start + 2 + lensize;
}
return val;
}
static int check_rsa_fields(const ut8* start, int nbfields) {
ut32 len = 0, type;
// Check if `start` points to an ensemble of BER fields
static int check_rsa_fields(const ut8* start) {
#define NB_PRIV_FIELDS 10
ut32 type, len = 0;
int i;
ut8 const* ptr = start;
ptr = parse_next_rsa_field (ptr, &type, &len); // skip sequence field
ptr = parse_next_rsa_field (start, &type, &len); // skip sequence field
if (!len || len > 1024)
return R_FALSE;
for (i = 0; i < nbfields; i++)
for (i = 0; i < NB_PRIV_FIELDS; i++)
if (!(ptr = parse_next_rsa_field (ptr, &type, &len)))
return R_FALSE;
return R_TRUE;
}
// Returns a pointer to the beginning of a BER-encoded key by working
// backwards from the given memory map offset, looking for the
// sequence identifier (this is not completely safe)
static int find_rsa_key_start(const ut8 *map, int offset) {
int k;
for (k = offset; k >= 0 && k > offset-20; k--)
if (map[k] == 0x30)
return k;
return 0;
}
// Finds and prints private (or private and public) keys in the memory
// map by searching for given target pattern
// Finds and return index of private RSA key
R_API int r_search_rsa_update(void* s, ut64 from, const ut8 *buf, int len) {
unsigned int i, index;
const ut8 versionmarker[4] = {0x02, 0x01, 0x00, 0x02};
unsigned int i, k, index;
const ut8 versionmarker[] = {0x02, 0x01, 0x00, 0x02};
for (i = 0; i < len - sizeof (versionmarker); i++) {
if (memcmp (&buf[i], versionmarker, sizeof (versionmarker)))
continue;
index = find_rsa_key_start (buf, i);
index = 0;
for (k=i; k >= 0 && k > i - 20; k--) {
if (buf[k] == '0'){ // The sequence identifier is '0'
index = k;
break;
}
}
if (!index)
continue;
const ut8* key = buf + index;
if (check_rsa_fields(key, NB_PRIVATES_FIELDS)) {
printf("FOUND PRIVATE KEY AT %x\n", (ut32)(key-buf));
if (check_rsa_fields(buf + index))
return i;
} else if (check_rsa_fields(key, NB_PUBLIC_FIELDS)) {
printf("FOUND PUBLIC KEY AT %x\n", (ut32)(key-buf));
return i;
}
}
return -1;
}