#include <idc.idc> //Microsoft C++ RTTI support for IDA //Version 3.0 2006.01.20 Igor Skochinsky <skochinsky@mail.ru> //#define DEBUG ////////////////////////////////////// // Unknown(long ea, long length) ////////////////////////////////////// // Mark the ea as unknown for a length // of length, but don't propagate. static Unknown( ea, length ) { auto i; if (ea==BADADDR) return; // Message("Unknown(%x,%d)\n",ea, length); for(i=0; i < length; i++) { MakeUnkn(ea+i,0); } } static ForceQword( x ) { //Make dword, undefine as needed if (x==BADADDR || x==0) return; if (!MakeQword( x )) { Unknown(x,8); MakeQword(x); } } static ForceDword( x ) { //Make dword, undefine as needed if (x==BADADDR || x==0) return; if (!MakeDword( x )) { Unknown(x,4); MakeDword(x); } } static ForceWord( x ) { //Make word, undefine as needed if (x==BADADDR || x==0) return; if (!MakeWord( x )) { Unknown(x,2); MakeWord( x ); } } static ForceByte( x ) { //Make byte, undefine as needed if (x==BADADDR || x==0) return; if (!MakeByte( x )) { MakeUnkn(x,0); MakeByte( x ); } } static SoftOff ( x ) { //Make offset if !=0 if (x==BADADDR || x==0) return; ForceDword(x); if (Dword(x)>0 && Dword(x)<=MaxEA()) OpOff(x,0,0); } static GetAsciizStr(x) { auto s,c; if (x==BADADDR || x==0) return ""; s = ""; while (c=Byte(x)) { s = form("%s%c",s,c); x = x+1; } return s; } //check if Dword(vtbl-4) points to typeinfo record and extract the type name from it static GetTypeName(vtbl) { auto x, s, c; if (vtbl==BADADDR) return; x = Dword(vtbl-4); if ((!x) || (x==BADADDR)) return ""; // if (Dword(x)||Dword(x+4)||Dword(x+8)) return ""; x = Dword(x+12); if ((!x) || (x==BADADDR)) return ""; s = ""; x = x+8; while (c=Byte(x)) { s = form("%s%c",s,c); x = x+1; } return s; } static DwordCmt(x, cmt) { if (x==BADADDR || x==0) return; ForceDword(x); MakeComm(x, cmt); } static OffCmt(x, cmt) { if (x==BADADDR || x==0) return; SoftOff(x); MakeComm(x, cmt); } static StrCmt(x, cmt) { auto save_str; if (x==BADADDR || x==0) return; MakeUnkn(x, 0); save_str = GetLongPrm(INF_STRTYPE); SetLongPrm(INF_STRTYPE,0); MakeStr(x, BADADDR); MakeName(x, ""); MakeComm(x, cmt); SetLongPrm(INF_STRTYPE,save_str); } static DwordArrayCmt(x, n, cmt) { if (x==BADADDR || x==0) return; Unknown(x,4*n); ForceDword(x); MakeArray(x,n); MakeComm(x, cmt); } //check if values match a pattern static matchBytes(addr,match) { auto i,len,s; len = strlen(match); if (len%2) { Warning("Bad match string in matchBytes: %s",match); return 0; } i=0; while (i<len) { s = substr(match,i,i+2); if (s!="??" && form("%02X",Byte(addr))!=s) return 0;//mismatch i = i+2; addr++; } return 1; } static ForceDWMember(id, offset, name) { if (0!=AddStrucMember(id, name,offset, FF_DWRD, -1, 4)) SetMemberName(id, offset, name); } static ForceStrucMember(id, offset, sub_id, name) { auto a,i; i = GetStrucSize(sub_id); if (0!=AddStrucMember(id,name,offset,FF_DATA|FF_STRU,sub_id,i)) { for (a=offset;a<offset+i;a++) DelStrucMember(id,a); AddStrucMember(id,name,offset,FF_DATA|FF_STRU,sub_id,i); //SetMemberName(id, offset, name); } } //add (or rename) a stack variable named name at frame offset offset (i.e. bp-based) //struc_id = structure variable //if struc_id == -1, then add a dword static CommentStack(start, offset, name, struc_id) { auto id,l,bp; id = GetFrame(start); l = GetFrameLvarSize(start); if ( (GetFunctionFlags(start) & FUNC_FRAME) == 0) l = l + GetFrameRegsSize(start); l = l+offset; //Message("%a: ebp offset = %02Xh\n",start,l); if (l<0) { //Message("growing the frame to locals=%d, regs=4, args=%d.\n",-offset, GetFrameArgsSize(start)); //we need to grow the locals MakeFrame(start, -offset, GetFrameRegsSize(start), GetFrameArgsSize(start)); l = 0; } if (struc_id==-1) ForceDWMember(id, l, name); else ForceStrucMember(id, l, struc_id, name); } static getRelJmpTarget(a) { auto b; b = Byte(a); if (b == 0xEB) { b = Byte(a+1); if (b&0x80) return a+2-((~b&0xFF)+1); else return a+2+b; } else if (b==0xE9) { b = Dword(a+1); if (b&0x80000000) return a+5-(~b+1); else return a+5+b; } else return BADADDR; } static getRelCallTarget(a) { auto b; b = Byte(a); if (b==0xE8) { b = Dword(a+1); if (b&0x80000000) return a+5-(~b+1); else return a+5+b; } else return BADADDR; } static MangleNumber(x) { // // 0 = A@ // X = X-1 (1<=X<=10) // -X = ?(X-1) // 0x0..0xF = 'A'..'P' auto s, sign; s=""; sign=0; if (x<0) { sign = 1; x = -x; } if (x==0) return "A@"; else if (x<=10) return form("%s%d",sign?"?":"",x-1); else { while (x>0) { s = form("%c%s",'A'+x%16,s); x = x / 16; } return sign?"?":""+s+"@"; } } static Parse_BCD(x, indent) { auto indent_str,i,a,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } /* struct _s_RTTIBaseClassDescriptor { struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class DWORD numContainedBases; //number of nested classes following in the array struct PMD where; //some displacement info DWORD attributes; //usually 0, sometimes 10h struct _s_RTTIClassHierarchyDescriptor *pClassHierarchyDescriptor; //of this base class }; struct PMD { int mdisp; //member displacement int pdisp; //vbtable displacement int vdisp; //displacement inside vbtable }; */ #ifdef DEBUG Message(indent_str+"0x%08.8X: RTTIBaseClassDescriptor\n", x); Message(indent_str+" pTypeDescriptor: %08.8Xh (%s)\n", Dword(x), GetAsciizStr(Dword(x)+8)); Message(indent_str+" numContainedBases: %08.8Xh\n", Dword(x+4)); Message(indent_str+" PMD where: (%d,%d,%d)\n", Dword(x+8), Dword(x+12), Dword(x+16)); Message(indent_str+" attributes: %08.8Xh\n", Dword(x+20)); #endif OffCmt(x, "pTypeDescriptor"); DwordCmt(x+4, "numContainedBases"); DwordArrayCmt(x+8, 3, "PMD where"); DwordCmt(x+20, "attributes"); OffCmt(x+24, "pClassHierarchyDescriptor"); if(substr(Name(Dword(x+24)),0,5) != "??_R3") { // assign dummy name to prevent infinite recursion MakeName(Dword(x+24),"??_R3"+form("%06x",x)+"@@8"); // a proper name will be assigned shortly Parse_CHD(Dword(x+24),indent-1); } s = Parse_TD(Dword(x), indent+1); //??_R1A@?0A@A@B@@8 = B::`RTTI Base Class Descriptor at (0,-1,0,0)' MakeName(x,"??_R1"+MangleNumber(Dword(x+8))+MangleNumber(Dword(x+12))+ MangleNumber(Dword(x+16))+MangleNumber(Dword(x+20))+substr(s,4,-1)+'8'); return s; } static GetClassName(p) { /*auto s; s = GetAsciizStr(Dword(p)+8); Message("demangling %s\n",s); return DemangleTIName(s);*/ auto s,s2; s = "??_7"+GetAsciizStr(Dword(p)+12)+"6B@"; //Message("demangling %s\n",s); s2 = Demangle(s,8); if (s2!=0) //CObject::`vftable' return substr(s2,0,strlen(s2)-11); else return s; } static DumpNestedClass(x, indent, contained) { auto indent_str,i,a,n,p,s,off; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } i=0; //indent=indent+1; a = x; while(i<contained) { p = Dword(a); off = Dword(p+8); s = form("%.4X: ",off); Message("%s%s%s\n", s, indent_str, GetClassName(p)); //fprintf(f, form("%s%s%s\n",s,indent_str,GetClassName(p))); n = Dword(p+4); if (n>0) //check numContainedBases DumpNestedClass(a+4, indent+1, n); //nested classes following a=a+4*(n+1); i=i+n+1; } } static Parse_CHD(x, indent) { auto indent_str,i,a,n,p,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } //Message(indent_str+"0x%08.8X: RTTIClassHierarchyDescriptor\n", x); /* struct _s_RTTIClassHierarchyDescriptor { DWORD signature; //always zero? DWORD attributes; //bit 0 = multiple inheritance, bit 1 = virtual inheritance DWORD numBaseClasses; //number of classes in pBaseClassArray struct _s_RTTIBaseClassArray* pBaseClassArray; }; */ a = Dword(x+4); if ((a&3)==1) p = "(MI)"; else if ((a&3)==2) p = "(VI)"; else if ((a&3)==3) p = "(MI VI)"; else p="(SI)"; #ifdef DEBUG Message(indent_str+" signature: %08.8Xh\n", Dword(x)); Message(indent_str+" attributes: %08.8Xh %s\n", a, p); Message(indent_str+" numBaseClasses: %08.8Xh\n", n); Message(indent_str+" pBaseClassArray: %08.8Xh\n", a); #endif DwordCmt(x, "signature"); DwordCmt(x+4, "attributes"); DwordCmt(x+8, "numBaseClasses"); OffCmt(x+12, "pBaseClassArray"); a=Dword(x+12); n=Dword(x+8); i=0; DumpNestedClass(a, indent, n); indent=indent+1; while(i<=n) { p = Dword(a); if (i==n && p!=0) break; //Message(indent_str+" BaseClass[%02d]: %08.8Xh\n", i, p); OffCmt(a, form("BaseClass[%02d]", i)); if (i==0) { s = Parse_BCD(p,indent); //??_R2A@@8 = A::`RTTI Base Class Array' MakeName(a,"??_R2"+substr(s,4,-1)+'8'); //??_R3A@@8 = A::`RTTI Class Hierarchy Descriptor' MakeName(x,"??_R3"+substr(s,4,-1)+'8'); } else Parse_BCD(p,indent); i=i+1; a=a+4; } return s; } static Parse_TD(x, indent) { auto indent_str,i,a; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } //Message(indent_str+"0x%08.8X: TypeDescriptor\n", x); /* struct TypeDescriptor { void* pVFTable; //always pointer to type_info::vftable ? void* spare; //seems to be zero for most classes, and default constructor for exceptions char name[0]; //mangled name, starting with .?A (.?AV=classes, .?AU=structs) }; */ a = GetAsciizStr(x+8); #ifdef DEBUG Message(indent_str+" pVFTable: %08.8Xh\n", Dword(x)); Message(indent_str+" spare: %08.8Xh\n", Dword(x+4)); Message(indent_str+" name: '%s'\n", a); #endif OffCmt(x, "pVFTable"); OffCmt(x+4, "spare"); StrCmt(x+8, "name"); //??_R0?AVA@@@8 = A `RTTI Type Descriptor' MakeName(x,"??_R0"+substr(a,1,-1)+"@8"); return a; } static Parse_COL(x, indent) { /* struct _s_RTTICompleteObjectLocator { DWORD signature; //always zero ? DWORD offset; //offset of this vtable in the class ? DWORD cdOffset; //no idea struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the class struct _s_RTTIClassHierarchyDescriptor* pClassDescriptor; //inheritance hierarchy };*/ auto indent_str,i,a,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } s = GetAsciizStr(Dword(x+12)+8); //Message(indent_str+"0x%08.8X: RTTICompleteObjectLocator\n", x); #ifdef DEBUG Message(indent_str+" signature: %08.8Xh\n", Dword(x)); Message(indent_str+" offset: %08.8Xh\n", Dword(x+4)); Message(indent_str+" cdOffset: %08.8Xh\n", Dword(x+8)); Message(indent_str+" pTypeDescriptor: %08.8Xh (%s)\n", Dword(x+12), DemangleTIName(s)); Message(indent_str+" pClassDescriptor: %08.8Xh\n", Dword(x+16)); #endif DwordCmt(x, "signature"); DwordCmt(x+4, "offset"); DwordCmt(x+8, "cdOffset"); OffCmt(x+12, "pTypeDescriptor"); OffCmt(x+16, "pClassDescriptor"); // Parse_CHD(Dword(x+16),indent+1); } static Parse_CT(x, indent) { auto indent_str,i,a,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } /* typedef const struct _s__CatchableType { unsigned int properties; _TypeDescriptor *pType; _PMD thisDisplacement; int sizeOrOffset; _PMFN copyFunction; } _CatchableType; struct PMD { int mdisp; //members displacement ??? int pdisp; // int vdisp; //vtable displacement ??? }; */ s = GetAsciizStr(Dword(x+4)+8); #ifdef DEBUG Message(indent_str+"0x%08.8X: CatchableType\n", x); Message(indent_str+" properties: %08.8Xh\n", Dword(x)); Message(indent_str+" pType: %08.8Xh (%s)\n", Dword(x+4), DemangleTIName(s)); Message(indent_str+" thisDisplacement: (%d,%d,%d)\n", Dword(x+8), Dword(x+12), Dword(x+16)); Message(indent_str+" sizeOrOffset: %08.8Xh\n", Dword(x+20)); Message(indent_str+" copyFunction: %08.8Xh\n", Dword(x+24)); #endif a = "properties"; i = Dword(x); if (i!=0) a = a+":"; if (i&1) a = a+" simple type"; if (i&2) a = a+" byref only"; if (i&4) a = a+" has vbases"; DwordCmt(x, a); OffCmt(x+4, "pType"); DwordArrayCmt(x+8, 3, "thisDisplacement"); DwordCmt(x+20, "sizeOrOffset"); OffCmt(x+24, "copyFunction"); ForceDword(x+28); //__CT??_R0 ?AVCTest@@ @81 = CTest::`catchable type' MakeName(x,"__CT??_R0?"+substr(s,1,-1)+"@81"); if (Dword(x+24)) //we have a copy constructor //.?AVexception@@ -> ??0exception@@QAE@ABV0@@Z = exception::exception(exception const &) MakeName(Dword(x+24),"??0"+substr(s,4,-1)+"QAE@ABV0@@Z"); return s; } static Parse_CTA(x, indent) { /* typedef const struct _s__CatchableTypeArray { int nCatchableTypes; _CatchableType *arrayOfCatchableTypes[]; } _CatchableTypeArray; */ auto indent_str,i,a,n,p,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } #ifdef DEBUG Message(indent_str+" nCatchableTypes: %08.8Xh\n", Dword(x)); Message(indent_str+" arrayOfCatchableTypes: %08.8Xh\n", Dword(x+4)); #endif DwordCmt(x, "nCatchableTypes"); //OffCmt(x+4, "arrayOfCatchableTypes"); a=x+4; n=Dword(x); i=0; indent=indent+1; while(i<n) { p = Dword(a); //Message(indent_str+" BaseClass[%02d]: %08.8Xh\n", i, p); OffCmt(a, form("CatchableType[%02d]", i)); if (i==0) { s = Parse_CT(p,indent); //__CTA1 ?AVCTest@@ = CTest::`catchable type array' MakeName(x,"__CTA1?"+substr(s,1,-1)); } else Parse_CT(p,indent); i=i+1; a=a+4; } return s; } //demangle names like .?AVxxx, .PAD, .H etc static DemangleTIName(s) { auto i; if (substr(s,0,1)!=".") return ""; s = Demangle("??_R0"+substr(s,1,-1)+"@8",8); i = strstr(s,"`RTTI Type Descriptor'"); if (i==-1) return ""; else { s = substr(s,0,i-1); //Message("throw %s;\n",s); return s; } } static Parse_ThrowInfo(x, indent) { /* typedef const struct _s__ThrowInfo { unsigned int attributes; _PMFN pmfnUnwind; int (__cdecl*pForwardCompat)(...); _CatchableTypeArray *pCatchableTypeArray; } _ThrowInfo; */ auto indent_str,i,a,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } #ifdef DEBUG Message(indent_str+"0x%08.8X: ThrowInfo\n", x); Message(indent_str+" attributes: %08.8Xh\n", Dword(x)); Message(indent_str+" pmfnUnwind: %08.8Xh\n", Dword(x+4)); Message(indent_str+" pForwardCompat: %08.8Xh\n", Dword(x+8)); Message(indent_str+" pCatchableTypeArray: %08.8Xh\n", Dword(x+12)); #endif a = "attributes"; i = Dword(x); if (i!=0) a = a+":"; if (i&1) a = a+" const"; if (i&2) a = a+" volatile"; DwordCmt(x, a); OffCmt(x+4, "pmfnUnwind"); OffCmt(x+8, "pForwardCompat"); OffCmt(x+12, "pCatchableTypeArray"); s = Parse_CTA(Dword(x+12), indent+1); if (s!="") { MakeName(x,"__TI1?"+substr(s,1,-1)); if (Dword(x+4)) //we have a destructor //.?AVexception@@ -> ??1exception@@UAE@XZ = exception::~exception(void) MakeName(Dword(x+4),"??1"+substr(s,4,-1)+"UAE@XZ"); i = Dword(x); //attributes a = DemangleTIName(s); if (i&1) a = "const "+a; if (i&2) a = "volatile "+a; a = "throw "+a; Message("%s\n",a); MakeRptCmt(x, a); } return s; } static Parse_TryBlock(x, indent) { /* typedef const struct _s_TryBlockMapEntry { int tryLow; //00 int tryHigh; //04 int catchHigh; //08 int nCatches; //0C const struct _s_HandlerType * pHandlerArray; //10 } TryBlockMapEntry; typedef const struct _s_HandlerType { unsigned int adjectives; //00 struct TypeDescriptor * pType; //04 int dispCatchObj; //08 void * addressOfHandler; //0C } */ auto indent_str,i,a,n,p,s; if (x==BADADDR || x==0) return; indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } #ifdef DEBUG Message(indent_str+" tryLow: %d\n", Dword(x)); Message(indent_str+" tryHigh: %d\n", Dword(x+4)); Message(indent_str+" catchHigh: %d\n", Dword(x+8)); Message(indent_str+" nCatches: %d\n", Dword(x+12)); Message(indent_str+" pHandlerArray: %08.8Xh\n", Dword(x+16)); #endif DwordCmt(x, "tryLow"); DwordCmt(x+4, "tryHigh"); DwordCmt(x+8, "catchHigh"); DwordCmt(x+12, "nCatches"); OffCmt(x+16, "pHandlerArray"); a=Dword(x+16); n=Dword(x+12); if (a==BADADDR || a==0 || n==0) return; i=0; indent=indent+1; while(i<n) { #ifdef DEBUG Message(indent_str+" adjectives: %08.8Xh\n", Dword(a)); Message(indent_str+" pType: %08.8Xh\n", Dword(a+4)); Message(indent_str+" dispCatchObj: %08.8Xh\n", Dword(a+8)); Message(indent_str+" addressOfHandler: %08.8Xh\n", Dword(a+12)); #endif DwordCmt(a, "adjectives"); OffCmt(a+4,"pType"); DwordCmt(a+8, "dispCatchObj"); OffCmt(a+12,"addressOfHandler"); p = Dword(a+4); if (p) { s = DemangleTIName(Parse_TD(p, indent+1)); if (Dword(a)&8) //reference s = s+"&"; if (Dword(a)&2) //volatile s = "volatile "+s; if (Dword(a)&1) //const s = "const "+s; s = s+" e"; } else s = "..."; p = Dword(a+12); if (p!=0 && p!=BADADDR) { ExtLinA(Dword(a+12),0,form("; catch (%s)",s)); ExtLinA(Dword(a+12),1,form("; states %d..%d",Dword(x),Dword(x+4))); p = Dword(a+8); if (p) { if (p&0x80000000) s = form("; e = [epb-%Xh]",-p); else s = form("; e = [epb+%Xh]",p); ExtLinA(Dword(a+12),2,s); } } i=i+1; a=a+16; } return s; } static Parse_FuncInfo(x, indent) { /* typedef const struct _s_FuncInfo { unsigned int magicNumber:29; //0 unsigned int bbtFlags:3; int maxState; //4 const struct _s_UnwindMapEntry * pUnwindMap; //8 unsigned int nTryBlocks; //C const struct _s_TryBlockMapEntry * pTryBlockMap; //10 unsigned int nIPMapEntries; //14 void * pIPtoStateMap; //18 const struct _s_ESTypeList * pESTypeList; //1C int EHFlags; //present only in vc8? //20 } FuncInfo; typedef const struct _s_UnwindMapEntry { int toState; //0 function * action; //4 } UnwindMapEntry; */ auto indent_str,i,a,s,n; if (x==BADADDR || x==0) return; if ((Dword(x)^0x19930520)>0xF) { Message("Magic is not 1993052Xh!\n"); return; } indent_str="";i=0; while(i<indent) { indent_str=indent_str+" "; i++; } #ifdef DEBUG Message(indent_str+"0x%08.8X: FuncInfo\n", x); Message(indent_str+" magicNumber: %08.8Xh\n", Dword(x)); Message(indent_str+" maxState: %d\n", Dword(x+4)); Message(indent_str+" pUnwindMap: %08.8Xh\n", Dword(x+8)); #endif n = Dword(x+4); i = 0; a = Dword(x+8); while (i<n) { #ifdef DEBUG Message(indent_str+" toState: %d\n", Dword(a)); Message(indent_str+" action: %08.8Xh\n", Dword(a+4)); #endif DwordCmt(a, "toState"); OffCmt(a+4, "action"); a = a+8; i = i+1; } #ifdef DEBUG Message(indent_str+" nTryBlocks: %d\n", Dword(x+12)); Message(indent_str+" pTryBlockMap: %08.8Xh\n", Dword(x+16)); #endif n = Dword(x+12); i = 0; a = Dword(x+16); while (i<n) { Parse_TryBlock(a, indent+1); a = a+20; i = i+1; } #ifdef DEBUG Message(indent_str+" nIPMapEntries: %d\n", Dword(x+20)); Message(indent_str+" pIPtoStateMap: %08.8Xh\n", Dword(x+24)); #endif DwordCmt(x, "magicNumber"); DwordCmt(x+4, "maxState"); OffCmt(x+8, "pUnwindMap"); //Parse_UnwindMap(Dword(x+8), indent+1); DwordCmt(x+12, "nTryBlocks"); OffCmt(x+16, "pTryBlockMap"); DwordCmt(x+20, "nIPMapEntries"); OffCmt(x+24, "pIPtoStateMap"); if ((Dword(x+8)-x)>=32 || Dword(x)>0x19930520) { #ifdef DEBUG Message(indent_str+" pESTypeList: %08.8Xh\n", Dword(x+28)); #endif OffCmt(x+28, "pESTypeList"); } if ((Dword(x+8)-x)>=36 || Dword(x)>0x19930521) { #ifdef DEBUG Message(indent_str+" EHFlags: %08.8Xh\n", Dword(x+32)); #endif OffCmt(x+32, "EHFlags"); } return s; } //get class name for this vtable instance static GetVtableClass(x) { auto offset, n, i, s, a, p; offset = Dword(x+4); x = Dword(x+16); //Class Hierarchy Descriptor a=Dword(x+12); //pBaseClassArray n=Dword(x+8); //numBaseClasses i = 0; s = ""; while(i<n) { p = Dword(a); //Message(indent_str+" BaseClass[%02d]: %08.8Xh\n", i, p); if (Dword(p+8)==offset) { //found it s = GetAsciizStr(Dword(p)+8); return s; } i=i+1; a=a+4; } //didn't find matching one, let's get the first vbase i=0; a=Dword(x+12); while(i<n) { p = Dword(a); if (Dword(p+12)!=-1) { s = GetAsciizStr(Dword(p)+8); return s; } i=i+1; a=a+4; } return s; } static Parse_Vtable(a) { auto i,s,s2; s=GetTypeName(a); if (substr(s,0,3)==".?A") { #ifdef DEBUG Message("RTTICompleteObjectLocator: %08.8Xh\n", Dword(a-4)); #endif Parse_COL(Dword(a-4),0); Unknown(a-4,4); SoftOff(a-4); i = Dword(a-4); //COL s2 = Dword(i+4); //offset i = Dword(i+16); //CHD i = Dword(i+4); //Attributes if ((i&3)==0 && s2==0) { //Single inheritance, so we don't need to worry about duplicate names (several vtables) s=substr(s,4,-1); MakeName(a,"??_7"+s+"6B@"); MakeName(Dword(a-4),"??_R4"+s+"6B@"); } else// if ((i&3)==1) { //Message("Multiple inheritance\n"); s2 = GetVtableClass(Dword(a-4)); s2 = substr(s2,4,-1); s = substr(s,4,-1); s = s+"6B"+s2+"@"; MakeName(a,"??_7"+s); MakeName(Dword(a-4),"??_R4"+s); } } } static ParseVtbl() { Parse_Vtable(ScreenEA()); } static ParseExc() { Parse_ThrowInfo(ScreenEA(), 0); } static ParseFI() { Parse_FuncInfo(ScreenEA(), 0); } static AddHotkeys() { AddHotkey("Alt-F7","ParseFI"); AddHotkey("Alt-F8","ParseVtbl"); 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"); } #ifndef __INCLUDED static main(void) { AddHotkeys(); } #endif