660 lines
18 KiB
C
660 lines
18 KiB
C
#include <idc.idc>
|
|
#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(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
|
|
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<indent)
|
|
{
|
|
indent_str=indent_str+" ";
|
|
i++;
|
|
}
|
|
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)";
|
|
|
|
fprintf(f, form("%s%s\n",indent_str,p));
|
|
a=Dword(x+12);
|
|
n=Dword(x+8);
|
|
DumpNestedClass2(a, indent, n, f);
|
|
}
|
|
|
|
static GetTypeName2(col)
|
|
{
|
|
auto x, s, c;
|
|
//Message("GetTypeName2(%X)\n",col)
|
|
x = Dword(col+12);
|
|
if ((!x) || (x==BADADDR)) return "";
|
|
return GetAsciizStr(x+8);
|
|
}
|
|
|
|
static GetVtblName2(col)
|
|
{
|
|
auto i, s, s2;
|
|
s = GetTypeName2(col);
|
|
i = Dword(col+16); //CHD
|
|
i = Dword(i+4); //Attributes
|
|
if ((i&3)==0 && Dword(col+4)==0)
|
|
{
|
|
//Single inheritance, so we don't need to worry about duplicate names (several vtables)
|
|
s=substr(s,4,-1);
|
|
return "??_7"+s+"6B@";
|
|
}
|
|
else //if ((i&3)==1) //multiple inheritance
|
|
{
|
|
s2 = GetVtableClass(col);
|
|
s2 = substr(s2,4,-1);
|
|
s = substr(s,4,-1);
|
|
s = s+"6B"+s2+"@";
|
|
return "??_7"+s;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
//check if Dword(vtbl-4) points to typeinfo record and extract the type name from it
|
|
static IsValidCOL(col)
|
|
{
|
|
auto x, s, c;
|
|
x = Dword(col+12);
|
|
if ((!x) || (x==BADADDR)) return "";
|
|
x = Dword(x+8);
|
|
if ((x&0xFFFFFF) == 0x413F2E) //.?A
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static funcStart(ea)
|
|
{
|
|
if (GetFunctionFlags(ea) == -1)
|
|
return -1;
|
|
|
|
if ((GetFlags(ea)&FF_FUNC)!=0)
|
|
return ea;
|
|
else
|
|
return PrevFunction(ea);
|
|
}
|
|
|
|
// Add ea to "Sorted Address List"
|
|
static AddAddr(ea)
|
|
{
|
|
auto id, idx, val;
|
|
|
|
if ( (id = GetArrayId("AddrList")) == -1 )
|
|
{
|
|
id = CreateArray("AddrList");
|
|
SetArrayLong(id, 0, ea);
|
|
return;
|
|
}
|
|
|
|
for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) )
|
|
{
|
|
val = GetArrayElement(AR_LONG, id, idx);
|
|
if ( val == ea )
|
|
return;
|
|
if ( val > 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<rmax)
|
|
{
|
|
x = Dword(a);
|
|
if (x>=cmin && x<cmax) //methods should reside in .text
|
|
{
|
|
a = DoVtable(a,f);
|
|
}
|
|
else
|
|
a = a + 4;
|
|
}
|
|
Message("Done\n");
|
|
fclose(f);
|
|
}
|
|
|
|
//check for `scalar deleting destructor'
|
|
static checkSDD(x,name,vtable,gate,f)
|
|
{
|
|
auto a,s,t;
|
|
//Message("checking function at %a\n",x);
|
|
|
|
t = 0; a = BADADDR;
|
|
|
|
if ((name!=0) && (substr(Name(x),0,3)=="??_") && (strstr(Name(x),substr(name,4,-1))==4))
|
|
name=0; //it's already named
|
|
|
|
if (Byte(x)==0xE9 || Byte(x)==0xEB) {
|
|
//E9 xx xx xx xx jmp xxxxxxx
|
|
return checkSDD(getRelJmpTarget(x),name,vtable,1,f);
|
|
}
|
|
else if (matchBytes(x,"83E9??E9")) {
|
|
//thunk
|
|
//83 E9 xx sub ecx, xx
|
|
//E9 xx xx xx xx jmp class::`scalar deleting destructor'(uint)
|
|
a = getRelJmpTarget(x+3);
|
|
Message(" %a: thunk to %a\n",x,a);
|
|
t = checkSDD(a,name,vtable,0,f);
|
|
if (t && name!=0)
|
|
{
|
|
//rename this function as a thunk
|
|
MakeName(x, MakeSpecialName(name,t,Byte(x+2)));
|
|
}
|
|
return t;
|
|
}
|
|
else if (matchBytes(x,"81E9????????E9")) {
|
|
//thunk
|
|
//81 E9 xx xx xx xx sub ecx, xxxxxxxx
|
|
//E9 xx xx xx xx jmp class::`scalar deleting destructor'(uint)
|
|
a = getRelJmpTarget(x+6);
|
|
Message(" %a: thunk to %a\n",x,a);
|
|
t = checkSDD(a,name,vtable,0,f);
|
|
if (t && name!=0)
|
|
{
|
|
//rename this function as a thunk
|
|
MakeName(x, MakeSpecialName(name,t,Dword(x+2)));
|
|
}
|
|
return t;
|
|
}
|
|
else if (matchBytes(x,"568BF1E8????????F64424080174") && matchBytes(x+15+Byte(x+14),"8BC65EC20400"))
|
|
{
|
|
//56 push esi
|
|
//8B F1 mov esi, ecx
|
|
//E8 xx xx xx xx call class::~class()
|
|
//F6 44 24 08 01 test [esp+arg_0], 1
|
|
//74 07 jz short @@no_free
|
|
//56 push esi
|
|
//
|
|
// call operator delete();
|
|
|
|
// @@no_free:
|
|
//8B C6 mov eax, esi
|
|
//5E pop esi
|
|
//C2 04 00 retn 4
|
|
|
|
t = SN_scalardtr;
|
|
a = getRelCallTarget(x+3);
|
|
if (gate && Byte(a)==0xE9)
|
|
{
|
|
//E9 xx xx xx xx jmp xxxxxxx
|
|
a = getRelJmpTarget(a);
|
|
}
|
|
}
|
|
else if (matchBytes(x,"568BF1FF15????????F64424080174") && matchBytes(x+16+Byte(x+15),"8BC65EC20400"))
|
|
{
|
|
//56 push esi
|
|
//8B F1 mov esi, ecx
|
|
//FF 15 xx xx xx xx call class::~class() //dllimport
|
|
//F6 44 24 08 01 test [esp+arg_0], 1
|
|
//74 07 jz short @@no_free
|
|
//56 push esi
|
|
//
|
|
// call operator delete();
|
|
|
|
// @@no_free:
|
|
//8B C6 mov eax, esi
|
|
//5E pop esi
|
|
//C2 04 00 retn 4
|
|
|
|
t = SN_scalardtr;
|
|
/*a = getRelCallTarget(x+3);
|
|
if (gate && Byte(a)==0xE9)
|
|
{
|
|
//E9 xx xx xx xx jmp xxxxxxx
|
|
a = getRelJmpTarget(a);
|
|
}*/
|
|
}
|
|
else if (matchBytes(x,"558BEC51894DFC8B4DFCE8????????8B450883E00185C0740C8B4DFC51E8????????83C4048B45FC8BE55DC20400") ||
|
|
matchBytes(x,"558BEC51894DFC8B4DFCE8????????8B450883E00185C074098B4DFC51E8????????8B45FC8BE55DC20400"))
|
|
{
|
|
//55 push ebp
|
|
//8B EC mov ebp, esp
|
|
//51 push ecx
|
|
//89 4D FC mov [ebp+var_4], ecx
|
|
//8B 4D FC mov ecx, [ebp+var_4]
|
|
//E8 xx xx xx xx call sub_10001099
|
|
//8B 45 08 mov eax, [ebp+arg_0]
|
|
//83 E0 01 and eax, 1
|
|
//85 C0 test eax, eax
|
|
//74 0C jz short skip
|
|
//8B 4D FC mov ecx, [ebp+var_4]
|
|
//51 push ecx
|
|
//E8 F0 56 05 00 call operator delete(void *)
|
|
//83 C4 04 add esp, 4
|
|
//
|
|
// skip:
|
|
//8B 45 FC mov eax, [ebp+var_4]
|
|
//8B E5 mov esp, ebp
|
|
//5D pop ebp
|
|
//C2 04 00 retn 4
|
|
|
|
t = SN_scalardtr;
|
|
a = getRelCallTarget(x+10);
|
|
if (gate && Byte(a)==0xE9)
|
|
{
|
|
//E9 xx xx xx xx jmp xxxxxxx
|
|
a = getRelJmpTarget(a);
|
|
}
|
|
}
|
|
else if (matchBytes(x,"568D71??578D7E??8BCFE8????????F644240C01"))
|
|
{
|
|
//56 push esi
|
|
//8D 71 xx lea esi, [ecx-XX]
|
|
//57 push edi
|
|
//8D 7E xx lea edi, [esi+XX]
|
|
//8B CF mov ecx, edi
|
|
//E8 xx xx xx xx call class::~class()
|
|
//F6 44 24 0C 01 test [esp+4+arg_0], 1
|
|
a = getRelCallTarget(x+10);
|
|
if (gate && Byte(a)==0xE9)
|
|
{
|
|
a = getRelJmpTarget(a);
|
|
}
|
|
t=SN_scalardtr;
|
|
}
|
|
else if (matchBytes(x,"568DB1????????578DBE????????8BCFE8????????F644240C01"))
|
|
{
|
|
//56 push esi
|
|
//8D B1 xx xx xx xx lea esi, [ecx-XX]
|
|
//57 push edi
|
|
//8D BE xx xx xx xx lea edi, [esi+XX]
|
|
//8B CF mov ecx, edi
|
|
//E8 xx xx xx xx call class::~class()
|
|
//F6 44 24 0C 01 test [esp+4+arg_0], 1
|
|
a = getRelCallTarget(x+16);
|
|
if (gate && Byte(a)==0xE9)
|
|
{
|
|
a = getRelJmpTarget(a);
|
|
}
|
|
t = SN_scalardtr;
|
|
}
|
|
else if ((matchBytes(x,"F644240401568BF1C706") /*&& Dword(x+10)==vtable*/) ||
|
|
(matchBytes(x,"8A442404568BF1A801C706") /*&& Dword(x+11)==vtable */) ||
|
|
(matchBytes(x,"568BF1C706????????E8????????F64424080174") && matchBytes(x+21+Byte(x+20),"8BC65EC20400"))
|
|
)
|
|
{
|
|
//F6 44 24 04 01 test [esp+arg_0], 1
|
|
//56 push esi
|
|
//8B F1 mov esi, ecx
|
|
// OR
|
|
//8A 44 24 04 mov al, [esp+arg_0]
|
|
//56 push esi
|
|
//8B F1 mov esi, ecx
|
|
//A8 01 test al, 1
|
|
|
|
//C7 06 xx xx xx xx mov dword ptr [esi], xxxxxxx //offset vtable
|
|
// <inlined destructor>
|
|
//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();
|
|
} |