Skip to content

Commit 4488576

Browse files
committed
wip
1 parent 3f2e25a commit 4488576

23 files changed

+444
-222
lines changed
Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import os
21
import ctypes
32
import dataclasses
4-
import traceback
53

64
import binaryninja
5+
from binaryninja import BinaryView
76
from binaryninja._binaryninjacore import BNFreeStringList, BNAllocString, BNFreeString
87

98
from . import _sharedcachecore as sccore
109
from .sharedcache_enums import *
1110

1211
@dataclasses.dataclass
1312
class CacheRegion:
14-
regionType: SharedCacheRegionType
13+
region_type: SharedCacheRegionType
1514
name: str
1615
start: int
1716
size: int
18-
imageStart: int
19-
flags: binaryninja.enums.SegmentFlag
17+
image_start: int
18+
# TODO: Might want to make this use the BN segment flag enum?
19+
flags: sccore.SegmentFlagEnum
2020

2121
def __str__(self):
2222
return repr(self)
@@ -27,40 +27,73 @@ def __repr__(self):
2727
@dataclasses.dataclass
2828
class CacheImage:
2929
name: str
30-
headerAddress: int
31-
regionStarts: [int]
30+
header_address: int
31+
region_starts: [int]
3232

3333
def __str__(self):
3434
return repr(self)
3535

3636
def __repr__(self):
37-
return f"<CacheImage '{self.name}': {self.headerAddress:x}>"
37+
return f"<CacheImage '{self.name}': {self.header_address:x}>"
3838

39-
def region_from_api(region):
39+
def region_from_api(region: sccore.BNSharedCacheRegion) -> CacheRegion:
4040
return CacheRegion(
41-
SharedCacheRegionType(region.regionType),
42-
region.name.decode('utf-8'),
43-
region.start,
44-
region.size,
45-
region.imageStart,
46-
binaryninja.enums.SegmentFlag(region.flags)
41+
region_type=SharedCacheRegionType(region.regionType),
42+
name=region.name,
43+
start=region.vmAddress,
44+
size=region.size,
45+
image_start=region.imageStart,
46+
flags=region.flags
4747
)
4848

49-
def image_from_api(image):
49+
def region_to_api(region: CacheRegion) -> sccore.BNSharedCacheRegion:
50+
return sccore.BNSharedCacheRegion(
51+
regionType=region.region_type,
52+
_name=BNAllocString(region.name),
53+
vmAddress=region.start,
54+
size=region.size,
55+
imageStart=region.image_start,
56+
flags=region.flags
57+
)
58+
59+
def image_from_api(image: sccore.BNSharedCacheImage) -> CacheImage:
5060
return CacheImage(
51-
image.name.decode('utf-8'),
61+
image.name,
5262
image.headerAddress,
5363
image.regionStarts
5464
)
5565

66+
def image_to_api(image: CacheImage) -> sccore.BNSharedCacheImage:
67+
region_start_array = (ctypes.POINTER(ctypes.c_ulonglong) * len(image.region_starts))()
68+
for i, region_start in enumerate(image.region_starts):
69+
region_start_array[i] = ctypes.c_ulonglong(region_start)
70+
return sccore.BNSharedCacheImage(
71+
_name=BNAllocString(image.name),
72+
headerAddress=image.header_address,
73+
regionStartCount=len(region_start_array),
74+
regionStarts=region_start_array
75+
)
76+
5677
class SharedCacheController:
57-
def __init__(self, view):
78+
def __init__(self, view: BinaryView):
5879
self.handle = sccore.BNGetSharedCacheController(view.handle)
5980

81+
def load_region(self, view: BinaryView, region: CacheRegion) -> bool:
82+
api_region: sccore.BNSharedCacheRegion = region_to_api(region)
83+
result = sccore.BNSharedCacheControllerLoadRegion(self.handle, view.handle, api_region)
84+
sccore.BNSharedCacheFreeRegion(api_region)
85+
return result
86+
87+
def load_image(self, view: BinaryView, image: CacheImage) -> bool:
88+
api_image: sccore.BNSharedCacheImage = image_to_api(image)
89+
result = sccore.BNSharedCacheControllerLoadImage(self.handle, view.handle, api_image)
90+
sccore.BNSharedCacheFreeImage(api_image)
91+
return result
92+
6093
@property
61-
def regions(self):
94+
def regions(self) -> [CacheRegion]:
6295
count = ctypes.c_ulonglong()
63-
value = sccore.BNGetSharedCacheRegions(self.handle, count)
96+
value = sccore.BNSharedCacheControllerGetRegions(self.handle, count)
6497
if value is None:
6598
return []
6699
result = []
@@ -69,15 +102,16 @@ def regions(self):
69102
sccore.BNSharedCacheFreeRegionList(value, count)
70103
return result
71104

