Skip to content

Commit e7b1fae

Browse files
committed
[RTTI] Add more error checking for malformed PE binaries
Fixes #7705 RTTI processing with malformed sections can still cause prolonged analysis, in extreme cases like the binary in the issue needing the user to stop the RTTI processing once it gets to the Itanium RTTI pass. More work to be done, I would like to solve this with some section heuristics using the sections/segments entropy.
1 parent 4c00d61 commit e7b1fae

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

plugins/rtti/itanium.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ using namespace BinaryNinja::RTTI::Itanium;
99
// TODO: Itanium doesnt really say anything about the sizing of these fields, i assume they are all u32 for thje most part.
1010

1111
constexpr const char *TYPE_SOURCE_ITANIUM = "rtti_itanium";
12+
constexpr int MAX_FAILED_SCAN_ATTEMPTS = 10;
1213

1314

1415
Ref<Symbol> GetRealSymbol(BinaryView *view, uint64_t relocAddr, uint64_t symAddr)
@@ -737,6 +738,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
737738
uint64_t maxTypeInfoSize = TypeInfoSize(m_view);
738739

739740
auto scan = [&](const Ref<Section> &section) {
741+
int failedAttempts = 0;
740742
for (uint64_t currAddr = section->GetStart(); currAddr <= section->GetEnd() - maxTypeInfoSize; currAddr += addrSize)
741743
{
742744
if (bgTask->IsCancelled())
@@ -748,9 +750,14 @@ void ItaniumRTTIProcessor::ProcessRTTI()
748750
}
749751
catch (std::exception& e)
750752
{
753+
if (failedAttempts++; failedAttempts > MAX_FAILED_SCAN_ATTEMPTS)
754+
break;
751755
m_logger->LogWarnForException(e, "Failed to process object at %llx... skipping", currAddr);
752756
}
753757
}
758+
759+
if (failedAttempts > MAX_FAILED_SCAN_ATTEMPTS)
760+
m_logger->LogWarn("Too many failed scans for section %llx... skipping", section->GetStart());
754761
};
755762

756763
m_view->BeginBulkModifySymbols();
@@ -763,8 +770,16 @@ void ItaniumRTTIProcessor::ProcessRTTI()
763770
// Some RTTI unfortunately will get put into a DefaultSectionSemantics section, so we have to check those.
764771
if (sectionSemantics == ReadOnlyDataSectionSemantics || sectionSemantics == DefaultSectionSemantics)
765772
{
766-
m_logger->LogDebug("Attempting to find RTTI in section %llx", section->GetStart());
767-
scan(section);
773+
// If a malformed binary makes the binary view set up unbacked sections we should not attempt to read in them.
774+
if (m_view->ReadBuffer(section->GetStart(), 4).GetLength() == 4)
775+
{
776+
m_logger->LogDebug("Attempting to find RTTI in section %llx", section->GetStart());
777+
scan(section);
778+
}
779+
else
780+
{
781+
m_logger->LogDebug("Unbacked start for section %llx... skipping", section->GetStart());
782+
}
768783
}
769784
}
770785
m_view->EndBulkModifySymbols();

plugins/rtti/microsoft.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -694,14 +694,34 @@ void MicrosoftRTTIProcessor::ProcessRTTI()
694694
{
695695
if (segment->GetFlags() == (SegmentReadable | SegmentContainsData))
696696
{
697+
// If a malformed binary makes the binary view set up unbacked segments we should not attempt to read in them.
698+
if (m_view->ReadBuffer(segment->GetStart(), 4).GetLength() != 4)
699+
{
700+
m_logger->LogInfo("Unbacked start for segment %llx... skipping", segment->GetStart());
701+
continue;
702+
}
697703
m_logger->LogDebug("Attempting to find RTTI in segment %llx", segment->GetStart());
698-
scan(segment);
704+
try
705+
{
706+
scan(segment);
707+
}
708+
catch (std::exception &e)
709+
{
710+
m_logger->LogWarn("Unhandled exception in segment scan %llx %s", segment->GetStart(), e.what());
711+
}
699712
}
700713
else if (checkWritableRData && rdataSection && rdataSection->GetStart() == segment->GetStart())
701714
{
702715
m_logger->LogDebug("Attempting to find RTTI in writable rdata segment %llx",
703716
segment->GetStart());
704-
scan(segment);
717+
try
718+
{
719+
scan(segment);
720+
}
721+
catch (std::exception &e)
722+
{
723+
m_logger->LogWarn("Unhandled exception in writable segment scan %llx %s", segment->GetStart(), e.what());
724+
}
705725
}
706726
}
707727

@@ -757,13 +777,27 @@ void MicrosoftRTTIProcessor::ProcessVFT()
757777
if (segment->GetFlags() == (SegmentReadable | SegmentContainsData))
758778
{
759779
m_logger->LogDebug("Attempting to find VirtualFunctionTables in segment %llx", segment->GetStart());
760-
scan(segment);
780+
try
781+
{
782+
scan(segment);
783+
}
784+
catch (std::exception &e)
785+
{
786+
m_logger->LogWarn("Unhandled exception in vtable segment scan %llx %s", segment->GetStart(), e.what());
787+
}
761788
}
762789
else if (checkWritableRData && rdataSection && rdataSection->GetStart() == segment->GetStart())
763790
{
764791
m_logger->LogDebug("Attempting to find VirtualFunctionTables in writable rdata segment %llx",
765792
segment->GetStart());
766-
scan(segment);
793+
try
794+
{
795+
scan(segment);
796+
}
797+
catch (std::exception &e)
798+
{
799+
m_logger->LogWarn("Unhandled exception in vtable writable segment scan %llx %s", segment->GetStart(), e.what());
800+
}
767801
}
768802
}
769803
}

0 commit comments

Comments
 (0)