summaryrefslogtreecommitdiff
path: root/reversing
diff options
context:
space:
mode:
authorPetr Mrázek2010-03-06 15:14:18 +0100
committerPetr Mrázek2010-03-06 15:14:18 +0100
commit15ec3fbc744340824d3b6898f73651c447b6bc61 (patch)
treea028a5919e3905c35d53902b6feb8fa6248f5f09 /reversing
parent7a6b1488cb1f7e967462d96482cf4bc2cbe1a8f0 (diff)
downloaddfhack-15ec3fbc744340824d3b6898f73651c447b6bc61.tar.gz
dfhack-15ec3fbc744340824d3b6898f73651c447b6bc61.tar.bz2
dfhack-15ec3fbc744340824d3b6898f73651c447b6bc61.tar.xz
IDA scripts from openrce and belal
Diffstat (limited to 'reversing')
-rw-r--r--reversing/ms_ehseh.idc802
-rw-r--r--reversing/ms_rtti.idc995
-rw-r--r--reversing/ms_rtti4.idc660
-rw-r--r--reversing/parseVTableLinux.pl8
-rw-r--r--reversing/vtable-linux-gcc.idc43
-rw-r--r--reversing/vtable.idc114
6 files changed, 2622 insertions, 0 deletions
diff --git a/reversing/ms_ehseh.idc b/reversing/ms_ehseh.idc
new file mode 100644
index 00000000..31701211
--- /dev/null
+++ b/reversing/ms_ehseh.idc
@@ -0,0 +1,802 @@
+//Microsoft Visual C++ Win32 SEH/C++ EH info parser
+//Version 3.0 2006.03.02 Igor Skochinsky <skochinsky@mail.ru>
+
+#include <idc.idc>
+#define __INCLUDED
+#include <ms_rtti.idc>
+
+static getEHRec()
+{
+ auto id;
+ id = GetStrucIdByName("EHRegistrationNode");
+ if (id==-1)
+ {
+ id = AddStruc(-1,"EHRegistrationNode");
+ ForceDWMember(id, 0, "pNext");
+ ForceDWMember(id, 4, "frameHandler");
+ ForceDWMember(id, 8, "state");
+ }
+ return id;
+}
+
+static getEHRecCatch()
+{
+ auto id;
+ id = GetStrucIdByName("EHRegistrationNodeCatch");
+ if (id==-1)
+ {
+ id = AddStruc(-1,"EHRegistrationNodeCatch");
+ ForceDWMember(id, 0, "SavedESP");
+ ForceDWMember(id, 4, "pNext");
+ ForceDWMember(id, 8, "frameHandler");
+ ForceDWMember(id, 12, "state");
+ }
+ return id;
+}
+
+static CommentStackEH(start, hasESP, EHCookie, GSCookie)
+{
+ if (hasESP)
+ CommentStack(start,-16, "__$EHRec$", getEHRecCatch());
+ else
+ CommentStack(start,-12, "__$EHRec$", getEHRec());
+ if (GSCookie)
+ CommentStack(start,-GSCookie, "__$GSCookie$",-1);
+ if (EHCookie)
+ CommentStack(start,-EHCookie, "__$EHCookie$",-1);
+}
+
+/* from frame.obj
+typedef struct _s_FuncInfo {
+ unsigned int magicNumber;
+ int maxState;
+ const struct _s_UnwindMapEntry * pUnwindMap;
+ unsigned int nTryBlocks;
+ const struct _s_TryBlockMapEntry * pTryBlockMap;
+ unsigned int nIPMapEntries;
+ void * pIPtoStateMap;
+ const struct _s_ESTypeList * pESTypeList;
+} FuncInfo;
+*/
+
+//handler:
+// mov eax, offset funcInfo
+// jmp ___CxxFrameHandler
+static ParseCxxHandler(func, handler, fixFunc)
+{
+ auto x, start, y, z, end, i, count, t, u, i2, cnt2, a, hasESP;
+ auto EHCookieOffset, GSCookieOffset;
+ start = func;
+ x = handler;
+ y = x;
+ z = x;
+ EHCookieOffset=0; GSCookieOffset=0;
+ if (matchBytes(x,"8B5424088D420C"))
+ // 8B 54 24 08 mov edx, [esp+8]
+ // 8D 42 0C lea eax, [edx+0Ch]
+ {
+ //EH cookie check:
+ // 8B 4A xx mov ecx, [edx-XXh]
+ // OR
+ // 8B 8A xx xx xx xx mov ecx, [edx-XXh]
+ // 33 C8 xor ecx, eax
+ // E8 xx xx xx xx call __security_check_cookie
+ x = x+7;
+ if (matchBytes(x,"8B4A??33C8E8"))
+ {
+ //byte argument
+ EHCookieOffset = (~Byte(x+2)+1)&0xFF;
+ EHCookieOffset = 12 + EHCookieOffset;
+ x = x+10;
+ }
+ else if (matchBytes(x,"8B8A????????33C8E8"))
+ {
+ //dword argument
+ EHCookieOffset = (~Dword(x+2)+1);
+ EHCookieOffset = 12 + EHCookieOffset;
+ x = x+13;
+ }
+ if (matchBytes(x,"8B4A??33C8E8"))
+ {
+ // 8B 4A xx mov ecx, [edx-XXh]
+ // 33 C8 xor ecx, eax
+ // E8 xx xx xx xx call __security_check_cookie
+ GSCookieOffset = (~Byte(x+2)+1)&0xFF;
+ GSCookieOffset = 12 + GSCookieOffset;
+ x = x+10;
+ }
+ else if (matchBytes(x,"8B8A????????33C8E8"))
+ {
+ //dword argument
+ GSCookieOffset = (~Dword(x+9)+1);
+ GSCookieOffset = 12 + GSCookieOffset;
+ x = x+13;
+ }
+ //Message("EH3: EH Cookie=%02X, GSCookie=%02X\n",EHCookieOffset, GSCookieOffset);
+ }
+ if (Byte(x)==0xB8) {
+ x = Dword(x+1);
+ }
+ else {
+ Message("\"mov eax, offset FuncInfo\" not found at offset %08X!\n",x);
+ return;
+ }
+ if (Dword(x)-0x19930520>0xF) {
+ Message("Magic is not 1993052Xh!\n");
+ return;
+ }
+ Message(form("Detected function start at %08X\n",start));
+ u = x; //FuncInfo;
+
+ //parse unwind handlers
+ count = Dword(u+4); //maxState
+ i=0;
+ x = Dword(u+8); //pUnwindMap
+ while (i<count) {
+ t = Dword(x+4); //unwind action address
+ if (t<MAXADDR && t>y) y=t; //find lowest
+ if (t!=0 && t<z) z=t; //find highest
+ x = x+8;
+ i = i+1;
+ }
+ if (y==0) {
+ Message("All pointers are NULL!\n");
+ return;
+ }
+ if (z>y)
+ {
+ Message("Something's very wrong!\n");
+ return;
+ }
+
+ end = FindFuncEnd(y);
+ if (end==BADADDR) {
+ if (fixFunc) MakeUnkn(y, 1);
+ if (BADADDR == FindFuncEnd(y))
+ {
+ Message(form("Can't find function end at 0x%08X\n",y));
+ return;
+ }
+ }
+ Message(form("Handlers block: %08X-%08X\n", z, y));
+ if (GetFunctionFlags(start) == -1)
+ {
+ if (fixFunc)
+ {
+ MakeUnkn(start, 1);
+ MakeCode(start);
+ MakeFunction(start, BADADDR);
+ }
+ else
+ {
+ Message("There is no function defined at 0x%08X!\n", start);
+ return;
+ }
+ }
+ a = FindFuncEnd(start);
+ Message("Function end: %08X\n", a);
+ if (fixFunc) AnalyseArea(start,a);
+ if (1)//(z>a) && ((z-a)>0x20))
+ {
+ //the handlers block is too far from the function end, make it a separate chunk
+ if (fixFunc)
+ {
+ Message("Making separate handlers block\n");
+ Unknown(z, y-z);
+ MakeCode(z);
+ MakeFunction(z,y);
+ AnalyseArea(z,y);
+ MakeCode(y);
+ MakeFunction(y,BADADDR);
+ }
+ SetFunctionFlags(z, GetFunctionFlags(start) | FUNC_FRAME);
+ SetFunctionCmt(z, form("Unwind handlers of %08X", start), 0);
+ }
+ else if (fixFunc)
+ {
+ Message("Merging handlers block with main function.\n");
+ Unknown(start, y-start);
+ MakeCode(start);
+ MakeFunction(start,y);
+ AnalyseArea(start,y);
+ }
+/*
+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
+}
+*/
+
+ //parse catch blocks
+ y = 0;
+ z = 0x7FFFFFFF;
+ i=0;
+ count = Dword(u+12); //nTryBlocks
+ x = Dword(u+16); //pTryBlocksMap
+ Message("%d try blocks\n",count);
+ while (i<count) {
+ cnt2 = Dword(x+12); //nCatches
+ a = Dword(x+16); //pHandlerArray
+ i2 = 0;
+ Message(" %d catches\n",cnt2);
+ while (i2<cnt2)
+ {
+ t = Dword(a+12);
+ //Message(" t=0x%08.8X\n",t);
+ if (t!=BADADDR && t>y)
+ y=t; //find lowest
+ if (z>t)
+ z=t; //find highest
+ a = a+16;
+ i2 = i2+1;
+ }
+ x = x+20;
+ i = i+1;
+ }
+ hasESP = 0;
+ if (count>0)
+ {
+ hasESP = 1;
+ //Message("y=0x%08.8X, z=0x%08.8X\n",y,z);
+ end = FindFuncEnd(y);
+ if (end==BADADDR) {
+ if (fixFunc)
+ {
+ MakeUnkn(y, 1);
+ MakeCode(y);
+ }
+ if (BADADDR == FindFuncEnd(y))
+ {
+ Message(form("Can't find function end at 0x%08X\n",y));
+ return;
+ }
+ }
+ Message(form("Catch blocks: %08X-%08X\n", z, end));
+ y = FindFuncEnd(start);
+ if (y ==-1 || end > y)
+ {
+ if (fixFunc)
+ {
+ Message("Merging catch blocks with main function.\n");
+ Unknown(start, end-start);
+ MakeCode(start);
+ MakeFunction(start,end);
+ AnalyseArea(start,end);
+ }
+ else
+ Message("Catch blocks are not inside the function!\n");
+ }
+ }
+
+ //comment unwind handlers
+ i=0;
+ count = Dword(u+4); //maxState
+ x = Dword(u+8); //pUnwindMap
+ while (i<count) {
+ t = Dword(x+4); //unwind action address
+ if (t!=0)
+ MakeComm(t, form("state %d -> %d",i, Dword(x)));
+ x = x+8;
+ i = i+1;
+ }
+ Parse_FuncInfo(u, 0);
+ CommentStackEH(func, hasESP, EHCookieOffset, GSCookieOffset);
+}
+
+static fixCxx(s, doSEH, fixFunc) {
+ auto x, start;
+ start = s;
+ if ((Word(start) != 0xA164) || (Dword(start+2)!=0)) {
+ Message("Should start with \"move eax, large fs:0\"!\n");
+ return;
+ }
+ if ( !doSEH && (Byte(start-10) == 0x55) && (Dword(start-9) == 0xFF6AEC8B))
+ {
+ //(ebp frame)
+ //00: 55 push ebp
+ //01: 8B EC mov ebp, esp
+ //03: 6A FF push 0FFFFFFFFh
+ //05: 68 xx xx xx xx push loc_xxxxxxxx
+ //0A: 64 A1 00 00 00 00 mov eax, large fs:0
+ //10: 50 push eax
+ //11: 64 89 25 00 00 00 00 mov large fs:0, esp
+ start = start - 10;
+ x = Dword(start+6);
+ //Message("Match 1\n");
+ }
+ else if (!doSEH && (Word(start+9) == 0xFF6A) && (Byte(start+11)==0x68))
+ {
+ //00: 64 A1 00 00 00 00 mov eax, large fs:0
+ //06: xx xx xx
+ //09: 6A FF push 0FFFFFFFFh
+ //0B: 68 xx xx xx xx push loc_xxxxxxxx
+ //10: 50 push eax
+ //
+ x = Dword(start+12);
+ //Message("Match 2\n");
+ }
+ else if (!doSEH && (Word(start-7) == 0xFF6A) && (Byte(start-5)==0x68))
+ {
+ //-7: 6A FF push 0FFFFFFFFh
+ //-5: 68 xx xx xx xx push loc_xxxxxxxx
+ //00: 64 A1 00 00 00 00 mov eax, large fs:0
+ //06: 50 push eax
+ //07: 64 89 25 00 00 00 00 mov large fs:0, esp
+ //
+ x = Dword(start-4);
+ start = start-7;
+ //Message("Match 3\n");
+ }
+ else if (!doSEH && (Word(start+6) == 0xFF6A) && (Byte(start+8)==0x68))
+ {
+ //00: 64 A1 00 00 00 00 mov eax, large fs:0
+ //06: 6A FF push 0FFFFFFFFh
+ //08: 68 xx xx xx xx push loc_xxxxxxxx
+ //0D: 50 push eax
+ //0E: 64 89 25 00 00 00 00 mov large fs:0, esp
+ x = Dword(start+9);
+ //Message("Match 4\n");
+ }
+ else if (doSEH && (Byte(start-5)==0x68) && (Byte(start-10)==0x68) && (Dword(start-15)==0x6AEC8B55))
+ {
+ //-15: 55 push ebp
+ //-14: 8B EC mov ebp, esp
+ //-12: 6A F? push 0FFFFFFF?h
+ //-10: 68 xx xx xx xx push offset __sehtable$_func1
+ //-5 : 68 xx xx xx xx push offset _except_handlerx
+ //00 : 64 A1 00 00 00 00 mov eax, large fs:0
+ x = Dword(start-9);
+ //Message("Match 5\n");
+ if (Byte(start-11) == 0xFF) //-1 = SEH3
+ fixSEHFunc(start-15,x, 3, fixFunc);
+ else if (Byte(start-11) == 0xFE) //-2 = SEH4
+ fixSEHFunc(start-15,x, 4, fixFunc);
+ else
+ Message("Unknown SEH handler!\n");
+ return;
+ }
+ else {
+ //probably a custom handler
+ //Message("\"push 0FFFFFFFFh; push offset loc\" not found!\n");
+ return;
+ }
+ Message(form("Fixing function at 0x%08X\n",start));
+ ParseCxxHandler(start, x, fixFunc);
+}
+
+static doEHProlog(name,fixFunc)
+{
+ auto i,s,a;
+ a=LocByName(name);
+ if (a==BADADDR)
+ return;
+ Message("%s = %08X\n",name,a);
+ i=RfirstB(a);
+ while(i!=BADADDR)
+ {
+ Message("- %08X - ",i);
+
+ // -5: mov eax, offset loc_XXXXXX
+ // 0: call __EH_prolog
+ if (Byte(i-5)==0xB8)
+ ParseCxxHandler(i-5, Dword(i-4),fixFunc);
+ else
+ {
+ Message(form("No mov eax, offset loc_XXXXXX at %08X!!!\n",i-5));
+ return;
+ }
+
+ if (SetFunctionFlags(i,GetFunctionFlags(i) | FUNC_FRAME))
+ {
+ MakeFrame(i,GetFrameLvarSize(i), 4, GetFrameArgsSize(i));
+ if (fixFunc) AnalyseArea(i, FindFuncEnd(i)+1);
+ Message("OK\n");
+ }
+ else
+ Message("Error\n");
+ i=RnextB(a,i);
+ }
+}
+
+static doEHPrologs(name, fixFunc)
+{
+ doEHProlog("j"+name,fixFunc);
+ doEHProlog("j_"+name,fixFunc);
+ doEHProlog(name,fixFunc);
+ doEHProlog("_"+name,fixFunc);
+}
+
+static fixEHPrologs(fixFunc)
+{
+ doEHPrologs("_EH_prolog",fixFunc);
+ doEHPrologs("_EH_prolog3",fixFunc);
+ doEHPrologs("_EH_prolog3_catch",fixFunc);
+ doEHPrologs("_EH_prolog3_GS",fixFunc);
+ doEHPrologs("_EH_prolog3_catch_GS",fixFunc);
+}
+
+static isInCodeSeg(a)
+{
+ if (SegName(a)==".text")
+ return 1;
+ else
+ return 0;
+}
+
+//check a scopetable entry
+static checkEntry(a,i,ver)
+{
+ auto x;
+ x = Dword(a);
+ //EnclosingLevel should be negative or less than i
+ if (x&0x80000000)
+ {
+ if (ver==3 && x!=0xFFFFFFFF)
+ return 0;
+ if (ver==4 && x!=0xFFFFFFFE)
+ return 0;
+ }
+ else if (x>=i)
+ return 0;
+
+ x = Dword(a+4);
+ if ((x!=0) && !isInCodeSeg(x)) //filter should be zero or point to the code
+ return 0;
+ x = Dword(a+8);
+ if (!isInCodeSeg(x)) //handler should point to the code
+ return 0;
+
+ //check if there are xref to fields (i.e. after the end of the scopetable)
+ if (((ver!=3)||(i>0)) && isRef(GetFlags(a)))
+ return 0;
+ if (isRef(GetFlags(a+4)) || isRef(GetFlags(a+8)))
+ return 0;
+ return 1;
+}
+
+//check if there's a valid scopetable and calculate number of entries in it
+static checkScopeTable(a, ver)
+{
+ auto i,k;
+ if (ver==4)
+ {
+ k = Dword(a);
+ if ((k&0x80000000)==0) //first field should be negative
+ return 0;
+ if ((k!=0xFFFFFFFE) && (k&3)!=0) //GS cookie offset should be -2 or dword-aligned
+ return 0;
+ k = Dword(a+8);
+ if ((k&0x80000000)==0) //offset should be negative
+ return 0;
+ if ((k&3)!=0) //EH cookie offset should be dword-aligned
+ return 0;
+ a = a+16; //move to the scope entries list
+ }
+
+ i = 0;
+ while (checkEntry(a,i,ver))
+ {
+ i = i+1;
+ a = a+12;
+ }
+ return i;
+}
+
+/*
+struct _EH4_EXCEPTION_REGISTRATION_RECORD {
+ void* SavedESP;
+ _EXCEPTION_POINTERS* ExceptionPointers;
+ _EXCEPTION_REGISTRATION_RECORD* Next;
+ enum _EXCEPTION_DISPOSITION (*Handler)(_EXCEPTION_RECORD*, void*, _CONTEXT*, void*);
+ DWORD EncodedScopeTable;
+ unsigned long TryLevel;
+};
+*/
+
+static getSEHRec()
+{
+ auto id;
+ id = GetStrucIdByName("SEHRegistrationNode");
+ if (id==-1)
+ {
+ id = AddStruc(-1,"SEHRegistrationNode");
+ ForceDWMember(id, 0, "SavedESP");
+ ForceDWMember(id, 4, "ExceptionPointers");
+ ForceDWMember(id, 8, "Next");
+ ForceDWMember(id, 12, "Handler");
+ ForceDWMember(id, 16, "EncodedScopeTable");
+ ForceDWMember(id, 20, "TryLevel");
+ }
+ return id;
+}
+
+static CommentStackSEH(start, scopetable)
+{
+ auto x;
+ CommentStack(start,-24, "__$SEHRec$", getSEHRec());
+ if (scopetable)
+ {
+ x = Dword(scopetable);
+ if (x!=-2)
+ CommentStack(start,x, "__$GSCookie$", -1);
+ x = Dword(scopetable+8);
+ CommentStack(start,x, "__$EHCookie$", -1);
+ }
+}
+
+static fixSEHFunc(func, scopetable, ver, fixFunc)
+{
+ auto k,i,t,u,x,y,z,hasESP,end;
+ k = checkScopeTable(scopetable, ver);
+ if (k==0)
+ {
+ Message("Bad scopetable\n");
+ return;
+ }
+ Message("function: %08X, scopetable: %08X (%d entries)\n", func, scopetable, k);
+ x = scopetable;
+ if (ver==4) x = x+16;
+
+ //parse the scopetable!
+ y = 0;
+ z = 0x7FFFFFFF;
+ i = 0;
+ hasESP = 0;
+ while (i<k) {
+ t = Dword(x+4);
+ if (t) {
+ hasESP=1;
+ if (t>y) y=t; //find lowest
+ if (z>t) z=t; //find highest
+ //Message("t=0x%08.8X\n",t);
+ //check the code just before, it could be jump to the end of try
+ if (Byte(t-2)==0xEB)
+ t = getRelJmpTarget(t-2);
+ else if (Byte(t-5)==0xE9)
+ t = getRelJmpTarget(t-5);
+ //Message("t=0x%08.8X\n",t);
+ if (t>y) y=t; //find lowest
+ if (z>t) z=t; //find highest
+ }
+ t = Dword(x+8);
+ //check the code just before, it could be jump to the end of try
+ if (t>y) y=t; //find lowest
+ if (z>t) z=t; //find highest
+ //Message("t=0x%08.8X\n",t);
+ if (Byte(t-2)==0xEB)
+ t = getRelJmpTarget(t-2);
+ else if (Byte(t-5)==0xE9)
+ t = getRelJmpTarget(t-5);
+ //Message("t=0x%08.8X\n",t);
+ if (t>y) y=t; //find lowest
+ if (z>t) z=t; //find highest
+ x = x+12;
+ i = i+1;
+ }
+
+
+ //Message("y=0x%08.8X, z=0x%08.8X\n",y,z);
+ if (1)
+ {
+ end = FindFuncEnd(y);
+ if (end==BADADDR) {
+ if (fixFunc)
+ {
+ MakeUnkn(y, 1);
+ MakeCode(y);
+ }
+ if (BADADDR == FindFuncEnd(y))
+ {
+ Message(form("Can't find function end at 0x%08X\n",y));
+ return;
+ }
+ }
+ //Message(form("Except blocks: %08X-%08X\n", z, end));
+ z = FindFuncEnd(func);
+ if (z ==-1 || end > z && fixFunc)
+ {
+ //Message("Merging except blocks with main function.\n");
+ Unknown(func, end-func);
+ MakeCode(func);
+ MakeFunction(func,end);
+ AnalyseArea(func,end);
+ }
+ }
+
+ //walk once more and fix finally entries
+ x = scopetable;
+ if (ver==4) x = x+16;
+ i = 0;
+ while (fixFunc && i<k) {
+ if (Dword(x+4)==0 && Dword(x+8)==y)
+ {
+ //the last handler is a finally handler
+ //check that it ends with a ret, call or jmp
+ z = FindFuncEnd(y);
+ if (z!=BADADDR &&
+ !(Byte(z-1)==0xC3 || Byte(z-5)==0xE9 || Byte(z-5)==0xE8 ||
+ Byte(z-2)==0xEB || Byte(z-1)==0xCC || Word(z-6)==0x15FF) )
+ {
+ //we need to add the following funclet to our function
+ end = FindFuncEnd(z);
+ if (end!=BADADDR)
+ {
+ Unknown(z, end-z);
+ MakeCode(z);
+ SetFunctionEnd(func,end);
+ }
+ }
+ }
+ x = x+12;
+ i = i+1;
+ }
+
+ //comment the table and handlers
+ x = scopetable;
+ ExtLinA(x,0,form("; SEH scopetable for %08X",func));
+ if (ver==4)
+ {
+ OffCmt(x,"GSCookieOffset");
+ OffCmt(x+4,"GSCookieXOROffset");
+ OffCmt(x+8,"EHCookieOffset");
+ OffCmt(x+12,"EHCookieXOROffset");
+ x = x+16;
+ CommentStackSEH(func,scopetable);
+ }
+ else
+ CommentStackSEH(func,0);
+ i = 0;
+ while (i<k) {
+ ForceDword(x);
+ SoftOff(x+4);
+ SoftOff(x+8);
+ MakeComm(x, form("try block %d, enclosed by %d",i, Dword(x)));
+ t = Dword(x+4); //exception filter
+ if (t!=0)
+ ExtLinA(t,0,form("; __except() filter for try block %d",i));
+ u = Dword(x+8);
+ if (t!=0)
+ ExtLinA(u,0,form("; __except {} handler for try block %d",i));
+ else
+ ExtLinA(u,0,form("; __finally {} handler for try block %d",i));
+ x = x+12;
+ i = i+1;
+ }
+}
+
+static doSEHProlog(name, ver, fixFunc)
+{
+ auto i,s,locals,scopetable,k,l,func,a;
+ a=LocByName(name);
+ if (a==BADADDR)
+ return;
+ Message("%s = %08X\n",name,a);
+ i=RfirstB(a);
+ while(i!=BADADDR)
+ {
+ Message("- %08X - ",i);
+
+ // -10 68 xx xx xx xx push xx
+ // or
+ // -7 6A xx push xx
+ // -5 68 xx xx xx xx push OFFSET __sehtable$_func
+ // 0 e8 00 00 00 00 call __SEH_prolog
+ //
+ //
+ locals = -1; scopetable=0;
+ if (Byte(i-5)==0x68)
+ {
+ scopetable = Dword(i-4);
+ if (Byte(i-7)==0x6A)
+ {
+ func = i-7;
+ locals = Byte(func+1);
+ }
+ else if (Byte(i-10)==0x68)
+ {
+ func = i-10;
+ locals = Dword(func+1);
+ }
+ if (GetFunctionFlags(func)==-1 && fixFunc)
+ {
+ MakeUnkn(func, 1);
+ MakeCode(func);
+ MakeFunction(func, BADADDR);
+ }
+ if (SetFunctionFlags(func,GetFunctionFlags(func)|FUNC_FRAME))
+ {
+ MakeFrame(func, GetFrameLvarSize(func), 4, GetFrameArgsSize(func));
+ fixSEHFunc(func, scopetable, ver, fixFunc);
+ Message("OK\n");
+ }
+ else
+ Message("Error\n");
+ }
+ i=RnextB(a,i);
+ }
+}
+
+static doSEHPrologs(name, ver, fixFunc)
+{
+ doSEHProlog("j"+name, ver, fixFunc);
+ doSEHProlog("j_"+name, ver, fixFunc);
+ doSEHProlog(name, ver, fixFunc);
+ doSEHProlog("_"+name, ver, fixFunc);
+}
+
+static fixSEHPrologs(fixFunc)
+{
+ doSEHPrologs("_SEH_prolog",3, fixFunc);
+ doSEHPrologs("__SEH_prolog",3, fixFunc);
+ doSEHPrologs("_SEH_prolog4",4, fixFunc);
+ doSEHPrologs("__SEH_prolog4",4, fixFunc);
+ doSEHPrologs("_SEH_prolog4_GS",4, fixFunc);
+ doSEHPrologs("__SEH_prolog4_GS",4, fixFunc);
+}
+
+static findFunc(name)
+{
+ auto a;
+ a = LocByName("j_"+name);
+ if (a==BADADDR)
+ a = LocByName(name);
+ return a;
+}
+
+static doSEH(fixFunc)
+{
+ auto start, a;
+ start = 0;
+ while (1) {
+ //mov eax, large fs:0
+ start = FindBinary(start+1, 3, "64 A1 00 00 00 00");
+ if (start==BADADDR)
+ break;
+ fixCxx(start,1,fixFunc);
+ }
+ fixSEHPrologs(fixFunc);
+}
+
+static doEH(fixFunc)
+{
+ auto start, a;
+ start = 0;
+ while (1) {
+ //mov eax, large fs:0
+ start = FindBinary(start+1, 3, "64 A1 00 00 00 00");
+ if (start==BADADDR)
+ break;
+ fixCxx(start,0,fixFunc);
+ }
+ fixEHPrologs(fixFunc);
+}
+
+static main(void)
+{
+ auto seh, fixseh, eh, fixeh;
+ seh = AskYN(1, "Do you wish to parse all Win32 SEH handlers?");
+ if (seh==-1) return;
+ if (seh) {
+ fixseh = AskYN(1, "Do you wish to fix function boundaries as needed?");
+ if (fixseh==-1) return;
+ }
+ eh = AskYN(1, "Do you wish to parse all C++ EH handlers?");
+ if (eh==-1) return;
+ if (eh) {
+ fixeh = AskYN(1, "Do you wish to fix function boundaries as needed?");
+ if (fixeh==-1) return;
+ }
+ if (seh) doSEH(fixseh);
+ if (eh) doEH(fixeh);
+ //fixCxx(ScreenEA());
+}
diff --git a/reversing/ms_rtti.idc b/reversing/ms_rtti.idc
new file mode 100644
index 00000000..052751f2
--- /dev/null
+++ b/reversing/ms_rtti.idc
@@ -0,0 +1,995 @@
+#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 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");
+
+ 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);
+ //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
diff --git a/reversing/ms_rtti4.idc b/reversing/ms_rtti4.idc
new file mode 100644
index 00000000..60802436
--- /dev/null
+++ b/reversing/ms_rtti4.idc
@@ -0,0 +1,660 @@
+#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();
+} \ No newline at end of file
diff --git a/reversing/parseVTableLinux.pl b/reversing/parseVTableLinux.pl
new file mode 100644
index 00000000..4f0e3556
--- /dev/null
+++ b/reversing/parseVTableLinux.pl
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+#local $/ = "\n\n";
+while(<>){
+ if(/([0-9A-Z]+).*?([a-z]+_.+?)st\n/s){
+ print "<class vtable=\"0x$1\" name=\"$2\" />\n";
+ }
+} \ No newline at end of file
diff --git a/reversing/vtable-linux-gcc.idc b/reversing/vtable-linux-gcc.idc
new file mode 100644
index 00000000..33217d68
--- /dev/null
+++ b/reversing/vtable-linux-gcc.idc
@@ -0,0 +1,43 @@
+#include <idc.idc>
+
+static main(void)
+{
+ auto SearchString;
+ auto searchStart;
+ auto searchTest;
+ auto occurances;
+ auto szFilePath,hFile;
+ auto strSize;
+ auto vTablePtr;
+ auto vTableLoc;
+ auto myString;
+ auto nextAddress;
+ auto byteVal;
+ occurances = 0;
+ searchStart = 0;
+
+ SearchString = AskStr("", "What vtable binary to search?");
+ szFilePath = AskFile(1, "*.txt", "Select output dump file:");
+ hFile = fopen(szFilePath, "wb");
+ Message("Scanning...");
+ searchStart = FindBinary(searchStart, SEARCH_DOWN, SearchString);
+ while(searchStart != BADADDR){
+ MakeStr(searchStart-2, BADADDR);
+ myString = GetString(searchStart-2,-1,GetStringType(searchStart-2));
+ strSize = strlen(myString);
+ nextAddress = searchStart-2+strSize+1;
+ byteVal = Byte(nextAddress);
+ while(byteVal == 0){
+ nextAddress++;
+ byteVal = Byte(nextAddress);
+ }
+ MakeDword(nextAddress);
+ vTableLoc = FindBinary(141301056,SEARCH_DOWN, form("%X", nextAddress));
+ MakeDword(nextAddress+4);
+ fprintf(hFile,"%a\t%s\n",vTableLoc,myString);
+ searchStart = FindBinary(searchStart+1, SEARCH_DOWN, SearchString);
+ occurances++;
+ }
+ fclose(hFile);
+ Message("Found %i Occurances",occurances);
+} \ No newline at end of file
diff --git a/reversing/vtable.idc b/reversing/vtable.idc
new file mode 100644
index 00000000..40bcca5b
--- /dev/null
+++ b/reversing/vtable.idc
@@ -0,0 +1,114 @@
+#include <idc.idc>
+static GetVtableSize(a)
+{
+ auto b,c,f;
+ b = BADADDR;
+ f = GetFlags(a);
+ //Message("checking vtable at: %a\n",a);
+ do {
+ f = GetFlags(a);
+ if (b == BADADDR) //first entry
+ {
+ b=a;
+ if (!(isRef(f) && (hasName(f) || (f&FF_LABL))))
+ {
+ //Message("Start of vtable should have a xref and a name (auto or manual)\n");
+ return 0;
+ }
+ }
+ else if (isRef(f)) //might mean start of next vtable
+ break;
+
+ //Message("hasValue(f):%d, isData(f):%d, isOff0(f):%d, (f & DT_TYPE) != FF_DWRD:%d\n",
+ // hasValue(f), isData(f), isOff0(f), (f & DT_TYPE) != FF_DWRD);
+ if (!hasValue(f) || !isData(f) /*|| !isOff0(f) || (f & DT_TYPE) != FF_DWRD*/)
+ break;
+ c = Dword(a);
+ if (c)
+ {
+ f = GetFlags(c);
+ if (!hasValue(f) || !isCode(f) || Dword(c)==0)
+ break;
+ }
+ a = a+4;
+ }
+ while (1);
+ if (b!=BADADDR)
+ {
+ c = (a-b)/4;
+ //Message("vtable: %08X-%08X, methods: %d\n",b,a,c);
+ return c;
+ }
+ else
+ {
+ //Message("no vtable at this EA\n");
+ return 0;
+ }
+}
+
+static main(void)
+{
+ auto a, c, k, name, i, struct_id, bNameMethods,e, methName;
+ a = ScreenEA();
+ k = GetVtableSize(a);
+ if (k>100)
+ {
+ if (1!=AskYN(0,form("%08X: This vtable appears to have %d methods. Are you sure you want to continue?",a,k)))
+ return;
+ }
+ if (hasName(GetFlags(a)))
+ name = Name(a);
+ else
+ name = "";
+ if (substr(name,0,4)=="??_7")
+ name = substr(name,4,strlen(name)-5);
+ name = AskStr(name,"Please enter the class name");
+ if (name==0)
+ return;
+ struct_id = GetStrucIdByName(name+"_vtable");
+ if (struct_id != -1)
+ {
+ i = AskYN(0,form("A vtable structure for %s already exists. Are you sure you want to remake it?",name));
+ if (i==-1)
+ return;
+ if (i==1)
+ {
+ DelStruc(struct_id);
+ struct_id = AddStrucEx(-1,name+"_vtable",0);
+ }
+ }
+ else
+ struct_id = AddStrucEx(-1,name+"_vtable",0);
+ if (struct_id == -1)
+ Warning("Could not create the vtable structure!.\nPlease check the entered class name.");
+ bNameMethods = (1==AskYN(0,form("Would you like to assign auto names to the virtual methods (%s_virtXX)?",name)));
+ for (i=0;i<k;i++)
+ {
+ c = Dword(a+i*4);
+ if (bNameMethods && !hasName(GetFlags(c)))
+ MakeName(c,form("%s_virt%02X",name,i*4));
+ if (hasName(GetFlags(c)))
+ {
+ methName = Name(c);
+ if (substr(methName,0,1)=="?")
+ {
+ methName = substr(methName,1,strstr(methName,"@"));
+ }
+ }
+ else
+ methName = form("virt%02X",i*4);
+ e = AddStrucMember(struct_id,methName,i*4,FF_DWRD|FF_DATA,-1,4);
+ if (0!=e)
+ {
+ if (e!=-2 && e!=-1)
+ {
+ Warning(form("Error adding a vtable entry (%d)!",e));
+ return;
+ }
+ else if (substr(GetMemberName(struct_id, i*4),0,6)=="field_")
+ SetMemberName(struct_id, i*4, form("virt%02X",i*4));
+ }
+ SetMemberComment(struct_id,i*4,form("-> %08X, args: 0x%X",c,GetFrameArgsSize(c)),1);
+ }
+ MakeName(a,"??_7"+name+"@@6B@");
+}