Skip to content

Commit 592bf5f

Browse files
committed
Parse sections containing Objective-C constants
This adds support for the `__objc_arrayobj`, `_objc_dictobj`, `__objc_intobj`, `__objc_floatobj`, `__objc_doubleobj` and `__objc_dateobj` sections that contain Objective-C constants. These are emitted by Apple's versions of Clang for `const` literals, amongst other things.
1 parent 6143812 commit 592bf5f

File tree

4 files changed

+294
-3
lines changed

4 files changed

+294
-3
lines changed

objectivec/objc.cpp

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,15 @@ void ObjCProcessor::ProcessObjCData()
15301530
m_relocationPointerRewrites.clear();
15311531
}
15321532

1533+
void ObjCProcessor::ProcessObjCLiterals()
1534+
{
1535+
ProcessCFStrings();
1536+
ProcessNSConstantArrays();
1537+
ProcessNSConstantDictionaries();
1538+
ProcessNSConstantIntegerNumbers();
1539+
ProcessNSConstantFloatingPointNumbers();
1540+
ProcessNSConstantDatas();
1541+
}
15331542

15341543
void ObjCProcessor::ProcessCFStrings()
15351544
{
@@ -1646,6 +1655,274 @@ void ObjCProcessor::ProcessCFStrings()
16461655
}
16471656
}
16481657

