#include #include "vtable.idc" #include "ms_rtti.idc" static GetAsciizStr(x) { auto s,c; s = ""; while (c=Byte(x)) { s = form("%s%c",s,c); x = x+1; } return s; } // ??1?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@UAE@XZ // ??_G CWin32Heap@ATL @@UAEPAXI@Z // ATL::CWin32Heap::`scalar deleting destructor'(uint) // .?AV?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@ // ??_7?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@6B@ // ??_G?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@@@UAEPAXI@Z #define SN_constructor 1 #define SN_destructor 2 #define SN_vdestructor 3 #define SN_scalardtr 4 #define SN_vectordtr 5 static MakeSpecialName(name, type, adj) { auto basename; //.?AUA@@ = typeid(struct A) //basename = A@@ basename = substr(name,4,-1); if (type==SN_constructor) { //??0A@@QAE@XZ = public: __thiscall A::A(void) if (adj==0) return "??0"+basename+"QAE@XZ"; else return "??0"+basename+"W"+MangleNumber(adj)+"AE@XZ"; } else if (type==SN_destructor) { //??1A@@QAE@XZ = "public: __thiscall A::~A(void)" if (adj==0) return "??1"+basename+"QAE@XZ"; else return "??1"+basename+"W"+MangleNumber(adj)+"AE@XZ"; } else if (type==SN_vdestructor) { //??1A@@UAE@XZ = public: virtual __thiscall A::~A(void) if (adj==0) return "??1"+basename+"UAE@XZ"; else return "??1"+basename+"W"+MangleNumber(adj)+"AE@XZ"; } else if (type==SN_scalardtr) // { //??_GA@@UAEPAXI@Z = public: virtual void * __thiscall A::`scalar deleting destructor'(unsigned int) if (adj==0) return "??_G"+basename+"UAEPAXI@Z"; else return "??_G"+basename+"W"+MangleNumber(adj)+"AEPAXI@Z"; } else if (type==SN_vectordtr) { //.?AUA@@ = typeid(struct A) //??_EA@@UAEPAXI@Z = public: virtual void * __thiscall A::`vector deleting destructor'(unsigned int) if (adj==0) return "??_E"+basename+"QAEPAXI@Z"; else return "??_E"+basename+"W"+MangleNumber(adj)+"AEPAXI@Z"; } } static DumpNestedClass2(x, indent, contained, f) { auto indent_str,i,a,n,p,s,off; indent_str="";i=0; while(i0) //check numContainedBases DumpNestedClass2(a+4, indent+1, n, f); //nested classes following a=a+4*(n+1); i=i+n+1; } } static Parse_CHD2(x, indent, f) { auto indent_str,i,a,n,p,s,off; indent_str="";i=0; while(i ea ) // InSort { for ( ; idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) { val = GetArrayElement(AR_LONG, id, idx); SetArrayLong(id, idx, ea); ea = val; } } } SetArrayLong(id, GetLastIndex(AR_LONG, id) + 1, ea); } static getArraySize(id) { auto idx, count; count = 0; for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) { count++; } return count; } static doAddrList(name,f) { auto idx, id, val, ctr, dtr; id = GetArrayId("AddrList"); ctr = 0; dtr = 0; if ( name!=0 && id != -1 ) { Message("refcount:%d\n",getArraySize(id)); if (getArraySize(id)!=2) return; for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) { val = GetArrayElement(AR_LONG, id, idx); if (Byte(val)==0xE9) val = getRelJmpTarget(val); if ((substr(Name(val),0,3)=="??1")) dtr = val; else ctr = val; } } if (ctr!=0 && dtr!=0) { Message(" constructor at %a\n",ctr); fprintf(f, " constructor: %08.8Xh\n",ctr); MakeName(ctr, MakeSpecialName(name,SN_constructor,0)); } DeleteArray(GetArrayId("AddrList")); } //check if there's a vtable at a and dump into to f //returns position after the end of vtable static DoVtable(a,f) { auto x,y,s,p,q,i,name; //check if it looks like a vtable y = GetVtableSize(a); if (y==0) return a+4; s = form("%08.8Xh: possible vtable (%d methods)\n", a, y); Message(s); fprintf(f,s); //check if it's named as a vtable name = Name(a); if (substr(name,0,4)!="??_7") name=0; x = Dword(a-4); //otherwise try to get it from RTTI if (IsValidCOL(x)) { Parse_Vtable(a); if (name==0) name = GetVtblName2(x); //only output object tree for main vtable if (Dword(x+4)==0) Parse_CHD2(Dword(x+16),0,f); MakeName(a, name); } if (name!=0) { s = Demangle(name, 0x00004006); Message("%s\n",s); fprintf(f, "%s\n", s); //convert vtable name into typeinfo name name = ".?AV"+substr(name, 4, strstr(name,"@@6B")+2); } { DeleteArray(GetArrayId("AddrList")); Message(" referencing functions: \n"); fprintf(f," referencing functions: \n"); q = 0; i = 1; for ( x=DfirstB(a); x != BADADDR; x=DnextB(a,x) ) { p = funcStart(x); if (p!=-1) { if (q==p) i++; else { if (q) { if (i>1) s = form(" %a (%d times)",q,i); else s = form(" %a",q); //if (strstr(Name(p),"sub_")!=0 && strstr(Name(p),"j_sub_")!=0) if (hasName(GetFlags(q))) s = s+" ("+Demangle(Name(q),8)+")"; s = s+"\n"; Message(s);fprintf(f,s); AddAddr(q); } i = 1; q = p; } } } if (q) { if (i>1) s = form(" %a (%d times)",q,i); else s = form(" %a",q); if (hasName(GetFlags(q))) s = s+" ("+Demangle(Name(q),8)+")"; s = s+"\n"; Message(s);fprintf(f,s); AddAddr(q); } x = a; while (y>0) { p = Dword(x); if (GetFunctionFlags(p) == -1) { MakeCode(p); MakeFunction(p, BADADDR); } checkSDD(p,name,a,0,f); y--; x = x+4; } doAddrList(name,f); Message("\n"); fprintf(f,"\n"); } return x; } static scan_for_vtables(void) { auto rmin, rmax, cmin, cmax, s, a, x, y,f; s = FirstSeg(); f = fopen("objtree.txt","w"); rmin = 0; rmax = 0; while (s!=BADADDR) { if (SegName(s)==".rdata") { rmin = s; rmax = NextSeg(s); } else if (SegName(s)==".text") { cmin = s; cmax = NextSeg(s); } s = NextSeg(s); } if (rmin==0) {rmin=cmin; rmax=cmax;} a = rmin; Message(".rdata: %08.8Xh - %08.8Xh, .text %08.8Xh - %08.8Xh\n", rmin, rmax, cmin, cmax); while (a=cmin && x //74 07 jz short @@no_free //56 push esi //E8 CA 2D 0D 00 call operator delete(void *) //59 pop ecx // @@no_free: //8B C6 mov eax, esi //5E pop esi //C2 04 00 retn 4 t = SN_scalardtr; } else if (matchBytes(x,"538A5C2408568BF1F6C302742B8B46FC578D7EFC68????????506A??56E8") || matchBytes(x,"538A5C2408F6C302568BF1742E8B46FC5768????????8D7EFC5068????????56E8")) { //53 push ebx //8A 5C 24 08 mov bl, [esp+arg_0] //56 push esi //8B F1 mov esi, ecx //F6 C3 02 test bl, 2 //74 2B jz short loc_100037F8 //8B 46 FC mov eax, [esi-4] //57 push edi //8D 7E FC lea edi, [esi-4] //68 xx xx xx xx push offset class::~class(void) //50 push eax //6A xx push xxh //56 push esi //E8 xx xx xx xx call `eh vector destructor iterator'(void *,uint,int,void (*)(void *)) t = SN_vectordtr; Message(" vector deleting destructor at %a\n",x); if (name!=0) a = Dword(x+21); if (gate && Byte(a)==0xE9) { a = getRelJmpTarget(a); } } if (t>0) { if (t==SN_vectordtr) s = "vector"; else s = "scalar"; Message(" %s deleting destructor at %a\n",s,x); fprintf(f, " %s deleting destructor: %08.8Xh\n",s,x); if (name!=0) MakeName(x, MakeSpecialName(name,t,0)); if (a!=BADADDR) { Message(" virtual destructor at %a\n",a); fprintf(f, " destructor: %08.8Xh\n",a); if (name!=0) MakeName(a, MakeSpecialName(name,SN_vdestructor,0)); } CommentStack(x, 4, "__flags$",-1); } return t; } static ParseVtbl2() { auto a, n; a = ScreenEA(); if (GetVtableSize(a)==0) { Warning("This location doesn't look like a vtable!"); return; } if (!hasName(GetFlags(a)) && !IsValidCOL(Dword(a-4))) { n = AskStr("","Enter class name"); if (n!=0) MakeName(a,"??_7"+n+"@@6B@"); } DoVtable(a,0); } static AddHotkeys() { AddHotkey("Alt-F7","ParseFI"); AddHotkey("Alt-F8","ParseVtbl2"); AddHotkey("Alt-F9","ParseExc"); Message("Use Alt-F7 to parse FuncInfo\n"); Message("Use Alt-F8 to parse vtable\n"); Message("Use Alt-F9 to parse throw info\n"); } static main(void) { if(AskYN(1, "Do you wish to scan the executable for vtables/RTTI?")) { Message("Scanning..."); scan_for_vtables(); //Message("See objtree.txt for the class list/hierarchy.\n"); Exec("objtree.txt"); } AddHotkeys(); }