22
33#include < regex>
44#include < __filesystem/directory_iterator.h>
5- #include < __filesystem/operations.h>
65
76#include " MachO.h"
7+ #include " SlideInfo.h"
88
99using namespace BinaryNinja ;
1010
@@ -99,6 +99,11 @@ std::optional<CacheEntry> CacheEntry::FromFile(const std::string& filePath, Cach
9999 return CacheEntry (filePath, type, header, mappings, images);
100100}
101101
102+ WeakFileAccessor CacheEntry::GetAccessor () const
103+ {
104+ return FileAccessorCache::Global ().Open (m_filePath);
105+ }
106+
102107SharedCache::SharedCache ()
103108{
104109 m_vm = std::make_shared<VirtualMemory>();
@@ -171,8 +176,14 @@ CacheEntryId SharedCache::AddEntry(CacheEntry entry)
171176 // read the memory of the mapped regions of the cache entry file.
172177 const auto & mappings = entry.GetMappings ();
173178 for (const auto & mapping: mappings)
179+ {
174180 m_vm->MapRegion (fileAccessor, {mapping.address , mapping.address + mapping.size }, mapping.fileOffset );
175181
182+ // Recalculate the base address.
183+ if (mapping.address < m_baseAddress)
184+ m_baseAddress = mapping.address ;
185+ }
186+
176187 // We are done and can make the entry visible to the entire cache.
177188 m_entries.insert ({id, std::move (entry)});
178189 return id;
@@ -192,6 +203,13 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
192203 auto machoProcessor = SharedCacheMachOProcessor (m_vm);
193204
194205 auto entryHeader = entry.GetHeader ();
206+
207+ // Apply slide info while we are processing.
208+ // TODO: If this file gets evicted our writes go away, move this to some place visible to the weak file accessor.
209+ auto fileLock = entry.GetAccessor ().lock ();
210+ auto slideInfoProcessor = SlideInfoProcessor (GetBaseAddress ());
211+ slideInfoProcessor.ProcessEntryInfo (entry);
212+
195213 // Collect pool addresses as non image memory regions.
196214 for (size_t i = 0 ; i < entryHeader.branchPoolsCount ; i++)
197215 {
@@ -222,8 +240,6 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
222240
223241 // Get the mapping.
224242 const auto & entryMappings = entry.GetMappings ();
225- // TODO: We probably just want to get the file _name_
226- const auto & entryFilePath = entry.GetFilePath ();
227243
228244 // DyldData, we should take all the mappings and make some regions for them!
229245 if (entry.GetType () == CacheEntryType::DyldData)
@@ -234,10 +250,7 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
234250 CacheRegion mappingRegion;
235251 mappingRegion.start = mapping.address ;
236252 mappingRegion.size = mapping.size ;
237- // auto pathBasename = subCachePath.substr(subCachePath.find_last_of("/\\") + 1);
238- // TODO: Is the filepath here the entire disk path?
239- // TODO: We probably just want something else...
240- mappingRegion.name = fmt::format (" {}::_data{}" , entryFilePath, i);
253+ mappingRegion.name = fmt::format (" {}::_data{}" , entry.GetFileName (), i);
241254 mappingRegion.flags = SegmentReadable;
242255 mappingRegion.type = CacheRegionType::DyldData;
243256
@@ -253,9 +266,7 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
253266 CacheRegion stubIslandRegion;
254267 stubIslandRegion.start = stubMapping.address ;
255268 stubIslandRegion.size = stubMapping.size ;
256- // auto pathBasename = subCachePath.substr(subCachePath.find_last_of("/\\") + 1);
257- // TODO: Is the filepath here the entire disk path?
258- stubIslandRegion.name = fmt::format (" {}::_stubs" , entryFilePath);
269+ stubIslandRegion.name = fmt::format (" {}::_stubs" , entry.GetFileName ());
259270 stubIslandRegion.flags = static_cast <BNSegmentFlag>(SegmentReadable | SegmentExecutable);
260271 stubIslandRegion.type = CacheRegionType::StubIsland;
261272
@@ -329,16 +340,37 @@ void SharedCache::ProcessEntry(BinaryView &view, const CacheEntry &entry)
329340
330341 AddImage (std::move (image));
331342 }
343+
344+ // TODO: See note above about slide info writes.
345+ fileLock.get ();
332346}
333347
334- uint64_t SharedCache::GetBaseAddress ( ) const
348+ std::optional<CacheEntry> SharedCache::GetEntryContaining ( const uint64_t address ) const
335349{
336- uint64_t lowestAddress = std::numeric_limits<uint64_t >::max ();
337- for (const auto &[_, entry]: m_entries)
338- for (const auto &mapping: entry.GetMappings ())
339- if (mapping.address < lowestAddress)
340- lowestAddress = mapping.address ;
341- return lowestAddress != std::numeric_limits<uint64_t >::max () ? lowestAddress : 0 ;
350+ for (const auto & entry : m_entries)
351+ {
352+ for (const auto & mapping : entry.second .GetMappings ())
353+ {
354+ if (address >= mapping.address && address < mapping.address + mapping.size )
355+ return entry.second ;
356+ }
357+ }
358+
359+ return std::nullopt ;
360+ }
361+
362+ std::optional<CacheEntry> SharedCache::GetEntryWithImage (const CacheImage &image) const
363+ {
364+ for (const auto & entry : m_entries)
365+ {
366+ for (const auto & [_, currentImage] : entry.second .GetImages ())
367+ {
368+ if (currentImage.address == image.headerAddress )
369+ return entry.second ;
370+ }
371+ }
372+
373+ return std::nullopt ;
342374}
343375
344376std::optional<CacheRegion> SharedCache::GetRegionAt (const uint64_t address) const
@@ -415,41 +447,6 @@ bool CacheProcessor::ProcessCache(SharedCache& cache)
415447 if (!baseEntry.has_value ())
416448 return false ;
417449
418- // Identify if we are dealing with multiple files or just this one.
419- auto baseHeader = baseEntry->GetHeader ();
420-
421- enum CacheFormat
422- {
423- RegularCacheFormat = 0 ,
424- // TODO: Why do these need to be separate ugh.
425- LargeCacheFormat,
426- SplitCacheFormat,
427- iOS16CacheFormat,
428- };
429-
430- // TODO: The only real difference we need is if imagesCountOld is not zero dont search for other files I think?
431- CacheFormat cacheFormat = RegularCacheFormat;
432- if (baseHeader.imagesCountOld != 0 )
433- cacheFormat = RegularCacheFormat;
434-
435- size_t subCacheOff = offsetof (struct dyld_cache_header , subCacheArrayOffset);
436- size_t headerEnd = baseHeader.mappingOffset ;
437- if (headerEnd > subCacheOff)
438- {
439- if (baseHeader.cacheType != 2 )
440- {
441- if (std::filesystem::exists (ResolveFilePath (m_view, baseFilePath + " .01" )))
442- cacheFormat = LargeCacheFormat;
443- else
444- cacheFormat = SplitCacheFormat;
445- }
446- else
447- cacheFormat = iOS16CacheFormat;
448- }
449-
450- // TODO: Make this debug.
451- LogInfo (" Cache Format: %d\n " , cacheFormat);
452-
453450 // Before we do anything else, add this to the cache so it's available to other entries.
454451 cache.AddEntry (std::move (*baseEntry));
455452
@@ -459,19 +456,20 @@ bool CacheProcessor::ProcessCache(SharedCache& cache)
459456 // NOTE: This is extremely error-prone!
460457 // We are going to start trying to find files next to this one on disk!
461458 std::filesystem::path basePath = std::filesystem::path (baseFilePath).parent_path ();
459+ std::string pattern = fmt::format (" .*{}\\ .([0-9]+|symbols|dylddata)$" , FileName (baseFilePath));
460+ auto subCachePattern = std::regex (pattern);
462461 for (const auto &entry : std::filesystem::directory_iterator (basePath))
463462 {
464463 if (!entry.is_regular_file ())
465464 continue ;
466465
466+ // Skip the base file itself
467467 auto currentFilePath = entry.path ().string ();
468468 if (currentFilePath == baseFilePath)
469- continue ; // Skip the base file itself
469+ continue ;
470470
471471 // Filter files that dont end with .NUMBER or .symbols or .dylddata
472- // TODO: Running this regex on a directory with 10000 files aint gonna go well.
473- // TODO: Remove this LMAO
474- if (!std::regex_match (currentFilePath, std::regex (" .*\\ .([0-9]+|symbols|dylddata)$" )))
472+ if (!std::regex_match (currentFilePath, subCachePattern))
475473 continue ;
476474
477475 auto additionalEntry = CacheEntry::FromFile (currentFilePath, CacheEntryType::Secondary);
0 commit comments