Skip to content

Commit d7445e2

Browse files
bdash0cyn
authored andcommitted
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 9ff07a9 commit d7445e2

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
@@ -1535,6 +1535,15 @@ void ObjCProcessor::ProcessObjCData()
15351535
m_relocationPointerRewrites.clear();
15361536
}
15371537

1538+
void ObjCProcessor::ProcessObjCLiterals()
1539+
{
1540+
ProcessCFStrings();
1541+
ProcessNSConstantArrays();
1542+
ProcessNSConstantDictionaries();
1543+
ProcessNSConstantIntegerNumbers();
1544+
ProcessNSConstantFloatingPointNumbers();
1545+
ProcessNSConstantDatas();
1546+
}
15381547

15391548
void ObjCProcessor::ProcessCFStrings()
15401549
{
@@ -1651,6 +1660,274 @@ void ObjCProcessor::ProcessCFStrings()
16511660
}
16521661
}
16531662

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

315322
std::optional<std::string> ClassNameForTargetOfPointerAt(ObjCReader* reader, uint64_t offset);
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:
@@ -333,7 +347,7 @@ namespace BinaryNinja {
333347

334348
ObjCProcessor(BinaryView* data, const char* loggerName, bool skipClassBaseProtocols = false);
335349
void ProcessObjCData();
336-
void ProcessCFStrings();
350+
void ProcessObjCLiterals();
337351
void AddRelocatedPointer(uint64_t location, uint64_t rewrite);
338352
};
339353
}

view/macho/machoview.cpp

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

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)