From bda248a6e0b6eec64094bffc93ff50b4d09ef638 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 17 Feb 2025 21:32:01 -0500 Subject: [SharedCache] Fix building on windows due to unresolved extern symbols This is _probably_ the fix? I am not actually sure I am pushing so the CI can figure it out for me :) --- view/sharedcache/core/SharedCache.cpp | 1308 ++++++++++++++++----------------- 1 file changed, 654 insertions(+), 654 deletions(-) (limited to 'view/sharedcache/core/SharedCache.cpp') diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index dece31d7..f4141e67 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -3195,813 +3195,813 @@ bool SharedCache::IsMemoryMapped(uint64_t address) return m_dscView->IsValidOffset(address); } -extern "C" +void Serialize(SerializationContext& context, const dyld_cache_mapping_info& value) { - BNSharedCache* BNGetSharedCache(BNBinaryView* data) - { - if (!data) - return nullptr; - - Ref view = new BinaryView(BNNewViewReference(data)); - if (auto cache = SharedCache::GetFromDSCView(view)) - { - cache->AddAPIRef(); - return cache->GetAPIObject(); - } - - return nullptr; - } + context.writer.StartArray(); + Serialize(context, value.address); + Serialize(context, value.size); + Serialize(context, value.fileOffset); + Serialize(context, value.maxProt); + Serialize(context, value.initProt); + context.writer.EndArray(); +} - BNSharedCache* BNNewSharedCacheReference(BNSharedCache* cache) +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + auto bArr = context.doc[name.data()].GetArray(); + for (auto& s : bArr) { - if (!cache->object) - return nullptr; - - cache->object->AddAPIRef(); - return cache; + dyld_cache_mapping_info mapping; + auto s2 = s.GetArray(); + mapping.address = s2[0].GetUint64(); + mapping.size = s2[1].GetUint64(); + mapping.fileOffset = s2[2].GetUint64(); + mapping.maxProt = s2[3].GetUint(); + mapping.initProt = s2[4].GetUint(); + b.push_back(mapping); } +} - void BNFreeSharedCacheReference(BNSharedCache* cache) +void Deserialize( + DeserializationContext& context, std::string_view name, std::optional>& value) +{ + if (!context.doc.HasMember(name.data())) { - if (!cache->object) - return; - - cache->object->ReleaseAPIRef(); + value = std::nullopt; + return; } - bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name, bool skipObjC) - { - std::string imageName = std::string(name); - // FIXME !!!!!!!! BNFreeString(name); - - if (cache->object) - return cache->object->LoadImageWithInstallName(imageName, skipObjC); + auto array = context.doc[name.data()].GetArray(); + value = {array[0].GetUint64(), array[1].GetUint64()}; +} - return false; - } +void Serialize(SerializationContext& context, const AddressRange& value) +{ + Serialize(context, std::make_pair(value.start, value.end)); +} - bool BNDSCViewLoadSectionAtAddress(BNSharedCache* cache, uint64_t addr) - { - if (cache->object) - { - return cache->object->LoadSectionAtAddress(addr); - } +void Deserialize(DeserializationContext& context, std::string_view name, AddressRange& value) +{ + auto array = context.doc[name.data()].GetArray(); + value = {array[0].GetUint64(), array[1].GetUint64()}; +} - return false; - } +void Serialize(SerializationContext& context, const MemoryRegionStatus& status) +{ + context.writer.StartArray(); + Serialize(context, status.loaded); + Serialize(context, status.headerInitialized); + context.writer.EndArray(); +} - bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address, bool skipObjC) +void Deserialize( + DeserializationContext& context, std::string_view name, std::unordered_map& statuses) +{ + auto array = context.doc[name.data()].GetArray(); + for (auto& pair : array) { - if (cache->object) - { - return cache->object->LoadImageContainingAddress(address, skipObjC); - } - - return false; + auto statusArray = pair[1].GetArray(); + MemoryRegionStatus status; + status.loaded = statusArray[0].GetBool(); + status.headerInitialized = statusArray[1].GetBool(); + statuses[pair[0].GetUint64()] = std::move(status); } +} - void BNDSCViewProcessObjCSectionsForImageWithInstallName(BNSharedCache* cache, char* name, bool deallocName) - { - std::string imageName = std::string(name); - if (deallocName) - BNFreeString(name); - - if (cache->object) - cache->object->ProcessObjCSectionsForImageWithInstallName(imageName); - } +void Serialize(SerializationContext& context, const Ref& value) +{ + context.writer.StartArray(); + Serialize(context, value->GetRawNameRef()); + Serialize(context, value->GetAddress()); + Serialize(context, value->GetType()); + context.writer.EndArray(); +} - void BNDSCViewProcessAllObjCSections(BNSharedCache* cache) +void Serialize(SerializationContext& context, const std::shared_ptr>>& value) +{ + context.writer.StartArray(); + for (const auto& [_, symbol] : *value) { - if (cache->object) - cache->object->ProcessAllObjCSections(); + Serialize(context, symbol); } + context.writer.EndArray(); +} - char** BNDSCViewGetInstallNames(BNSharedCache* cache, size_t* count) +void Serialize(SerializationContext& context, const std::shared_ptr>>& value) +{ + Serialize(context, *value); +} + +void Deserialize(DeserializationContext& context, std::string_view name, + std::unordered_map>>>& value) +{ + auto array = context.doc[name.data()].GetArray(); + for (auto& pair : array) { - if (cache->object) + auto symbols_array = pair[1].GetArray(); + std::unordered_map> symbols; + for (auto& symbol_value : symbols_array) { - auto value = cache->object->GetAvailableImages(); - *count = value.size(); - - std::vector cstrings; - cstrings.reserve(value.size()); - for (size_t i = 0; i < value.size(); i++) - { - cstrings.push_back(value[i].c_str()); - } - return BNAllocStringList(cstrings.data(), cstrings.size()); + auto symbol_array = symbol_value.GetArray(); + std::string symbolName = symbol_array[0].GetString(); + uint64_t address = symbol_array[1].GetUint64(); + BNSymbolType type = (BNSymbolType)symbol_array[2].GetUint(); + symbols.insert({address, new Symbol(type, symbolName, address)}); } - *count = 0; - return nullptr; + value[pair[0].GetUint64()] = std::make_shared>>(std::move(symbols)); } +} - BNDSCSymbolRep* BNDSCViewLoadAllSymbolsAndWait(BNSharedCache* cache, size_t* count) +void Deserialize(DeserializationContext& context, std::string_view name, + std::unordered_map>>>& value) +{ + auto array = context.doc[name.data()].GetArray(); + for (auto& pair : array) { - if (cache->object) + auto symbols_array = pair[1].GetArray(); + std::vector> symbols; + symbols.reserve(symbols_array.Size()); + for (auto& symbol_value : symbols_array) { - auto symbolsByImageName = cache->object->LoadAllSymbolsAndWait(); - size_t totalSymbolCount = 0; - for (const auto& [_, symbols] : symbolsByImageName) - { - totalSymbolCount += symbols.size(); - } - *count = totalSymbolCount; - - BNDSCSymbolRep* outputSymbols = new BNDSCSymbolRep[totalSymbolCount]; - size_t i = 0; - for (const auto& [imageName, symbols] : symbolsByImageName) - { - for (const auto& symbol : symbols) - { - outputSymbols[i].address = symbol->GetAddress(); - outputSymbols[i].name = BNDuplicateStringRef(symbol->GetRawNameRef().GetObject()); - outputSymbols[i].image = BNAllocStringWithLength(imageName.c_str(), imageName.length()); - ++i; - } - } - assert(i == totalSymbolCount); - return outputSymbols; + auto symbol_array = symbol_value.GetArray(); + std::string symbolName = symbol_array[0].GetString(); + uint64_t address = symbol_array[1].GetUint64(); + BNSymbolType type = (BNSymbolType)symbol_array[2].GetUint(); + symbols.push_back(new Symbol(type, symbolName, address)); } - *count = 0; - return nullptr; + value[pair[0].GetUint64()] = std::make_shared>>(std::move(symbols)); } +} - void BNDSCViewFreeSymbols(BNDSCSymbolRep* symbols, size_t count) +void Deserialize(DeserializationContext& context, std::string_view name, std::optional& viewState) +{ + auto& value = context.doc[name.data()]; + if (value.IsNull()) + viewState = std::nullopt; + else + viewState = (DSCViewState)value.GetUint(); +} + +void SharedCache::CacheInfo::Store(SerializationContext& context) const +{ + Serialize(context, "metadataVersion", METADATA_VERSION); + + MSS(backingCaches); + MSS(headers); + MSS(images); + MSS(imageStarts); + MSS(memoryRegions); + MSS(objcOptimizationDataRange); + MSS(baseFilePath); + MSS_CAST(cacheFormat, uint8_t); +} + +// static +std::optional SharedCache::CacheInfo::Load(DeserializationContext& context) +{ + if (!context.doc.HasMember("metadataVersion")) { - for (size_t i = 0; i < count; i++) - { - BNFreeStringRef(symbols[i].name); - BNFreeString(symbols[i].image); - } - delete symbols; + LogError("Shared Cache metadata version missing"); + return std::nullopt; } - char* BNDSCViewGetNameForAddress(BNSharedCache* cache, uint64_t address) + if (context.doc["metadataVersion"].GetUint() != METADATA_VERSION) { - if (cache->object) - { - return BNAllocString(cache->object->NameForAddress(address).c_str()); - } + LogError("Shared Cache metadata version mismatch"); + return std::nullopt; + } - return nullptr; - } - - char* BNDSCViewGetImageNameForAddress(BNSharedCache* cache, uint64_t address) - { - if (cache->object) - { - return BNAllocString(cache->object->ImageNameForAddress(address).c_str()); - } - - return nullptr; - } - - uint64_t BNDSCViewLoadedImageCount(BNSharedCache* cache) - { - // FIXME? - return 0; - } - - BNDSCViewState BNDSCViewGetState(BNSharedCache* cache) - { - if (cache->object) - { - return (BNDSCViewState)cache->object->ViewState(); - } - - return BNDSCViewState::Unloaded; - } - - - BNDSCMappedMemoryRegion* BNDSCViewGetLoadedRegions(BNSharedCache* cache, size_t* count) - { - if (cache->object) - { - auto regions = cache->object->GetMappedRegions(); - *count = regions.size(); - BNDSCMappedMemoryRegion* mappedRegions = new BNDSCMappedMemoryRegion[regions.size()]; - for (size_t i = 0; i < regions.size(); i++) - { - mappedRegions[i].vmAddress = regions[i]->start; - mappedRegions[i].size = regions[i]->size; - mappedRegions[i].name = - BNAllocStringWithLength(regions[i]->prettyName.c_str(), regions[i]->prettyName.length()); - } - return mappedRegions; - } - *count = 0; - return nullptr; - } - - void BNDSCViewFreeLoadedRegions(BNDSCMappedMemoryRegion* images, size_t count) - { - for (size_t i = 0; i < count; i++) - { - BNFreeString(images[i].name); - } - delete images; - } - - - BNDSCBackingCache* BNDSCViewGetBackingCaches(BNSharedCache* cache, size_t* count) - { - BNDSCBackingCache* caches = nullptr; - - if (cache->object) - { - auto viewCaches = cache->object->BackingCaches(); - *count = viewCaches.size(); - caches = new BNDSCBackingCache[viewCaches.size()]; - for (size_t i = 0; i < viewCaches.size(); i++) - { - caches[i].path = BNAllocString(viewCaches[i].path.c_str()); - caches[i].cacheType = viewCaches[i].cacheType; - - BNDSCBackingCacheMapping* mappings; - mappings = new BNDSCBackingCacheMapping[viewCaches[i].mappings.size()]; - - size_t j = 0; - for (const auto& mapping : viewCaches[i].mappings) - { - mappings[j].vmAddress = mapping.address; - mappings[j].size = mapping.size; - mappings[j].fileOffset = mapping.fileOffset; - j++; - } - caches[i].mappings = mappings; - caches[i].mappingCount = viewCaches[i].mappings.size(); - } - } - - return caches; - } - - void BNDSCViewFreeBackingCaches(BNDSCBackingCache* caches, size_t count) - { - for (size_t i = 0; i < count; i++) - { - delete[] caches[i].mappings; - BNFreeString(caches[i].path); - } - delete[] caches; - } + CacheInfo cacheInfo; + cacheInfo.MSL(backingCaches); + cacheInfo.MSL(headers); + cacheInfo.MSL(images); + cacheInfo.MSL(imageStarts); + cacheInfo.MSL(memoryRegions); + cacheInfo.MSL(objcOptimizationDataRange); + cacheInfo.MSL(baseFilePath); + cacheInfo.MSL_CAST(cacheFormat, uint8_t, SharedCacheFormat); + return cacheInfo; +} +void State::Store(SerializationContext& context, std::optional viewState) const +{ + MSS(memoryRegionStatus); + MSS(exportInfos); + MSS(symbolInfos); + MSS(viewState); +} - void BNDSCFindSymbolAtAddressAndApplyToAddress(BNSharedCache* cache, uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) - { - if (cache->object) - { - cache->object->FindSymbolAtAddrAndApplyToAddr(symbolLocation, targetLocation, triggerReanalysis); - } - } +void SharedCache::ModifiedState::Store(SerializationContext& context) const +{ + State::Store(context, viewState); +} - BNDSCImage* BNDSCViewGetAllImages(BNSharedCache* cache, size_t* count) - { - if (cache->object) - { - try { - auto vm = cache->object->GetVMMap(); - auto viewImageHeaders = cache->object->AllImageHeaders(); - *count = viewImageHeaders.size(); - BNDSCImage* images = new BNDSCImage[viewImageHeaders.size()]; - size_t i = 0; - for (const auto& [baseAddress, header] : viewImageHeaders) - { - images[i].name = BNAllocString(header.installName.c_str()); - images[i].headerAddress = baseAddress; - images[i].mappingCount = header.sections.size(); - images[i].mappings = new BNDSCImageMemoryMapping[header.sections.size()]; - for (size_t j = 0; j < header.sections.size(); j++) - { - const auto sectionStart = header.sections[j].addr; - images[i].mappings[j].rawViewOffset = header.sections[j].offset; - images[i].mappings[j].vmAddress = sectionStart; - images[i].mappings[j].size = header.sections[j].size; - images[i].mappings[j].name = BNAllocString(header.sectionNames[j].c_str()); - auto fileAccessor = vm->MappingAtAddress(sectionStart).first.fileAccessor; - images[i].mappings[j].filePath = BNAllocStringWithLength(fileAccessor->filePath().data(), fileAccessor->filePath().length()); - images[i].mappings[j].loaded = cache->object->IsMemoryMapped(sectionStart); - } - i++; - } - return images; - } - catch (...) - { - LogError("SharedCache: Failed to load image listing. Likely caused by a ser/deserialization error or load failure"); - *count = 0; - return nullptr; - } - } - *count = 0; - return nullptr; - } +SharedCache::ModifiedState SharedCache::ModifiedState::Load(DeserializationContext& context) +{ + SharedCache::ModifiedState state; + state.MSL(memoryRegionStatus); + state.MSL(exportInfos); + state.MSL(symbolInfos); + state.MSL(viewState); + return state; +} - void BNDSCViewFreeAllImages(BNDSCImage* images, size_t count) +SharedCache::ModifiedState SharedCache::ModifiedState::LoadAll(BinaryNinja::BinaryView *dscView, const CacheInfo& cacheInfo) +{ + uint64_t stateCount = dscView->GetUIntMetadata(SharedCacheMetadata::ModifiedStateCountTag); + SharedCache::ModifiedState state; + for (uint64_t i = 0; i < stateCount; ++i) { - for (size_t i = 0; i < count; i++) - { - for (size_t j = 0; j < images[i].mappingCount; j++) - { - BNFreeString(images[i].mappings[j].name); - BNFreeString(images[i].mappings[j].filePath); - } - delete[] images[i].mappings; - BNFreeString(images[i].name); - } - delete[] images; + std::string key = SharedCacheMetadata::ModifiedStateTagPrefix + std::to_string(i); + std::string serialized = dscView->GetStringMetadata(key); + auto thisState = SharedCache::ModifiedState::LoadFromString(serialized); + state.Merge(std::move(thisState)); } + return state; +} - char* BNDSCViewGetImageHeaderForAddress(BNSharedCache* cache, uint64_t address) - { - if (cache->object) - { - auto header = cache->object->SerializedImageHeaderForAddress(address); - return BNAllocString(header.c_str()); - } - - return nullptr; - } +void SharedCache::ModifiedState::Merge(SharedCache::ModifiedState&& newer) +{ + memoryRegionStatus.merge(newer.memoryRegionStatus); + exportInfos.merge(newer.exportInfos); + symbolInfos.merge(newer.symbolInfos); - char* BNDSCViewGetImageHeaderForName(BNSharedCache* cache, char* name) - { - std::string imageName = std::string(name); - BNFreeString(name); - if (cache->object) - { - auto header = cache->object->SerializedImageHeaderForName(imageName); - return BNAllocString(header.c_str()); - } + if (newer.viewState) + viewState = newer.viewState; +} - return nullptr; - } +void BackingCache::Store(SerializationContext& context) const +{ + MSS(path); + MSS_CAST(cacheType, uint32_t); + MSS(mappings); +} - BNDSCMemoryUsageInfo BNDSCViewGetMemoryUsageInfo() - { - BNDSCMemoryUsageInfo info; - info.mmapRefs = MMapCount(); - info.sharedCacheRefs = sharedCacheReferences.load(); - return info; - } +BackingCache BackingCache::Load(DeserializationContext& context) +{ + BackingCache cache; + cache.MSL(path); + cache.MSL_CAST(cacheType, uint32_t, BNBackingCacheType); + cache.MSL(mappings); + return cache; +} - BNDSCViewLoadProgress BNDSCViewGetLoadProgress(uint64_t sessionID) - { - if (auto viewSpecificState = ViewSpecificStateForId(sessionID, false)) - return viewSpecificState->progress; +void CacheImage::Store(SerializationContext& context) const +{ + MSS(installName); + MSS(headerLocation); + MSS(regionStarts); +} - return LoadProgressNotStarted; - } +// static +CacheImage CacheImage::Load(DeserializationContext& context) +{ + CacheImage cacheImage; + cacheImage.MSL(installName); + cacheImage.MSL(headerLocation); + cacheImage.MSL(regionStarts); + return cacheImage; +} - uint64_t BNDSCViewFastGetBackingCacheCount(BNBinaryView* data) - { - Ref view = new BinaryView(BNNewViewReference(data)); - return SharedCache::FastGetBackingCacheCount(view); - } +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +{ + auto array = context.doc[name.data()].GetArray(); + for (auto& value: array) + b.push_back(BackingCache::LoadFromValue(value)); } -void Serialize(SerializationContext& context, const dyld_cache_mapping_info& value) +void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) { - context.writer.StartArray(); - Serialize(context, value.address); - Serialize(context, value.size); - Serialize(context, value.fileOffset); - Serialize(context, value.maxProt); - Serialize(context, value.initProt); - context.writer.EndArray(); + auto array = context.doc[name.data()].GetArray(); + for (auto& value: array) + b.push_back(CacheImage::LoadFromValue(value)); } -void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) +void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) { - auto bArr = context.doc[name.data()].GetArray(); - for (auto& s : bArr) + auto array = context.doc[name.data()].GetArray(); + for (auto& pair_value : array) { - dyld_cache_mapping_info mapping; - auto s2 = s.GetArray(); - mapping.address = s2[0].GetUint64(); - mapping.size = s2[1].GetUint64(); - mapping.fileOffset = s2[2].GetUint64(); - mapping.maxProt = s2[3].GetUint(); - mapping.initProt = s2[4].GetUint(); - b.push_back(mapping); + auto pair = pair_value.GetArray(); + b[pair[0].GetUint64()] = SharedCacheMachOHeader::LoadFromValue(pair[1]); } } -void Deserialize( - DeserializationContext& context, std::string_view name, std::optional>& value) +void Deserialize(DeserializationContext& context, std::string_view name, AddressRangeMap& b) { - if (!context.doc.HasMember(name.data())) + auto array = context.doc[name.data()].GetArray(); + for (auto& key_value : array) { - value = std::nullopt; - return; + auto key_value_pair = key_value.GetArray(); + auto key_pair = key_value_pair[0].GetArray(); + AddressRange key = {key_pair[0].GetUint64(), key_pair[1].GetUint64()}; + b[key] = MemoryRegion::LoadFromValue(key_value_pair[1]); } - - auto array = context.doc[name.data()].GetArray(); - value = {array[0].GetUint64(), array[1].GetUint64()}; } -void Serialize(SerializationContext& context, const AddressRange& value) +const std::vector& SharedCache::BackingCaches() const { - Serialize(context, std::make_pair(value.start, value.end)); + return m_cacheInfo->backingCaches; } -void Deserialize(DeserializationContext& context, std::string_view name, AddressRange& value) +DSCViewState SharedCache::ViewState() const { + { + std::lock_guard lock(m_mutex); + if (auto& viewState = m_modifiedState->viewState) + return *viewState; + } + + return m_viewSpecificState->viewState; +} + +const std::unordered_map& SharedCache::AllImageStarts() const { - auto array = context.doc[name.data()].GetArray(); - value = {array[0].GetUint64(), array[1].GetUint64()}; + return m_cacheInfo->imageStarts; } -void Serialize(SerializationContext& context, const MemoryRegionStatus& status) +const std::unordered_map& SharedCache::AllImageHeaders() const { - context.writer.StartArray(); - Serialize(context, status.loaded); - Serialize(context, status.headerInitialized); - context.writer.EndArray(); + return m_cacheInfo->headers; } -void Deserialize( - DeserializationContext& context, std::string_view name, std::unordered_map& statuses) +uint64_t SharedCache::CacheInfo::BaseAddress() const { - auto array = context.doc[name.data()].GetArray(); - for (auto& pair : array) + uint64_t base = std::numeric_limits::max(); + for (const auto& backingCache : backingCaches) { - auto statusArray = pair[1].GetArray(); - MemoryRegionStatus status; - status.loaded = statusArray[0].GetBool(); - status.headerInitialized = statusArray[1].GetBool(); - statuses[pair[0].GetUint64()] = std::move(status); + for (const auto& mapping : backingCache.mappings) + { + if (mapping.address < base) + { + base = mapping.address; + break; + } + } } + return base; } -void Serialize(SerializationContext& context, const Ref& value) +// Intentionally takes a copy to avoid modifying the cursor position in the original reader. +std::optional SharedCache::GetObjCOptimizationHeader(VMReader reader) const { - context.writer.StartArray(); - Serialize(context, value->GetRawNameRef()); - Serialize(context, value->GetAddress()); - Serialize(context, value->GetType()); - context.writer.EndArray(); + if (!m_cacheInfo->objcOptimizationDataRange) + return {}; + + ObjCOptimizationHeader header{}; + // Ignoring `objcOptsSize` in favor of `sizeof(ObjCOptimizationHeader)` matches dyld's behavior. + reader.Read(&header, m_cacheInfo->BaseAddress() + m_cacheInfo->objcOptimizationDataRange->first, sizeof(ObjCOptimizationHeader)); + + return header; } -void Serialize(SerializationContext& context, const std::shared_ptr>>& value) +uint64_t SharedCache::GetObjCRelativeMethodBaseAddress(const VMReader& reader) const { - context.writer.StartArray(); - for (const auto& [_, symbol] : *value) - { - Serialize(context, symbol); - } - context.writer.EndArray(); + if (auto header = GetObjCOptimizationHeader(reader); header.has_value()) + return m_cacheInfo->BaseAddress() + header->relativeMethodSelectorBaseAddressOffset; + return 0; } -void Serialize(SerializationContext& context, const std::shared_ptr>>& value) +std::shared_ptr SharedCache::MapFile(const std::string& path) { - Serialize(context, *value); + return MMappedFileAccessor:: + Open(m_dscView, m_dscView->GetFile()->GetSessionId(), path, [this](std::shared_ptr mmap) { + ParseAndApplySlideInfoForFile(mmap, m_cacheInfo->BaseAddress()); + })->lock(); } -void Deserialize(DeserializationContext& context, std::string_view name, - std::unordered_map>>>& value) +std::shared_ptr SharedCache::MapFileWithoutApplyingSlide(const std::string& path) { - auto array = context.doc[name.data()].GetArray(); - for (auto& pair : array) - { - auto symbols_array = pair[1].GetArray(); - std::unordered_map> symbols; - for (auto& symbol_value : symbols_array) - { - auto symbol_array = symbol_value.GetArray(); - std::string symbolName = symbol_array[0].GetString(); - uint64_t address = symbol_array[1].GetUint64(); - BNSymbolType type = (BNSymbolType)symbol_array[2].GetUint(); - symbols.insert({address, new Symbol(type, symbolName, address)}); - } - value[pair[0].GetUint64()] = std::make_shared>>(std::move(symbols)); - } + return std::make_shared(path); } -void Deserialize(DeserializationContext& context, std::string_view name, - std::unordered_map>>>& value) +const std::string SharedCacheMetadata::Tag = "SHAREDCACHE-SharedCacheData"; +const std::string SharedCacheMetadata::CacheInfoTag = "SHAREDCACHE-CacheInfo"; +const std::string SharedCacheMetadata::ModifiedStateTagPrefix = "SHAREDCACHE-ModifiedState-"; +const std::string SharedCacheMetadata::ModifiedStateCountTag = "SHAREDCACHE-ModifiedState-Count"; + +SharedCacheMetadata::~SharedCacheMetadata() = default; +SharedCacheMetadata::SharedCacheMetadata(SharedCacheMetadata&&) = default; +SharedCacheMetadata& SharedCacheMetadata::operator=(SharedCacheMetadata&&) = default; + +SharedCacheMetadata::SharedCacheMetadata(SharedCache::CacheInfo cacheInfo, SharedCache::ModifiedState state) : + cacheInfo(std::make_unique(std::move(cacheInfo))), + state(std::make_unique(std::move(state))) +{} + + +// static +bool SharedCacheMetadata::ViewHasMetadata(BinaryView* view) { - auto array = context.doc[name.data()].GetArray(); - for (auto& pair : array) - { - auto symbols_array = pair[1].GetArray(); - std::vector> symbols; - symbols.reserve(symbols_array.Size()); - for (auto& symbol_value : symbols_array) - { - auto symbol_array = symbol_value.GetArray(); - std::string symbolName = symbol_array[0].GetString(); - uint64_t address = symbol_array[1].GetUint64(); - BNSymbolType type = (BNSymbolType)symbol_array[2].GetUint(); - symbols.push_back(new Symbol(type, symbolName, address)); - } - value[pair[0].GetUint64()] = std::make_shared>>(std::move(symbols)); - } + return view->QueryMetadata(Tag); } -void Deserialize(DeserializationContext& context, std::string_view name, std::optional& viewState) +// static +std::optional SharedCacheMetadata::LoadFromView(BinaryView* view) { - auto& value = context.doc[name.data()]; - if (value.IsNull()) - viewState = std::nullopt; - else - viewState = (DSCViewState)value.GetUint(); + Ref viewMetadata = view->QueryMetadata(Tag); + if (!viewMetadata) + return std::nullopt; + + auto cacheInfo = SharedCache::CacheInfo::LoadFromString(viewMetadata->GetString()); + if (!cacheInfo) + return std::nullopt; + + auto modifiedState = SharedCache::ModifiedState::LoadAll(view, *cacheInfo); + return SharedCacheMetadata(std::move(*cacheInfo), std::move(modifiedState)); } -void SharedCache::CacheInfo::Store(SerializationContext& context) const +const std::unordered_map>>>& SharedCacheMetadata::ExportInfos() const { - Serialize(context, "metadataVersion", METADATA_VERSION); + return state->exportInfos; +} - MSS(backingCaches); - MSS(headers); - MSS(images); - MSS(imageStarts); - MSS(memoryRegions); - MSS(objcOptimizationDataRange); - MSS(baseFilePath); - MSS_CAST(cacheFormat, uint8_t); +std::string SharedCacheMetadata::InstallNameForImageBaseAddress(uint64_t baseAddress) const +{ + auto it = std::find_if(cacheInfo->imageStarts.begin(), cacheInfo->imageStarts.end(), [=](auto& pair) { + return pair.second == baseAddress; + }); + + if (it == cacheInfo->imageStarts.end()) + return ""; + + return it->first; } -// static -std::optional SharedCache::CacheInfo::Load(DeserializationContext& context) +} // namespace SharedCacheCore + +namespace { + +[[maybe_unused]] DSCViewType* g_dscViewType; + +} + +void InitDSCViewType() { + MMappedFileAccessor::InitialVMSetup(); + std::atexit(VMShutdown); + + static DSCViewType type; + BinaryViewType::Register(&type); + g_dscViewType = &type; +} + +extern "C" { - if (!context.doc.HasMember("metadataVersion")) + BNSharedCache* BNGetSharedCache(BNBinaryView* data) + { + if (!data) + return nullptr; + + Ref view = new BinaryView(BNNewViewReference(data)); + if (auto cache = SharedCache::GetFromDSCView(view)) + { + cache->AddAPIRef(); + return cache->GetAPIObject(); + } + + return nullptr; + } + + BNSharedCache* BNNewSharedCacheReference(BNSharedCache* cache) { - LogError("Shared Cache metadata version missing"); - return std::nullopt; + if (!cache->object) + return nullptr; + + cache->object->AddAPIRef(); + return cache; } - if (context.doc["metadataVersion"].GetUint() != METADATA_VERSION) + void BNFreeSharedCacheReference(BNSharedCache* cache) { - LogError("Shared Cache metadata version mismatch"); - return std::nullopt; + if (!cache->object) + return; + + cache->object->ReleaseAPIRef(); } - CacheInfo cacheInfo; - cacheInfo.MSL(backingCaches); - cacheInfo.MSL(headers); - cacheInfo.MSL(images); - cacheInfo.MSL(imageStarts); - cacheInfo.MSL(memoryRegions); - cacheInfo.MSL(objcOptimizationDataRange); - cacheInfo.MSL(baseFilePath); - cacheInfo.MSL_CAST(cacheFormat, uint8_t, SharedCacheFormat); - return cacheInfo; -} -void State::Store(SerializationContext& context, std::optional viewState) const -{ - MSS(memoryRegionStatus); - MSS(exportInfos); - MSS(symbolInfos); - MSS(viewState); -} + bool BNDSCViewLoadImageWithInstallName(BNSharedCache* cache, char* name, bool skipObjC) + { + std::string imageName = std::string(name); + // FIXME !!!!!!!! BNFreeString(name); -void SharedCache::ModifiedState::Store(SerializationContext& context) const -{ - State::Store(context, viewState); -} + if (cache->object) + return cache->object->LoadImageWithInstallName(imageName, skipObjC); -SharedCache::ModifiedState SharedCache::ModifiedState::Load(DeserializationContext& context) -{ - SharedCache::ModifiedState state; - state.MSL(memoryRegionStatus); - state.MSL(exportInfos); - state.MSL(symbolInfos); - state.MSL(viewState); - return state; -} + return false; + } -SharedCache::ModifiedState SharedCache::ModifiedState::LoadAll(BinaryNinja::BinaryView *dscView, const CacheInfo& cacheInfo) -{ - uint64_t stateCount = dscView->GetUIntMetadata(SharedCacheMetadata::ModifiedStateCountTag); - SharedCache::ModifiedState state; - for (uint64_t i = 0; i < stateCount; ++i) + bool BNDSCViewLoadSectionAtAddress(BNSharedCache* cache, uint64_t addr) { - std::string key = SharedCacheMetadata::ModifiedStateTagPrefix + std::to_string(i); - std::string serialized = dscView->GetStringMetadata(key); - auto thisState = SharedCache::ModifiedState::LoadFromString(serialized); - state.Merge(std::move(thisState)); + if (cache->object) + { + return cache->object->LoadSectionAtAddress(addr); + } + + return false; } - return state; -} -void SharedCache::ModifiedState::Merge(SharedCache::ModifiedState&& newer) -{ - memoryRegionStatus.merge(newer.memoryRegionStatus); - exportInfos.merge(newer.exportInfos); - symbolInfos.merge(newer.symbolInfos); + bool BNDSCViewLoadImageContainingAddress(BNSharedCache* cache, uint64_t address, bool skipObjC) + { + if (cache->object) + { + return cache->object->LoadImageContainingAddress(address, skipObjC); + } - if (newer.viewState) - viewState = newer.viewState; -} + return false; + } -void BackingCache::Store(SerializationContext& context) const -{ - MSS(path); - MSS_CAST(cacheType, uint32_t); - MSS(mappings); -} + void BNDSCViewProcessObjCSectionsForImageWithInstallName(BNSharedCache* cache, char* name, bool deallocName) + { + std::string imageName = std::string(name); + if (deallocName) + BNFreeString(name); -BackingCache BackingCache::Load(DeserializationContext& context) -{ - BackingCache cache; - cache.MSL(path); - cache.MSL_CAST(cacheType, uint32_t, BNBackingCacheType); - cache.MSL(mappings); - return cache; -} + if (cache->object) + cache->object->ProcessObjCSectionsForImageWithInstallName(imageName); + } -void CacheImage::Store(SerializationContext& context) const -{ - MSS(installName); - MSS(headerLocation); - MSS(regionStarts); -} + void BNDSCViewProcessAllObjCSections(BNSharedCache* cache) + { + if (cache->object) + cache->object->ProcessAllObjCSections(); + } -// static -CacheImage CacheImage::Load(DeserializationContext& context) -{ - CacheImage cacheImage; - cacheImage.MSL(installName); - cacheImage.MSL(headerLocation); - cacheImage.MSL(regionStarts); - return cacheImage; -} + char** BNDSCViewGetInstallNames(BNSharedCache* cache, size_t* count) + { + if (cache->object) + { + auto value = cache->object->GetAvailableImages(); + *count = value.size(); -void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) -{ - auto array = context.doc[name.data()].GetArray(); - for (auto& value: array) - b.push_back(BackingCache::LoadFromValue(value)); -} + std::vector cstrings; + cstrings.reserve(value.size()); + for (size_t i = 0; i < value.size(); i++) + { + cstrings.push_back(value[i].c_str()); + } + return BNAllocStringList(cstrings.data(), cstrings.size()); + } + *count = 0; + return nullptr; + } -void Deserialize(DeserializationContext& context, std::string_view name, std::vector& b) -{ - auto array = context.doc[name.data()].GetArray(); - for (auto& value: array) - b.push_back(CacheImage::LoadFromValue(value)); -} + BNDSCSymbolRep* BNDSCViewLoadAllSymbolsAndWait(BNSharedCache* cache, size_t* count) + { + if (cache->object) + { + auto symbolsByImageName = cache->object->LoadAllSymbolsAndWait(); + size_t totalSymbolCount = 0; + for (const auto& [_, symbols] : symbolsByImageName) + { + totalSymbolCount += symbols.size(); + } + *count = totalSymbolCount; -void Deserialize(DeserializationContext& context, std::string_view name, std::unordered_map& b) -{ - auto array = context.doc[name.data()].GetArray(); - for (auto& pair_value : array) + BNDSCSymbolRep* outputSymbols = new BNDSCSymbolRep[totalSymbolCount]; + size_t i = 0; + for (const auto& [imageName, symbols] : symbolsByImageName) + { + for (const auto& symbol : symbols) + { + outputSymbols[i].address = symbol->GetAddress(); + outputSymbols[i].name = BNDuplicateStringRef(symbol->GetRawNameRef().GetObject()); + outputSymbols[i].image = BNAllocStringWithLength(imageName.c_str(), imageName.length()); + ++i; + } + } + assert(i == totalSymbolCount); + return outputSymbols; + } + *count = 0; + return nullptr; + } + + void BNDSCViewFreeSymbols(BNDSCSymbolRep* symbols, size_t count) { - auto pair = pair_value.GetArray(); - b[pair[0].GetUint64()] = SharedCacheMachOHeader::LoadFromValue(pair[1]); + for (size_t i = 0; i < count; i++) + { + BNFreeStringRef(symbols[i].name); + BNFreeString(symbols[i].image); + } + delete symbols; } -} -void Deserialize(DeserializationContext& context, std::string_view name, AddressRangeMap& b) -{ - auto array = context.doc[name.data()].GetArray(); - for (auto& key_value : array) + char* BNDSCViewGetNameForAddress(BNSharedCache* cache, uint64_t address) { - auto key_value_pair = key_value.GetArray(); - auto key_pair = key_value_pair[0].GetArray(); - AddressRange key = {key_pair[0].GetUint64(), key_pair[1].GetUint64()}; - b[key] = MemoryRegion::LoadFromValue(key_value_pair[1]); + if (cache->object) + { + return BNAllocString(cache->object->NameForAddress(address).c_str()); + } + + return nullptr; } -} -const std::vector& SharedCache::BackingCaches() const -{ - return m_cacheInfo->backingCaches; -} + char* BNDSCViewGetImageNameForAddress(BNSharedCache* cache, uint64_t address) + { + if (cache->object) + { + return BNAllocString(cache->object->ImageNameForAddress(address).c_str()); + } -DSCViewState SharedCache::ViewState() const { + return nullptr; + } + + uint64_t BNDSCViewLoadedImageCount(BNSharedCache* cache) { - std::lock_guard lock(m_mutex); - if (auto& viewState = m_modifiedState->viewState) - return *viewState; + // FIXME? + return 0; } - return m_viewSpecificState->viewState; -} + BNDSCViewState BNDSCViewGetState(BNSharedCache* cache) + { + if (cache->object) + { + return (BNDSCViewState)cache->object->ViewState(); + } -const std::unordered_map& SharedCache::AllImageStarts() const -{ - return m_cacheInfo->imageStarts; -} + return BNDSCViewState::Unloaded; + } -const std::unordered_map& SharedCache::AllImageHeaders() const -{ - return m_cacheInfo->headers; -} -uint64_t SharedCache::CacheInfo::BaseAddress() const -{ - uint64_t base = std::numeric_limits::max(); - for (const auto& backingCache : backingCaches) + BNDSCMappedMemoryRegion* BNDSCViewGetLoadedRegions(BNSharedCache* cache, size_t* count) { - for (const auto& mapping : backingCache.mappings) + if (cache->object) { - if (mapping.address < base) + auto regions = cache->object->GetMappedRegions(); + *count = regions.size(); + BNDSCMappedMemoryRegion* mappedRegions = new BNDSCMappedMemoryRegion[regions.size()]; + for (size_t i = 0; i < regions.size(); i++) { - base = mapping.address; - break; + mappedRegions[i].vmAddress = regions[i]->start; + mappedRegions[i].size = regions[i]->size; + mappedRegions[i].name = + BNAllocStringWithLength(regions[i]->prettyName.c_str(), regions[i]->prettyName.length()); } + return mappedRegions; } + *count = 0; + return nullptr; } - return base; -} - -// Intentionally takes a copy to avoid modifying the cursor position in the original reader. -std::optional SharedCache::GetObjCOptimizationHeader(VMReader reader) const -{ - if (!m_cacheInfo->objcOptimizationDataRange) - return {}; - - ObjCOptimizationHeader header{}; - // Ignoring `objcOptsSize` in favor of `sizeof(ObjCOptimizationHeader)` matches dyld's behavior. - reader.Read(&header, m_cacheInfo->BaseAddress() + m_cacheInfo->objcOptimizationDataRange->first, sizeof(ObjCOptimizationHeader)); - - return header; -} - -uint64_t SharedCache::GetObjCRelativeMethodBaseAddress(const VMReader& reader) const -{ - if (auto header = GetObjCOptimizationHeader(reader); header.has_value()) - return m_cacheInfo->BaseAddress() + header->relativeMethodSelectorBaseAddressOffset; - return 0; -} - -std::shared_ptr SharedCache::MapFile(const std::string& path) -{ - return MMappedFileAccessor:: - Open(m_dscView, m_dscView->GetFile()->GetSessionId(), path, [this](std::shared_ptr mmap) { - ParseAndApplySlideInfoForFile(mmap, m_cacheInfo->BaseAddress()); - })->lock(); -} -std::shared_ptr SharedCache::MapFileWithoutApplyingSlide(const std::string& path) -{ - return std::make_shared(path); -} + void BNDSCViewFreeLoadedRegions(BNDSCMappedMemoryRegion* images, size_t count) + { + for (size_t i = 0; i < count; i++) + { + BNFreeString(images[i].name); + } + delete images; + } -const std::string SharedCacheMetadata::Tag = "SHAREDCACHE-SharedCacheData"; -const std::string SharedCacheMetadata::CacheInfoTag = "SHAREDCACHE-CacheInfo"; -const std::string SharedCacheMetadata::ModifiedStateTagPrefix = "SHAREDCACHE-ModifiedState-"; -const std::string SharedCacheMetadata::ModifiedStateCountTag = "SHAREDCACHE-ModifiedState-Count"; -SharedCacheMetadata::~SharedCacheMetadata() = default; -SharedCacheMetadata::SharedCacheMetadata(SharedCacheMetadata&&) = default; -SharedCacheMetadata& SharedCacheMetadata::operator=(SharedCacheMetadata&&) = default; + BNDSCBackingCache* BNDSCViewGetBackingCaches(BNSharedCache* cache, size_t* count) + { + BNDSCBackingCache* caches = nullptr; -SharedCacheMetadata::SharedCacheMetadata(SharedCache::CacheInfo cacheInfo, SharedCache::ModifiedState state) : - cacheInfo(std::make_unique(std::move(cacheInfo))), - state(std::make_unique(std::move(state))) -{} + if (cache->object) + { + auto viewCaches = cache->object->BackingCaches(); + *count = viewCaches.size(); + caches = new BNDSCBackingCache[viewCaches.size()]; + for (size_t i = 0; i < viewCaches.size(); i++) + { + caches[i].path = BNAllocString(viewCaches[i].path.c_str()); + caches[i].cacheType = viewCaches[i].cacheType; + BNDSCBackingCacheMapping* mappings; + mappings = new BNDSCBackingCacheMapping[viewCaches[i].mappings.size()]; -// static -bool SharedCacheMetadata::ViewHasMetadata(BinaryView* view) -{ - return view->QueryMetadata(Tag); -} + size_t j = 0; + for (const auto& mapping : viewCaches[i].mappings) + { + mappings[j].vmAddress = mapping.address; + mappings[j].size = mapping.size; + mappings[j].fileOffset = mapping.fileOffset; + j++; + } + caches[i].mappings = mappings; + caches[i].mappingCount = viewCaches[i].mappings.size(); + } + } -// static -std::optional SharedCacheMetadata::LoadFromView(BinaryView* view) -{ - Ref viewMetadata = view->QueryMetadata(Tag); - if (!viewMetadata) - return std::nullopt; + return caches; + } - auto cacheInfo = SharedCache::CacheInfo::LoadFromString(viewMetadata->GetString()); - if (!cacheInfo) - return std::nullopt; + void BNDSCViewFreeBackingCaches(BNDSCBackingCache* caches, size_t count) + { + for (size_t i = 0; i < count; i++) + { + delete[] caches[i].mappings; + BNFreeString(caches[i].path); + } + delete[] caches; + } - auto modifiedState = SharedCache::ModifiedState::LoadAll(view, *cacheInfo); - return SharedCacheMetadata(std::move(*cacheInfo), std::move(modifiedState)); -} + void BNDSCFindSymbolAtAddressAndApplyToAddress(BNSharedCache* cache, uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) + { + if (cache->object) + { + cache->object->FindSymbolAtAddrAndApplyToAddr(symbolLocation, targetLocation, triggerReanalysis); + } + } -const std::unordered_map>>>& SharedCacheMetadata::ExportInfos() const -{ - return state->exportInfos; -} + BNDSCImage* BNDSCViewGetAllImages(BNSharedCache* cache, size_t* count) + { + if (cache->object) + { + try { + auto vm = cache->object->GetVMMap(); + auto viewImageHeaders = cache->object->AllImageHeaders(); + *count = viewImageHeaders.size(); + BNDSCImage* images = new BNDSCImage[viewImageHeaders.size()]; + size_t i = 0; + for (const auto& [baseAddress, header] : viewImageHeaders) + { + images[i].name = BNAllocString(header.installName.c_str()); + images[i].headerAddress = baseAddress; + images[i].mappingCount = header.sections.size(); + images[i].mappings = new BNDSCImageMemoryMapping[header.sections.size()]; + for (size_t j = 0; j < header.sections.size(); j++) + { + const auto sectionStart = header.sections[j].addr; + images[i].mappings[j].rawViewOffset = header.sections[j].offset; + images[i].mappings[j].vmAddress = sectionStart; + images[i].mappings[j].size = header.sections[j].size; + images[i].mappings[j].name = BNAllocString(header.sectionNames[j].c_str()); + auto fileAccessor = vm->MappingAtAddress(sectionStart).first.fileAccessor; + images[i].mappings[j].filePath = BNAllocStringWithLength(fileAccessor->filePath().data(), fileAccessor->filePath().length()); + images[i].mappings[j].loaded = cache->object->IsMemoryMapped(sectionStart); + } + i++; + } + return images; + } + catch (...) + { + LogError("SharedCache: Failed to load image listing. Likely caused by a ser/deserialization error or load failure"); + *count = 0; + return nullptr; + } + } + *count = 0; + return nullptr; + } -std::string SharedCacheMetadata::InstallNameForImageBaseAddress(uint64_t baseAddress) const -{ - auto it = std::find_if(cacheInfo->imageStarts.begin(), cacheInfo->imageStarts.end(), [=](auto& pair) { - return pair.second == baseAddress; - }); + void BNDSCViewFreeAllImages(BNDSCImage* images, size_t count) + { + for (size_t i = 0; i < count; i++) + { + for (size_t j = 0; j < images[i].mappingCount; j++) + { + BNFreeString(images[i].mappings[j].name); + BNFreeString(images[i].mappings[j].filePath); + } + delete[] images[i].mappings; + BNFreeString(images[i].name); + } + delete[] images; + } - if (it == cacheInfo->imageStarts.end()) - return ""; + char* BNDSCViewGetImageHeaderForAddress(BNSharedCache* cache, uint64_t address) + { + if (cache->object) + { + auto header = cache->object->SerializedImageHeaderForAddress(address); + return BNAllocString(header.c_str()); + } - return it->first; -} + return nullptr; + } -} // namespace SharedCacheCore + char* BNDSCViewGetImageHeaderForName(BNSharedCache* cache, char* name) + { + std::string imageName = std::string(name); + BNFreeString(name); + if (cache->object) + { + auto header = cache->object->SerializedImageHeaderForName(imageName); + return BNAllocString(header.c_str()); + } -namespace { + return nullptr; + } -[[maybe_unused]] DSCViewType* g_dscViewType; + BNDSCMemoryUsageInfo BNDSCViewGetMemoryUsageInfo() + { + BNDSCMemoryUsageInfo info; + info.mmapRefs = MMapCount(); + info.sharedCacheRefs = sharedCacheReferences.load(); + return info; + } -} + BNDSCViewLoadProgress BNDSCViewGetLoadProgress(uint64_t sessionID) + { + if (auto viewSpecificState = ViewSpecificStateForId(sessionID, false)) + return viewSpecificState->progress; -void InitDSCViewType() { - MMappedFileAccessor::InitialVMSetup(); - std::atexit(VMShutdown); + return LoadProgressNotStarted; + } - static DSCViewType type; - BinaryViewType::Register(&type); - g_dscViewType = &type; -} + uint64_t BNDSCViewFastGetBackingCacheCount(BNBinaryView* data) + { + Ref view = new BinaryView(BNNewViewReference(data)); + return SharedCache::FastGetBackingCacheCount(view); + } +} \ No newline at end of file -- cgit v1.3.1