Skip to content

Commit 58309a4

Browse files
committed
wip
1 parent f37faca commit 58309a4

File tree

3 files changed

+279
-345
lines changed

3 files changed

+279
-345
lines changed

view/sharedcache/core/SharedCache.cpp

Lines changed: 67 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,13 @@ WeakFileAccessor CacheEntry::GetAccessor() const
104104
return FileAccessorCache::Global().Open(m_filePath);
105105
}
106106

107-
SharedCache::SharedCache()
107+
SharedCache::SharedCache(uint64_t addressSize)
108108
{
109+
m_addressSize = addressSize;
109110
m_vm = std::make_shared<VirtualMemory>();
110111
}
111112

113+
112114
void SharedCache::AddImage(CacheImage image)
113115
{
114116
m_images.insert({image.headerAddress, std::move(image)});
@@ -189,15 +191,14 @@ CacheEntryId SharedCache::AddEntry(CacheEntry entry)
189191
return id;
190192
}
191193

192-
void SharedCache::ProcessEntries(BinaryView &view)
194+
void SharedCache::ProcessEntries()
193195
{
194196
for (const auto& [id, entry] : m_entries)
195-
ProcessEntry(view, entry);
197+
ProcessEntry(entry);
196198
}
197199

198-
void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
200+
void SharedCache::ProcessEntry(const CacheEntry &entry)
199201
{
200-
uint64_t addrSize = view.GetAddressSize();
201202
// !!! At this point in time we should have loaded all relevant mappings for the virtual memory.
202203
// If we do not we will throw an exception!
203204
auto machoProcessor = SharedCacheMachOProcessor(m_vm);
@@ -213,7 +214,7 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
213214
// Collect pool addresses as non image memory regions.
214215
for (size_t i = 0; i < entryHeader.branchPoolsCount; i++)
215216
{
216-
auto branchPoolAddr = entryHeader.branchPoolsOffset + (i * addrSize);
217+
auto branchPoolAddr = entryHeader.branchPoolsOffset + (i * m_addressSize);
217218
auto header = machoProcessor.ParseHeaderForAddress(branchPoolAddr, "dyld_shared_cache_branch_islands_" + std::to_string(i));
218219
// Stop processing branch pools if a header fails to parse.
219220
if (!header.has_value())
@@ -274,73 +275,77 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
274275
AddRegion(std::move(stubIslandRegion));
275276
}
276277

277-
// Process all images.
278-
for (const auto& [imagePath, imageInfo] : entry.GetImages())
278+
// Process all images. Only for primary right now i guess.
279+
// TODO: When can an entry have images not found in the primary?
280+
if (entry.GetType() == CacheEntryType::Primary)
279281
{
280-
auto imageHeader = machoProcessor.ParseHeaderForAddress(imageInfo.address, imagePath);
281-
if (!imageHeader.has_value())
282-
continue;
283-
284-
// Add the image to the cache.
285-
CacheImage image;
286-
image.headerAddress = imageInfo.address;
287-
image.path = imagePath;
288-
289-
// Add all image regions.
290-
for (const auto& segment : imageHeader->segments)
282+
for (const auto& [imagePath, imageInfo] : entry.GetImages())
291283
{
292-
char segName[17];
293-
memcpy(segName, segment.segname, 16);
294-
segName[16] = 0;
284+
auto imageHeader = machoProcessor.ParseHeaderForAddress(imageInfo.address, imagePath);
285+
if (!imageHeader.has_value())
286+
continue;
287+
288+
// Add the image to the cache.
289+
CacheImage image;
290+
image.headerAddress = imageInfo.address;
291+
image.path = imagePath;
295292

296-
// Many images include a __LINKEDIT segment that share a single region in the shared cache.
297-
// Reuse the same `MemoryRegion` to represent all of these link edit regions.
298-
// Check to see if we have a shared region, if so skip it.
299-
if (std::string(segName) == "__LINKEDIT")
293+
// Add all image regions.
294+
for (const auto& segment : imageHeader->segments)
300295
{
301-
auto existingRegion = m_regions.find(AddressRange(segment.vmaddr, segment.vmaddr + segment.vmsize));
302-
if (existingRegion != m_regions.end())
296+
char segName[17];
297+
memcpy(segName, segment.segname, 16);
298+
segName[16] = 0;
299+
300+
// Many images include a __LINKEDIT segment that share a single region in the shared cache.
301+
// Reuse the same `MemoryRegion` to represent all of these link edit regions.
302+
// Check to see if we have a shared region, if so skip it.
303+
if (std::string(segName) == "__LINKEDIT")
303304
{
304-
image.regionStarts.push_back(existingRegion->second.start);
305-
continue;
305+
// TODO: Loosen this to any shared region?
306+
if (auto linkEditRegion = GetRegionAt(segment.vmaddr))
307+
{
308+
image.regionStarts.push_back(linkEditRegion->start);
309+
continue;
310+
}
306311
}
307-
}
308312

309-
CacheRegion sectionRegion;
310-
sectionRegion.type = CacheRegionType::Image;
311-
sectionRegion.name = imageHeader->identifierPrefix + "::" + std::string(segName);
312-
sectionRegion.start = segment.vmaddr;
313-
sectionRegion.size = segment.vmsize;
314-
// Associate this region with this image, this makes it easier to identify what image owns this region.
315-
sectionRegion.imageStart = image.headerAddress;
316-
317-
uint32_t flags = SegmentFlagsFromMachOProtections(segment.initprot, segment.maxprot);
318-
// if we're positive we have an entry point for some reason, force the segment
319-
// executable. this helps with kernel images.
320-
for (auto &entryPoint : imageHeader->m_entryPoints)
321-
if (segment.vmaddr <= entryPoint && (entryPoint < (segment.vmaddr + segment.filesize)))
322-
flags |= SegmentExecutable;
323-
sectionRegion.flags = static_cast<BNSegmentFlag>(flags);
324-
325-
// Add the image section to the cache and also to the image region starts
326-
if (AddNonOverlappingRegion(sectionRegion))
327-
image.regionStarts.push_back(sectionRegion.start);
328-
}
313+
CacheRegion sectionRegion;
314+
sectionRegion.type = CacheRegionType::Image;
315+
sectionRegion.name = imageHeader->identifierPrefix + "::" + std::string(segName);
316+
sectionRegion.start = segment.vmaddr;
317+
sectionRegion.size = segment.vmsize;
318+
// Associate this region with this image, this makes it easier to identify what image owns this region.
319+
sectionRegion.imageStart = image.headerAddress;
320+
321+
uint32_t flags = SegmentFlagsFromMachOProtections(segment.initprot, segment.maxprot);
322+
// if we're positive we have an entry point for some reason, force the segment
323+
// executable. this helps with kernel images.
324+
for (auto &entryPoint : imageHeader->m_entryPoints)
325+
if (segment.vmaddr <= entryPoint && (entryPoint < (segment.vmaddr + segment.filesize)))
326+
flags |= SegmentExecutable;
327+
sectionRegion.flags = static_cast<BNSegmentFlag>(flags);
328+
329+
// Add the image section to the cache and also to the image region starts
330+
if (AddNonOverlappingRegion(sectionRegion))
331+
image.regionStarts.push_back(sectionRegion.start);
332+
}
329333

330-
// TODO: Populating symbols here means that we have all of the symbols for the entire shared cache loaded always.
331-
// TODO: We should make this lazy (i.e. GetSymbolAt should check the symbols list then do actual work).
332-
// Populate symbols with this images symbols.
333-
// std::vector<CacheSymbol> symbols = imageHeader->ReadSymbolTable(view, *m_vm);
334-
// AddSymbols(std::move(symbols));
334+
// TODO: Populating symbols here means that we have all of the symbols for the entire shared cache loaded always.
335+
// TODO: We should make this lazy (i.e. GetSymbolAt should check the symbols list then do actual work).
336+
// Populate symbols with this images symbols.
337+
// std::vector<CacheSymbol> symbols = imageHeader->ReadSymbolTable(view, *m_vm);
338+
// AddSymbols(std::move(symbols));
335339

336-
// TODO: Should export symbols be put in a different bucket? How are they consumed differently?
337-
std::vector<CacheSymbol> exportSymbols = imageHeader->ReadExportSymbolTable(view, *m_vm);
338-
AddSymbols(std::move(exportSymbols));
340+
// TODO: Should export symbols be put in a different bucket? How are they consumed differently?
341+
std::vector<CacheSymbol> exportSymbols = imageHeader->ReadExportSymbolTable(*m_vm);
342+
AddSymbols(std::move(exportSymbols));
339343

340-
// This is behind a shared pointer as the header itself is very large.
341-
image.header = std::make_shared<SharedCacheMachOHeader>(*imageHeader);
344+
// This is behind a shared pointer as the header itself is very large.
345+
image.header = std::make_shared<SharedCacheMachOHeader>(*imageHeader);
342346

343-
AddImage(std::move(image));
347+
AddImage(std::move(image));
348+
}
344349
}
345350

