Skip to content

Commit b90b45b

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 a45466f commit b90b45b

File tree

4 files changed

+294
-4
lines changed

4 files changed

+294
-4
lines changed

objectivec/objc.cpp

+277
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,15 @@ void ObjCProcessor::ProcessObjCData()
14521452
m_relocationPointerRewrites.clear();
14531453
}
14541454

1455+
void ObjCProcessor::ProcessObjCLiterals()
1456+
{
1457+
ProcessCFStrings();
1458+
ProcessNSConstantArrays();
1459+
ProcessNSConstantDictionaries();
1460+
ProcessNSConstantIntegerNumbers();
1461+
ProcessNSConstantFloatingPointNumbers();
1462+
ProcessNSConstantDatas();
1463+
}
14551464

14561465
void ObjCProcessor::ProcessCFStrings()
14571466
{
@@ -1570,6 +1579,274 @@ void ObjCProcessor::ProcessCFStrings()
15701579
delete m_symbolQueue;
15711580
}
15721581

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

objectivec/objc.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ namespace BinaryNinja {
275275
QualifiedName protocolList;
276276
QualifiedName ivar;
277277
QualifiedName ivarList;
278+
QualifiedName nsConstantArray;
279+
QualifiedName nsConstantDictionary;
280+
QualifiedName nsConstantDoubleNumber;
281+
QualifiedName nsConstantFloatNumber;
282+
QualifiedName nsConstantIntegerNumber;
283+
QualifiedName nsConstantDate;
284+
QualifiedName nsConstantData;
278285
} m_typeNames;
279286

280287
bool m_isBackedByDatabase;
@@ -314,6 +321,13 @@ namespace BinaryNinja {
314321
bool ApplyMethodType(Class& cls, Method& method, bool isInstanceMethod);
315322
void ApplyMethodTypes(Class& cls);
316323

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

319333
protected:
@@ -332,9 +346,8 @@ namespace BinaryNinja {
332346
virtual ~ObjCProcessor() = default;
333347

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

view/macho/machoview.cpp

+1-1
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ bool SharedCacheController::ApplyImage(BinaryView& view, const CacheImage& image
222222
if (m_processObjC)
223223
objcProcessor.ProcessObjCData();
224224
if (m_processCFStrings)
225-
objcProcessor.ProcessCFStrings();
225+
objcProcessor.ProcessObjCLiterals();
226226
}
227227
catch (std::exception& e)
228228
{

0 commit comments

Comments
 (0)