Guest User

Untitled

a guest
Aug 14th, 2018
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.65 KB | None | 0 0
  1. #include <idc.idc>
  2.  
  3. static GetAsciizStr(anOffset)
  4. {
  5.   auto aResult, aByte;
  6.   aResult = "";
  7.   while (aByte=Byte(anOffset))
  8.   {
  9.     aResult = form("%s%c", aResult, aByte);
  10.     anOffset = anOffset + 1;
  11.   }
  12.   return aResult;
  13. }
  14.  
  15. static MangleNumber(aNumber)
  16. {
  17. //
  18. // 0 = A@
  19. // X = X-1 (1<=X<=10)
  20. // -X = ?(X-1)
  21. // 0x0..0xF = 'A'..'P'
  22.  
  23.     auto aMangledName, aSign;
  24.  
  25.     aMangledName = "";
  26.     aSign = "";
  27.  
  28.     if (aNumber < 0)
  29.     {
  30.         aSign = "?";
  31.         aNumber = -aNumber;
  32.     }  
  33.    
  34.     if (aNumber == 0)
  35.     {
  36.         return "A@";
  37.     }
  38.     else if (aNumber <= 10)
  39.     {
  40.         return form("%s%d", aSign, aNumber-1);
  41.     }
  42.     else
  43.     {
  44.         while (aNumber > 0)
  45.         {
  46.             aMangledName = form("%c%s", 'A' + aNumber%16, aMangledName);
  47.             aNumber = aNumber / 16;
  48.         }
  49.         return aSign + aMangledName + "@";
  50.     }
  51. }
  52.  
  53. /*
  54. struct RTTITypeDescriptor
  55. {
  56.     void* pVFTable;  //always pointer to type_info::vftable ?
  57.     void* spare;     //seems to be zero for most classes, and default constructor for exceptions
  58.     char name[0];    //mangled name, starting with .?A (.?AV=classes, .?AU=structs)
  59. };
  60.  
  61. struct RTTIPMD
  62. {
  63.     int mdisp;  //member displacement
  64.     int pdisp;  //vbtable displacement
  65.     int vdisp;  //displacement inside vbtable
  66. };
  67.  
  68. struct RTTIBaseClassDescriptor
  69. {
  70.     struct RTTITypeDescriptor* pTypeDescriptor; //type descriptor of the class
  71.     DWORD numContainedBases; //number of nested classes following in the array
  72.     struct RTTIPMD where;        //some displacement info
  73.     DWORD attributes;        //usually 0, sometimes 10h
  74. };
  75.  
  76. struct RTTIClassHierarchyDescriptor
  77. {
  78.     DWORD signature;      //always zero?
  79.     DWORD attributes;     //bit 0 = multiple inheritance, bit 1 = virtual inheritance
  80.     DWORD numBaseClasses; //number of classes in pBaseClassArray
  81.     struct RTTIBaseClassArray* pBaseClassArray;
  82. };
  83.  
  84. struct RTTICompleteObjectLocator
  85. {
  86.     DWORD signature; //always zero ?
  87.     DWORD offset;    //offset of this vtable in the class ?
  88.     DWORD cdOffset;  //no idea
  89.     struct RTTITypeDescriptor* pTypeDescriptor; //TypeDescriptor of the class
  90.     struct RTTIClassHierarchyDescriptor* pClassDescriptor; //inheritance hierarchy
  91. };
  92.  
  93. */
  94.  
  95.  
  96. static makeRttiStruct(void)
  97. {
  98.     auto aTDStructId, aTDName;
  99.     auto aPMDStructId, aPMDName;
  100.     auto aBCDStructId, aBCDName;
  101.     auto aCHDStructId, aCHDName;
  102.     auto aCOLStructId, aCOLName;
  103.    
  104.     aTDName = "RTTITypeDescriptor";
  105.     aPMDName = "RTTIPMD";
  106.     aBCDName = "RTTIBaseClassDescriptor";
  107.     aCHDName = "RTTIClassHierarchyDescriptor";
  108.     aCOLName = "RTTICompleteObjectLocator";
  109.    
  110.     aTDStructId = GetStrucIdByName(aTDName);
  111.     if (aTDStructId != -1)
  112.     {
  113.         DelStruc(aTDStructId);
  114.     }
  115.     aTDStructId = AddStruc(-1, aTDName);
  116.     AddStrucMember(aTDStructId, "pVFTable", 0, FF_DWRD|FF_DATA, -1, 4);
  117.     AddStrucMember(aTDStructId, "pSpare", 4, FF_DWRD|FF_DATA, -1, 4);
  118.    
  119.     aPMDStructId = GetStrucIdByName(aPMDName);
  120.     if (aPMDStructId != -1)
  121.     {
  122.         DelStruc(aPMDStructId);
  123.     }
  124.     aPMDStructId = AddStruc(-1, aPMDName);
  125.     AddStrucMember(aPMDStructId, "mDisp", 0, FF_DWRD|FF_DATA, -1, 4);
  126.     AddStrucMember(aPMDStructId, "pDisp", 4, FF_DWRD|FF_DATA, -1, 4);
  127.     AddStrucMember(aPMDStructId, "vDisp", 8, FF_DWRD|FF_DATA, -1, 4);
  128.    
  129.     aBCDStructId = GetStrucIdByName(aBCDName);
  130.     if (aBCDStructId != -1)
  131.     {
  132.         DelStruc(aBCDStructId);
  133.     }
  134.     aBCDStructId = AddStruc(-1, aBCDName);
  135.     AddStrucMember(aBCDStructId, "pTypeDescriptor", 0, FF_DWRD|FF_DATA, -1, 4);
  136.     AddStrucMember(aBCDStructId, "numContainedBases", 4, FF_DWRD|FF_DATA, -1, 4);
  137.     AddStrucMember(aBCDStructId, "where", 8, FF_STRU, aPMDStructId, 12);
  138.     AddStrucMember(aBCDStructId, "attributes", 20, FF_DWRD|FF_DATA, -1, 4);
  139.    
  140.     aCHDStructId = GetStrucIdByName(aCHDName);
  141.     if (aCHDStructId != -1)
  142.     {
  143.         DelStruc(aCHDStructId);
  144.     }
  145.     aCHDStructId = AddStruc(-1, aCHDName);
  146.     AddStrucMember(aCHDStructId, "signature", 0, FF_DWRD|FF_DATA, -1, 4);
  147.     AddStrucMember(aCHDStructId, "attributes", 4, FF_DWRD|FF_DATA, -1, 4);
  148.     AddStrucMember(aCHDStructId, "numBaseClasses", 8, FF_DWRD|FF_DATA, -1, 4);
  149.     AddStrucMember(aCHDStructId, "pBaseClassArray", 12, FF_DWRD|FF_DATA, -1, 4);
  150.    
  151.     aCOLStructId = GetStrucIdByName(aCOLName);
  152.     if (aCOLStructId != -1)
  153.     {
  154.         DelStruc(aCOLStructId);
  155.     }
  156.     aCOLStructId = AddStruc(-1, aCOLName);
  157.     AddStrucMember(aCOLStructId, "signature", 0, FF_DWRD|FF_DATA, -1, 4);
  158.     AddStrucMember(aCOLStructId, "offset", 4, FF_DWRD|FF_DATA, -1, 4);
  159.     AddStrucMember(aCOLStructId, "cdOffset", 8, FF_DWRD|FF_DATA, -1, 4);
  160.     AddStrucMember(aCOLStructId, "pTypeDescriptor", 12, FF_DWRD|FF_DATA, -1, 4);
  161.     AddStrucMember(aCOLStructId, "pClassHierarchyDescriptor", 16, FF_DWRD|FF_DATA, -1, 4);
  162. }
  163.  
  164. static MakeStructForce(anAddress, aStructName)
  165. {
  166.     MakeUnknown(anAddress, GetStrucSize(GetStrucIdByName(aStructName)), 0);
  167.     return MakeStruct(anAddress, aStructName);
  168. }
  169.  
  170. static MakeNameSafe(anAddress, aName)
  171. {
  172.     if (!hasName(GetFlags(anAddress)))
  173.     {
  174.         MakeName(anAddress, aName);
  175.     }
  176. }
  177.  
  178. static makeCOL(anAddress, aVTableAddress, aName)
  179. {
  180.     auto aCHDAddress, aBCAAddress, aNumBaseClasses, aBCAItem, aFoundBaseClass, i;
  181.     auto aBaseClassName, aVTableName, aReturnName;
  182.    
  183.     aReturnName = aName;
  184.     aVTableName = "";
  185.     if (!MakeStructForce(anAddress, "RTTICompleteObjectLocator"))
  186.     {
  187.         Message("An error occured while trying to change an offset to a RTTICompleteObjectLocator: %X\n", anAddress);
  188.     }
  189.     else
  190.     {
  191.         aBaseClassName = "";
  192.         aCHDAddress = Dword(anAddress + 16);
  193.         // COL offset == 0 && CHD attributes & 3 == 0
  194.         if (Dword(anAddress + 4) == 0
  195.             && (Dword(aCHDAddress + 4) & 3 == 0))
  196.         {
  197.             // Single inheritance no conflict
  198.            
  199.             //??_R4A@@6B@ = A::`RTTI Complete Object Locator'
  200.             MakeNameSafe(anAddress, "??_R4" + substr(aName, 4, -1) + "6B@");
  201.             MakeNameSafe(aVTableAddress, "??_7" + substr(aName, 4, -1) + "6B@");
  202.         }
  203.         else
  204.         {
  205.             aBCAAddress = Dword(aCHDAddress + 12);
  206.             aNumBaseClasses = Dword(aCHDAddress + 8);
  207.            
  208.             i = 0;
  209.             aFoundBaseClass = 0;
  210.            
  211.             while (i < aNumBaseClasses)
  212.             {
  213.                 aBCAItem = aBCAAddress + i * 4;
  214.                 if (Dword(Dword(aBCAItem) + 8) == Dword(anAddress + 4))
  215.                 {
  216.                     aBaseClassName = GetAsciizStr(Dword(Dword(aBCAItem)) + 8);
  217.                     aFoundBaseClass = 1;
  218.                     break;
  219.                 }
  220.                 i = i + 1;
  221.             }
  222.            
  223.             if (!aFoundBaseClass)
  224.             {
  225.                 i = 0;
  226.                 while (i < aNumBaseClasses)
  227.                 {
  228.                     aBCAItem = aBCAAddress + i * 4;
  229.                     if (Dword(Dword(aBCAItem) + 12) != -1)
  230.                     {
  231.                         aBaseClassName = GetAsciizStr(Dword(Dword(aBCAItem)) + 8);
  232.                         aFoundBaseClass = 1;
  233.                         break;
  234.                     }
  235.                     i = i + 1;
  236.                 }
  237.                 if (!aFoundBaseClass)
  238.                 {
  239.                     Message("An error occured while trying to fetch the name of the base class for the RTTICompleteObjectLocator at address: %X\n", anAddress);
  240.                 }
  241.             }
  242.            
  243.             aReturnName = substr(aName, 4, -1) + "6B" + substr(aBaseClassName, 4, -1) + "@";
  244.            
  245.             MakeNameSafe(anAddress, "??_R4" + substr(aName, 4, -1) + "6B" + substr(aBaseClassName, 4, -1) + "@");
  246.             MakeNameSafe(aVTableAddress, "??_7" + substr(aName, 4, -1) + "6B" + substr(aBaseClassName, 4, -1) + "@");
  247.         }
  248.         makeCHD(Dword(anAddress + 16), aName);
  249.     }
  250.    
  251.     return aReturnName;
  252. }
  253.  
  254. static makeTD(anAddress, aName)
  255. {
  256.     if (!MakeStructForce(anAddress, "RTTITypeDescriptor"))
  257.     {
  258.         Message("An error occured while trying to change an offset to a RTTITypeDescriptor: %X\n", anAddress);
  259.     }
  260.     else
  261.     {
  262.         //??_R0?AVA@@@8 = A::`RTTI Type Descriptor'
  263.         MakeNameSafe(anAddress, "??_R0" + substr(aName, 1, -1) + "@8");
  264.     }
  265. }
  266.  
  267. static makeBCD(anAddress, aName)
  268. {
  269.     auto aBCName;
  270.    
  271.     if (!MakeStructForce(anAddress, "RTTIBaseClassDescriptor"))
  272.     {
  273.         Message("An error occured while trying to change an offset to a RTTIBaseClassDescriptor: %X\n", anAddress);
  274.     }
  275.     else
  276.     {
  277.         aBCName = GetAsciizStr(Dword(anAddress) + 8);
  278.        
  279.         MakeNameSafe(anAddress, "??_R1"
  280.                                 + MangleNumber(Dword(anAddress+8))
  281.                                 + MangleNumber(Dword(anAddress+12))
  282.                                 + MangleNumber(Dword(anAddress+16))
  283.                                 + MangleNumber(Dword(anAddress+20))
  284.                                 + substr(aBCName, 4, -1)
  285.                                 + "8");
  286.     }
  287. }
  288.  
  289. static makeCHD(anAddress, aName)
  290. {
  291.     auto aBaseClassArray, aBaseClassAddress;
  292.     auto i, aNumBaseClasses;
  293.     if (!MakeStructForce(anAddress, "RTTIClassHierarchyDescriptor"))
  294.     {
  295.         Message("An error occured while trying to change an offset to a RTTIClassHierarchyDescriptor: %X\n", anAddress);
  296.     }
  297.     else
  298.     {
  299.         //??_R3A@@8 = A::`RTTI Class Hierarchy Descriptor'
  300.         MakeNameSafe(anAddress,"??_R3" + substr(aName,4,-1) + '8');
  301.        
  302.         aBaseClassArray = Dword(anAddress + 12);
  303.        
  304.         //??_R2A@@8 = A::`RTTI Base Class Array'
  305.         MakeNameSafe(aBaseClassArray,"??_R2" + substr(aName,4,-1) + '8');
  306.        
  307.         aNumBaseClasses = Dword(anAddress + 8);
  308.        
  309.         MakeUnknown(aBaseClassArray, aNumBaseClasses * 4, 0);
  310.        
  311.         i = 0;
  312.         while (i < aNumBaseClasses)
  313.         {
  314.             makeBCD(Dword(aBaseClassArray + i * 4), aName);
  315.             MakeDword(aBaseClassArray + i * 4);
  316.             i = i + 1;
  317.         }
  318.     }
  319. }
  320.  
  321. #define IS_TD(address) ((Dword(address) == aVTableTypeInfoAddress) && ((Dword(address + 8) & 0xFFFFFF) == 0x413F2E)) // .?AV
  322.  
  323. static main(void)
  324. {
  325.     // First step detecting rdata and text segments
  326.     auto aCurrentSeg, aCurrentAddress, aMiscAddress;
  327.     auto aMinDataSeg, aMaxDataSeg;
  328.     auto aMinRDataSeg, aMaxRDataSeg;
  329.     auto aMinTextSeg, aMaxTextSeg;
  330.    
  331.     auto aVTableTypeInfoAddress;
  332.    
  333.     auto aName, aVTableName, aBaseClassName;
  334.    
  335.     auto anArrayIndex, i, j;
  336.     auto aMaxBaseClassNum, aBaseClassNum;
  337.     auto aVTableAddressArray, aVTableBaseClassNumArray, aVTableClassNameArray;
  338.     auto aVTableAddressArrayId, aVTableBaseClassNumArrayId, aVTableClassNameArrayId;
  339.    
  340.     aMaxBaseClassNum = 0;
  341.     anArrayIndex = 0;
  342.    
  343.     aVTableAddressArray = "aVTableAddressArray";
  344.     aVTableBaseClassNumArray = "aVTableBaseClassNumArray";
  345.     aVTableClassNameArray = "aVTableClassNameArray";
  346.    
  347.    
  348.     aVTableAddressArrayId = GetArrayId(aVTableAddressArray);
  349.     aVTableBaseClassNumArrayId = GetArrayId(aVTableBaseClassNumArray);
  350.     aVTableClassNameArrayId = GetArrayId(aVTableClassNameArray);
  351.    
  352.     DeleteArray(aVTableAddressArrayId);
  353.     DeleteArray(aVTableBaseClassNumArrayId);
  354.     DeleteArray(aVTableClassNameArrayId);
  355.    
  356.     aVTableAddressArrayId = CreateArray(aVTableAddressArray);
  357.     aVTableBaseClassNumArrayId = CreateArray(aVTableBaseClassNumArray);
  358.     aVTableClassNameArrayId = CreateArray(aVTableClassNameArray);
  359.    
  360.     Message("vtables_rtti script started.\n");
  361.    
  362.     makeRttiStruct();
  363.    
  364.     aMinDataSeg = 0;
  365.     aMaxDataSeg = 0;
  366.     aMinRDataSeg = 0;
  367.     aMaxRDataSeg = 0;
  368.     aMinTextSeg = 0;
  369.     aMaxTextSeg = 0;
  370.    
  371.     aCurrentSeg = FirstSeg();
  372.    
  373.     while (aCurrentSeg != BADADDR)
  374.     {
  375.         if (SegName(aCurrentSeg)==".rdata")
  376.         {
  377.             aMinRDataSeg = aCurrentSeg;
  378.             aMaxRDataSeg = NextSeg(aCurrentSeg);
  379.         }
  380.         else if (SegName(aCurrentSeg)==".text")
  381.         {
  382.             aMinTextSeg = aCurrentSeg;
  383.             aMaxTextSeg = NextSeg(aCurrentSeg);
  384.         }
  385.         else if (SegName(aCurrentSeg)==".data")
  386.         {
  387.             aMinDataSeg = aCurrentSeg;
  388.             aMaxDataSeg = NextSeg(aCurrentSeg);
  389.         }
  390.         aCurrentSeg = NextSeg(aCurrentSeg);
  391.     }
  392.    
  393.     if (aMinRDataSeg == 0)
  394.     {
  395.         aMinRDataSeg=aMinTextSeg;
  396.         aMaxRDataSeg=aMaxTextSeg;
  397.     }
  398.    
  399.     Message(".data: %08.8Xh - %08.8Xh, .rdata: %08.8Xh - %08.8Xh, .text %08.8Xh - %08.8Xh\n", aMinDataSeg, aMaxDataSeg, aMinRDataSeg, aMaxRDataSeg, aMinTextSeg, aMaxTextSeg);
  400.    
  401.     Message("Parsing .data for type_info TypeDescriptor.\n");
  402.    
  403.     aVTableTypeInfoAddress = 0;
  404.     aCurrentAddress = aMinDataSeg;
  405.     while (aCurrentAddress < aMaxDataSeg)
  406.     {
  407.         // .?AVtype_info@@
  408.         if (Dword(aCurrentAddress) == 0x56413F2E         // .?AV
  409.             && Dword(aCurrentAddress + 4) == 0x65707974  // type
  410.             && Dword(aCurrentAddress + 8) == 0x666e695f  // _inf
  411.             && Dword(aCurrentAddress + 12) == 0x0040406f) // o@@\0
  412.         {
  413.             aVTableTypeInfoAddress = Dword(aCurrentAddress - 8);
  414.             break;
  415.         }
  416.         aCurrentAddress = aCurrentAddress + 4;
  417.     }
  418.    
  419.     if (!aVTableTypeInfoAddress)
  420.     {
  421.         Message("Type_info TypeDescriptor not found, aborting.\n");
  422.         return;
  423.     }
  424.     else
  425.     {
  426.         Message("Found type_info TypeDescriptor VTable at: %X\n", aVTableTypeInfoAddress);
  427.        
  428.         Message("Parsing .data for all TypeDescriptors.\n");
  429.        
  430.         aCurrentAddress = aMinDataSeg;
  431.         while (aCurrentAddress < aMaxDataSeg)
  432.         {
  433.             if (IS_TD(aCurrentAddress))
  434.             {
  435.                 aName = GetAsciizStr(aCurrentAddress + 8);
  436.                 makeTD(aCurrentAddress, aName);
  437.             }
  438.            
  439.             aCurrentAddress = aCurrentAddress + 4;
  440.         }
  441.        
  442.         Message("Parsed all TypeDescriptors.\n");
  443.     }
  444.    
  445.     Message("Parsing .rdata for VTables.\n");
  446.    
  447.     aCurrentAddress = aMinRDataSeg;
  448.     while (aCurrentAddress < aMaxRDataSeg)
  449.     {
  450.         aMiscAddress = Dword(aCurrentAddress);
  451.         if (aMinTextSeg < aMiscAddress
  452.             && aMaxTextSeg > aMiscAddress)
  453.         {
  454.             aMiscAddress = Dword(aCurrentAddress - 4);
  455.             if (aMinRDataSeg < aMiscAddress
  456.                 && aMaxRDataSeg > aMiscAddress)
  457.             {
  458.                 aMiscAddress = Dword(aMiscAddress + 12);
  459.                 if (IS_TD(aMiscAddress))
  460.                 {
  461.                     aName = GetAsciizStr(aMiscAddress + 8);
  462.                     aBaseClassName = makeCOL(Dword(aCurrentAddress - 4), aCurrentAddress, aName);
  463.                     MakeNameSafe(aCurrentAddress, aVTableName);
  464.                    
  465.                     aBaseClassNum = Dword(Dword(Dword(aCurrentAddress - 4) + 16) + 8);
  466.                    
  467.                     if (aBaseClassNum > aMaxBaseClassNum)
  468.                     {
  469.                         aMaxBaseClassNum = aBaseClassNum;
  470.                         Message("MaxBaseClassNum: %d\n", aMaxBaseClassNum);
  471.                     }
  472.                    
  473.                     SetArrayLong(aVTableAddressArrayId, anArrayIndex, aCurrentAddress);
  474.                     SetArrayLong(aVTableBaseClassNumArrayId, anArrayIndex, aBaseClassNum);
  475.                     SetArrayString(aVTableClassNameArrayId, anArrayIndex, aBaseClassName);
  476.                    
  477.                     anArrayIndex = anArrayIndex + 1;
  478.                 }
  479.             }
  480.         }
  481.         aCurrentAddress = aCurrentAddress + 4;
  482.     }
  483.    
  484.     i = 0;
  485.     while (i <= aMaxBaseClassNum)
  486.     {
  487.         j = 0;
  488.         while (j < anArrayIndex)
  489.         {
  490.             if (GetArrayElement(AR_LONG, aVTableBaseClassNumArrayId, j) == i)
  491.             {
  492.                 aCurrentAddress = GetArrayElement(AR_LONG, aVTableAddressArrayId, j);
  493.                 while (aMinTextSeg < Dword(aCurrentAddress)
  494.                        && aMaxTextSeg > Dword(aCurrentAddress))
  495.                 {
  496.                     aName = form("%s%d", "?virt_", aCurrentAddress - GetArrayElement(AR_LONG, aVTableAddressArrayId, j));
  497.                     MakeNameSafe(Dword(aCurrentAddress), aName + "@" + GetArrayElement(AR_STR, aVTableClassNameArrayId, j));
  498.                     MakeDword(aCurrentAddress);
  499.                     aCurrentAddress = aCurrentAddress + 4;
  500.                 }
  501.             }
  502.             j = j + 1;
  503.         }
  504.         i = i + 1;
  505.     }
  506.    
  507.     DeleteArray(aVTableAddressArrayId);
  508.     DeleteArray(aVTableBaseClassNumArrayId);
  509.     DeleteArray(aVTableClassNameArrayId);
  510.    
  511.     Message("vtables_rtti script ended.\n");
  512. }
Add Comment
Please, Sign In to add comment