346351
// TODO: See note above about slide info writes.

view/sharedcache/core/SharedCacheView.cpp

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
//
2-
// Created by kat on 5/23/23.
3-
//
4-
5-
/*
6-
* If you're here looking for the code to load caches, out of luck.
7-
*
8-
* The VIEW_NAME is essentially a blank slate that only knows how to deserialize and reserialize itself
9-
* based on some metadata encoded in it.
10-
*
11-
* The actual controller logic that does _all_ of the image loading is invoked via API -> SharedCache.cpp
12-
*
13-
* */
14-
151
#include "SharedCacheView.h"
162

173
#include <regex>
@@ -636,7 +622,7 @@ bool SharedCacheView::Init()
636622
DefineType("dyld_cache_header", headerType.name, headerType.type);
637623
DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), new Symbol(DataSymbol, "primary_cache_header", primaryBase), headerType.type);
638624

639-
auto sharedCache = SharedCache();
625+
auto sharedCache = SharedCache(GetAddressSize());
640626

641627
CacheProcessor cacheProcessor = CacheProcessor(this);
642628
if (!cacheProcessor.ProcessCache(sharedCache))
@@ -651,7 +637,7 @@ bool SharedCacheView::Init()
651637
// TODO: Add up everything here blud
652638
// TODO: Run this up on a seperate thread maybe and have callback notifications?
653639
auto startTime = std::chrono::high_resolution_clock::now();
654-
sharedCache.ProcessEntries(*this);
640+
sharedCache.ProcessEntries();
655641
auto endTime = std::chrono::high_resolution_clock::now();
656642
std::chrono::duration<double> elapsed = endTime - startTime;
657643
LogInfo("Processing entries took %.3f seconds", elapsed.count());
@@ -672,6 +658,7 @@ SharedCacheViewType::SharedCacheViewType() : BinaryViewType(VIEW_NAME, VIEW_NAME
672658
{
673659
}
674660

661+
// We register all our one-shot stuff here, such as the object destructor.
675662
void SharedCacheViewType::Register()
676663
{
677664
auto fdLimit = AdjustFileDescriptorLimit();
@@ -681,7 +668,7 @@ void SharedCacheViewType::Register()
681668
FileAccessorCache::Global().SetCacheSize(fdLimit);
682669

683670
// TODO: Register object destructor to clear accessor cache
684-
// TODO: Register object destructor to clear shared cache controller
671+
RegisterSharedCacheControllerDestructor();
685672

686673
static SharedCacheViewType type;
687674
BinaryViewType::Register(&type);
@@ -790,7 +777,7 @@ Ref<BinaryView> SharedCacheViewType::Parse(BinaryView* data)
790777
return new SharedCacheView(VIEW_NAME, data, true);
791778
}
792779

793-
bool SharedCacheViewType::IsTypeValidForData(BinaryNinja::BinaryView* data)
780+
bool SharedCacheViewType::IsTypeValidForData(BinaryView* data)
794781
{
795782
if (!data)
796783
return false;

0 commit comments

Comments
 (0)