72-
73105
@property
74-
def images(self):
106+
def images(self) -> [CacheImage]:
75107
count = ctypes.c_ulonglong()
76-
value = sccore.BNGetSharedCacheImages(self.handle, count)
108+
value = sccore.BNSharedCacheControllerGetImages(self.handle, count)
77109
if value is None:
78110
return []
79111
result = []
80112
for i in range(count.value):
81113
result.append(image_from_api(value[i]))
82114
sccore.BNSharedCacheFreeImageList(value, count)
83-
return result
115+
return result
116+
117+

view/sharedcache/api/sharedcache.cpp

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

111-
SharedCacheController::SharedCacheController(BNSharedCacheController *controller)
111+
SharedCacheController::SharedCacheController(BNSharedCacheController* controller)
112112
{
113113
m_object = controller;
114114
}
115115

116116
DSCRef<SharedCacheController> SharedCacheController::GetController(BinaryView& view)
117117
{
118118
BNSharedCacheController* controller = BNGetSharedCacheController(view.GetObject());
119-
if (!controller)
119+
if (controller == nullptr)
120120
return nullptr;
121121
return new SharedCacheController(controller);
122122
}

view/sharedcache/api/sharedcacheapi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ namespace SharedCacheAPI {
293293
static DSCRef<SharedCacheController> GetController(BinaryNinja::BinaryView& view);
294294

295295
bool LoadRegion(BinaryNinja::BinaryView& view, const CacheRegion& region);
296+
297+
// Attempt to load the given image into the view.
298+
//
299+
// It is the callers responsibility to run linear sweep and update analysis, as you might want to add
300+
// multiple images at a time.
296301
bool LoadImage(BinaryNinja::BinaryView& view, const CacheImage& image);
297302

298303
std::optional<CacheRegion> GetRegionAt(uint64_t address) const;

view/sharedcache/api/sharedcachecore.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,6 @@ extern "C"
116116
SHAREDCACHE_FFI_API bool BNSharedCacheControllerLoadImage(BNSharedCacheController* controller, BNBinaryView* view, BNSharedCacheImage* image);
117117
SHAREDCACHE_FFI_API bool BNSharedCacheControllerLoadRegion(BNSharedCacheController* controller, BNBinaryView* view, BNSharedCacheRegion* region);
118118

119-
// SHAREDCACHE_FFI_API void BNDSCViewProcessObjCSectionsForImageWithInstallName(BNSharedCacheController* cache, const char* name);
120-
// SHAREDCACHE_FFI_API void BNDSCViewProcessAllObjCSections(BNSharedCacheController* cache);
121-
// SHAREDCACHE_FFI_API BNDSCSymbolRep* BNSharedCacheControllerLoadAllSymbolsAndWait(BNSharedCacheController* cache, size_t* count);
122-
// SHAREDCACHE_FFI_API void BNSharedCacheControllerFreeSymbols(BNDSCSymbolRep* symbols, size_t count);
123-
124119
SHAREDCACHE_FFI_API bool BNSharedCacheControllerGetRegionAt(BNSharedCacheController* controller, uint64_t address, BNSharedCacheRegion* outRegion);
125120
SHAREDCACHE_FFI_API bool BNSharedCacheControllerGetRegionContaining(BNSharedCacheController* controller, uint64_t address, BNSharedCacheRegion* region);
126121

view/sharedcache/core/FileAccessorCache.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ WeakFileAccessor FileAccessorCache::Open(const std::string &filePath)
6262
// TODO: Make this mechanism more thought out...
6363
throw std::runtime_error("Failed to open file: " + filePath);
6464
}
65-
auto sharedAccessor = std::make_shared<MappedFileAccessor>(*accessor);
65+
auto sharedAccessor = std::make_shared<MappedFileAccessor>(std::move(*accessor));
6666
m_accessors.insert_or_assign(id, sharedAccessor);
6767
m_cache.push_back(id);
6868

