From d2f59c5f90ece0658df90875919963384f7f7e24 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 6 May 2018 10:26:14 -0600 Subject: [PATCH] Update Contributing (IDA Freeware 7.0, cl-linux-debug being 32-bit only) Also add my IDC script for doing RTTI on 64-bit Windows binaries --- Contributing.rst | 10 +- reversing/ms_rtti64.idc | 1086 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 1091 insertions(+), 5 deletions(-) create mode 100644 reversing/ms_rtti64.idc diff --git a/Contributing.rst b/Contributing.rst index 59ff8285f..e358e66b3 100644 --- a/Contributing.rst +++ b/Contributing.rst @@ -49,16 +49,16 @@ In general, you'll need a good memory viewer and optionally something to look at machine code without getting crazy :) Using publicly known information and analyzing the game's data is preferred. -Good windows tools include: +Good Windows tools include: +* IDA Freeware 7.0 (for non-commercial use, supports 32-bit and 64-bit) * Cheat Engine -* IDA Pro 5.0 (freely available for non-commercial use) -Good linux tools: +Good Linux tools: -* angavrilov's df-structures gui (visit us on IRC for details). +* angavrilov's df-structures gui (32-bit only, visit us on IRC for details) +* IDA Freeware 7.0 (see above) * edb (Evan's Debugger) -* IDA Pro 5.0 running under Wine * Some of the tools residing in the ``legacy`` dfhack branch. Using the library as a developer diff --git a/reversing/ms_rtti64.idc b/reversing/ms_rtti64.idc new file mode 100644 index 000000000..da26ae916 --- /dev/null +++ b/reversing/ms_rtti64.idc @@ -0,0 +1,1086 @@ +#include + +#define isRef(F) ((F & FF_REF) != 0) +#define hasName(F) ((F & FF_NAME) != 0) + +static GetVtableSize(a) +{ + auto b,c,f; + b = BADADDR; + f = GetFlags(a); + do { + f = GetFlags(a); + if (b == BADADDR) //first entry + { + b=a; + if (!(isRef(f) && (hasName(f) || (f&FF_LABL)))) + { + return 0; + } + } + else if (isRef(f)) //might mean start of next vtable + break; + + if (!hasValue(f) || !isData(f)) + break; + c = Qword(a); + if (c) + { + f = GetFlags(c); + if (!hasValue(f) || !isCode(f) || Dword(c)==0) + break; + } + a = a+8; + } + while (1); + if (b!=BADADDR) + { + c = (a-b)/8; + return c; + } + else + { + return 0; + } +} + +static Unknown( ea, length ) +{ + auto i; + if (ea==BADADDR) + return; + for(i=0; i < length; i++) + { + MakeUnkn(ea+i,0); + } +} + +static DwordRel(x) +{ + x = Dword(x) + 0x140000000; + return x; +} + +static ForceQword( x ) { //Make dword, undefine as needed + if (x==BADADDR || x==0) + return; + if (!MakeQword( x )) + { + Unknown(x,8); + MakeQword(x); + } +} + +static ForceDword( x ) { //Make dword, undefine as needed + if (x==BADADDR || x==0) + return; + if (!MakeDword( x )) + { + Unknown(x,4); + MakeDword(x); + } +} + +static SoftOff64 ( x ) { //Make 64-bit offset if !=0 + if (x==BADADDR || x==0) + return; + ForceQword(x); + if (Qword(x)>0 && Qword(x)<=MaxEA()) OpOff(x, 0, 0); +} + +static SoftOff ( x ) { //Make 32-bit base-relative offset if !=0 + if (x==BADADDR || x==0) + return; + ForceDword(x); + if (Dword(x)>0 && Dword(x)<=MaxEA()) OpOffEx(x,0,REF_OFF32|REFINFO_RVA|REFINFO_SIGNEDOP, -1, 0, 0); +} + +//check if pointer is to typeinfo record and extract the type name from it +static GetTypeName(vtbl) +{ + auto x; + if (vtbl==BADADDR) + return; + x = DwordRel(vtbl+12); + if ((!x) || (x==BADADDR)) return ""; + return GetAsciizStr(x+16); +} + +static DwordCmt(x, cmt) +{ + if (x==BADADDR || x==0) + return; + ForceDword(x); + MakeComm(x, cmt); +} +static OffCmt(x, cmt) +{ + if (x==BADADDR || x==0) + return; + SoftOff(x); + if (cmt != "") + MakeComm(x, cmt); +} +static OffCmt64(x, cmt) +{ + if (x==BADADDR || x==0) + return; + SoftOff64(x); + MakeComm(x, cmt); +} +static StrCmt(x, cmt) +{ + auto save_str; + if (x==BADADDR || x==0) + return; + MakeUnkn(x, 0); + save_str = GetLongPrm(INF_STRTYPE); + SetLongPrm(INF_STRTYPE,0); + MakeStr(x, BADADDR); + MakeName(x, ""); + MakeComm(x, cmt); + SetLongPrm(INF_STRTYPE,save_str); +} +static DwordArrayCmt(x, n, cmt) +{ + if (x==BADADDR || x==0) + return; + Unknown(x,4*n); + ForceDword(x); + MakeArray(x,n); + MakeComm(x, cmt); +} + +//check if values match a pattern +static matchBytes(addr,match) +{ + auto i,len,s; + len = strlen(match); + if (len%2) + { + Warning("Bad match string in matchBytes: %s",match); + return 0; + } + i=0; + while (i 2147483647) x = x - 4294967296; + if (x<0) + { + sign = 1; + x = -x; + } + if (x==0) + return "A@"; + else if (x<=10) + return form("%s%d",sign?"?":"",x-1); + else + { + while (x>0) + { + s = form("%c%s",'A'+x%16,s); + x = x / 16; + } + return sign?"?":""+s+"@"; + } +} +static Parse_BCD(x, indent) +{ + auto indent_str,i,a,s; + if (x==BADADDR || x==0) + return; + indent_str="";i=0; + while(i0) //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 ea ) // InSort + { + for ( ; idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) + { + val = GetArrayElement(AR_LONG, id, idx); + SetArrayLong(id, idx, ea); + ea = val; + } + } + } + SetArrayLong(id, GetLastIndex(AR_LONG, id) + 1, ea); +} +static getArraySize(id) +{ + auto idx, count; + count = 0; + for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) + { + count++; + } + return count; +} + +static doAddrList(name) +{ + auto idx, id, val, ctr, dtr; + id = GetArrayId("AddrList"); + ctr = 0; dtr = 0; + if ( name!=0 && id != -1 ) + { + if (getArraySize(id)!=2) + return; + for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) + { + val = GetArrayElement(AR_LONG, id, idx); + if (Byte(val)==0xE9) + val = getRelJmpTarget(val); + if ((substr(Name(val),0,3)=="??1")) + dtr = val; + else + ctr = val; + } + } + if (ctr!=0 && dtr!=0) + { + MakeName(ctr, MakeSpecialName(name,SN_constructor,0)); + } + DeleteArray(GetArrayId("AddrList")); +} + +//check if there's a vtable at a and dump into to f +//returns position after the end of vtable +static DoVtable(a) +{ + auto x,y,s,p,q,i,name; + + //check if it looks like a vtable + y = GetVtableSize(a); + if (y == 0) + return a+8; + + //check if it's named as a vtable + name = Name(a); + if (substr(name,0,4)!="??_7") name=0; + + x = Qword(a-8); + //otherwise try to get it from RTTI + if (IsValidCOL(x)) + { + Parse_Vtable(a); + if (name==0) + name = GetVtblName(x); + MakeName(a, name); + } + if (name!=0) + { + name = ".?AV"+substr(name, 4, strstr(name,"@@6B")+2); + } + { + DeleteArray(GetArrayId("AddrList")); + q = 0; i = 1; + for ( x=DfirstB(a); x != BADADDR; x=DnextB(a,x) ) + { + p = funcStart(x); + if (p!=-1) + { + if (q==p) + i++; + else + { + if (q) { + AddAddr(q); + } + i = 1; + q = p; + } + } + } + if (q) + { + AddAddr(q); + } + + x = a; + while (y>0) + { + p = Dword(x); + if (GetFunctionFlags(p) == -1) + { + MakeCode(p); + MakeFunction(p, BADADDR); + } + checkSDD(p,name,a,0); + y--; + x = x+8; + } + doAddrList(name); + } + return x; +} + +static scan_for_vtables(void) +{ + auto rmin, rmax, cmin, cmax, s, a, x, y; + s = FirstSeg(); + rmin = 0; rmax = 0; + while (s!=BADADDR) + { + if (SegName(s)==".rdata") + { + rmin = s; + rmax = NextSeg(s); + } + else if (SegName(s)==".text") + { + cmin = s; + cmax = NextSeg(s); + } + s = NextSeg(s); + } + if (rmin==0) {rmin=cmin; rmax=cmax;} + a = rmin; + while (a=cmin && x + //74 07 jz short @@no_free + //56 push esi + //E8 CA 2D 0D 00 call operator delete(void *) + //59 pop ecx + // @@no_free: + //8B C6 mov eax, esi + //5E pop esi + //C2 04 00 retn 4 + t = SN_scalardtr; + } + else if (matchBytes(x,"538A5C2408568BF1F6C302742B8B46FC578D7EFC68????????506A??56E8") || + matchBytes(x,"538A5C2408F6C302568BF1742E8B46FC5768????????8D7EFC5068????????56E8")) + { + //53 push ebx + //8A 5C 24 08 mov bl, [esp+arg_0] + //56 push esi + //8B F1 mov esi, ecx + //F6 C3 02 test bl, 2 + //74 2B jz short loc_100037F8 + //8B 46 FC mov eax, [esi-4] + //57 push edi + //8D 7E FC lea edi, [esi-4] + //68 xx xx xx xx push offset class::~class(void) + //50 push eax + //6A xx push xxh + //56 push esi + //E8 xx xx xx xx call `eh vector destructor iterator'(void *,uint,int,void (*)(void *)) + t = SN_vectordtr; + if (name!=0) + a = Dword(x+21); + if (gate && Byte(a)==0xE9) + { + a = getRelJmpTarget(a); + } + } + + if (t>0) + { + if (t==SN_vectordtr) + s = "vector"; + else + s = "scalar"; + if (name!=0) + MakeName(x, MakeSpecialName(name,t,0)); + if (a!=BADADDR) + { + if (name!=0) + MakeName(a, MakeSpecialName(name,SN_vdestructor,0)); + } + CommentStack(x, 4, "__flags$",-1); + } + return t; +} + +static main(void) +{ + scan_for_vtables(); +} \ No newline at end of file