1+ #include " itanium.h"
2+
3+ using namespace BinaryNinja ;
4+ using namespace BinaryNinja ::RTTI;
5+ using namespace BinaryNinja ::RTTI::Itanium;
6+
7+ // TODO: Need to add the boiler plate stuff
8+ // TODO: Can we find the object offset for the vtable entry?
9+ // TODO: Itanium doesnt really say anything about the sizing of these fields, i assume they are all u32 for thje most part.
10+
11+ constexpr const char *TYPE_SOURCE_ITANIUM = " rtti_itanium" ;
12+
13+ TypeInfo::TypeInfo (BinaryView *view, uint64_t address)
14+ {
15+ BinaryReader reader = BinaryReader (view);
16+ reader.Seek (address);
17+ base = reader.ReadPointer ();
18+ auto typeNameAddr = reader.ReadPointer ();
19+ reader.Seek (typeNameAddr);
20+ type_name = reader.ReadCString (512 );
21+ }
22+
23+
24+ SIClassTypeInfo::SIClassTypeInfo (BinaryView *view, uint64_t address) : ClassTypeInfo(view, address)
25+ {
26+ BinaryReader reader = BinaryReader (view);
27+ // TODO: Manually seeking to the offset is ugly.
28+ reader.Seek (address + 0x10 );
29+ base_type = reader.ReadPointer ();
30+ }
31+
32+
33+ BaseClassTypeInfo::BaseClassTypeInfo (BinaryView *view, uint64_t address)
34+ {
35+ BinaryReader reader = BinaryReader (view);
36+ reader.Seek (address);
37+ base_type = reader.ReadPointer ();
38+ offset_flags = reader.Read32 ();
39+ // TODO: Test this...
40+ offset_flags_masks = static_cast <OffsetFlagsMasks>(reader.Read32 ());
41+ }
42+
43+
44+ VMIClassTypeInfo::VMIClassTypeInfo (BinaryView *view, uint64_t address) : ClassTypeInfo(view, address)
45+ {
46+ BinaryReader reader = BinaryReader (view);
47+ // TODO: Manually seeking to the offset is ugly.
48+ reader.Seek (address + 0x10 );
49+ flags = reader.Read32 ();
50+ base_count = reader.Read32 ();
51+ base_info = {};
52+ for (size_t i = 1 ; i < base_count; i++)
53+ {
54+ // TODO: Verify this is correct.
55+ uint64_t currentBaseAddr = reader.GetOffset ();
56+ base_info.emplace_back (view, reader.GetOffset ());
57+ reader.Seek (currentBaseAddr + 12 );
58+ }
59+ }
60+
61+
62+ Ref<Type> TypeInfoType (BinaryView *view)
63+ {
64+ auto typeId = Type::GenerateAutoTypeId (TYPE_SOURCE_ITANIUM, QualifiedName (" TypeInfo" ));
65+ Ref<Type> typeCache = view->GetTypeById (typeId);
66+
67+ if (typeCache == nullptr )
68+ {
69+ Ref<Architecture> arch = view->GetDefaultArchitecture ();
70+
71+ StructureBuilder structureBuilder;
72+ Ref<Type> pBaseType = Type::PointerType (arch, Type::VoidType ());
73+ structureBuilder.AddMember (pBaseType, " __base" );
74+ Ref<Type> pTypeNameType = Type::PointerType (arch, Type::IntegerType (1 , true , " char" ));
75+ structureBuilder.AddMember (pTypeNameType, " __type_name" );
76+
77+ Ref<Type> structureType = TypeBuilder::StructureType (structureBuilder.Finalize ()).Finalize ();
78+ // TODO: std::type_info or __cxxabiv1::__type_info ?
79+ view->DefineType (typeId, QualifiedName (" std::type_info" ), structureType);
80+
81+ typeCache = view->GetTypeById (typeId);
82+ }
83+
84+ return typeCache;
85+ }
86+
87+
88+ Ref<Type> ClassTypeInfoType (BinaryView *view)
89+ {
90+ auto typeId = Type::GenerateAutoTypeId (TYPE_SOURCE_ITANIUM, QualifiedName (" ClassTypeInfo" ));
91+ Ref<Type> typeCache = view->GetTypeById (typeId);
92+
93+ if (typeCache == nullptr )
94+ {
95+ StructureBuilder structureBuilder;
96+ BaseStructure typeInfoBase = BaseStructure (TypeInfoType (view), 0 );
97+ structureBuilder.SetBaseStructures ({typeInfoBase});
98+ // TODO: This exists because if you have no members but a base struct things get screwy.
99+ structureBuilder.SetWidth (0x10 );
100+
101+ Ref<Type> structureType = TypeBuilder::StructureType (structureBuilder.Finalize ()).Finalize ();
102+ view->DefineType (typeId, QualifiedName (" __cxxabiv1::__class_type_info" ), structureType);
103+
104+ typeCache = view->GetTypeById (typeId);
105+ }
106+
107+ return typeCache;
108+ }
109+
110+ Ref<Type> SIClassTypeInfoType (BinaryView *view)
111+ {
112+ auto typeId = Type::GenerateAutoTypeId (TYPE_SOURCE_ITANIUM, QualifiedName (" SIClassTypeInfo" ));
113+ Ref<Type> typeCache = view->GetTypeById (typeId);
114+
115+ if (typeCache == nullptr )
116+ {
117+ Ref<Architecture> arch = view->GetDefaultArchitecture ();
118+
119+ StructureBuilder structureBuilder;
120+ Ref<Type> pBaseType = Type::PointerType (arch, Type::VoidType ());
121+ structureBuilder.AddMemberAtOffset (pBaseType, " __base_type" , 0x10 );
122+ BaseStructure classTypeInfoBase = BaseStructure (ClassTypeInfoType (view), 0 );
123+ structureBuilder.SetBaseStructures ({classTypeInfoBase});
124+
125+ Ref<Type> structureType = TypeBuilder::StructureType (structureBuilder.Finalize ()).Finalize ();
126+ view->DefineType (typeId, QualifiedName (" __cxxabiv1::__si_class_type_info" ), structureType);
127+
128+ typeCache = view->GetTypeById (typeId);
129+ }
130+
131+ return typeCache;
132+ }
133+
134+
135+ Ref<Type> OffsetFlagsMasksType (BinaryView *view)
136+ {
137+ auto typeId = Type::GenerateAutoTypeId (TYPE_SOURCE_ITANIUM, QualifiedName (" OffsetFlagsMasks" ));
138+ Ref<Type> typeCache = view->GetTypeById (typeId);
139+
140+ if (typeCache == nullptr )
141+ {
142+ Ref<Architecture> arch = view->GetDefaultArchitecture ();
143+ Ref<Type> uintType = Type::IntegerType (4 , false );
144+
145+ EnumerationBuilder enumerationBuilder;
146+ enumerationBuilder.AddMemberWithValue (" __virtual_mask" , 0x1 );
147+ enumerationBuilder.AddMemberWithValue (" __public_mask" , 0x2 );
148+ enumerationBuilder.AddMemberWithValue (" __offset_shift" , 0x8 );
149+
150+ Ref<Type> enumerationType = TypeBuilder::EnumerationType (arch, enumerationBuilder.Finalize ()).Finalize ();
151+ view->DefineType (typeId, QualifiedName (" __cxxabiv1::__offset_flags_masks" ), enumerationType);
152+
153+ typeCache = view->GetTypeById (typeId);
154+ }
155+
156+ return typeCache;
157+ }
158+
159+
160+ Ref<Type> BaseClassTypeInfoType (BinaryView *view)
161+ {
162+ auto typeId = Type::GenerateAutoTypeId (TYPE_SOURCE_ITANIUM, QualifiedName (" BaseClassTypeInfo" ));
163+ Ref<Type> typeCache = view->GetTypeById (typeId);
164+
165+ if (typeCache == nullptr )
166+ {
167+ Ref<Architecture> arch = view->GetDefaultArchitecture ();
168+ Ref<Type> uintType = Type::IntegerType (4 , false );
169+
170+ StructureBuilder structureBuilder;
171+ Ref<Type> pBaseType = Type::PointerType (arch, Type::VoidType ());
172+ structureBuilder.AddMember (pBaseType, " __base_type" );
173+ structureBuilder.AddMember (uintType, " __offset_flags" );
174+ structureBuilder.AddMember (OffsetFlagsMasksType (view), " __offset_flags_masks" );
175+
176+ Ref<Type> structureType = TypeBuilder::StructureType (structureBuilder.Finalize ()).Finalize ();
177+ view->DefineType (typeId, QualifiedName (" __cxxabiv1::__base_class_type_info" ), structureType);
178+
179+ typeCache = view->GetTypeById (typeId);
180+ }
181+
182+ return typeCache;
183+ }
184+
185+
186+ Ref<Type> VMIClassTypeInfoType (BinaryView *view, int baseCount)
187+ {
188+ Ref<Architecture> arch = view->GetDefaultArchitecture ();
189+ Ref<Type> uintType = Type::IntegerType (4 , false );
190+
191+ StructureBuilder structureBuilder;
192+ structureBuilder.AddMemberAtOffset (uintType, " __flags" , 0x10 );
193+ structureBuilder.AddMemberAtOffset (uintType, " __base_count" , 0x14 );
194+ Ref<Type> baseInfoType = Type::ArrayType (BaseClassTypeInfoType (view), baseCount);
195+ structureBuilder.AddMemberAtOffset (baseInfoType, " __base_info" , 0x18 );
196+ BaseStructure classTypeInfoBase = BaseStructure (ClassTypeInfoType (view), 0 );
197+ structureBuilder.SetBaseStructures ({classTypeInfoBase});
198+
199+ return TypeBuilder::StructureType (structureBuilder.Finalize ()).Finalize ();
200+ }
201+
202+
203+ std::optional<TypeInfoVariant> ReadTypeInfoVariant (BinaryView *view, uint64_t objectAddr)
204+ {
205+ auto typeInfo = TypeInfo (view, objectAddr);
206+
207+ // TODO: What if there is no symbol?
208+ // If there is a symbol at objectAddr pointing to a symbol starting with "vtable for __cxxabiv1"
209+ auto baseSym = view->GetSymbolByAddress (typeInfo.base );
210+ if (baseSym == nullptr )
211+ return std::nullopt ;
212+ if (baseSym->GetType () != ExternalSymbol)
213+ return std::nullopt ;
214+ auto baseSymName = baseSym->GetShortName ();
215+
216+ // TODO: __vmi_class_type_info seems to point to operator delete(void*)
217+ // TODO: For now we just bruteforce it with the type_name check...
218+
219+ if (baseSymName.find (" __cxxabiv1" ) != std::string::npos)
220+ {
221+ // symbol takes the form of `abi::base_name`
222+ auto baseTyStartPos = baseSymName.find (" ::" );
223+ if (baseTyStartPos != std::string::npos)
224+ baseSymName = baseSymName.substr (baseTyStartPos + 2 );
225+
226+ if (baseSymName == " __class_type_info" )
227+ return TIVClass;
228+ if (baseSymName == " __si_class_type_info" )
229+ return TIVSIClass;
230+ if (baseSymName == " __vmi_class_type_info" )
231+ return TIVVMIClass;
232+ }
233+ else if (typeInfo.type_name .length () > 2 )
234+ {
235+ // TODO: This is so ugly
236+ switch (typeInfo.type_name .at (0 ))
237+ {
238+ case ' 7' :
239+ return TIVClass;
240+ case ' 9' :
241+ return TIVSIClass;
242+ case ' 1' :
243+ if (typeInfo.type_name .at (1 ) == ' 4' )
244+ return TIVVMIClass;
245+ default :
246+ return std::nullopt ;
247+ }
248+ }
249+
250+ return std::nullopt ;
251+ }
252+
253+
254+ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI (uint64_t objectAddr)
255+ {
256+ // TODO: You cant get subobject offsets from rtti, its stored above this ptr in vtable.
257+ // Get object as type info then check to see if it's valid.
258+ auto typeInfoVariant = ReadTypeInfoVariant (m_view, objectAddr);
259+ if (!typeInfoVariant.has_value ())
260+ return std::nullopt ;
261+
262+ auto typeInfo = TypeInfo (m_view, objectAddr);
263+ auto className = DemangleNameGNU3 (m_view, allowMangledClassNames, typeInfo.type_name );
264+ if (!className.has_value ())
265+ return std::nullopt ;
266+ auto classInfo = ClassInfo{className.value ()};
267+
268+ // TODO: className starts with 7, 9, 14
269+ // 7 == class_type
270+ // 9 == si_class_type
271+ // 14 == vmi_class_type
272+
273+ auto typeInfoName = fmt::format (" _typeinfo_for_{}" , classInfo.className );
274+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, typeInfoName, objectAddr});
275+
276+ if (typeInfoVariant == TIVSIClass)
277+ {
278+ // Read the base class.
279+ auto siClassTypeInfo = SIClassTypeInfo (m_view, objectAddr);
280+ auto subTypeInfoVariant = ReadTypeInfoVariant (m_view, siClassTypeInfo.base_type );
281+ if (!subTypeInfoVariant.has_value ())
282+ return std::nullopt ;
283+ auto subTypeInfo = TypeInfo (m_view, siClassTypeInfo.base_type );
284+ // Demangle base class name and set
285+ auto baseClassName = DemangleNameGNU3 (m_view, allowMangledClassNames, subTypeInfo.type_name );
286+ if (!baseClassName.has_value ())
287+ {
288+ m_logger->LogWarn (" Skipping base class with mangled name %llx" , siClassTypeInfo.base_type );
289+ return std::nullopt ;
290+ }
291+ classInfo.baseClassName = baseClassName;
292+ m_view->DefineDataVariable (objectAddr, Confidence (SIClassTypeInfoType (m_view), 255 ));
293+ }
294+ else if (typeInfoVariant == TIVVMIClass)
295+ {
296+ // TODO: Read multiple base classes.
297+ auto vmiClassTypeInfo = VMIClassTypeInfo (m_view, objectAddr);
298+ m_view->DefineDataVariable (objectAddr, Confidence (VMIClassTypeInfoType (m_view, vmiClassTypeInfo.base_count ), 255 ));
299+ }
300+ else
301+ {
302+ // auto classTypeInfo = ClassTypeInfo(m_view, objectAddr);
303+ m_view->DefineDataVariable (objectAddr, Confidence (ClassTypeInfoType (m_view), 255 ));
304+ }
305+
306+ return classInfo;
307+ }
308+
309+
310+ ItaniumRTTIProcessor::ItaniumRTTIProcessor (const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep) : m_view(view)
311+ {
312+ m_logger = new Logger (" Itanium RTTI" );
313+ allowMangledClassNames = useMangled;
314+ checkWritableRData = checkRData;
315+ m_classInfo = {};
316+ virtualFunctionTableSweep = vftSweep;
317+
318+ auto metadata = view->QueryMetadata (VIEW_METADATA_RTTI);
319+ if (metadata != nullptr )
320+ {
321+ // TODO: This will pull in microsoft RTTI, which is really weird behavior possibly.
322+ // Load in metadata to the processor.
323+ // DeserializedMetadata(metadata);
324+ }
325+ }
326+
327+
328+ void ItaniumRTTIProcessor::ProcessRTTI ()
329+ {
330+ auto start_time = std::chrono::high_resolution_clock::now ();
331+ auto addrSize = m_view->GetAddressSize ();
332+ // TODO: This probably needs to change
333+ uint64_t maxTypeInfoSize = 0x10 ;
334+
335+ auto scan = [&](const Ref<Section> §ion) {
336+ for (uint64_t currAddr = section->GetStart (); currAddr <= section->GetEnd () - maxTypeInfoSize; currAddr += addrSize)
337+ {
338+ if (auto classInfo = ProcessRTTI (currAddr))
339+ m_classInfo[currAddr] = classInfo.value ();
340+ }
341+ };
342+
343+ // Scan data sections for rtti.
344+ for (const Ref<Section> §ion: m_view->GetSections ())
345+ {
346+ if (section->GetSemantics () == ReadOnlyDataSectionSemantics)
347+ {
348+ m_logger->LogDebug (" Attempting to find RTTI in section %llx" , section->GetStart ());
349+ scan (section);
350+ }
351+ }
352+
353+ auto end_time = std::chrono::high_resolution_clock::now ();
354+ std::chrono::duration<double > elapsed_time = end_time - start_time;
355+ m_logger->LogInfo (" ProcessRTTI took %f seconds" , elapsed_time.count ());
356+ }
0 commit comments