dfhack/reversing/ms_rtti64.idc

1086 lines
25 KiB
C

#include <idc.idc>
#define isRef(F) ((F & FF_REF) != 0)
#define hasName(F) ((F & FF_NAME) != 0)
static GetVtableSize(a)
{
auto b,c,f;
b = BADADDR;
f = GetFlags(a);
do {
f = GetFlags(a);
if (b == BADADDR) //first entry
{
b=a;
if (!(isRef(f) && (hasName(f) || (f&FF_LABL))))
{
return 0;
}
}
else if (isRef(f)) //might mean start of next vtable
break;
if (!hasValue(f) || !isData(f))
break;
c = Qword(a);
if (c)
{
f = GetFlags(c);
if (!hasValue(f) || !isCode(f) || Dword(c)==0)
break;
}
a = a+8;
}
while (1);
if (b!=BADADDR)
{
c = (a-b)/8;
return c;
}
else
{
return 0;
}
}
static Unknown( ea, length )
{
auto i;
if (ea==BADADDR)
return;
for(i=0; i < length; i++)
{
MakeUnkn(ea+i,0);
}
}
static DwordRel(x)
{
x = Dword(x) + 0x140000000;
return x;
}
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 SoftOff64 ( x ) { //Make 64-bit offset if !=0
if (x==BADADDR || x==0)
return;
ForceQword(x);
if (Qword(x)>0 && Qword(x)<=MaxEA()) OpOff(x, 0, 0);
}
static SoftOff ( x ) { //Make 32-bit base-relative offset if !=0
if (x==BADADDR || x==0)
return;
ForceDword(x);
if (Dword(x)>0 && Dword(x)<=MaxEA()) OpOffEx(x,0,REF_OFF32|REFINFO_RVA|REFINFO_SIGNEDOP, -1, 0, 0);
}
//check if pointer is to typeinfo record and extract the type name from it
static GetTypeName(vtbl)
{
auto x;
if (vtbl==BADADDR)
return;
x = DwordRel(vtbl+12);
if ((!x) || (x==BADADDR)) return "";
return GetAsciizStr(x+16);
}
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);
if (cmt != "")
MakeComm(x, cmt);
}
static OffCmt64(x, cmt)
{
if (x==BADADDR || x==0)
return;
SoftOff64(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;
if (l<0)
{
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 > 2147483647) x = x - 4294967296;
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
};
*/
OffCmt(x, "pTypeDescriptor");
DwordCmt(x+4, "numContainedBases");
DwordArrayCmt(x+8, 3, "PMD where");
DwordCmt(x+20, "attributes");
OffCmt(x+24, "pClassHierarchyDescriptor");
if(substr(Name(DwordRel(x+24)),0,5) != "??_R3")
{
// assign dummy name to prevent infinite recursion
MakeName(DwordRel(x+24),"??_R3"+form("%06x",x)+"@@8");
// a proper name will be assigned shortly
Parse_CHD(DwordRel(x+24),indent-1);
}
s = Parse_TD(DwordRel(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,s2;
s = "??_7"+GetAsciizStr(DwordRel(p)+20)+"6B@";
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 = DwordRel(a);
off = Dword(p+8);
s = form("%.4X: ",off);
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++;
}
/*
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)";
DwordCmt(x, "signature");
DwordCmt(x+4, "attributes");
DwordCmt(x+8, "numBaseClasses");
OffCmt(x+12, "pBaseClassArray");
a=DwordRel(x+12);
n=Dword(x+8);
i=0;
DumpNestedClass(a, indent, n);
indent=indent+1;
while(i<=n)
{
p = DwordRel(a);
if (i==n && p!=0)
break;
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++;
}
/*
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+16);
OffCmt64(x, "pVFTable");
OffCmt64(x+8, "spare");
StrCmt(x+16, "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(DwordRel(x+12)+16);
DwordCmt(x, "signature");
DwordCmt(x+4, "offset");
DwordCmt(x+8, "cdOffset");
OffCmt(x+12, "pTypeDescriptor");
OffCmt(x+16, "pClassDescriptor");
OffCmt(x+20, "");
//
Parse_CHD(DwordRel(x+16),indent+1);
}
//get class name for this vtable instance
static GetVtableClass(x)
{
auto offset, n, i, s, a, p;
offset = Dword(x+4);
x = DwordRel(x+16); //Class Hierarchy Descriptor
a=DwordRel(x+12); //pBaseClassArray
n=Dword(x+8); //numBaseClasses
i = 0;
s = "";
while(i<n)
{
p = DwordRel(a);
if (DwordRel(p+16)==offset)
{
//found it
s = GetAsciizStr(DwordRel(p)+16);
return s;
}
i=i+1;
a=a+8;
}
//didn't find matching one, let's get the first vbase
i=0;
a=DwordRel(x+12);
while(i<n)
{
p = DwordRel(a);
if (DwordRel(p+20)!=-1)
{
s = GetAsciizStr(DwordRel(p)+16);
return s;
}
i=i+1;
a=a+4;
}
return s;
}
static Parse_Vtable(a)
{
auto i,s,s2;
s=GetTypeName(Qword(a-8));
if (substr(s,0,3)==".?A")
{
Parse_COL(Qword(a-8),0);
Unknown(a-8,8);
SoftOff64(a-8);
i = Qword(a-8); //COL
s2 = Dword(i+4); //offset
i = DwordRel(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(Qword(a-8),"??_R4"+s+"6B@");
}
else// if ((i&3)==1)
{
s2 = GetVtableClass(Qword(a-8));
s2 = substr(s2,4,-1);
s = substr(s,4,-1);
s = s+"6B"+s2+"@";
MakeName(a,"??_7"+s);
MakeName(Qword(a-8),"??_R4"+s);
}
}
}
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 GetVtblName(col)
{
auto i, s, s2;
s = GetTypeName(col);
i = DwordRel(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 = DwordRel(col+12);
if ((!x) || (x==BADADDR)) return "";
x = Dword(x+16);
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)
{
auto idx, id, val, ctr, dtr;
id = GetArrayId("AddrList");
ctr = 0; dtr = 0;
if ( name!=0 && id != -1 )
{
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)
{
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)
{
auto x,y,s,p,q,i,name;
//check if it looks like a vtable
y = GetVtableSize(a);
if (y == 0)
return a+8;
//check if it's named as a vtable
name = Name(a);
if (substr(name,0,4)!="??_7") name=0;
x = Qword(a-8);
//otherwise try to get it from RTTI
if (IsValidCOL(x))
{
Parse_Vtable(a);
if (name==0)
name = GetVtblName(x);
MakeName(a, name);
}
if (name!=0)
{
name = ".?AV"+substr(name, 4, strstr(name,"@@6B")+2);
}
{
DeleteArray(GetArrayId("AddrList"));
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) {
AddAddr(q);
}
i = 1;
q = p;
}
}
}
if (q)
{
AddAddr(q);
}
x = a;
while (y>0)
{
p = Dword(x);
if (GetFunctionFlags(p) == -1)
{
MakeCode(p);
MakeFunction(p, BADADDR);
}
checkSDD(p,name,a,0);
y--;
x = x+8;
}
doAddrList(name);
}
return x;
}
static scan_for_vtables(void)
{
auto rmin, rmax, cmin, cmax, s, a, x, y;
s = FirstSeg();
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;
while (a<rmax)
{
x = Qword(a);
if (x>=cmin && x<cmax) //methods should reside in .text
{
a = DoVtable(a);
}
else
a = a + 8;
}
}
//check for `scalar deleting destructor'
static checkSDD(x,name,vtable,gate)
{
auto a,s,t;
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);
}
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);
t = checkSDD(a,name,vtable,0);
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);
t = checkSDD(a,name,vtable,0);
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;
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";
if (name!=0)
MakeName(x, MakeSpecialName(name,t,0));
if (a!=BADADDR)
{
if (name!=0)
MakeName(a, MakeSpecialName(name,SN_vdestructor,0));
}
CommentStack(x, 4, "__flags$",-1);
}
return t;
}
static main(void)
{
scan_for_vtables();
}