/*
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 "x86.hpp"
#include "ppc.hpp"
#include "patchdiff.hpp"
#include "pchart.hpp"
#include "os.hpp"
extern cpu_t patchdiff_cpu;
/*------------------------------------------------*/
/* function : pget_func_name */
/* description: Gets function name */
/*------------------------------------------------*/
char * pget_func_name(ea_t ea, char * buffer, size_t blen)
{
char * pos;
char tmp[512];
if (!get_func_name(ea, buffer, blen))
return NULL;
// make sure this is not a c++ class/struct badly defined as a function
demangle_name(tmp, blen, buffer, inf.long_demnames);
if ( (strstr(tmp, "public: static") || strstr(tmp, "private: static")) &&
(!strstr(tmp, "(") || strstr(tmp, "public: static long (__stdcall")) )
return NULL;
demangle_name(buffer, blen, buffer, inf.short_demnames);
// remove duplicates of the same name
pos = strstr(buffer, "Z$0");
if (pos)
pos[0] = '\0';
return buffer;
}
/*------------------------------------------------*/
/* function : sig_init */
/* description: Allocates and initializes a new */
/* function signature */
/*------------------------------------------------*/
psig_t * sig_init()
{
psig_t * sig;
sig = (psig_t *)qalloc(sizeof(*sig));
if (!sig)
return NULL;
memset(sig, 0, sizeof(*sig));
sig->mtype = DIFF_UNMATCHED;
sig->msig = NULL;
return sig;
}
/*------------------------------------------------*/
/* function : frefs_free */
/* description: Frees chained list */
/*------------------------------------------------*/
void frefs_free(frefs_t * frefs)
{
fref_t * fref, * next;
fref = frefs->list;
while (fref)
{
next = fref->next;
qfree(fref);
fref = next;
}
qfree(frefs);
}
/*------------------------------------------------*/
/* function : dsig_free */
/* description: Frees chained list */
/*------------------------------------------------*/
void dsig_free(dpsig_t * ds)
{
dpsig_t * next;
while (ds)
{
next = ds->next;
qfree(ds);
ds = next;
}
qfree(ds);
}
/*------------------------------------------------*/
/* function : clist_free */
/* description: Frees clist_t structure */
/*------------------------------------------------*/
void clist_free(clist_t * cl)
{
dsig_free(cl->sigs);
dsig_free(cl->msigs);
qfree(cl);
}
/*------------------------------------------------*/
/* function : sig_free */
/* description: Frees signature */
/*------------------------------------------------*/
void sig_free(psig_t * sig)
{
if (sig->name)
{
qfree(sig->name);
sig->name = NULL;
}
if (sig->dl.lines != NULL)
qfree(sig->dl.lines);
if (sig->prefs) frefs_free(sig->prefs);
if (sig->srefs) frefs_free(sig->srefs);
if (sig->cp) clist_free(sig->cp);
if (sig->cs) clist_free(sig->cs);
qfree(sig);
}
/*------------------------------------------------*/
/* function : sig_set_name */
/* description: Sets function signature name */
/*------------------------------------------------*/
void sig_set_name(psig_t * sig, const char * name)
{
sig->name = qstrdup(name);
}
/*------------------------------------------------*/
/* function : sig_set_start */
/* description: Sets function start address */
/*------------------------------------------------*/
void sig_set_start(psig_t * sig, ea_t ea)
{
sig->startEA = ea;
}
/*------------------------------------------------*/
/* function : sig_get_start */
/* description: Returns function start address */
/*------------------------------------------------*/
ea_t sig_get_start(psig_t * sig)
{
return sig->startEA;
}
/*------------------------------------------------*/
/* function : sig_get_preds */
/* description: Returns signature pred xrefs */
/*------------------------------------------------*/
frefs_t * sig_get_preds(psig_t * sig)
{
return sig->prefs;
}
/*------------------------------------------------*/
/* function : sig_get_succs */
/* description: Returns signature succ xrefs */
/*------------------------------------------------*/
frefs_t * sig_get_succs(psig_t * sig)
{
return sig->srefs;
}
/*------------------------------------------------*/
/* function : sig_get_crefs */
/* description: Returns signature cxrefs */
/*------------------------------------------------*/
clist_t * sig_get_crefs(psig_t * sig, int type)
{
if (type == SIG_PRED)
return sig->cp;
if (type == SIG_SUCC)
return sig->cs;
return NULL;
}
/*------------------------------------------------*/
/* function : sig_set_crefs */
/* description: Sets signature cxrefs */
/*------------------------------------------------*/
void sig_set_crefs(psig_t * sig, int type, clist_t * cl)
{
if (type == SIG_PRED)
sig->cp = cl;
else if (type == SIG_SUCC)
sig->cs = cl;
}
/*------------------------------------------------*/
/* function : sig_set_nfile */
/* description: Sets file number */
/*------------------------------------------------*/
void sig_set_nfile(psig_t * sig, int num)
{
sig->nfile = num;
}
/*------------------------------------------------*/
/* function : sig_set_matched_sig */
/* description: Sets matched address */
/*------------------------------------------------*/
void sig_set_matched_sig(psig_t * sig, psig_t * sig2, int type)
{
sig->msig = sig2;
sig->matchedEA = sig2->startEA;
sig2->msig = sig;
sig2->matchedEA = sig->startEA;
sig->mtype = sig2->mtype = type;
if (sig->crc_hash != sig2->crc_hash)
sig->id_crc = sig2->id_crc = 1;
}
/*------------------------------------------------*/
/* function : sig_get_matched_sig */
/* description: Returns matched address */
/*------------------------------------------------*/
psig_t * sig_get_matched_sig(psig_t * sig)
{
return sig->msig;
}
/*------------------------------------------------*/
/* function : sig_get_matched_type */
/* description: Returns matched type */
/*------------------------------------------------*/
int sig_get_matched_type(psig_t * sig)
{
return sig->mtype;
}
/*------------------------------------------------*/
/* function : sig_add_fref */
/* description: Adds a function reference to the */
/* signature */
/*------------------------------------------------*/
int sig_add_fref(frefs_t ** frefs, ea_t ea, int type, char rtype)
{
fref_t * ref, * next;
if (!*frefs)
{
*frefs = (frefs_t *)qalloc(sizeof(**frefs));
if (!*frefs) return -1;
memset(*frefs, 0, sizeof(**frefs));
}
else
{
//don't add duplicates
next = (*frefs)->list;
while(next)
{
if (next->ea == ea)
return -1;
next = next->next;
}
}
ref = (fref_t *)qalloc(sizeof(*ref));
if (!ref) return -1;
ref->ea = ea;
ref->type = type;
ref->rtype = rtype;
ref->next = (*frefs)->list;
(*frefs)->num++;
(*frefs)->list = ref;
return 0;
}
/*------------------------------------------------*/
/* function : sig_add_pref */
/* description: Adds a function reference to the */
/* signature */
/*------------------------------------------------*/
int sig_add_pref(psig_t * sig, ea_t ea, int type, char rtype)
{
return sig_add_fref(&sig->prefs, ea, type, rtype);
}
/*------------------------------------------------*/
/* function : sig_add_sref */
/* description: Adds a function reference to the */
/* signature */
/*------------------------------------------------*/
int sig_add_sref(psig_t * sig, ea_t ea, int type, char rtype)
{
return sig_add_fref(&sig->srefs, ea, type, rtype);
}
/*------------------------------------------------*/
/* function : is_fake_jump */
/* description: Returns TRUE if the instruction at*/
/* ea is a jump */
/*------------------------------------------------*/
bool is_fake_jump(ea_t ea)
{
switch(patchdiff_cpu)
{
case CPU_X8632:
case CPU_X8664:
if (x86_get_fake_jump(ea) != BADADDR)
return true;
default:
return false;
}
}
/*------------------------------------------------*/
/* function : ignore_jump */
/* description: Returns TRUE if the instruction at*/
/* ea is a jump that must be ignored */
/* in the signature */
/*------------------------------------------------*/
bool ignore_jump(ea_t ea)
{
switch(patchdiff_cpu)
{
case CPU_X8632:
case CPU_X8664:
if (!x86_is_direct_jump(ea))
return false;
default:
return true;
}
}
/*------------------------------------------------*/
/* function : is_jump */
/* description: Returns TRUE if the instruction at*/
/* ea is a jump */
/*------------------------------------------------*/
bool is_jump(psig_t * sig, ea_t ea, bool * call, bool * cj)
{
xrefblk_t xb;
cref_t cr;
*call = false;
*cj = false;
if (xb.first_from(ea, XREF_FAR))
{
cr = (cref_t)xb.type;
if (xb.iscode && (cr == fl_JF || cr == fl_JN)) {
if (ignore_jump(ea)) {
return true;
} else {
*cj = true;
}
}
if (xb.iscode && (cr == fl_CF || cr == fl_CN))
{
if (sig->type == 1)
sig_add_sref(sig, xb.to, 0, CHECK_REF);
*call = true;
}
}
else
return is_fake_jump(ea);
return false;
}
/*------------------------------------------------*/
/* function : remove_instr */
/* description: Returns TRUE if the instruction at*/
/* ea must not be added to the sig */
/*------------------------------------------------*/
bool remove_instr(unsigned char byte, ea_t ea)
{
switch (patchdiff_cpu)
{
case CPU_X8632:
case CPU_X8664:
return x86_remove_instr(byte, ea);
case CPU_PPC:
return ppc_remove_instr(byte, ea);
default:
return false;
}
}
/*------------------------------------------------*/
/* function : get_byte_with_optimization */
/* description: Returns byte at address ea */
/* note: Uses the processor optimized function if */
/* available */
/*------------------------------------------------*/
char get_byte_with_optimization(ea_t ea)
{
switch (patchdiff_cpu)
{
case CPU_X8632:
case CPU_X8664:
return x86_get_byte(ea);
case CPU_PPC:
return ppc_get_byte(ea);
default:
{
decode_insn(ea);
return (char)cmd.itype;
}
}
}
unsigned long ror(unsigned long val, int r)
{
return (val >> r) | (val available < (len+3))
{
dll = (char *)qrealloc(dl->lines, sizeof(char*) * (dl->num+len+256));
if (!dll) return -1;
dl->available = len+256;
dl->lines = dll;
}
if (dl->num)
{
dl->lines[dl->num] = '\n';
dl->num++;
}
memcpy(&dl->lines[dl->num], buf, len);
dl->available -= len+1;
dl->num += len;
dl->lines[dl->num] = '\0';
return 0;
}
/*------------------------------------------------*/
/* function : sig_add_address */
/* description: Adds an address to the signature */
/*------------------------------------------------*/
int sig_add_address(psig_t * sig, short opcodes[256], ea_t ea, bool b, bool line, char options)
{
unsigned char byte;
unsigned char buf[200];
uint32 s, i;
bool call;
bool cj;
ea_t tea;
flags_t f;
if (line)
dline_add(&sig->dl, ea, options);
if (is_jump(sig, ea, &call, &cj))
return -1;
byte = get_byte_with_optimization(ea);
if (remove_instr(byte, ea))
return -1;
sig->lines++;
opcodes[byte]++;
if (!b && !call)
{
if (cj)
{
buf[0] = byte;
s = 1;
}
else
{
s = (uint32)get_item_size(ea);
if (s > sizeof(buf)) s = sizeof(buf);
get_many_bytes(ea, buf, s);
}
for (i=0; icrc_hash += buf[i];
sig->crc_hash += ( sig->crc_hash crc_hash ^= ( sig->crc_hash >> 6 );
}
}
else if (b)
{
tea = get_first_dref_from(ea);
if (tea != BADADDR)
{
f = getFlags(tea);
if (isASCII(f))
{
opinfo_t op_info;
get_opinfo(tea, 0, f, &op_info);
s = get_max_ascii_length(tea, op_info.strtype);
if (!get_ascii_contents2(tea, s, op_info.strtype, buf, sizeof(buf)))
s = sizeof(buf);
for (i=0; istr_hash += buf[i]*i;
}
}
}
return 0;
}
/*------------------------------------------------*/
/* function : sig_add_block */
/* description: Adds a block to the signature */
/*------------------------------------------------*/
int sig_add_block(psig_t * sig, short opcodes[256], ea_t startEA, ea_t endEA, bool line, char options)
{
ea_t ea;
flags_t flags;
bool b;
ea = startEA;
while (ea < endEA)
{
flags = getFlags (ea);
if (!isCode (flags))
return -1;
b = get_first_dref_from(ea) != BADADDR ? true : false;
sig_add_address(sig, opcodes, ea, isOff(flags, OPND_ALL) || b, line, options);
ea += get_item_size(ea);
}
return 0;
}
int OS_CDECL compare(const void *arg1, const void *arg2)
{
return *((short *)arg1) - *((short *)arg2);
}
/*------------------------------------------------*/
/* function : sig_calc_sighash */
/* description: generates a sig/hash for the */
/* signature opcodes */
/*------------------------------------------------*/
int sig_calc_sighash(psig_t * sig, short _opcodes[256], int do_sig)
{
short tmp;
short opcodes[256];
int i, j;
memcpy(opcodes, _opcodes, sizeof(opcodes));
qsort(opcodes, 256, sizeof(short), compare);
for (i=0; ihash2 = 0;
if (do_sig) sig->sig = 0;
for (i=0; isig += opcodes[i] * i;
sig->hash2 = ror(sig->hash2, 13);
sig->hash2 += _opcodes[i];
}
return 0;
}
/*------------------------------------------------*/
/* function : sig_parse_dref_list */
/* description: checks if the data ref is a class */
/* like structure. Returns class ea */
/* on success */
/*------------------------------------------------*/
ea_t sig_parse_dref_list(psig_t * sig, ea_t ea)
{
ea_t fref;
flags_t f;
// scan up
do
{
fref = get_first_dref_from(ea);
if (fref == BADADDR)
return BADADDR;
f = getFlags(fref);
if (!isCode(f))
return BADADDR;
fref = get_first_dref_to(ea);
if (fref != BADADDR)
{
f = getFlags(fref);
if (!isCode(f))
return BADADDR;
return ea;
}
ea = prev_visea(ea);
} while(ea != BADADDR);
return ea;
}
/*------------------------------------------------*/
/* function : sig_is_class */
/* description: Returns true is the signature is */
/* a class */
/*------------------------------------------------*/
bool sig_is_class(psig_t * sig)
{
if (sig->sig == CLASS_SIG && sig->hash == CLASS_SIG && sig->crc_hash == CLASS_SIG)
return true;
return false;
}
/*------------------------------------------------*/
/* function : sig_class_generate */
/* description: generates a signature for the */
/* class structure */
/*------------------------------------------------*/
psig_t * sig_class_generate(ea_t ea)
{
func_t * xfct;
psig_t * sig;
ea_t fref;
char buf[512];
sig = sig_init();
if (!sig)
return NULL;
// Adds function start address
sig_set_start(sig, ea);
// Adds function name
qsnprintf(buf, sizeof(buf), "sub_%a", ea);
sig_set_name(sig, buf);
// Adds class references
fref = get_first_dref_to(ea);
while (fref != BADADDR)
{
xfct = get_func(fref);
if (xfct)
sig_add_sref(sig, xfct->startEA, 0, CHECK_REF);
fref = get_next_dref_to(ea, fref);
}
sig->hash = sig->crc_hash = sig->sig = CLASS_SIG;
return sig;
}
/*------------------------------------------------*/
/* function : sig_generate */
/* description: generates a signature for the */
/* given function */
/*------------------------------------------------*/
psig_t * sig_generate(size_t fct_num, qvector & class_l)
{
func_t * fct, * xfct;
pflow_chart_t * fchart;
psig_t * sig;
ea_t fref, ea;
int bnum, i;
char buf[512];
short opcodes[256];
qvector call_list;
flags_t f;
fct = getn_func(fct_num);
memset(opcodes, '\0', sizeof(opcodes));
fchart = new pflow_chart_t(fct);
sig = sig_init();
if (!sig)
{
delete fchart;
return NULL;
}
sig->type = 1;
// Adds function start address
sig_set_start(sig, fct->startEA);
// Adds function name
if (pget_func_name(fct->startEA, buf, sizeof(buf)))
sig_set_name(sig, buf);
else return NULL;
// Adds function references
fref = get_first_dref_to(fct->startEA);
while (fref != BADADDR)
{
f = getFlags(fref);
if (isCode(f))
{
xfct = get_func(fref);
if (xfct && xfct->startEA != fct->startEA)
sig_add_pref(sig, xfct->startEA, 0, CHECK_REF);
}
else
{
ea = sig_parse_dref_list(sig, fref);
if (ea != BADADDR)
{
sig_add_pref(sig, ea, 0, CHECK_REF);
class_l.add_unique(ea);
}
}
fref = get_next_dref_to(fct->startEA, fref);
}
// Adds each block to the signature
bnum = fchart->nproper;
sig->hash = 0;
sig->sig = 0;
for (i=0; insucc(i);
sig->sig += (i+1) + smax*i;
sig_add_block(sig, opcodes, fchart->blocks[i].startEA, fchart->blocks[i].endEA, 0, 0);
for(j=0; jhash = ror(sig->hash, 13);
ttype = fchart->blocks[i].succ[j].type;
if (ttype == 2) ttype--;
sig->hash += ttype;
}
}
sig_calc_sighash(sig, opcodes, 0);
delete fchart;
return sig;
}
/*------------------------------------------------*/
/* function : sig_save */
/* description: Saves signature refs to disk */
/*------------------------------------------------*/
void sig_save_refs(FILE * fp, frefs_t * refs)
{
int num, i;
fref_t * tmp;
if (refs)
{
num = refs->num;
qfwrite(fp, &num, sizeof(num));
tmp = refs->list;
for (i=0; iea, sizeof(tmp->ea));
qfwrite(fp, &tmp->type, sizeof(tmp->type));
tmp = tmp->next;
}
}
else
{
num = 0;
qfwrite(fp, &num, sizeof(num));
}
}
/*------------------------------------------------*/
/* function : sig_save */
/* description: Saves signature to disk */
/*------------------------------------------------*/
int sig_save(psig_t * sig, FILE * fp)
{
size_t len;
// saves function name
len = strlen(sig->name);
qfwrite(fp, &len, sizeof(len));
qfwrite(fp, sig->name, len);
// saves function start address
qfwrite(fp, &sig->startEA, sizeof(sig->startEA));
// saves function lines
qfwrite(fp, &sig->dl.num, sizeof(sig->dl.num));
qfwrite(fp, sig->dl.lines, sig->dl.num);
// saves sig/hash
qfwrite(fp, &sig->sig, sizeof(sig->sig));
qfwrite(fp, &sig->hash, sizeof(sig->hash));
qfwrite(fp, &sig->hash2, sizeof(sig->hash2));
qfwrite(fp, &sig->crc_hash, sizeof(sig->crc_hash));
qfwrite(fp, &sig->str_hash, sizeof(sig->str_hash));
// saves function refs
sig_save_refs(fp, sig->prefs);
sig_save_refs(fp, sig->srefs);
return 0;
}
/*------------------------------------------------*/
/* function : sig_load_prefs */
/* description: Loads signature refs from disk */
/*------------------------------------------------*/
void sig_load_prefs(psig_t * sig, FILE * fp, int type)
{
int num, i;
pedge_t * eatab;
// loads function refs in reverse order
qfread(fp, &num, sizeof(num));
eatab = (pedge_t *)qalloc(num * sizeof(*eatab));
for (i=0; i0; i--)
{
if (type == SIG_PRED)
sig_add_pref(sig, eatab[i-1].ea, eatab[i-1].type, CHECK_REF);
else
sig_add_sref(sig, eatab[i-1].ea, eatab[i-1].type, CHECK_REF);
}
qfree(eatab);
}
/*------------------------------------------------*/
/* function : sig_load */
/* description: Loads signature from disk */
/*------------------------------------------------*/
psig_t * sig_load(FILE * fp)
{
size_t len;
psig_t * sig;
char buf[512];
sig = sig_init();
if (!sig) return NULL;
// loads function name
qfread(fp, &len, sizeof(len));
qfread(fp, buf, len);
buf[len] = '\0';
sig_set_name(sig, buf);
// loads function start address
qfread(fp, &sig->startEA, sizeof(sig->startEA));
// loads function line
qfread(fp, &sig->dl.num, sizeof(sig->dl.num));
sig->dl.lines = (char *)qalloc((sig->dl.num+1) * sizeof(char));
if (sig->dl.lines)
{
qfread(fp, sig->dl.lines, sig->dl.num);
sig->dl.lines[sig->dl.num] = '\0';
}
else
sig->dl.num = 0;
// loads sig/hash
qfread(fp, &sig->sig, sizeof(sig->sig));
qfread(fp, &sig->hash, sizeof(sig->hash));
qfread(fp, &sig->hash2, sizeof(sig->hash2));
qfread(fp, &sig->crc_hash, sizeof(sig->crc_hash));
qfread(fp, &sig->str_hash, sizeof(sig->str_hash));
// loads sig refs
sig_load_prefs(sig, fp, SIG_PRED);
sig_load_prefs(sig, fp, SIG_SUCC);
return sig;
}
/*------------------------------------------------*/
/* function : siglist_init */
/* description: Initializes a new signature list */
/*------------------------------------------------*/
slist_t * siglist_init(size_t num, char * file)
{
slist_t * l;
l = (slist_t *)qalloc(sizeof(*l));
if (!l) return NULL;
l->file = file;
l->num = 0;
l->org_num = num;
l->sigs = (psig_t **)qalloc(num * sizeof(*l->sigs));
if (!l->sigs && l->org_num != 0)
{
qfree(l);
return NULL;
}
return l;
}
/*------------------------------------------------*/
/* function : siglist_realloc */
/* description: Realloc a signature list */
/*------------------------------------------------*/
bool siglist_realloc(slist_t * sl, size_t num)
{
psig_t ** sigs;
sigs = (psig_t **)qrealloc(sl->sigs, (sl->org_num + num) * sizeof(*sl->sigs));
if (!sigs)
return false;
sl->org_num += num;
sl->sigs = sigs;
return true;
}
/*------------------------------------------------*/
/* function : sig_compare */
/* description: Compares two signature */
/*------------------------------------------------*/
int OS_CDECL sig_compare(const void *arg1, const void *arg2)
{
unsigned long v1, v2;
v1 = (*(psig_t **)arg1)->sig;
v2 = (*(psig_t **)arg2)->sig;
if (v2 > v1) return 1;
if (v2 < v1) return -1;
v1 = (*(psig_t **)arg1)->hash;
v2 = (*(psig_t **)arg2)->hash;
if (v2 > v1) return 1;
if (v2 < v1) return -1;
v1 = (*(psig_t **)arg1)->crc_hash;
v2 = (*(psig_t **)arg2)->crc_hash;
if (v2 > v1) return 1;
if (v2 < v1) return -1;
v1 = (*(psig_t **)arg1)->str_hash;
v2 = (*(psig_t **)arg2)->str_hash;
if (v2 > v1) return 1;
if (v2 < v1) return -1;
return 0;
}
/*------------------------------------------------*/
/* function : siglist_sort */
/* description: Sorts the signature to the list */
/*------------------------------------------------*/
void siglist_sort(slist_t * sl)
{
qsort(sl->sigs, sl->num, sizeof(*sl->sigs), sig_compare);
}
/*------------------------------------------------*/
/* function : siglist_add */
/* description: Adds a new signature to the list */
/*------------------------------------------------*/
void siglist_add(slist_t * sl, psig_t * sig)
{
if (sl->num >= sl->org_num)
{
if (!siglist_realloc(sl, 32))
return;
}
sig->node = sl->num;
sl->sigs[sl->num++] = sig;
}
/*------------------------------------------------*/
/* function : siglist_remove */
/* description: Removes a new signature to the */
/* list */
/*------------------------------------------------*/
void siglist_remove(slist_t * sl, size_t n)
{
if ( (n+1) < sl->num )
memmove(&sl->sigs[n], &sl->sigs[n+1], ((sl->num - 1) - n) * sizeof(*(sl->sigs)));
sl->num--;
}
/*------------------------------------------------*/
/* function : siglist_free */
/* description: Frees a new signature list */
/*------------------------------------------------*/
void siglist_free(slist_t * sl)
{
size_t i;
for (i=0; inum; i++)
sig_free(sl->sigs[i]);
qfree(sl->sigs);
qfree(sl);
}
/*------------------------------------------------*/
/* function : siglist_partial_free */
/* description: Frees a new signature list */
/*------------------------------------------------*/
void siglist_partial_free(slist_t * sl)
{
qfree(sl->sigs);
qfree(sl);
}
/*------------------------------------------------*/
/* function : siglist_getnum */
/* description: Returns number of signature in */
/* list */
/*------------------------------------------------*/
size_t siglist_getnum(slist_t * sl)
{
return sl->num;
}
/*------------------------------------------------*/
/* function : siglist_save */
/* description: Saves signature list to disk */
/*------------------------------------------------*/
int siglist_save(slist_t * sl, const char * filename)
{
FILE * fp;
size_t num, i;
fp = qfopen(filename, "wb+");
if (fp == 0) return -1;
num = siglist_getnum(sl);
qfwrite(fp, &num, sizeof(num));
for (i=0; isigs[i], fp);
qfclose(fp);
return 0;
}
/*------------------------------------------------*/
/* function : siglist_load */
/* description: Loads signature list from disk */
/*------------------------------------------------*/
slist_t * siglist_load(const char *filename)
{
FILE * fp;
slist_t * sl;
psig_t * sig;
size_t num, i;
fp = qfopen(filename, "rb");
if (fp < 0) return NULL;
if (qfread(fp, &num, sizeof(num)) != sizeof(num))
{
qfclose(fp);
return NULL;
}
sl = siglist_init(num, NULL);
if (!sl)
{
qfclose(fp);
return NULL;
}
for (i=0; i