/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: dumper.cpp 1918 2008-07-30 14:06:24Z itsme $ */ #include #include #include #include #include #include #include "boost/format.hpp" #include #include #include "pro.h" // for basic types. #include "ida.hpp" // for ida constants and types. #include "idp.hpp" // for interface version #include "netnode.hpp" // for RootNode #include "expr.hpp" // for IDCFuncs typedef std::vector CharVector; #define vectorptr(v) (&(v)[0]) typedef struct { char *function_name; // 00 char *end_function_name; // 04 ulong w1; // 08 ulong w2; // 0c uchar *after_end_fnname; // 10 ulong w4; // 14 ulong nrparams; // 18 uchar *body; // 1c uchar *end_body; // 20 ulong w5; // 24 ulong w6; // 28 ulong w7; // 2c ulong w8; // 30 } compiled_func1_t; typedef struct { char *function_name; // 00 char *end_function_name; // 04 ulong w1; // 08 ulong w2; // 0c uchar *after_end_fnname; // 10 ulong w4; // 14 ulong nrparams; // 18 uchar *body; // 1c ulong bodysize; // 20 ulong w5; // 24 } compiled_func2_t; // !!! GLOBAL ... initialized by dump_compiled_functions // used by disassemble, to resolve compiled functions indexes. compiled_func1_t *g_flist1; compiled_func1_t *g_end1; compiled_func2_t *g_flist2; compiled_func2_t *g_end2; std::string getcompiledname(int id) { if (g_flist1) return g_flist1[id].function_name; else if (g_flist2) return g_flist2[id].function_name; else return "unknown!!!"; } std::string hexdump(const uchar *p, int len) { if (p==NULL) return "(null)"; std::string str; for (int i=0 ; i=' ' && tag<='~') { char strbuf[2]; strbuf[0]= tag; strbuf[1]= 0; return std::string(strbuf); } else { char strbuf[16]; qsnprintf(strbuf, 16, "%02x", (uchar)tag); return std::string(strbuf); } } std::ostream& operator<<(std::ostream& os, nodeidx_t idx) { return os << boost::format("%08lx") % ((int)idx); } #if IDP_INTERFACE_VERSION<76 std::ostream& operator<<(std::ostream& os, netnode& node) { os << boost::format("node %08lx ll=%d %s\n") % ((nodeidx_t)node) % node.last_length() % (node.name()?node.name():"(null)"); if (node.value_exists()) { os << boost::format("long_value: %08lx str=%s\n") % ascdump((unsigned char*)node.value(), MAXSPECSIZE); } else { os << "no value\n"; } for (int tag= 0 ; tag < 0x100 ; tag++) for (nodeidx_t idx= node.sup1st(tag) ; idx!=BADNODE ; idx= node.supnxt(idx, tag)) { os << boost::format("[%s, %08lx] : alt=%08lx ch=%02x sup=%s\n") % tagstr(tag) % idx % node.altval(idx, tag) % ((int)node.charval(idx, tag)) % ascdump((unsigned char*)node.supval(idx, tag), MAXSPECSIZE); } /* for (int tag=0 ; tag<0x100 ; tag++) for (char* idx= node.hash1st(tag) ; idx ; idx=node.hashnxt(idx, tag)) os << boost::format("hashval(%s, %s) : %s\n") % tagstr(tag) % idx % (node.hashval(idx, tag)?node.hashval(idx, tag):"(null)"); */ /* ... netlink is missing from ida.lib netlink l; if (l.start()) os << boost::format("listing links of type %s\n") % l.name(); do { for (netnode n= l.firstlink(node); n!=BADNODE ; n= l.nextlink(node, n)) { os << boost::format(" link to %08lx %s\n") % (nodeidx_t)n % n.name(); } } while (l.next()); */ return os; } #else // idp >= 76 std::ostream& operator<<(std::ostream& os, netnode& node) { char name[MAXNAMESIZE]; char buf[MAXSPECSIZE]; os << boost::format("node %08lx %s %s\n") % ((nodeidx_t)node) % ascdump((unsigned char*)name, node.name(name, MAXNAMESIZE)) % ascdump((unsigned char*)buf, node.valobj(buf, MAXSPECSIZE)); for (int tag= 0 ; tag < 0x100 ; tag++) for (nodeidx_t idx= node.sup1st(tag) ; idx!=BADNODE ; idx= node.supnxt(idx, tag)) { os << boost::format("[%s, %08lx] : %s\n") % tagstr(tag) % idx % ascdump((unsigned char*)buf, node.supval(idx, buf, MAXSPECSIZE, tag)); } for (int tag=0 ; tag<0x100 ; tag++) { char idx[2][1024]; int hs[2]; hs[0]=0; hs[1]=0; int i=0; memset(idx, 0, sizeof(idx)); for (hs[i]= node.hash1st(idx[i], 1024, tag) ; hs[i]>0 ; hs[i]=node.hashnxt(idx[i^1], idx[i], 1024, tag)) { if (hs[0]==hs[1] && memcmp(idx[0], idx[1], hs[0])==0) break; i ^= 1; if (node.supval(*(sval_t*)idx[i^1], NULL, 0, tag)<0) os << boost::format("hashval(%s, %s) : %s\n") % tagstr(tag) % ascdump((unsigned char*)idx[i^1], hs[i^1]) % ascdump((unsigned char*)buf, node.hashval(idx[i^1], buf, MAXSPECSIZE, tag)); } } /* ... netlink is missing from ida.lib netlink l; if (l.start()) os << boost::format("listing links of type %s\n") % l.name(); do { for (netnode n= l.firstlink(node); n!=BADNODE ; n= l.nextlink(node, n)) { os << boost::format(" link to %08lx %s\n") % (nodeidx_t)n % n.name(); } } while (l.next()); */ return os; } #endif std::string functionargs_string(const char *args) { std::string str; if (args==NULL) return "(null)"; while (*args) { if (!str.empty()) str += ", "; switch(*args) { case VT_STR: str += "string"; break; case VT_LONG: str += "long"; break; case VT_FLOAT: str += "float"; break; case VT_WILD: str += "..."; break; default: char strbuf[16]; qsnprintf(strbuf, 16, "VT_%08lx", *args); str += strbuf; } args++; } return str; } std::string escapestring(const std::string& ascstr) { std::string esc; for (std::string::const_iterator i= ascstr.begin() ; i!=ascstr.end() ; ++i) { if ((*i)=='\n') esc += "\\n"; // 0x0a newline else if ((*i)=='\r') esc += "\\r"; // 0x0d carriage return else if ((*i)=='\t') esc += "\\t"; // 0x09 tab else if ((*i)=='\\') esc += "\\\\"; // 0x5c backslash else if ((*i)=='\v') esc += "\\v"; // 0x0b vertical tab else if ((*i)=='\b') esc += "\\b"; // 0x08 backspace else if ((*i)=='\f') esc += "\\f"; // 0x0c form feed else if ((*i)=='\a') esc += "\\a"; // 0x07 bell else if ((*i)=='\"') esc += "\\\""; // 0x22 double quote else if (isprint(*i)) esc += (*i); else esc += str(boost::format("\\x%02x") % (int)(*i)); } return esc; } void disassemble(std::ostream&os, const uchar *body, int len) { for (int i=0 ; i= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; call %04x %s\n") % byte % byte % IDCFuncs.f[byte].name; i++; break; case 0x81: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; call %04x %s\n") % word % word % IDCFuncs.f[word].name; i += 2; break; case 0x82: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; call compiled func %02x %s\n") % byte % byte % getcompiledname(byte); i++; break; case 0x83: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; call compiled func %04x %s\n") % word % word % getcompiledname(word); i += 2; break; case 0x84: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; pop var%02x\n") % byte % byte; i++; break; case 0x85: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; pop var%04x\n") % word % word; i += 2; break; case 0x86: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; param%02x := tos\n") % byte % byte; i++; break; case 0x87: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; param%04x := tos\n") % word % word; i += 2; break; case 0x88: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; var%02x := tos\n") % byte % byte; i++; break; case 0x89: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; var%04x := tos\n") % word % word; i += 2; break; case 0x8a: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; pop param%02x\n") % byte % byte; i++; break; case 0x8b: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; pop param%04x\n") % word % word; i += 2; break; case 0x8c: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; push var%02x\n") % byte % byte; i++; break; case 0x8d: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; push var%04x\n") % word % word; i += 2; break; case 0x8e: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; push param%02x\n") % byte % byte; i++; break; case 0x8f: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; push param%04x\n") % word % word; i += 2; break; case 0xa0: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; push #%02x\n") % byte % byte; i++; break; case 0xa1: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; push #%04x\n") % word % word; i+=2; break; case 0xa2: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; unknown %02x\n") % byte % byte; i++; break; case 0xa3: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; unknown %04x\n") % word % word; i+=2; break; case 0xa4: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; allocate %d local variables\n") % byte % byte; i++; break; case 0xa5: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; allocate %d local variables\n") % word % word; i+=2; break; case 0xa6: os << boost::format(" ; unknown\n"); break; case 0xa7: if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %08x ; push #%08x\n") % dword % dword; i+=4; break; case 0xa8: if (i >= len-2-word) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ... ; push \"%s\"\n") % word % escapestring(std::string((char*)body+i+3, word)).c_str(); i+=word+2; break; case 0xa9: os << boost::format(" ; pop\n"); break; case 0xaa: os << boost::format(" ; start function param list\n"); break; case 0xab: if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %08x ; branch always %08x -> %04x\n") % dword % dword % (i+dword+5); i+=4; break; case 0xac: if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %08x ; branch do_while true %08x -> %04x\n") % dword % dword % (i+dword+5); i+=4; break; case 0xad: if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %08x ; branch if true %08x -> %04x\n") % dword % dword % (i+dword+5); i+=4; break; case 0xae: if (i >= len-2-word) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ... ; call by name \"%s\"\n") % word % escapestring(std::string((char*)body+i+3, word)).c_str(); i+=word+2; break; case 0xaf: os << boost::format(" ; return\n"); break; case 0xb0: os << boost::format(" ; add\n"); break; case 0xb1: os << boost::format(" ; substract\n"); break; case 0xb2: os << boost::format(" ; multiply\n"); break; case 0xb3: os << boost::format(" ; divide\n"); break; case 0xb4: os << boost::format(" ; modulus\n"); break; case 0xb5: os << boost::format(" ; logical or\n"); break; case 0xb6: os << boost::format(" ; logical and\n"); break; case 0xb7: os << boost::format(" ; logical not\n"); break; case 0xb8: os << boost::format(" ; bitwise or\n"); break; case 0xb9: os << boost::format(" ; bitwise and\n"); break; case 0xba: os << boost::format(" ; bitwise xor\n"); break; case 0xbb: os << boost::format(" ; unary bitwise negate\n"); break; case 0xbc: os << boost::format(" ; shiftright\n"); break; case 0xbd: os << boost::format(" ; shiftleft\n"); break; case 0xbe: os << boost::format(" ; unary minus\n"); break; // case 0xbf: unused case 0xc0: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; increment var%02x\n") % byte % byte; i++; break; case 0xc1: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; increment var%04x\n") % word % word; i += 2; break; case 0xc2: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; increment param%02x\n") % byte % byte; i++; break; case 0xc3: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; increment param%04x\n") % word % word; i+=2; break; case 0xc4: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; decrement var%02x\n") % byte % byte; i++; break; case 0xc5: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; decrement var%04x\n") % word % word; i+=2; break; case 0xc6: if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %02x ; decrement param%02x\n") % byte % byte; i++; break; case 0xc7: if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" %04x ; decrement param%04x\n") % word % word; i+=2; break; case 0xc8: os << boost::format(" ; compare ==\n"); break; case 0xc9: os << boost::format(" ; compare !=\n"); break; case 0xca: os << boost::format(" ; compare <=\n"); break; case 0xcb: os << boost::format(" ; compare >=\n"); break; case 0xcc: os << boost::format(" ; compare <\n"); break; case 0xcd: os << boost::format(" ; compare >\n"); break; case 0xce: os << boost::format(" ; cv to integer\n"); break; case 0xcf: os << boost::format(" ; cv to string\n"); break; case 0xd0: os << boost::format(" ; cv to float\n"); break; case 0xd1: if (i >= len-12) { os << boost::format("\nERROR: unexpected end of code\n"); break; } os << boost::format(" .......... ; push float %s\n") % hexdump(body+i+1, 12); i+=12; break; case 0xd3: os << boost::format(" ; unknown\n"); break; // case 0xd2 .. 0xdf: unused default: os << boost::format(" ; ERROR: unused opcode\n"); } } } } void funcbody(std::ostream&os, const char *name) { int nargs=0; size_t bodylen=0; #if IDP_INTERFACE_VERSION>=70 // get_idc_func_body is only available since version 4.70 uchar *body= get_idc_func_body(name, &nargs, &bodylen); if (body) { os << boost::format("body: %08lx-%08lx: %s(%d)\n") % ((int)body) % ((int)body+bodylen) % name % nargs; disassemble(os, body, bodylen); os << "\n"; } #endif } std::ostream& operator<<(std::ostream& os, const extfun_t& f) { funcbody(os, f.name); #if IDP_INTERFACE_VERSION>70 return os << boost::format("fu=%08lx fl=%08lx %s(%s)") % ((int)f.fp) % f.flags % (f.name ? f.name : "(null)") % functionargs_string(f.args); #else // no 'flags' in ida 4.70 and earlier return os << boost::format("fu=%08lx %s(%s)") % ((int)f.fp) % f.name % functionargs_string(f.args); #endif } std::ostream& operator<<(std::ostream& os, funcset_t& fset) { os << boost::format("%d functions in set %08lx\n") % fset.qnty % (long)&fset; for (int i=0 ; istart; g_end1= flist->end; for (compiled_func1_t *f= g_flist1 ; fbody) % ((int)f->end_body) % f->function_name % ((int)f->nrparams); disassemble(os, f->body, f->end_body-f->body); } } void dump_idc_funcs2(std::ostream& os, listinfo2_t *flist) { g_flist2= flist->start; g_end2= flist->start+flist->count; for (compiled_func2_t *f= g_flist2 ; fbody) % (((int)f->body)+f->bodysize) % f->function_name % ((int)f->nrparams); disassemble(os, f->body, f->bodysize); } } void dump_idc_funcs(std::ostream& os) { DWORD listptr= 0; int type=0; switch((DWORD)&IDCFuncs) { //case 0x100b76b8: flist=(listinfo_t*) 0; break; //case 0x1009ad8c: flist=(listinfo_t*) 0; break; //case 0x100b31e4: flist=(listinfo_t*) 0; break; //case 0x100b5224: flist=(listinfo_t*) 0; break; case 0x100baaf3: type=1; listptr= 0x100db2bc; break; // ?? 0x100EC1B0; case 0x100bf3c0: type=1; listptr= 0x100F3CCC; break; case 0x100d3748: type=1; listptr= 0x101019C0; break; case 0x100e9778: type=1; listptr= 0x1011c2c0; break; case 0x100eb778: type=1; listptr= 0x1011e880; break; case 0x100f9f44: type=1; listptr= 0x1012a860; break; //case 0x100f9a44: type=1; listptr= 0; break; case 0x1010837a: type=2; listptr= 0x10136ef0; break; case 0x10103116: type=2; listptr= 0x101310C0; if (*(DWORD*)listptr==0) listptr= 0x101310AC; break; case 0x1010a63e: type=2; listptr= 0x10137224; break; } if (listptr==NULL) { msg("IDCFuncs unknown: %08lx\n", &IDCFuncs); return; } if (type==1) dump_idc_funcs1(os, (listinfo1_t *)listptr); else if (type==2) dump_idc_funcs2(os, (listinfo2_t *)listptr); } void dump_db(int flags) { std::filebuf fb; fb.open("dump_db.log", std::ios::out); std::ostream os(&fb); if (flags&1) { os << "------------rootnode-----------\n"; os << RootNode; os << "------------node.start.next-----------\n"; netnode n; if (n.start()) do { os << n; } while (n.next()); } else { os << "------------idcfuncs-----------\n"; os << IDCFuncs; // note: there seems to be no official way of getting a list of // currently loaded idc functions. os << "------------compiled functions-----------\n"; // most of these functions are from // http://www.xs4all.nl/~itsme/projects/disassemblers/ida.html // http://nah6.com/~itsme/cvs-xdadevtools/idcscripts/formatdata.idc dump_idc_funcs(os); } }