/*
Patchdiff2
Portions (C) 2010 - 2011 Nicolas Pouvesle
Portions (C) 2007 - 2009 Tenable Network Security, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "precomp.hpp"
#include "sig.hpp"
#include "diff.hpp"
#include "options.hpp"
#include "backup.hpp"
static void buffer_serialize_data(char * buf, size_t blen, size_t * pos, void * data, size_t dsize)
{
if ( (*pos + dsize) > blen)
{
*pos = blen;
return;
}
memcpy(buf+*pos, data, dsize);
*pos += dsize;
}
static void buffer_unserialize_data(char * buf, size_t blen, size_t * pos, void * data, size_t dsize)
{
if ( (*pos + dsize) > blen)
{
*pos = blen;
return;
}
memcpy(data, buf+*pos, dsize);
*pos += dsize;
}
static void buffer_serialize_ea(char * buf, size_t blen, size_t * pos, ea_t ea)
{
buffer_serialize_data(buf, blen, pos, &ea, sizeof(ea));
}
static void buffer_serialize_bool(char * buf, size_t blen, size_t * pos, bool b)
{
buffer_serialize_data(buf, blen, pos, &b, sizeof(b));
}
static void buffer_serialize_char(char * buf, size_t blen, size_t * pos, char c)
{
buffer_serialize_data(buf, blen, pos, &c, sizeof(c));
}
static void buffer_serialize_int(char * buf, size_t blen, size_t * pos, int i)
{
buffer_serialize_data(buf, blen, pos, &i, sizeof(i));
}
static void buffer_serialize_long(char * buf, size_t blen, size_t * pos, unsigned long l)
{
buffer_serialize_data(buf, blen, pos, &l, sizeof(l));
}
static void buffer_serialize_size(char * buf, size_t blen, size_t * pos, size_t size)
{
buffer_serialize_data(buf, blen, pos, &size, sizeof(size));
}
static void buffer_unserialize_ea(char * buf, size_t blen, size_t * pos, ea_t * ea)
{
buffer_unserialize_data(buf, blen, pos, ea, sizeof(*ea));
}
static void buffer_unserialize_bool(char * buf, size_t blen, size_t * pos, bool * b)
{
buffer_unserialize_data(buf, blen, pos, b, sizeof(*b));
}
static void buffer_unserialize_char(char * buf, size_t blen, size_t * pos, char * c)
{
buffer_unserialize_data(buf, blen, pos, c, sizeof(*c));
}
static void buffer_unserialize_int(char * buf, size_t blen, size_t * pos, int * i)
{
buffer_unserialize_data(buf, blen, pos, i, sizeof(*i));
}
static void buffer_unserialize_long(char * buf, size_t blen, size_t * pos, unsigned long * l)
{
buffer_unserialize_data(buf, blen, pos, l, sizeof(*l));
}
static void buffer_unserialize_size(char * buf, size_t blen, size_t * pos, size_t * size)
{
buffer_unserialize_data(buf, blen, pos, size, sizeof(*size));
}
/*------------------------------------------------*/
/* function : buffer_serialize_string */
/* description: Serializes a string */
/*------------------------------------------------*/
static void buffer_serialize_string(char * buf, size_t blen, size_t * pos, char * s)
{
size_t len;
len = strlen(s) + 1;
if ( (*pos + len) > blen)
{
*pos = blen;
return;
}
memcpy(buf+*pos, s, len);
*pos += len;
}
/*------------------------------------------------*/
/* function : buffer_unserialize_string */
/* description: Unserializes a string */
/*------------------------------------------------*/
static void buffer_unserialize_string(char * buf, size_t blen, size_t * pos, char ** s)
{
*s = qstrdup(buf+*pos);
*pos += strlen(*s) + 1;
}
/*------------------------------------------------*/
/* function : singleton_serialize */
/* description: Serializes a signature */
/*------------------------------------------------*/
static size_t singleton_serialize(char * buf, size_t blen, psig_t * s, int nfile)
{
size_t pos = 0;
fref_t * fref = NULL;
int num, i;
buffer_serialize_ea(buf, blen, &pos, s->startEA);
buffer_serialize_int(buf, blen, &pos, s->mtype);
buffer_serialize_int(buf, blen, &pos, s->id_crc);
buffer_serialize_int(buf, blen, &pos, nfile);
buffer_serialize_long(buf, blen, &pos, s->sig);
buffer_serialize_long(buf, blen, &pos, s->hash);
buffer_serialize_long(buf, blen, &pos, s->crc_hash);
buffer_serialize_long(buf, blen, &pos, s->str_hash);
buffer_serialize_int(buf, blen, &pos, s->flag);
buffer_serialize_long(buf, blen, &pos, s->lines);
num= 0;
if (s->srefs)
{
fref = s->srefs->list;
num = s->srefs->num;
}
buffer_serialize_int(buf, blen, &pos, num);
for (i=0; iea);
buffer_serialize_int(buf, blen, &pos, fref->type);
fref = fref->next;
}
if (nfile == 2)
{
if (!strncmp(s->name, "sub_", 4))
{
buffer_serialize_char(buf, blen, &pos, 0);
}
else
{
buffer_serialize_char(buf, blen, &pos, 1);
buffer_serialize_string(buf, blen, &pos, s->name);
}
}
return pos;
}
/*------------------------------------------------*/
/* function : singleton_unserialize */
/* description: Serializes a signature */
/*------------------------------------------------*/
static size_t singleton_unserialize(char * buf, size_t blen, psig_t ** s, int version)
{
char tmp[512];
size_t pos = 0;
char c;
int num, i;
ea_t ea;
int type;
*s = sig_init();
if (!(*s)) return 0;
buffer_unserialize_ea(buf, blen, &pos, &(*s)->startEA);
buffer_unserialize_int(buf, blen, &pos, &(*s)->mtype);
buffer_unserialize_int(buf, blen, &pos, &(*s)->id_crc);
buffer_unserialize_int(buf, blen, &pos, &(*s)->nfile);
buffer_unserialize_long(buf, blen, &pos, &(*s)->sig);
buffer_unserialize_long(buf, blen, &pos, &(*s)->hash);
buffer_unserialize_long(buf, blen, &pos, &(*s)->crc_hash);
if (version >= 2)
buffer_unserialize_long(buf, blen, &pos, &(*s)->str_hash);
if (version >= 3)
buffer_unserialize_int(buf, blen, &pos, &(*s)->flag);
buffer_unserialize_long(buf, blen, &pos, &(*s)->lines);
buffer_unserialize_int(buf, blen, &pos, &num);
for (i=0; infile == 2)
{
buffer_unserialize_char(buf, blen, &pos, &c);
if (c == 1)
buffer_unserialize_string(buf, blen, &pos, &(*s)->name);
else
{
qsnprintf(tmp, sizeof(tmp), "sub_%" PRIea_t, (*s)->startEA);
sig_set_name((*s), tmp);
}
}
else
{
pget_func_name((*s)->startEA, tmp, sizeof(tmp));
sig_set_name(*s, tmp);
}
return pos;
}
/*------------------------------------------------*/
/* function : pair_serialize */
/* description: Serializes a signature and the */
/* matched signature */
/*------------------------------------------------*/
static size_t pair_serialize(char * buf, size_t blen, psig_t * s)
{
size_t len;
len = singleton_serialize(buf, blen, s, 1);
len += singleton_serialize(buf+len, blen-len, s->msig, 2);
return len;
}
/*------------------------------------------------*/
/* function : pair_unserialize */
/* description: Unserializes a signature and the */
/* matched signature */
/*------------------------------------------------*/
static size_t pair_unserialize(char * buf, size_t blen, psig_t ** s, int version)
{
size_t len;
len = singleton_unserialize(buf, blen, s, version);
len += singleton_unserialize(buf+len, blen-len, &(*s)->msig, version);
(*s)->msig->msig = (*s);
return len;
}
/*------------------------------------------------*/
/* function : backup_save_list */
/* description: Backups result list inside a */
/* netnode */
/*------------------------------------------------*/
static void backup_save_list(const char *node_name, slist_t * sl)
{
char buf[5000];
size_t i;
size_t len;
netnode node;
if (!sl) return;
node.create(node_name);
for (i=0; inum; i++)
{
nodeidx_t nidx = node.altval(i);
if (nidx != 0)
{
msg("backup failed: netnode already exists !!\n");
return;
}
netnode n(nidx);
n.create();
node.altset(i, n);
if (sl->sigs[i]->msig != NULL)
len = pair_serialize(buf, sizeof(buf), sl->sigs[i]);
else
len = singleton_serialize(buf, sizeof(buf), sl->sigs[i], sl->sigs[i]->nfile);
n.setblob(buf, len, 0, 'P');
}
}
/*------------------------------------------------*/
/* function : backup_load_list */
/* description: Loads result list from a netnode */
/*------------------------------------------------*/
static bool backup_load_list(const char *node_name, slist_t * sl, int type, int version)
{
char buf[5000];
size_t i;
size_t len;
netnode node;
nodeidx_t nidx;
if (!sl) return true;
node.create(node_name);
for (i=0; iorg_num; i++)
{
nidx = node.altval(i);
if (nidx == BADNODE)
{
msg("backup failed: netnode does not exist !!\n");
return false;
}
netnode n(nidx);
len = sizeof(buf);
if (!n.getblob(buf, &len, 0, 'P'))
{
msg("backup failed: netnode blob does not exist !!\n");
return false;
}
if (type)
pair_unserialize(buf, len, &sl->sigs[i], version);
else
singleton_unserialize(buf, len, &sl->sigs[i], version);
}
sl->num = sl->org_num;
return true;
}
/*------------------------------------------------*/
/* function : backup_free_node */
/* description: Removes node from the IDB */
/*------------------------------------------------*/
static void backup_free_node(const char *node_name, size_t size)
{
netnode node;
size_t i;
node.create(node_name);
for (i=0; imlist ? eng->mlist->org_num : 0);
backup_free_node("$ pdiff2_identical", eng->ilist ? eng->ilist->org_num : 0);
backup_free_node("$ pdiff2_unmatched", eng->ulist ? eng->ulist->org_num : 0);
backup_free_node("$ pdiff2_eng", 1);
}
/*------------------------------------------------*/
/* function : backup_save_eng */
/* description:Saves engine data inside a netnode */
/*------------------------------------------------*/
static void backup_save_eng(const char *node_name, deng_t * eng)
{
char buf[1000];
char * file;
size_t pos = 0;
netnode node;
size_t msize, isize, usize;
node.create(node_name);
nodeidx_t nidx = node.altval(0);
if (nidx != 0)
{
backup_cleanup(eng);
node.create(node_name);
nidx = node.altval(0);
if (nidx != 0)
{
msg("backup eng failed: netnode already exists !!\n");
return;
}
}
netnode n(nidx);
n.create();
node.altset(0, n);
msize = isize = usize = 0;
if (eng->mlist)
{
file = eng->mlist->file;
msize = eng->mlist->num;
}
if (eng->ilist)
{
file = eng->ilist->file;
isize = eng->ilist->num;
}
if (eng->ulist)
{
file = eng->ulist->file;
usize = eng->ulist->num;
}
buffer_serialize_int(buf, sizeof(buf), &pos, PDIFF_BACKUP_VERSION);
buffer_serialize_string(buf, sizeof(buf), &pos, file);
buffer_serialize_size(buf, sizeof(buf), &pos, msize);
buffer_serialize_size(buf, sizeof(buf), &pos, isize);
buffer_serialize_size(buf, sizeof(buf), &pos, usize);
buffer_serialize_bool(buf, sizeof(buf), &pos, eng->opt->ipc);
n.setblob(buf, pos, 0, 'P');
}
/*------------------------------------------------*/
/* function : backup_load_file */
/* description:Loads engine data inside a netnode */
/*------------------------------------------------*/
static deng_t * backup_load_eng(const char *node_name, options_t * opt, int * version)
{
char buf[1000];
deng_t * eng;
char * file = NULL;
size_t blen, pos = 0;
netnode node;
size_t msize, isize, usize;
node.create(node_name);
nodeidx_t nidx = node.altval(0);
if (nidx == 0)
return NULL;
netnode n(nidx);
blen = sizeof(buf);
n.getblob(buf, &blen, 0, 'P');
if (!blen)
return NULL;
eng = (deng_t *)qalloc(sizeof(*eng));
if (!eng)
return NULL;
eng->magic = 0x0BADF00D;
eng->wnum = 0;
eng->opt = opt;
msize = isize = usize = 0;
buffer_unserialize_int(buf, sizeof(buf), &pos, version);
buffer_unserialize_string(buf, sizeof(buf), &pos, &file);
buffer_unserialize_size(buf, sizeof(buf), &pos, &msize);
buffer_unserialize_size(buf, sizeof(buf), &pos, &isize);
buffer_unserialize_size(buf, sizeof(buf), &pos, &usize);
buffer_unserialize_bool(buf, sizeof(buf), &pos, &eng->opt->ipc);
// no need to save that in the IDB
eng->opt->save_db = true;
eng->mlist = siglist_init(msize, file);
eng->ilist = siglist_init(isize, file);
eng->ulist = siglist_init(usize, file);
return eng;
}
/*------------------------------------------------*/
/* function : backup_save_results */
/* description: Saves diff results inside the */
/* IDB */
/*------------------------------------------------*/
void backup_save_results(deng_t * eng)
{
backup_save_eng("$ pdiff2_eng", eng);
backup_save_list("$ pdiff2_matched", eng->mlist);
backup_save_list("$ pdiff2_identical", eng->ilist);
backup_save_list("$ pdiff2_unmatched", eng->ulist);
}
/*------------------------------------------------*/
/* function : backup_load_results */
/* description: Loads diff results from the IDB */
/*------------------------------------------------*/
int backup_load_results(deng_t ** eng, options_t * opt)
{
int ret;
int version;
if (*eng)
{
ret = askbuttons_c("Reuse", "Refresh", "Cancel", 1,
"Previous diff results have been found. Please specify the action to perform.");
if (ret == 0)
{
diff_engine_free(*eng);
*eng = NULL;
}
return ret;
}
*eng = backup_load_eng("$ pdiff2_eng", opt, &version);
if (!(*eng)) return 0;
ret = askbuttons_c("Reuse", "Refresh", "Cancel", 1,
"Previous diff results have been found. Please specify the action to perform.");
if (ret != 1) goto error;
msg("Loading backup results... ");
if (!backup_load_list("$ pdiff2_matched", (*eng)->mlist, 1, version)) goto error;
if (!backup_load_list("$ pdiff2_identical", (*eng)->ilist, 1, version)) goto error;
if (!backup_load_list("$ pdiff2_unmatched", (*eng)->ulist, 0, version)) goto error;
msg("done.\n");
return ret;
error:
diff_engine_free(*eng);
*eng = NULL;
return ret;
}