Skip to content

Commit 32fea4f

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 f9ac749 commit 32fea4f

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
@@ -1461,6 +1461,15 @@ void ObjCProcessor::ProcessObjCData()
14611461
m_relocationPointerRewrites.clear();
14621462
}
14631463

1464+
void ObjCProcessor::ProcessObjCLiterals()
1465+
{
1466+
ProcessCFStrings();
1467+
ProcessNSConstantArrays();
1468+
ProcessNSConstantDictionaries();
1469+
ProcessNSConstantIntegerNumbers();
1470+
ProcessNSConstantFloatingPointNumbers();
1471+
ProcessNSConstantDatas();
1472+
}
14641473

14651474
void ObjCProcessor::ProcessCFStrings()
14661475
{
@@ -1579,6 +1588,274 @@ void ObjCProcessor::ProcessCFStrings()
15791588
delete m_symbolQueue;
15801589
}
15811590

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