Skip to content

Commit 41efab8

Browse files
committed
for demo
1 parent bd6b96c commit 41efab8

File tree

3 files changed

+81
-46
lines changed

3 files changed

+81
-46
lines changed

plugins/rtti/itanium.cpp

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,10 @@ TypeInfo::TypeInfo(BinaryView *view, uint64_t address)
1616
reader.Seek(address);
1717
base = reader.ReadPointer();
1818
auto typeNameAddr = reader.ReadPointer();
19+
if (!view->IsValidOffset(typeNameAddr))
20+
return;
1921
reader.Seek(typeNameAddr);
20-
// For the sake of my sanity we just do this...
21-
try
22-
{
23-
type_name = reader.ReadCString(512);
24-
}
25-
catch (std::exception& e)
26-
{
27-
type_name = "";
28-
}
22+
type_name = reader.ReadCString(512);
2923
}
3024

3125

@@ -276,22 +270,21 @@ std::optional<BaseClassInfo> ItaniumRTTIProcessor::ProcessVFTBaseClassInfo(uint6
276270
reader.Seek(vftAddr - 0x10);
277271

278272
auto adjustmentOffset = static_cast<int32_t>(reader.Read32());
279-
[[maybe_unused]]
280-
auto _what = static_cast<int32_t>(reader.Read32());
273+
auto baseIdx = static_cast<int32_t>(reader.Read32());
281274
uint64_t classOffset = std::abs(adjustmentOffset);
282275

283276
std::optional<BaseClassInfo> selectedBaseClassInfo = std::nullopt;
284277
// Assuming we do not have a baseClassInfo already passed we can deduce it here.
285278
for (auto& baseClass : classInfo.baseClasses)
286279
{
287-
if (baseClass.offset == 0)
288-
{
289-
// If the base class is at offset 0 that means it has yet to be adjusted.
290-
// NOTE: This should only happen for `TIVSIClass`. If this assigns more than
291-
// one base class to this offset we are screwed.
292-
baseClass.offset = classOffset;
293-
LogInfo("Adjusting base class offset for %llx to %llx", vftAddr, classOffset);
294-
}
280+
// if (baseClass.offset == 0)
281+
// {
282+
// // If the base class is at offset 0 that means it has yet to be adjusted.
283+
// // NOTE: This should only happen for `TIVSIClass`. If this assigns more than
284+
// // one base class to this offset we are screwed.
285+
// baseClass.offset = classOffset;
286+
// LogInfo("Adjusting base class offset for %llx to %llx", vftAddr, classOffset);
287+
// }
295288

296289
if (baseClass.offset == classOffset)
297290
{
@@ -345,6 +338,8 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
345338
if (!subTypeInfoVariant.has_value())
346339
{
347340
// Allow externals to be used in place of a backed subtype.
341+
// TODO: We should probably warn that vtables will likely be inaccurate.
342+
// TODO: Because we wont know what offsets are valid.
348343
auto externTypeName = nameFromTypeInfoSymbol(siClassTypeInfo.base_type);
349344
if (!externTypeName.has_value())
350345
return std::nullopt;
@@ -431,12 +426,17 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_
431426
{
432427
// TODO: Sometimes vFunc idx will be zeroed iirc.
433428
// We allow vfuncs to point to extern functions.
434-
if (!m_view->GetSymbolByAddress(vFuncAddr))
429+
auto vFuncSym = m_view->GetSymbolByAddress(vFuncAddr);
430+
if (!vFuncSym)
435431
break;
436432
DataVariable dv;
437433
bool foundDv = m_view->GetDataVariableAtAddress(vFuncAddr, dv);
438434
// Last virtual function, or hit the next vtable.
439-
if (!foundDv || dv.type.GetValue() == nullptr || !dv.type->IsFunction())
435+
if (!foundDv || !dv.type->m_object)
436+
break;
437+
// Void externs are very likely to be a func.
438+
// TODO: Add some sanity checks for this!
439+
if (!dv.type->IsFunction() && !(dv.type->IsVoid() && vFuncSym->GetType() == ExternalSymbol))
440440
break;
441441
}
442442
else
@@ -488,6 +488,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_
488488
// We should set the vtable as a base class so that xrefs are propagated (among other things).
489489
// NOTE: this means that `this` params will be assumed pre-adjusted, this is normally fine assuming type propagation
490490
// NOTE: never occurs on the vft types. Other-wise we need to change this.
491+
// TODO: Different type name please lol
491492
auto baseVftTypeName = fmt::format("{}::VTable", baseClassInfo->className);
492493
NamedTypeReferenceBuilder baseVftNTR;
493494
baseVftNTR.SetName(baseVftTypeName);
@@ -595,6 +596,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
595596
}
596597
};
597598

599+
m_view->BeginBulkModifySymbols();
598600
// Scan data sections for rtti.
599601
for (const Ref<Section> &section: m_view->GetSections())
600602
{
@@ -604,6 +606,49 @@ void ItaniumRTTIProcessor::ProcessRTTI()
604606
scan(section);
605607
}
606608
}
609+
m_view->EndBulkModifySymbols();
610+
611+
// Go through all classes and recurse into the base classes using the base class name
612+
for (auto &[classAddr, classInfo]: m_classInfo)
613+
{
614+
std::set<std::string> visitedBases;
615+
std::deque<BaseClassInfo> baseQueue(classInfo.baseClasses.begin(), classInfo.baseClasses.end());
616+
617+
while (!baseQueue.empty())
618+
{
619+
BaseClassInfo baseClass = baseQueue.front();
620+
baseQueue.pop_front();
621+
622+
if (visitedBases.find(baseClass.className) != visitedBases.end())
623+
continue;
624+
625+
visitedBases.insert(baseClass.className);
626+
627+
auto baseClassIt = std::find_if(m_classInfo.begin(), m_classInfo.end(),
628+
[&](const auto &item) {
629+
return item.second.className == baseClass.className;
630+
});
631+
632+
if (baseClassIt != m_classInfo.end())
633+
{
634+
const ClassInfo &nestedBaseClassInfo = baseClassIt->second;
635+
baseQueue.insert(baseQueue.end(), nestedBaseClassInfo.baseClasses.begin(),
636+
nestedBaseClassInfo.baseClasses.end());
637+
}
638+
639+
classInfo.baseClasses.push_back(baseClass);
640+
}
641+
642+
// Remove duplicates in the baseClasses vector while preserving order
643+
std::sort(classInfo.baseClasses.begin(), classInfo.baseClasses.end(),
644+
[](const BaseClassInfo &a, const BaseClassInfo &b) { return a.className < b.className; });
645+
646+
classInfo.baseClasses.erase(
647+
std::unique(classInfo.baseClasses.begin(), classInfo.baseClasses.end(),
648+
[](const BaseClassInfo &a, const BaseClassInfo &b) { return a.className == b.className; }),
649+
classInfo.baseClasses.end()
650+
);
651+
}
607652

608653
auto end_time = std::chrono::high_resolution_clock::now();
609654
std::chrono::duration<double> elapsed_time = end_time - start_time;
@@ -613,6 +658,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
613658

614659
void ItaniumRTTIProcessor::ProcessVFT()
615660
{
661+
BinaryReader optReader = BinaryReader(m_view);
616662
std::map<uint64_t, std::set<uint64_t>> vftMap = {};
617663
std::map<uint64_t, std::optional<VirtualFunctionTableInfo>> vftFinishedMap = {};
618664
auto start_time = std::chrono::high_resolution_clock::now();
@@ -624,6 +670,11 @@ void ItaniumRTTIProcessor::ProcessVFT()
624670
DataVariable dv;
625671
if (m_view->GetDataVariableAtAddress(ref, dv) && m_classInfo.find(dv.address) != m_classInfo.end())
626672
continue;
673+
// Verify that there is two 4 byte values above the type info pointer
674+
optReader.Seek(ref - 8);
675+
auto beforeTypeInfoRef = optReader.ReadPointer();
676+
if (m_view->IsValidOffset(beforeTypeInfoRef))
677+
continue;
627678
// TODO: This is not pointing at where it should, remember that the vtable will be inside another structure.
628679
auto vftAddr = ref + m_view->GetAddressSize();
629680
// Found a vtable reference to colocator
@@ -634,7 +685,6 @@ void ItaniumRTTIProcessor::ProcessVFT()
634685

635686
if (virtualFunctionTableSweep)
636687
{
637-
BinaryReader optReader = BinaryReader(m_view);
638688
auto addrSize = m_view->GetAddressSize();
639689
auto scan = [&](const Ref<Segment> &segment) {
640690
uint64_t startAddr = segment->GetStart();

plugins/rtti/plugin.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ extern "C" {
6363
// Add RTTI analysis.
6464
rttiMetaWorkflow->RegisterActivity(R"~({
6565
"title": "RTTI Analysis",
66-
"name": "plugin.rtti.rttiAnalysis",
66+
"name": "analysis.rtti.rttiAnalysis",
6767
"role": "action",
6868
"description": "This analysis step attempts to parse and symbolize rtti information.",
6969
"eligibility": {
@@ -74,7 +74,7 @@ extern "C" {
7474
// Add Virtual Function Table analysis.
7575
rttiMetaWorkflow->RegisterActivity(R"~({
7676
"title": "VFT Analysis",
77-
"name": "plugin.rtti.vftAnalysis",
77+
"name": "analysis.rtti.vftAnalysis",
7878
"role": "action",
7979
"description": "This analysis step attempts to parse and symbolize virtual function table information.",
8080
"eligibility": {
@@ -84,9 +84,9 @@ extern "C" {
8484
})~", &VFTAnalysis);
8585

8686
// Run rtti before debug info is applied.
87-
rttiMetaWorkflow->Insert("core.module.loadDebugInfo", "plugin.rtti.rttiAnalysis");
87+
rttiMetaWorkflow->Insert("core.module.loadDebugInfo", "analysis.rtti.rttiAnalysis");
8888
// Run vft after functions have analyzed (so that the virtual functions have analyzed)
89-
rttiMetaWorkflow->Insert("core.module.deleteUnusedAutoFunctions", "plugin.rtti.vftAnalysis");
89+
rttiMetaWorkflow->Insert("core.module.deleteUnusedAutoFunctions", "analysis.rtti.vftAnalysis");
9090
Workflow::RegisterWorkflow(rttiMetaWorkflow);
9191

9292
return true;

plugins/rtti/rtti.cpp

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,11 @@ std::optional<std::string> RTTI::DemangleNameMS(BinaryView* view, bool allowMang
1414
}
1515

1616

17-
std::string RemoveItaniumPrefix(std::string& name) {
18-
// Remove class prefixes.
19-
// 1 and 7 is class_type
20-
// 9 is si_class_type
21-
// 1..4 is vmi_class_type
22-
if (name.rfind('1', 0) == 0)
23-
name = name.substr(1);
24-
if (name.rfind('7', 0) == 0)
25-
name = name.substr(1);
26-
if (name.rfind('9', 0) == 0)
27-
name = name.substr(1);
28-
if (name.rfind('8', 0) == 0)
29-
name = name.substr(1);
30-
if (name.rfind('4', 0) == 0)
31-
name = name.substr(1);
32-
if (name.rfind('6', 0) == 0)
33-
name = name.substr(1);
34-
if (name.rfind('2', 0) == 0)
35-
name = name.substr(1);
36-
if (name.rfind('2', 0) == 0)
17+
std::string RemoveItaniumPrefix(std::string &name)
18+
{
19+
// Remove numerical prefixes.
20+
// TODO: We might want to use the numbers for figuring out the class info.
21+
while (!name.empty() && std::isdigit(name[0]))
3722
name = name.substr(1);
3823
return name;
3924
}

0 commit comments

Comments
 (0)