view/sharedcache/core/MachO.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ SharedCacheMachOProcessor::SharedCacheMachOProcessor(std::shared_ptr<VirtualMemo
1515

1616
std::optional<SharedCacheMachOHeader> SharedCacheMachOProcessor::ParseHeaderForAddress(uint64_t address, const std::string& imagePath)
1717
{
18+
// Sanity check to make sure that the header is mapped.
19+
// This should really only fail if we didn't grab all the required entries.
20+
if (!m_vm->IsAddressMapped(address))
21+
return std::nullopt;
22+
1823
SharedCacheMachOHeader header;
1924

2025
header.textBase = address;
@@ -434,8 +439,6 @@ void SharedCacheMachOProcessor::ApplyHeader(Ref<BinaryView> view, SharedCacheMac
434439
if (settings && settings->Contains("loader.dsc.processFunctionStarts"))
435440
applyFunctionStarts = settings->Get<bool>("loader.dsc.processFunctionStarts", view);
436441

437-
BinaryReader virtualReader(view);
438-
439442
header.ApplyHeaderSections(view);
440443

441444
// TODO: Wtf is this?
@@ -807,6 +810,13 @@ std::vector<CacheSymbol> SharedCacheMachOHeader::ReadSymbolTable(BinaryView& vie
807810
// NOTE: The symbol table will exist within the link edit segment, the table offsets are relative to the file not the linkedit segment.
808811
uint64_t symbolsAddress = GetLinkEditFileBase() + symtab.symoff;
809812
uint64_t stringsAddress = GetLinkEditFileBase() + symtab.stroff;
813+
uint64_t link = GetLinkEditFileBase();
814+
LogInfo("link edit file base %llx", link);
815+
if (!vm.IsAddressMapped(link))
816+
{
817+
LogError("Link edit segment not mapped");
818+
return {};
819+
}
810820
auto strings = vm.ReadBuffer(stringsAddress, symtab.strsize);
811821

812822
// TODO: This needs to be passed in as an optional argument.
@@ -843,7 +853,7 @@ std::vector<CacheSymbol> SharedCacheMachOHeader::ReadSymbolTable(BinaryView& vie
843853
if (nlist.n_strx >= symtab.strsize)
844854
{
845855
// TODO: where logger?
846-
LogError("Symbol entry at index %llu has a string offset of %u which is outside the strings buffer of size %llu for symbol table %llx", entryIndex, nlist.n_strx, symtab.strsize, symtab.stroff);
856+
LogError("Symbol entry at index %llu has a string offset of %u which is outside the strings buffer of size %u for symbol table %x", entryIndex, nlist.n_strx, symtab.strsize, symtab.stroff);
847857
continue;
848858
}
849859

view/sharedcache/core/MappedFile.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#else
44
#include <sys/mman.h>
55
#include <fcntl.h>
6-
#include <stdlib.h>
6+
#include <cstdlib>
77
#include <sys/resource.h>
88
#endif
99

@@ -14,10 +14,17 @@
1414
#ifndef _MSC_VER
1515
uint64_t AdjustFileDescriptorLimit()
1616
{
17+
// The soft file descriptor limit on Linux and Mac is a lot lower than
18+
// on Windows (1024 for Linux, 256 for Mac). Recent iOS shared caches
19+
// have 60+ files which may not leave much headroom if a user opens
20+
// more than one at a time. Attempt to increase the file descriptor
21+
// limit to 1024, and limit ourselves to caching half of them as a
22+
// memory vs performance trade-off (closing and re-opening a file
23+
// requires parsing and applying the slide information again).
24+
uint64_t maxFPLimit = 1024;
25+
1726
//check for BN_SHAREDCACHE_FP_MAX
1827
// if it exists, set maxFPLimit to that value
19-
uint64_t maxFPLimit = 0;
20-
2128
if (auto env = getenv("BN_SHAREDCACHE_FP_MAX"); env)
2229
{
2330
// FIXME behav on 0 here is unintuitive, '0123' will interpret as octal and be 83 according to manpage. meh.
@@ -33,20 +40,13 @@ uint64_t AdjustFileDescriptorLimit()
3340
}
3441
}
3542

36-
// The soft file descriptor limit on Linux and Mac is a lot lower than
37-
// on Windows (1024 for Linux, 256 for Mac). Recent iOS shared caches
38-
// have 60+ files which may not leave much headroom if a user opens
39-
// more than one at a time. Attempt to increase the file descriptor
40-
// limit to 1024, and limit ourselves to caching half of them as a
41-
// memory vs performance trade-off (closing and re-opening a file
42-
// requires parsing and applying the slide information again).
43-
constexpr rlim_t TargetFileDescriptorLimit = 1024;
4443
rlimit rlim {};
4544
getrlimit(RLIMIT_NOFILE, &rlim);
4645
uint64_t previousLimit = rlim.rlim_cur;
47-
if (rlim.rlim_cur < TargetFileDescriptorLimit)
46+
uint64_t targetLimit = std::min(maxFPLimit, rlim.rlim_max);
47+
if (rlim.rlim_cur < targetLimit)
4848
{
49-
rlim.rlim_cur = std::min(TargetFileDescriptorLimit, rlim.rlim_max);
49+
rlim.rlim_cur = targetLimit;
5050
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
5151
{
5252
perror("setrlimit(RLIMIT_NOFILE)");
@@ -58,6 +58,12 @@ uint64_t AdjustFileDescriptorLimit()
5858
return maxFPLimit;
5959
}
6060

61+
MappedFile::~MappedFile()
62+
{
63+
Unmap();
64+
if (fd) fclose(fd);
65+
}
66+
6167
std::optional<MappedFile> MappedFile::OpenFile(const std::string& path)
6268
{
6369
MappedFile file;
@@ -75,24 +81,26 @@ std::optional<MappedFile> MappedFile::OpenFile(const std::string& path)
7581

7682
MapStatus MappedFile::Map()
7783
{
78-
if (mapped)
84+
if (_mmap)
7985
return MapStatus::Success;
8086

8187
void *result = mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(fd), 0u);
8288
if (result == MAP_FAILED)
89+
{
90+
BinaryNinja::LogInfo("mmap failed: %s", strerror(errno)); // Use errno to log the reason
8391
return MapStatus::Error;
92+
}
8493
_mmap = static_cast<uint8_t*>(result);
8594

86-
mapped = true;
8795
return MapStatus::Success;
8896
}
8997

9098
MapStatus MappedFile::Unmap()
9199
{
92-
if (mapped)
100+
if (_mmap)
93101
{
94102
munmap(_mmap, len);
95-
mapped = false;
103+
_mmap = nullptr;
96104
}
97105
return MapStatus::Success;
98106
}
@@ -102,6 +110,12 @@ uint64_t AdjustFileDescriptorLimit()
102110
return 0x1000000;
103111
}
104112

113+
MappedFile::~MappedFile()
114+
{
115+
Unmap();
116+
if (hFile) CloseHandle(hFile);
117+
}
118+
105119
std::optional<MappedFile> MappedFile::OpenFile(const std::string &path)
106120
{
107121
MappedFile file;
@@ -131,7 +145,7 @@ std::optional<MappedFile> MappedFile::OpenFile(const std::string &path)
131145

132146
MMapStatus MappedFile::Map()
133147
{
134-
if (mapped)
148+
if (_mmap)
135149
return MMapStatus::Success;
136150

137151
HANDLE hMapping = CreateFileMapping(
@@ -162,8 +176,6 @@ MMapStatus MappedFile::Map()
162176
return MMapStatus::Error;
163177
}
164178

165-
mapped = true;
166-
167179
CloseHandle(hMapping);
168180
CloseHandle(hFile);
169181

@@ -175,7 +187,6 @@ MMapStatus MappedFile::Unmap()
175187
if (_mmap)
176188
{
177189
UnmapViewOfFile(_mmap);
178-
mapped = false;
179190
}
180191
return MMapStatus::Success;
181192
}

0 commit comments

Comments
 (0)