Skip to content

Commit 7f42cbd

Browse files
committed
wip
1 parent 6267492 commit 7f42cbd

26 files changed

+905
-613
lines changed

docs/dev/workflows.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ You can query the list of all registered workflows or filter them by type using
145145
# List all Module and Function workflows
146146
list(Workflow)
147147
[<Workflow: core.function.baseAnalysis>,
148-
<Workflow: core.function.dsc>,
148+
<Workflow: core.function.sharedCache>,
149149
<Workflow: core.function.metaAnalysis>,
150150
<Workflow: core.function.objectiveC>,
151151
<Workflow: core.module.baseAnalysis>,
@@ -157,7 +157,7 @@ Settings().query_property_string_list("analysis.workflows.moduleWorkflow", "enum
157157

158158
# List all function workflows from the Settings API
159159
>>> Settings().query_property_string_list("analysis.workflows.functionWorkflow", "enum")
160-
['core.function.baseAnalysis', 'core.function.dsc', 'core.function.metaAnalysis', 'core.function.objectiveC']
160+
['core.function.baseAnalysis', 'core.function.sharedCache', 'core.function.metaAnalysis', 'core.function.objectiveC']
161161
```
162162

163163
Once you've queried the available workflows, you can create your own by cloning and modifying an existing workflow. Below are some simple examples that demonstrate how to modify module-level analysis.

view/sharedcache/api/python/sharedcache.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,21 @@ def symbol_to_api(symbol: CacheSymbol) -> sccore.BNSharedCacheSymbol:
107107

108108
class SharedCacheController:
109109
def __init__(self, view: BinaryView):
110+
"""
111+
Retrieve the shared cache controller for a given view.
112+
Call `is_valid` to check if the controller is valid.
113+
"""
110114
self.handle = sccore.BNGetSharedCacheController(view.handle)
111115

116+
def __str__(self):
117+
return repr(self)
118+
119+
def __repr__(self):
120+
return f"<SharedCacheController: {len(self.images)} images, {len(self.regions)} regions>"
121+
122+
def is_valid(self) -> bool:
123+
return self.handle is not None
124+
112125
def apply_region(self, view: BinaryView, region: CacheRegion) -> bool:
113126
api_region: sccore.BNSharedCacheRegion = region_to_api(region)
114127
result = sccore.BNSharedCacheControllerApplyRegion(self.handle, view.handle, api_region)
@@ -256,13 +269,21 @@ def symbols(self) -> [CacheSymbol]:
256269
return result
257270

258271

259-
def _get_dsc(instance: binaryninja.PythonScriptingInstance):
260-
if instance.interpreter.active_view is None:
261-
return None
262-
return SharedCache(instance.interpreter.active_view)
272+
def _get_shared_cache(instance: binaryninja.PythonScriptingInstance):
273+
if instance.interpreter.active_view is None:
274+
return None
275+
controller = SharedCacheController(instance.interpreter.active_view)
276+
if not controller.is_valid():
277+
return None
278+
return controller
263279

264280

265281
binaryninja.PythonScriptingProvider.register_magic_variable(
266282
"dsc",
267-
_get_dsc
283+
_get_shared_cache
284+
)
285+
286+
binaryninja.PythonScriptingProvider.register_magic_variable(
287+
"shared_cache",
288+
_get_shared_cache
268289
)

view/sharedcache/api/sharedcache.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,23 @@ CacheSymbol SymbolFromApi(BNSharedCacheSymbol apiSymbol)
108108
return symbol;
109109
}
110110

111+
std::string SharedCacheAPI::GetRegionTypeAsString(const BNSharedCacheRegionType &type)
112+
{
113+
switch (type)
114+
{
115+
case SharedCacheRegionTypeImage:
116+
return "Image";
117+
case SharedCacheRegionTypeStubIsland:
118+
return "StubIsland";
119+
case SharedCacheRegionTypeDyldData:
120+
return "DyldData";
121+
case SharedCacheRegionTypeNonImage:
122+
return "NonImage";
123+
default:
124+
return "Unknown";
125+
}
126+
}
127+
111128
SharedCacheController::SharedCacheController(BNSharedCacheController* controller)
112129
{
113130
m_object = controller;

view/sharedcache/api/sharedcacheapi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ namespace SharedCacheAPI {
259259
BNSegmentFlag flags;
260260
};
261261

262+
std::string GetRegionTypeAsString(const BNSharedCacheRegionType& type);
263+
262264
struct CacheMappingInfo
263265
{
264266
uint64_t vmAddress;

view/sharedcache/core/FileAccessorCache.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,45 @@ WeakFileAccessor FileAccessorCache::Open(const std::string &filePath)
6767
m_cache.push_back(id);
6868

6969
return WeakFileAccessor(sharedAccessor, filePath);
70-
}
70+
}
71+
72+
void FileAccessorWriteLog::AddPointer(const size_t address, const size_t pointer)
73+
{
74+
std::unique_lock<std::shared_mutex> lock(m_persistedMutex);
75+
m_persistedPointers[address] = pointer;
76+
}
77+
78+
void FileAccessorWriteLog::ApplyWrites(MappedFileAccessor& accessor)
79+
{
80+
std::shared_lock<std::shared_mutex> lock(m_persistedMutex);
81+
for (const auto &[address, pointer]: m_persistedPointers)
82+
accessor.WritePointer(address, pointer);
83+
}
84+
85+
std::shared_ptr<MappedFileAccessor> WeakFileAccessor::lock()
86+
{
87+
auto sharedPtr = m_weakPtr.lock();
88+
if (!sharedPtr)
89+
{
90+
// This will revive other weak pointers to the same shared ptr.
91+
// Update the weak pointer to the newly created shared instance
92+
m_weakPtr = FileAccessorCache::Global().Open(m_filePath).m_weakPtr;
93+
sharedPtr = m_weakPtr.lock();
94+
95+
// Apply any previously written pointers back.
96+
if (sharedPtr)
97+
m_writeLog->ApplyWrites(*sharedPtr);
98+
}
99+
100+
return sharedPtr;
101+
}
102+
103+
void WeakFileAccessor::WritePointer(const size_t address, const size_t pointer)
104+
{
105+
// Persist the pointer after the file accessor is revived.
106+
m_writeLog->AddPointer(address, pointer);
107+
108+
// And then actually apply the written pointer...
109+
if (auto sharedPtr = m_weakPtr.lock())
110+
sharedPtr->WritePointer(address, pointer);
111+
}

view/sharedcache/core/FileAccessorCache.h

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,31 +39,44 @@ class FileAccessorCache
3939
void SetCacheSize(uint64_t size) { m_cacheSize = size; };
4040
};
4141

42+
// Write log to be used in conjunction with `WeakFileAccessor` to re-apply written data to a "revived" file.
43+
struct FileAccessorWriteLog
44+
{
45+
// To persist writes to a file accessor being revived (within the lock() function)
46+
// we keep a list of writes that will be re-applied in the lock function.
47+
std::shared_mutex m_persistedMutex;
48+
std::unordered_map<size_t, uint64_t> m_persistedPointers;
49+
50+
FileAccessorWriteLog() = default;
51+
52+
// Add the pointer to the persisted pointers.
53+
void AddPointer(size_t address, size_t pointer);
54+
55+
// Apply all logged writes to the given accessor.
56+
void ApplyWrites(MappedFileAccessor& accessor);
57+
};
58+
4259
class WeakFileAccessor
4360
{
4461
// Weak pointer to the mapped file accessor, once this is expired we will re-open.
4562
std::weak_ptr<MappedFileAccessor> m_weakPtr;
4663
// File path for re-opening if needed
4764
std::string m_filePath;
65+
66+
std::shared_ptr<FileAccessorWriteLog> m_writeLog;
67+
4868
// TODO: Store a weak_ptr/shared_ptr to FileAccessorCache? That way we dont access Global()
4969
// TODO: Only need to do the above if we want multiple caches.
5070
public:
5171
explicit WeakFileAccessor(std::weak_ptr<MappedFileAccessor> weakPtr, std::string filePath)
5272
: m_weakPtr(std::move(weakPtr))
5373
, m_filePath(std::move(filePath))
74+
, m_writeLog(std::make_shared<FileAccessorWriteLog>())
5475
{}
5576

56-
std::shared_ptr<MappedFileAccessor> lock()
57-
{
58-
auto sharedPtr = m_weakPtr.lock();
59-
if (!sharedPtr)
60-
{
61-
// This will revive other weak pointers to the same shared ptr.
62-
// Update the weak pointer to the newly created shared instance
63-
m_weakPtr = FileAccessorCache::Global().Open(m_filePath).m_weakPtr;
64-
sharedPtr = m_weakPtr.lock();
65-
}
66-
67-
return sharedPtr;
68-
}
77+
std::shared_ptr<MappedFileAccessor> lock();
78+
79+
// Persists the written pointer within this weak file accessor.
80+
// This works as we expect the weak file accessor to be stored per virtual memory region.
81+
void WritePointer(size_t address, size_t pointer);
6982
};

view/sharedcache/core/MachO.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,9 @@ std::optional<CacheSymbol> SharedCacheMachOHeader::AddExportTerminalSymbol(const
580580
break;
581581
}
582582
}
583+
584+
// TODO: Is this enough to determine a function symbol?
585+
// TODO: Might be the cause of https://github.com/Vector35/binaryninja-api/issues/6526
583586
// Check the sections flags to see if we actually have a function symbol instead.
584587
if ((sectionFlags & S_ATTR_PURE_INSTRUCTIONS) == S_ATTR_PURE_INSTRUCTIONS
585588
|| (sectionFlags & S_ATTR_SOME_INSTRUCTIONS) == S_ATTR_SOME_INSTRUCTIONS)

view/sharedcache/core/MachOProcessor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ uint64_t SharedCacheMachOProcessor::ApplyHeaderSections(SharedCacheMachOHeader&
183183
semantics = ReadWriteDataSectionSemantics;
184184
if (strncmp(section.segname, "__DATA_CONST", sizeof(section.segname)) == 0)
185185
semantics = ReadOnlyDataSectionSemantics;
186+
if (strncmp(section.segname, "__auth_got", sizeof(section.segname)) == 0)
187+
semantics = ReadOnlyDataSectionSemantics;
186188

187189
m_view->AddUserSection(sectionName, section.addr, section.size, semantics,
188190
type, section.align);

view/sharedcache/core/MappedFile.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#endif
99

1010
#include "MappedFile.h"
11-
1211
#include "binaryninjaapi.h"
1312

1413
#ifndef _MSC_VER

view/sharedcache/core/MappedFileAccessor.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ std::shared_ptr<MappedFileAccessor> MappedFileAccessor::Open(const std::string&
1111
return std::make_shared<MappedFileAccessor>(std::move(*file));
1212
}
1313

14+
// TODO: Will obviously not work on 32bit binaries, need to make WritePointer64 and 32 equiv.
1415
void MappedFileAccessor::WritePointer(size_t address, size_t pointer)
1516
{
1617
m_dirty = true;
@@ -72,23 +73,22 @@ int64_t MappedFileAccessor::ReadInt64(size_t address)
7273
BinaryNinja::DataBuffer MappedFileAccessor::ReadBuffer(size_t addr, size_t length)
7374
{
7475
if (addr + length > Length())
75-
throw UnmappedAccessException();
76-
76+
throw UnmappedAccessException(addr + length, Length());
7777
return {&m_file._mmap[addr], length};
7878
}
7979

8080
std::pair<const uint8_t*, const uint8_t*> MappedFileAccessor::ReadSpan(size_t addr, size_t length)
8181
{
8282
if (addr + length > Length())
83-
throw UnmappedAccessException();
83+
throw UnmappedAccessException(addr + length, Length());
8484
const uint8_t* data = &m_file._mmap[addr];
8585
return {data, data + length};
8686
}
8787

8888
void MappedFileAccessor::Read(void *dest, size_t addr, size_t length) const
8989
{
9090
if (addr + length > Length())
91-
throw UnmappedAccessException();
91+
throw UnmappedAccessException(addr + length, Length());
9292
memcpy(dest, &m_file._mmap[addr], length);
9393
}
9494

0 commit comments

Comments
 (0)