Skip to content

Commit 47523e2

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 5ecf8d5 commit 47523e2

File tree

4 files changed

+294
-4
lines changed

4 files changed

+294
-4
lines changed

objectivec/objc.cpp

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,15 @@ void ObjCProcessor::ProcessObjCData()
14671467
m_relocationPointerRewrites.clear();
14681468
}
14691469

1470+
void ObjCProcessor::ProcessObjCLiterals()
1471+
{
1472+
ProcessCFStrings();
1473+
ProcessNSConstantArrays();
1474+
ProcessNSConstantDictionaries();
1475+
ProcessNSConstantIntegerNumbers();
1476+
ProcessNSConstantFloatingPointNumbers();
1477+
ProcessNSConstantDatas();
1478+
}
14701479

14711480
void ObjCProcessor::ProcessCFStrings()
14721481
{
@@ -1585,6 +1594,274 @@ void ObjCProcessor::ProcessCFStrings()
15851594
delete m_symbolQueue;
15861595
}
15871596

1597+
void ObjCProcessor::ProcessNSConstantArrays()
1598+
{
1599+
m_symbolQueue = new SymbolQueue();
1600+
uint64_t ptrSize = m_data->GetAddressSize();
1601+
1602+
auto idType = Type::NamedType(m_data, m_typeNames.id);
1603+
StructureBuilder nsConstantArrayBuilder;
1604+
nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1605+
nsConstantArrayBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
1606+
nsConstantArrayBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
1607+
auto type = finalizeStructureBuilder(m_data, nsConstantArrayBuilder, "__NSConstantArray");
1608+
m_typeNames.nsConstantArray = type.first;
1609+
1610+
auto reader = GetReader();
1611+
if (auto arrays = GetSectionWithName("__objc_arrayobj"))
1612+
{
1613+
auto start = arrays->GetStart();
1614+
auto end = arrays->GetEnd();
1615+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantArray)->GetWidth();
1616+
m_data->BeginBulkModifySymbols();
1617+
for (view_ptr_t i = start; i < end; i += typeWidth)
1618+
{
1619+
reader->Seek(i + ptrSize);
1620+
uint64_t count = reader->ReadPointer();
1621+
auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
1622+
DefineObjCSymbol(
1623+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsarray_{:x}_data", i), dataLoc, true);
1624+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantArray),
1625+
fmt::format("nsarray_{:x}", i), i, true);
1626+
}
1627+
auto id = m_data->BeginUndoActions();
1628+
m_symbolQueue->Process();
1629+
m_data->EndBulkModifySymbols();
1630+
m_data->ForgetUndoActions(id);
1631+
}
1632+
delete m_symbolQueue;
1633+
}
1634+
1635+
void ObjCProcessor::ProcessNSConstantDictionaries()
1636+
{
1637+
m_symbolQueue = new SymbolQueue();
1638+
uint64_t ptrSize = m_data->GetAddressSize();
1639+
1640+
auto idType = Type::NamedType(m_data, m_typeNames.id);
1641+
StructureBuilder nsConstantDictionaryBuilder;
1642+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1643+
nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "options");
1644+
nsConstantDictionaryBuilder.AddMember(Type::IntegerType(ptrSize, false), "count");
1645+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "keys");
1646+
nsConstantDictionaryBuilder.AddMember(Type::PointerType(ptrSize, idType), "objects");
1647+
auto type = finalizeStructureBuilder(m_data, nsConstantDictionaryBuilder, "__NSConstantDictionary");
1648+
m_typeNames.nsConstantDictionary = type.first;
1649+
1650+
auto reader = GetReader();
1651+
if (auto dicts = GetSectionWithName("__objc_dictobj"))
1652+
{
1653+
auto start = dicts->GetStart();
1654+
auto end = dicts->GetEnd();
1655+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDictionary)->GetWidth();
1656+
m_data->BeginBulkModifySymbols();
1657+
for (view_ptr_t i = start; i < end; i += typeWidth)
1658+
{
1659+
reader->Seek(i + (ptrSize * 2));
1660+
// TODO: Do we need to do anything with `options`? It appears to always be 1.
1661+
uint64_t count = reader->ReadPointer();
1662+
auto keysLoc = ReadPointerAccountingForRelocations(reader.get());
1663+
auto objectsLoc = ReadPointerAccountingForRelocations(reader.get());
1664+
DefineObjCSymbol(
1665+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_keys", i), keysLoc, true);
1666+
DefineObjCSymbol(
1667+
DataSymbol, Type::ArrayType(idType, count), fmt::format("nsdict_{:x}_objects", i), objectsLoc, true);
1668+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantDictionary),
1669+
fmt::format("nsdict_{:x}", i), i, true);
1670+
}
1671+
auto id = m_data->BeginUndoActions();
1672+
m_symbolQueue->Process();
1673+
m_data->EndBulkModifySymbols();
1674+
m_data->ForgetUndoActions(id);
1675+
}
1676+
delete m_symbolQueue;
1677+
}
1678+
1679+
void ObjCProcessor::ProcessNSConstantIntegerNumbers()
1680+
{
1681+
m_symbolQueue = new SymbolQueue();
1682+
uint64_t ptrSize = m_data->GetAddressSize();
1683+
1684+
StructureBuilder nsConstantIntegerNumberBuilder;
1685+
nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1686+
nsConstantIntegerNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, true)), "encoding");
1687+
nsConstantIntegerNumberBuilder.AddMember(Type::IntegerType(ptrSize, true), "value");
1688+
auto type = finalizeStructureBuilder(m_data, nsConstantIntegerNumberBuilder, "__NSConstantIntegerNumber");
1689+
m_typeNames.nsConstantIntegerNumber = type.first;
1690+
1691+
auto reader = GetReader();
1692+
if (auto numbers = GetSectionWithName("__objc_intobj"))
1693+
{
1694+
auto start = numbers->GetStart();
1695+
auto end = numbers->GetEnd();
1696+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber)->GetWidth();
1697+
m_data->BeginBulkModifySymbols();
1698+
for (view_ptr_t i = start; i < end; i += typeWidth)
1699+
{
1700+
reader->Seek(i + ptrSize);
1701+
uint64_t encodingLoc = ReadPointerAccountingForRelocations(reader.get());
1702+
uint64_t value = reader->Read64();
1703+
reader->Seek(encodingLoc);
1704+
uint8_t encoding = reader->Read8();
1705+
1706+
switch (encoding)
1707+
{
1708+
case 'c':
1709+
case 's':
1710+
case 'i':
1711+
case 'l':
1712+
case 'q':
1713+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
1714+
fmt::format("nsint_{:x}_{}", i, (int64_t)value), i, true);
1715+
break;
1716+
case 'C':
1717+
case 'S':
1718+
case 'I':
1719+
case 'L':
1720+
case 'Q':
1721+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantIntegerNumber),
1722+
fmt::format("nsint_{:x}_{}", i, value), i, true);
1723+
break;
1724+
default:
1725+
m_logger->LogWarn("Unknown type encoding '%c' in number literal object at %p", encoding, i);
1726+
continue;
1727+
}
1728+
}
1729+
auto id = m_data->BeginUndoActions();
1730+
m_symbolQueue->Process();
1731+
m_data->EndBulkModifySymbols();
1732+
m_data->ForgetUndoActions(id);
1733+
}
1734+
delete m_symbolQueue;
1735+
}
1736+
1737+
void ObjCProcessor::ProcessNSConstantFloatingPointNumbers()
1738+
{
1739+
uint64_t ptrSize = m_data->GetAddressSize();
1740+
1741+
StructureBuilder nsConstantFloatNumberBuilder;
1742+
nsConstantFloatNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1743+
nsConstantFloatNumberBuilder.AddMember(Type::FloatType(4), "value");
1744+
auto type = finalizeStructureBuilder(m_data, nsConstantFloatNumberBuilder, "__NSConstantFloatNumber");
1745+
m_typeNames.nsConstantFloatNumber = type.first;
1746+
1747+
StructureBuilder nsConstantDoubleNumberBuilder;
1748+
nsConstantDoubleNumberBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1749+
nsConstantDoubleNumberBuilder.AddMember(Type::FloatType(8), "value");
1750+
type = finalizeStructureBuilder(m_data, nsConstantDoubleNumberBuilder, "__NSConstantDoubleNumber");
1751+
m_typeNames.nsConstantDoubleNumber = type.first;
1752+
1753+
StructureBuilder nsConstantDateBuilder;
1754+
nsConstantDateBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1755+
nsConstantDateBuilder.AddMember(Type::FloatType(8), "ti");
1756+
type = finalizeStructureBuilder(m_data, nsConstantDateBuilder, "__NSConstantDate");
1757+
m_typeNames.nsConstantDate = type.first;
1758+
1759+
enum SectionType
1760+
{
1761+
Float,
1762+
Double,
1763+
Date,
1764+
};
1765+
1766+
constexpr std::pair<std::string_view, SectionType> sections[] = {
1767+
{"__objc_floatobj", Float},
1768+
{"__objc_doubleobj", Double},
1769+
{"__objc_dateobj", Date},
1770+
};
1771+
1772+
auto reader = GetReader();
1773+
for (auto& [sectionName, sectionType] : sections)
1774+
{
1775+
auto numbers = GetSectionWithName(sectionName.data());
1776+
if (!numbers)
1777+
continue;
1778+
1779+
m_symbolQueue = new SymbolQueue();
1780+
auto start = numbers->GetStart();
1781+
auto end = numbers->GetEnd();
1782+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantDoubleNumber)->GetWidth();
1783+
m_data->BeginBulkModifySymbols();
1784+
for (view_ptr_t i = start; i < end; i += typeWidth)
1785+
{
1786+
reader->Seek(i + ptrSize);
1787+
1788+
QualifiedName* typeName = nullptr;
1789+
std::string name;
1790+
1791+
switch (sectionType)
1792+
{
1793+
case Float:
1794+
{
1795+
float value = 0;
1796+
reader->Read(&value, sizeof(value));
1797+
name = fmt::format("nsfloat_{:x}_{}", i, value);
1798+
typeName = &m_typeNames.nsConstantFloatNumber;
1799+
break;
1800+
}
1801+
case Double:
1802+
{
1803+
double value = 0;
1804+
reader->Read(&value, sizeof(value));
1805+
name = fmt::format("nsdouble_{:x}_{}", i, value);
1806+
typeName = &m_typeNames.nsConstantDoubleNumber;
1807+
break;
1808+
}
1809+
case Date:
1810+
{
1811+
double value = 0;
1812+
reader->Read(&value, sizeof(value));
1813+
name = fmt::format("nsdate_{:x}_{}", i, value);
1814+
typeName = &m_typeNames.nsConstantDate;
1815+
break;
1816+
}
1817+
}
1818+
DefineObjCSymbol(DataSymbol, Type::NamedType(m_data, *typeName), name, i, true);
1819+
}
1820+
auto id = m_data->BeginUndoActions();
1821+
m_symbolQueue->Process();
1822+
m_data->EndBulkModifySymbols();
1823+
m_data->ForgetUndoActions(id);
1824+
delete m_symbolQueue;
1825+
}
1826+
}
1827+
1828+
void ObjCProcessor::ProcessNSConstantDatas()
1829+
{
1830+
m_symbolQueue = new SymbolQueue();
1831+
uint64_t ptrSize = m_data->GetAddressSize();
1832+
1833+
StructureBuilder nsConstantDataBuilder;
1834+
nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::VoidType()), "isa");
1835+
nsConstantDataBuilder.AddMember(Type::IntegerType(ptrSize, false), "length");
1836+
nsConstantDataBuilder.AddMember(Type::PointerType(ptrSize, Type::IntegerType(1, false)), "bytes");
1837+
auto type = finalizeStructureBuilder(m_data, nsConstantDataBuilder, "__NSConstantData");
1838+
m_typeNames.nsConstantData = type.first;
1839+
1840+
auto reader = GetReader();
1841+
if (auto datas = GetSectionWithName("__objc_dataobj"))
1842+
{
1843+
auto start = datas->GetStart();
1844+
auto end = datas->GetEnd();
1845+
auto typeWidth = Type::NamedType(m_data, m_typeNames.nsConstantData)->GetWidth();
1846+
m_data->BeginBulkModifySymbols();
1847+
for (view_ptr_t i = start; i < end; i += typeWidth)
1848+
{
1849+
reader->Seek(i + ptrSize);
1850+
uint64_t length = reader->ReadPointer();
1851+
auto dataLoc = ReadPointerAccountingForRelocations(reader.get());
1852+
DefineObjCSymbol(DataSymbol, Type::ArrayType(Type::IntegerType(1, false), length),
1853+
fmt::format("nsdata_{:x}_data", i), dataLoc, true);
1854+
DefineObjCSymbol(
1855+
DataSymbol, Type::NamedType(m_data, m_typeNames.nsConstantData), fmt::format("nsdata_{:x}", i), i, true);
1856+
}
1857+
auto id = m_data->BeginUndoActions();
1858+
m_symbolQueue->Process();
1859+
m_data->EndBulkModifySymbols();
1860+
m_data->ForgetUndoActions(id);
1861+
}
1862+
delete m_symbolQueue;
1863+
}
1864+
15881865
void ObjCProcessor::AddRelocatedPointer(uint64_t location, uint64_t rewrite)
15891866
{
15901867
m_relocationPointerRewrites[location] = rewrite;

objectivec/objc.h

Lines changed: 15 additions & 2 deletions
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;
@@ -313,6 +320,13 @@ namespace BinaryNinja {
313320
bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
314321
void ApplyMethodTypes(Class& cls);
315322

323+
void ProcessCFStrings();
324+
void ProcessNSConstantArrays();
325+
void ProcessNSConstantDictionaries();
326+
void ProcessNSConstantIntegerNumbers();
327+
void ProcessNSConstantFloatingPointNumbers();
328+
void ProcessNSConstantDatas();
329+
316330
void PostProcessObjCSections(ObjCReader* reader);
317331

318332
protected:
@@ -331,9 +345,8 @@ namespace BinaryNinja {
331345
virtual ~ObjCProcessor() = default;
332346

333347
ObjCProcessor(BinaryView* data, const char* loggerName, bool isBackedByDatabase, bool skipClassBaseProtocols = false);
334-
// TODO: Instead of passing in image name the processor must be given section refs in a structure that outlines all objc sections.
335348
void ProcessObjCData();
336-
void ProcessCFStrings();
349+
void ProcessObjCLiterals();
337350
void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
338351
};
339352
}

view/macho/machoview.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2336,7 +2336,7 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
23362336
if (parseCFStrings)
23372337
{
23382338
try {
2339-
m_objcProcessor->ProcessCFStrings();
2339+
m_objcProcessor->ProcessObjCLiterals();
23402340
}
23412341
catch (std::exception& ex)
23422342
{

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)