1658+
void ObjCProcessor::ProcessNSConstantArrays()
1659+
{
1660+
m_symbolQueue = new SymbolQueue();
1661+
uint64_t ptrSize = m_data->GetAddressSize();
1662+
1663+
auto idType = Type::NamedType(m_data, m_typeNames.id);
1664+
StructureBuilder nsConstantArrayBuilder;
1665+
nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1666+
nsConstantArrayBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
1667+
nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
1668+
auto type = finalizeStructureBuilder(m_data, nsConstantArrayBuilder, "__NSConstantArray");
1669+
m_typeNames.nsConstantArray = type.first;
1670+
1671+
auto reader = GetReader();
1672+
if (auto arrays = GetSectionWithName("__objc_arrayobj"))
1673+
{
1674+
auto start = arrays->GetStart();
1675+
auto end = arrays->GetEnd();
1676+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantArray)->GetWidth();
1677+
m_data->BeginBulkModifySymbols();
1678+
for (view_ptr_t i = start; i < end; i += typeWidth)
1679+
{
1680+
reader->Seek(i + ptrSize);
1681+
uint64_t count = reader->ReadPointer();
1682+
auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
1683+
DefineObjCSymbol(
1684+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsarray_{:x}_data", i), dataLoc, true);
1685+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantArray),
1686+
fmt::format("nsarray_{:x}", i), i, true);
1687+
}
1688+
auto id = m_data->BeginUndoActions();
1689+
m_symbolQueue->Process();
1690+
m_data->EndBulkModifySymbols();
1691+
m_data->ForgetUndoActions(id);
1692+
}
1693+
delete m_symbolQueue;
1694+
}
1695+
1696+
void ObjCProcessor::ProcessNSConstantDictionaries()
1697+
{
1698+
m_symbolQueue = new SymbolQueue();
1699+
uint64_t ptrSize = m_data->GetAddressSize();
1700+
1701+
auto idType = Type::NamedType(m_data, m_typeNames.id);
1702+
StructureBuilder nsConstantDictionaryBuilder;
1703+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1704+
nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "options");
1705+
nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
1706+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "keys");
1707+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
1708+
auto type = finalizeStructureBuilder(m_data, nsConstantDictionaryBuilder, "__NSConstantDictionary");
1709+
m_typeNames.nsConstantDictionary = type.first;
1710+
1711+
auto reader = GetReader();
1712+
if (auto dicts = GetSectionWithName("__objc_dictobj"))
1713+
{
1714+
auto start = dicts->GetStart();
1715+
auto end = dicts->GetEnd();
1716+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDictionary)->GetWidth();
1717+
m_data->BeginBulkModifySymbols();
1718+
for (view_ptr_t i = start; i < end; i += typeWidth)
1719+
{
1720+
reader->Seek(i + (ptrSize * 2));
1721+
// TODO: Do we need to do anything with `options`? It appears to always be 1.
1722+
uint64_t count = reader->ReadPointer();
1723+
auto keysLoc = ReadPointerAccountingForRelocations(reader.get());
1724+
auto objectsLoc = ReadPointerAccountingForRelocations(reader.get());
1725+
DefineObjCSymbol(
1726+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_keys", i), keysLoc, true);
1727+
DefineObjCSymbol(
1728+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_objects", i), objectsLoc, true);
1729+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantDictionary),
1730+
fmt::format("nsdict_{:x}", i), i, true);
1731+
}
1732+
auto id = m_data->BeginUndoActions();
1733+
m_symbolQueue->Process();
1734+
m_data->EndBulkModifySymbols();
1735+
m_data->ForgetUndoActions(id);
1736+
}
1737+
delete m_symbolQueue;
1738+
}
1739+
1740+
void ObjCProcessor::ProcessNSConstantIntegerNumbers()
1741+
{
1742+
m_symbolQueue = new SymbolQueue();
1743+
uint64_t ptrSize = m_data->GetAddressSize();
1744+
1745+
StructureBuilder nsConstantIntegerNumberBuilder;
1746+
nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1747+
nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, true)), "encoding");
1748+
nsConstantIntegerNumberBuilder.AddMember(Type::IntegerType(ptrSize, true), "value");
1749+
auto type = finalizeStructureBuilder(m_data, nsConstantIntegerNumberBuilder, "__NSConstantIntegerNumber");
1750+
m_typeNames.nsConstantIntegerNumber = type.first;
1751+
1752+
auto reader = GetReader();
1753+
if (auto numbers = GetSectionWithName("__objc_intobj"))
1754+
{
1755+
auto start = numbers->GetStart();
1756+
auto end = numbers->GetEnd();
1757+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber)->GetWidth();
1758+
m_data->BeginBulkModifySymbols();
1759+
for (view_ptr_t i = start; i < end; i += typeWidth)
1760+
{
1761+
reader->Seek(i + ptrSize);
1762+
uint64_t encodingLoc = ReadPointerAccountingForRelocations(reader.get());
1763+
uint64_t value = reader->Read64();
1764+
reader->Seek(encodingLoc);
1765+
uint8_t encoding = reader->Read8();
1766+
1767+
switch (encoding)
1768+
{
1769+
case 'c':
1770+
case 's':
1771+
case 'i':
1772+
case 'l':
1773+
case 'q':
1774+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
1775+
fmt::format("nsint_{:x}_{}", i, (int64_t)value), i, true);
1776+
break;
1777+
case 'C':
1778+
case 'S':
1779+
case 'I':
1780+
case 'L':
1781+
case 'Q':
1782+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
1783+
fmt::format("nsint_{:x}_{}", i, value), i, true);
1784+
break;
1785+
default:
1786+
m_logger->LogWarn("Unknown type encoding '%c' in number literal object at %p", encoding, i);
1787+
continue;
1788+
}
1789+
}
1790+
auto id = m_data->BeginUndoActions();
1791+
m_symbolQueue->Process();
1792+
m_data->EndBulkModifySymbols();
1793+
m_data->ForgetUndoActions(id);
1794+
}
1795+
delete m_symbolQueue;
1796+
}
1797+
1798+
void ObjCProcessor::ProcessNSConstantFloatingPointNumbers()
1799+
{
1800+
uint64_t ptrSize = m_data->GetAddressSize();
1801+
1802+
StructureBuilder nsConstantFloatNumberBuilder;
1803+
nsConstantFloatNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1804+
nsConstantFloatNumberBuilder.AddMember(Type::FloatType(4), "value");
1805+
auto type = finalizeStructureBuilder(m_data, nsConstantFloatNumberBuilder, "__NSConstantFloatNumber");
1806+
m_typeNames.nsConstantFloatNumber = type.first;
1807+
1808+
StructureBuilder nsConstantDoubleNumberBuilder;
1809+
nsConstantDoubleNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1810+
nsConstantDoubleNumberBuilder.AddMember(Type::FloatType(8), "value");
1811+
type = finalizeStructureBuilder(m_data, nsConstantDoubleNumberBuilder, "__NSConstantDoubleNumber");
1812+
m_typeNames.nsConstantDoubleNumber = type.first;
1813+
1814+
StructureBuilder nsConstantDateBuilder;
1815+
nsConstantDateBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1816+
nsConstantDateBuilder.AddMember(Type::FloatType(8), "ti");
1817+
type = finalizeStructureBuilder(m_data, nsConstantDateBuilder, "__NSConstantDate");
1818+
m_typeNames.nsConstantDate = type.first;
1819+
1820+
enum SectionType
1821+
{
1822+
Float,
1823+
Double,
1824+
Date,
1825+
};
1826+
1827+
constexpr std::pair<std::string_view, SectionType> sections[] = {
1828+
{"__objc_floatobj", Float},
1829+
{"__objc_doubleobj", Double},
1830+
{"__objc_dateobj", Date},
1831+
};
1832+
1833+
auto reader = GetReader();
1834+
for (auto& [sectionName, sectionType] : sections)
1835+
{
1836+
auto numbers = GetSectionWithName(sectionName.data());
1837+
if (!numbers)
1838+
continue;
1839+
1840+
m_symbolQueue = new SymbolQueue();
1841+
auto start = numbers->GetStart();
1842+
auto end = numbers->GetEnd();
1843+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDoubleNumber)->GetWidth();
1844+
m_data->BeginBulkModifySymbols();
1845+
for (view_ptr_t i = start; i < end; i += typeWidth)
1846+
{
1847+
reader->Seek(i + ptrSize);
1848+
1849+
QualifiedName* typeName = nullptr;
1850+
std::string name;
1851+
1852+
switch (sectionType)
1853+
{
1854+
case Float:
1855+
{
1856+
float value = 0;
1857+
reader->Read(&value, sizeof(value));
1858+
name = fmt::format("nsfloat_{:x}_{}", i, value);
1859+
typeName = &m_typeNames.nsConstantFloatNumber;
1860+
break;
1861+
}
1862+
case Double:
1863+
{
1864+
double value = 0;
1865+
reader->Read(&value, sizeof(value));
1866+
name = fmt::format("nsdouble_{:x}_{}", i, value);
1867+
typeName = &m_typeNames.nsConstantDoubleNumber;
1868+
break;
1869+
}
1870+
case Date:
1871+
{
1872+
double value = 0;
1873+
reader->Read(&value, sizeof(value));
1874+
name = fmt::format("nsdate_{:x}_{}", i, value);
1875+
typeName = &m_typeNames.nsConstantDate;
1876+
break;
1877+
}
1878+
}
1879+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, *typeName), name, i, true);
1880+
}
1881+
auto id = m_data->BeginUndoActions();
1882+
m_symbolQueue->Process();
1883+
m_data->EndBulkModifySymbols();
1884+
m_data->ForgetUndoActions(id);
1885+
delete m_symbolQueue;
1886+
}
1887+
}
1888+
1889+
void ObjCProcessor::ProcessNSConstantDatas()
1890+
{
1891+
m_symbolQueue = new SymbolQueue();
1892+
uint64_t ptrSize = m_data->GetAddressSize();
1893+
1894+
StructureBuilder nsConstantDataBuilder;
1895+
nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1896+
nsConstantDataBuilder.AddMember(Type::IntegerType(ptrSize, false), "length");
1897+
nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, false)), "bytes");
1898+
auto type = finalizeStructureBuilder(m_data, nsConstantDataBuilder, "__NSConstantData");
1899+
m_typeNames.nsConstantData = type.first;
1900+
1901+
auto reader = GetReader();
1902+
if (auto datas = GetSectionWithName("__objc_dataobj"))
1903+
{
1904+
auto start = datas->GetStart();
1905+
auto end = datas->GetEnd();
1906+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantData)->GetWidth();
1907+
m_data->BeginBulkModifySymbols();
1908+
for (view_ptr_t i = start; i < end; i += typeWidth)
1909+
{
1910+
reader->Seek(i + ptrSize);
1911+
uint64_t length = reader->ReadPointer();
1912+
auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
1913+
DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, false), length),
1914+
fmt::format("nsdata_{:x}_data", i), dataLoc, true);
1915+
DefineObjCSymbol(
1916+
DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantData), fmt::format("nsdata_{:x}", i), i, true);
1917+
}
1918+
auto id = m_data->BeginUndoActions();
1919+
m_symbolQueue->Process();
1920+
m_data->EndBulkModifySymbols();
1921+
m_data->ForgetUndoActions(id);
1922+
}
1923+
delete m_symbolQueue;
1924+
}
1925+
16491926
void ObjCProcessor::AddRelocatedPointer(uint64_t location, uint64_t rewrite)
16501927
{
16511928
m_relocationPointerRewrites[location] = rewrite;

objectivec/objc.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ namespace BinaryNinja {
274274
QualifiedName protocolList;
275275
QualifiedName ivar;
276276
QualifiedName ivarList;
277+
QualifiedName nsConstantArray;
278+
QualifiedName nsConstantDictionary;
279+
QualifiedName nsConstantDoubleNumber;
280+
QualifiedName nsConstantFloatNumber;
281+
QualifiedName nsConstantIntegerNumber;
282+
QualifiedName nsConstantDate;
283+
QualifiedName nsConstantData;
277284
} m_typeNames;
278285

279286
bool m_isBackedByDatabase;
@@ -315,6 +322,13 @@ namespace BinaryNinja {
315322

316323
std::optional<std::string> ClassNameForTargetOfPointerAt(ObjCReader* reader, uint64_t offset);
317324

325+
void ProcessCFStrings();
326+
void ProcessNSConstantArrays();
327+
void ProcessNSConstantDictionaries();
328+
void ProcessNSConstantIntegerNumbers();
329+
void ProcessNSConstantFloatingPointNumbers();
330+
void ProcessNSConstantDatas();
331+
318332
void PostProcessObjCSections(ObjCReader* reader);
319333

320334
protected:
@@ -334,7 +348,7 @@ namespace BinaryNinja {
334348

335349
ObjCProcessor(BinaryView* data, const char* loggerName, bool isBackedByDatabase, bool skipClassBaseProtocols = false);
336350
void ProcessObjCData();
337-
void ProcessCFStrings();
351+
void ProcessObjCLiterals();
338352
void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
339353
};
340354
}

view/macho/machoview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2365,7 +2365,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
23652365
if (parseCFStrings)
23662366
{
23672367
try {
2368-
m_objcProcessor->ProcessCFStrings();
2368+
m_objcProcessor->ProcessObjCLiterals();
23692369
}
23702370
catch (std::exception& ex)
23712371
{

view/sharedcache/core/SharedCacheController.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image
233233
if (m_processObjC)
234234
objcProcessor.ProcessObjCData();
235235
if (m_processCFStrings)
236-
objcProcessor.ProcessCFStrings();
236+
objcProcessor.ProcessObjCLiterals();
237237
}
238238
catch (std::exception& e)
239239
{

0 commit comments

Comments
 (0)