diff options
| author | Petr Mrázek | 2010-03-06 15:14:18 +0100 |
|---|---|---|
| committer | Petr Mrázek | 2010-03-06 15:14:18 +0100 |
| commit | 15ec3fbc744340824d3b6898f73651c447b6bc61 (patch) | |
| tree | a028a5919e3905c35d53902b6feb8fa6248f5f09 /reversing | |
| parent | 7a6b1488cb1f7e967462d96482cf4bc2cbe1a8f0 (diff) | |
| download | dfhack-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.idc | 802 | ||||
| -rw-r--r-- | reversing/ms_rtti.idc | 995 | ||||
| -rw-r--r-- | reversing/ms_rtti4.idc | 660 | ||||
| -rw-r--r-- | reversing/parseVTableLinux.pl | 8 | ||||
| -rw-r--r-- | reversing/vtable-linux-gcc.idc | 43 | ||||
| -rw-r--r-- | reversing/vtable.idc | 114 |
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@"); +} |
