Skip to content

Commit fff5292

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 ec3d735 commit fff5292

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

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

14641473
void ObjCProcessor::ProcessCFStrings()
14651474
{
@@ -1578,6 +1587,274 @@ void ObjCProcessor::ProcessCFStrings()
15781587
delete m_symbolQueue;
15791588
}
15801589

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