/* 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.h" #include "sig.h" #include "x86.h" #include "ppc.h" #include "patchdiff.h" #include "pchart.h" #include "os.h" 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; #if IDA_SDK_VERSION <= 670 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); #else qstring name; qstring demangled; int32 dm_res; if (get_func_name2(&name, ea) == 0) { return NULL; } qstrncpy(buffer, name.c_str(), blen); #if IDA_SDK_VERSION < 730 uint32 long_demnames = inf.long_demnames; #else uint32 long_demnames = inf_get_long_demnames(); #endif dm_res = demangle_name2(&demangled, name.c_str(), long_demnames); if (dm_res >= 0) { if ( (demangled.find("public: static") != -1 || demangled.find("private: static") != -1) && (demangled.find("(") == -1 || demangled.find("public: static long (__stdcall") == -1) ) { return NULL; } #if IDA_SDK_VERSION < 730 uint32 short_demnames = inf.short_demnames; #else uint32 short_demnames = inf_get_short_demnames(); #endif dm_res = demangle_name2(&demangled, name.c_str(), short_demnames); qstrncpy(buffer, demangled.c_str(), blen); } #endif // remove duplicates of the same name pos = strstr(buffer, "Z$0"); if (pos) { pos[0] = '\0'; } return buffer; } /*------------------------------------------------*/ /* function : sig_t::sig_t() */ /* description: Allocates and initializes a new */ /* function signature */ /*------------------------------------------------*/ sig_t::sig_t() { memset(this, 0, sizeof(sig_t)); mtype = DIFF_UNMATCHED; msig = NULL; } /*------------------------------------------------*/ /* function : frefs_free */ /* description: Frees chained list */ /*------------------------------------------------*/ void frefs_free(frefs_t *frefs) { fref_t *fref; fref_t *next; fref = frefs->list; while (fref) { next = fref->next; delete fref; fref = next; } delete frefs; } /*------------------------------------------------*/ /* function : ~dpsig_t */ /* description: Frees chained list */ /*------------------------------------------------*/ dpsig_t::~dpsig_t() { if (next) { delete next; } } /*------------------------------------------------*/ /* function : sig_t:~sig_t() */ /* description: Frees signature */ /*------------------------------------------------*/ sig_t::~sig_t() { if (dl.lines) { delete [] dl.lines; } if (prefs) { frefs_free(prefs); } if (srefs) { frefs_free(srefs); } if (cp) { delete cp; } if (cs) { delete cs; } } /*------------------------------------------------*/ /* function : sig_set_name */ /* description: Sets function signature name */ /*------------------------------------------------*/ void sig_t::set_name(const char *_name) { name = _name; } void sig_t::set_name(const qstring &_name) { name = _name; } /*------------------------------------------------*/ /* function : sig_set_start */ /* description: Sets function start address */ /*------------------------------------------------*/ void sig_t::set_start(ea_t ea) { startEA = ea; } /*------------------------------------------------*/ /* function : sig_get_start */ /* description: Returns function start address */ /*------------------------------------------------*/ ea_t sig_t::get_start() { return startEA; } /*------------------------------------------------*/ /* function : sig_get_preds */ /* description: Returns signature pred xrefs */ /*------------------------------------------------*/ frefs_t *sig_t::get_preds() { return prefs; } /*------------------------------------------------*/ /* function : sig_get_succs */ /* description: Returns signature succ xrefs */ /*------------------------------------------------*/ frefs_t *sig_t::get_succs() { return srefs; } /*------------------------------------------------*/ /* function : sig_get_crefs */ /* description: Returns signature cxrefs */ /*------------------------------------------------*/ clist_t *sig_t::get_crefs(int _type) { if (_type == SIG_PRED) { return cp; } if (_type == SIG_SUCC) { return cs; } return NULL; } /*------------------------------------------------*/ /* function : sig_set_crefs */ /* description: Sets signature cxrefs */ /*------------------------------------------------*/ void sig_t::set_crefs(int _type, clist_t *_cl) { if (_type == SIG_PRED) { cp = _cl; } else if (_type == SIG_SUCC) { cs = _cl; } } /*------------------------------------------------*/ /* function : sig_set_nfile */ /* description: Sets file number */ /*------------------------------------------------*/ void sig_t::set_nfile(int _num) { nfile = _num; } /*------------------------------------------------*/ /* function : sig_set_matched_sig */ /* description: Sets matched address */ /*------------------------------------------------*/ void sig_t::set_matched_sig(sig_t *_sig2, int _type) { msig = _sig2; matchedEA = _sig2->startEA; _sig2->msig = this; _sig2->matchedEA = startEA; mtype = _sig2->mtype = _type; if (crc_hash != _sig2->crc_hash) id_crc = _sig2->id_crc = 1; } /*------------------------------------------------*/ /* function : sig_get_matched_sig */ /* description: Returns matched address */ /*------------------------------------------------*/ sig_t *sig_t::get_matched_sig() { return msig; } /*------------------------------------------------*/ /* function : sig_get_matched_type */ /* description: Returns matched type */ /*------------------------------------------------*/ int sig_t::get_matched_type() { return 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; fref_t *next; if (!*frefs) { *frefs = new frefs_t(); 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 = new fref_t(); 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_t::add_pref(ea_t _ea, int _type, char _rtype) { return sig_add_fref(&prefs, _ea, _type, _rtype); } /*------------------------------------------------*/ /* function : sig_add_sref */ /* description: Adds a function reference to the */ /* signature */ /*------------------------------------------------*/ int sig_t::add_sref(ea_t _ea, int _type, char _rtype) { return sig_add_fref(&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 sig_t::is_jump(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 (type == 1) { add_sref(_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: { #if IDA_SDK_VERSION >= 700 insn_t cmd; decode_insn(&cmd, ea); #else decode_insn(ea); #endif return (char)cmd.itype; } } } unsigned long ror(unsigned long val, int r) { return (val >> r) | (val << (32-r)); } /*------------------------------------------------*/ /* function : dline_add */ /* description: Adds a disassembled line to the */ /* signature */ /*------------------------------------------------*/ #if IDA_SDK_VERSION < 700 int dline_add(dline_t *dl, ea_t ea, char options) { char buf[256]; char tmp[256]; char dis[256]; char addr[30]; int len; flags_t f; buf[0] = '\0'; f = getFlags(ea); generate_disasm_line(ea, dis, sizeof(dis)); decode_insn(ea); init_output_buffer(buf, sizeof(buf)); // Adds block label if (has_dummy_name(f)) { get_nice_colored_name(ea, tmp, sizeof(tmp), GNCN_NOSEG | GNCN_NOFUNC); out_snprintf("%s", tmp); out_line(":\n", COLOR_DATNAME); } if (options) { qsnprintf(addr, sizeof(addr), "%a", ea); out_snprintf("%s ", addr); } out_insert(get_output_ptr(), dis); term_output_buffer(); len = strlen(buf); if (dl->available < (len + 3)) { char *dll = new char[dl->num + len + 256]; if (!dll) { return -1; } if (dl->lines) { memcpy(dll, dl->lines, dl->num); delete dl->lines; } 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; } #else int dline_add(dline_t *dl, ea_t ea, char options) { qstring dis; insn_t cmd; qstring tmp; int len; flags_t f; f = get_flags(ea); generate_disasm_line(&dis, ea); decode_insn(&cmd, ea); outctx_base_t *pctx = create_outctx(ea); // Adds block label if (has_dummy_name(f)) { get_nice_colored_name(&tmp, ea, GNCN_NOSEG | GNCN_NOFUNC); pctx->out_printf("%s", tmp.c_str()); pctx->out_line(":\n", COLOR_DATNAME); } if (options) { pctx->out_printf("%a ", ea); } pctx->out_printf("%s", dis.c_str()); len = pctx->outbuf.length(); if (dl->available < (len + 3)) { char *dll = new char[dl->num + len + 256]; if (!dll) { return -1; } if (dl->lines) { memcpy(dll, dl->lines, dl->num); delete dl->lines; } dl->available = len + 256; dl->lines = dll; } if (dl->num) { dl->lines[dl->num] = '\n'; dl->num++; } memcpy(&dl->lines[dl->num], pctx->outbuf.c_str(), len); dl->available -= len + 1; dl->num += len; dl->lines[dl->num] = '\0'; delete pctx; return 0; } #endif /*------------------------------------------------*/ /* function : sig_add_address */ /* description: Adds an address to the signature */ /*------------------------------------------------*/ int sig_t::add_address(short opcodes[256], ea_t _ea, bool _b, bool _line, char _options) { unsigned char _byte; unsigned char _buf[200]; uint32_t _s, _i; bool _call; bool _cj; ea_t _tea; flags_t _f; if (_line) { dline_add(&dl, _ea, _options); } if (is_jump(_ea, &_call, &_cj)) { return -1; } _byte = get_byte_with_optimization(_ea); if (remove_instr(_byte, _ea)) { return -1; } lines++; opcodes[_byte]++; if (!_b && !_call) { if (_cj) { _buf[0] = _byte; _s = 1; } else { _s = (uint32_t)get_item_size(_ea); if (_s > sizeof(_buf)) { _s = sizeof(_buf); } get_many_bytes(_ea, _buf, _s); } for (_i = 0; _i < _s; _i++) { crc_hash += _buf[_i]; crc_hash += ( crc_hash << 10 ); crc_hash ^= ( 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; #if IDA_SDK_VERSION < 700 get_opinfo(_tea, 0, _f, &_op_info); #else get_opinfo(&_op_info, _tea, 0, _f); #endif _s = get_max_ascii_length(_tea, _op_info.strtype); #if IDA_SDK_VERSION < 700 if (!get_ascii_contents2(_tea, _s, _op_info.strtype, _buf, sizeof(_buf))) { _s = sizeof(_buf); } for (_i = 0; _i < _s; _i++) { str_hash += _buf[_i] * _i; } #else qstring _strlit; _s = get_strlit_contents(&_strlit, _tea, _s, _op_info.strtype); //the following attempts to match behavior of pre-7.0 patchdiff if (_s > sizeof(_buf)) { _s = sizeof(_buf); } for (_i = 0; _i < _s; _i++) { str_hash += _strlit[_i] * _i; } #endif } } } return 0; } /*------------------------------------------------*/ /* function : sig_add_block */ /* description: Adds a block to the signature */ /*------------------------------------------------*/ int sig_t::add_block(short _opcodes[256], ea_t _startEA, ea_t _endEA, bool _line, char _options) { ea_t _ea = _startEA; while (_ea < _endEA) { flags_t _flags = getFlags (_ea); if (!isCode (_flags)) { return -1; } bool _b = get_first_dref_from(_ea) != BADADDR ? true : false; add_address(_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_t::calc_sighash(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; _i < 256; _i++) { for (_j = 0; _j < 255; _j++) { if (opcodes[_j] > opcodes[_j + 1]) { _tmp = opcodes[_j + 1]; opcodes[_j + 1] = opcodes[_j]; opcodes[_j] = _tmp; } } } hash2 = 0; if (_do_sig) { sig = 0; } for (_i = 0; _i < 256; _i++) { if (_do_sig) { sig += opcodes[_i] * _i; } hash2 = ror(hash2, 13); hash2 += _opcodes[_i]; } return 0; } /*------------------------------------------------*/ /* function : parse_dref_list */ /* description: checks if the data ref is a class */ /* like structure. Returns class ea */ /* on success */ /*------------------------------------------------*/ ea_t parse_dref_list(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_t::is_class() { if (sig == CLASS_SIG && hash == CLASS_SIG && crc_hash == CLASS_SIG) { return true; } return false; } /*------------------------------------------------*/ /* function : sig_class_generate */ /* description: generates a signature for the */ /* class structure */ /*------------------------------------------------*/ sig_t *sig_class_generate(ea_t ea) { func_t *xfct; sig_t *sig; ea_t fref; sig = new sig_t(); if (!sig) { return NULL; } // Adds function start address sig->set_start(ea); // Adds function name sig->name.sprnt("sub_%a", ea); // Adds class references fref = get_first_dref_to(ea); while (fref != BADADDR) { xfct = get_func(fref); if (xfct) { sig->add_sref(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 */ /*------------------------------------------------*/ sig_t *sig_generate(size_t fct_num, qvector &class_l) { func_t *fct, *xfct; pflow_chart_t *fchart; sig_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 = new sig_t(); if (!sig) { delete fchart; return NULL; } sig->type = 1; // Adds function start address sig->set_start(fct->startEA); // Adds function name if (pget_func_name(fct->startEA, buf, sizeof(buf))) { sig->set_name(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(xfct->startEA, 0, CHECK_REF); } } else { ea = parse_dref_list(fref); if (ea != BADADDR) { sig->add_pref(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; i < bnum; i++) { int j; int ttype; int smax = fchart->nsucc(i); sig->sig += (i + 1) + smax * i; sig->add_block(opcodes, fchart->blocks[i].startEA, fchart->blocks[i].endEA, 0, 0); for (j = 0; j < smax; j++) { sig->hash = ror(sig->hash, 13); ttype = fchart->blocks[i].succ[j].type; if (ttype == 2) { ttype--; } sig->hash += ttype; } } sig->calc_sighash(opcodes, 0); delete fchart; return sig; } /*------------------------------------------------*/ /* function : sig_save */ /* description: Saves signature refs to disk */ /*------------------------------------------------*/ void sig_save_refs(FILE *fp, frefs_t *refs) { uint32_t num, i; fref_t *tmp; if (refs) { num = refs->num; qfwrite(fp, &num, sizeof(num)); tmp = refs->list; for (i = 0; i < num; i++) { qfwrite(fp, &tmp->ea, sizeof(tmp->ea)); qfwrite(fp, &tmp->type, sizeof(tmp->type)); tmp = tmp->next; } } else { num = 0; qfwrite(fp, &num, sizeof(num)); } } /*------------------------------------------------*/ /* function : sig_t::save */ /* description: Saves signature to disk */ /*------------------------------------------------*/ int sig_t::save(FILE *_fp) { uint32_t _len; // saves function name _len = name.length(); qfwrite(_fp, &_len, sizeof(_len)); qfwrite(_fp, name.c_str(), _len); // saves function start address qfwrite(_fp, &startEA, sizeof(startEA)); // saves function lines qfwrite(_fp, &dl.num, sizeof(dl.num)); qfwrite(_fp, dl.lines, dl.num); // saves sig/hash qfwrite(_fp, &sig, sizeof(sig)); qfwrite(_fp, &hash, sizeof(hash)); qfwrite(_fp, &hash2, sizeof(hash2)); qfwrite(_fp, &crc_hash, sizeof(crc_hash)); qfwrite(_fp, &str_hash, sizeof(str_hash)); // saves function refs sig_save_refs(_fp, prefs); sig_save_refs(_fp, srefs); return 0; } /*------------------------------------------------*/ /* function : sig_load_prefs */ /* description: Loads signature refs from disk */ /*------------------------------------------------*/ void sig_t::load_prefs(FILE *_fp, int _type) { uint32_t _num, _i; pedge_t *_eatab; // loads function refs in reverse order qfread(_fp, &_num, sizeof(_num)); _eatab = new pedge_t[_num]; for (_i = 0; _i < _num; _i++) { qfread(_fp, &_eatab[_i].ea, sizeof(_eatab[_i].ea)); qfread(_fp, &_eatab[_i].type, sizeof(_eatab[_i].type)); } for (_i = _num; _i > 0; _i--) { if (_type == SIG_PRED) { add_pref(_eatab[_i - 1].ea, _eatab[_i - 1].type, CHECK_REF); } else { add_sref(_eatab[_i - 1].ea, _eatab[_i - 1].type, CHECK_REF); } } delete [] _eatab; } /*------------------------------------------------*/ /* function : sig_load */ /* description: Loads signature from disk */ /*------------------------------------------------*/ sig_t *sig_load(FILE *fp) { uint32_t len; sig_t * sig; char buf[512]; sig = new sig_t(); if (!sig) { return NULL; } // loads function name qfread(fp, &len, sizeof(len)); qfread(fp, buf, len); buf[len] = '\0'; sig->set_name(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 = new char[sig->dl.num + 1]; 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(fp, SIG_PRED); sig->load_prefs(fp, SIG_SUCC); return sig; } /*------------------------------------------------*/ /* function : slist_t() */ /* description: Initializes a new signature list */ /*------------------------------------------------*/ bool slist_t::init(uint32_t initial_num, const char *file) { this->file = file; num = 0; org_num = initial_num; sigs = new sig_t *[initial_num]; if (!sigs && org_num != 0) { return false; } return true; } slist_t::slist_t(uint32_t num, const char *file) { init(num, file); } /*------------------------------------------------*/ /* function : slist_t::realloc */ /* description: Realloc a signature list */ /*------------------------------------------------*/ bool slist_t::realloc(uint32_t new_num) { sig_t **new_sigs = new sig_t *[org_num + new_num]; if (!new_sigs) { return false; } if (sigs) { memcpy(new_sigs, sigs, org_num * sizeof(sig_t*)); delete sigs; } org_num += new_num; sigs = new_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 = (*(sig_t **)arg1)->sig; v2 = (*(sig_t **)arg2)->sig; if (v2 > v1) { return 1; } if (v2 < v1) { return -1; } v1 = (*(sig_t **)arg1)->hash; v2 = (*(sig_t **)arg2)->hash; if (v2 > v1) { return 1; } if (v2 < v1) { return -1; } v1 = (*(sig_t **)arg1)->crc_hash; v2 = (*(sig_t **)arg2)->crc_hash; if (v2 > v1) { return 1; } if (v2 < v1) { return -1; } v1 = (*(sig_t **)arg1)->str_hash; v2 = (*(sig_t **)arg2)->str_hash; if (v2 > v1) { return 1; } if (v2 < v1) { return -1; } return 0; } /*------------------------------------------------*/ /* function : slist_t::sort */ /* description: Sorts the signature to the list */ /*------------------------------------------------*/ void slist_t::sort() { qsort(sigs, num, sizeof(*sigs), sig_compare); } /*------------------------------------------------*/ /* function : slist_t::add */ /* description: Adds a new signature to the list */ /*------------------------------------------------*/ void slist_t::add(sig_t *sig) { if (num >= org_num) { if (!realloc(32)) { return; } } sig->node = num; sigs[num++] = sig; } /*------------------------------------------------*/ /* function : slist_t::remove */ /* description: Removes a new signature to the */ /* list */ /*------------------------------------------------*/ void slist_t::remove(uint32_t n) { if ( (n+1) < num ) { memmove(&sigs[n], &sigs[n+1], ((num - 1) - n) * sizeof(*(sigs))); } num--; } /*------------------------------------------------*/ /* function : slist_t::~slist_t */ /* description: Frees a new signature list */ /*------------------------------------------------*/ slist_t::~slist_t() { delete [] sigs; } /*------------------------------------------------*/ /* function : slist_t::free_sigs */ /* description: Frees a new signature list */ /*------------------------------------------------*/ void slist_t::free_sigs() { for (uint32_t i = 0; i < num; i++) { delete sigs[i]; } } /*------------------------------------------------*/ /* function : slist_t::save */ /* description: Saves signature list to disk */ /*------------------------------------------------*/ int slist_t::save(const char *filename) { FILE * fp; uint32_t i; fp = qfopen(filename, "wb+"); if (fp == NULL) { return -1; } qfwrite(fp, &num, sizeof(num)); for (i = 0; i < num; i++) { sigs[i]->save(fp); } qfclose(fp); return 0; } /*------------------------------------------------*/ /* function : slist_t() */ /* description: Loads signature list from disk */ /*------------------------------------------------*/ slist_t::slist_t(const char *filename) { uint32_t init_num; num = 0; org_num = 0; file = NULL; dclk = false; gv = NULL; unique = false; msl = NULL; sigs = NULL; FILE *fp = qfopen(filename, "rb"); if (fp == NULL) { msg("slist_t::load: qfopen('%s', 'rb') failed\n", filename); } if (qfread(fp, &init_num, sizeof(init_num)) != sizeof(init_num)) { msg("slist_t::load: qfread(...) failed\n"); qfclose(fp); return; } if (init(init_num, NULL)) { for (uint32_t i = 0; i < init_num; i++) { add(sig_load(fp)); } sort(); } qfclose(fp); }