diff options
| author | kat <kat@vector35.com> | 2025-03-18 03:25:27 -0400 |
|---|---|---|
| committer | kat <kat@vector35.com> | 2025-03-18 03:57:05 -0400 |
| commit | 1bbb0e1dd640abe0278bf5bf947f9ae453f25373 (patch) | |
| tree | bd2939499e7197efd486dab3c813138875273ee5 /view/sharedcache/api/python/sharedcache.py | |
| parent | c00bf1a9dd87769bb9a85f46fcdb90e176eda1e8 (diff) | |
Documentation and type hints for sharedcache.py, properly import binaryninja.sharedcache automatically
Diffstat (limited to 'view/sharedcache/api/python/sharedcache.py')
| -rw-r--r-- | view/sharedcache/api/python/sharedcache.py | 174 |
1 files changed, 148 insertions, 26 deletions
diff --git a/view/sharedcache/api/python/sharedcache.py b/view/sharedcache/api/python/sharedcache.py index e3ccbb9b..dab5583e 100644 --- a/view/sharedcache/api/python/sharedcache.py +++ b/view/sharedcache/api/python/sharedcache.py @@ -59,14 +59,14 @@ class DSCBackingCache: return repr(self) def __repr__(self): - match self.cacheType: - case BackingCacheType.BackingCacheTypePrimary: - cacheTypeStr = 'Primary' - case BackingCacheType.BackingCacheTypeSecondary: - cacheTypeStr = 'Secondary' - case BackingCacheType.BackingCacheTypeSymbols: - cacheTypeStr = 'Symbols' - return f"<DSCBackingCache {self.path} {cacheTypeStr} | {len(self.mappings)} mappings>" + cache_type_str = 'Unknown' + if self.cacheType == BackingCacheType.BackingCacheTypePrimary: + cache_type_str = 'Primary' + elif self.cacheType == BackingCacheType.BackingCacheTypeSecondary: + cache_type_str = 'Secondary' + elif self.cacheType == BackingCacheType.BackingCacheTypeSymbols: + cache_type_str = 'Symbols' + return f"<DSCBackingCache {self.path} {cache_type_str} | {len(self.mappings)} mappings>" @dataclasses.dataclass @@ -112,26 +112,75 @@ class DSCSymbol: class SharedCache: + """ + SharedCache is the primary class for interacting with the shared cache processor and DSCView metadata. + + You can create a SharedCache object from a BinaryView object by calling `SharedCache(bv)`, where `bv` is the BinaryView. + + By default `bv` in the console will return the instance of the BinaryView that is currently open, \ + so in the UI, you can use `dsc = SharedCache(bv)` to create a SharedCache object in the scripting console. + + Methods and attributes in this class have documentation which can be viewed by typing `SharedCache.method_or_attribute_name?` in the console. + """ def __init__(self, view): self.handle = sccore.BNGetSharedCache(view.handle) - def load_image_with_install_name(self, installName, skipObjC = False): - return sccore.BNDSCViewLoadImageWithInstallName(self.handle, installName, skipObjC) + def load_image_with_install_name(self, install_name, skip_loading_objective_c = False) -> bool: + """ + Locate an image with the provided install name and load it into the shared cache view + + :param install_name: Install name of the image + :param skip_loading_objective_c: Whether to skip process Objective-C information for this image. Default false. + :return: + """ + return sccore.BNDSCViewLoadImageWithInstallName(self.handle, install_name, skip_loading_objective_c) + + def load_section_at_address(self, addr) -> bool: + """ + Load a singular section at the provided address into the shared cache view. + + This will partial-load the image, only mapping the requested segment containing this section. - def load_section_at_address(self, addr): + Image info will still be processed, but will only be applied to mapped regions. + + :param addr: Address within the section + :return: + """ return sccore.BNDSCViewLoadSectionAtAddress(self.handle, addr) - def load_image_containing_address(self, addr, skipObjC = False): - return sccore.BNDSCViewLoadImageContainingAddress(self.handle, addr, skipObjC) + def load_image_containing_address(self, addr, skip_loading_objective_c = False) -> bool: + """ + Load the image containing the provided address into the shared cache view. + + :param addr: Address within the image to load + :param skip_loading_objective_c: Whether to skip processing Objective-C information for this image. Default false. + :return: + """ + return sccore.BNDSCViewLoadImageContainingAddress(self.handle, addr, skip_loading_objective_c) + + def process_objc_sections_for_image_with_install_name(self, install_name) -> bool: + """ + Process Objective-C information for the image with the provided install name. + + :param install_name: Install name of the image + :return: + """ + return sccore.BNDSCViewProcessObjCSectionsForImageWithInstallName(self.handle, install_name, False) - def process_objc_sections_for_image_with_install_name(self, installName): - return sccore.BNDSCViewProcessObjCSectionsForImageWithInstallName(self.handle, installName, False) + def process_all_objc_sections(self) -> bool: + """ + Process Objective-C information for all images in the shared cache view. - def process_all_objc_sections(self): + :return: + """ return sccore.BNDSCViewProcessAllObjCSections(self.handle) @property - def caches(self): + def caches(self) -> list[DSCBackingCache]: + """ + Get all backing caches in the shared cache. + :return: + """ count = ctypes.c_ulonglong() value = sccore.BNDSCViewGetBackingCaches(self.handle, count) if value is None: @@ -157,7 +206,11 @@ class SharedCache: return result @property - def images(self): + def images(self) -> list[DSCImage]: + """ + Get all images in the shared cache + :return: + """ count = ctypes.c_ulonglong() value = sccore.BNDSCViewGetAllImages(self.handle, count) if value is None: @@ -186,7 +239,7 @@ class SharedCache: return result @property - def loaded_regions(self): + def loaded_regions(self) -> list[LoadedRegion]: """ Get all loaded regions in the shared cache @@ -214,7 +267,23 @@ class SharedCache: sccore.BNDSCViewFreeLoadedRegions(value, count) return result - def load_all_symbols_and_wait(self): + def load_all_symbols_and_wait(self) -> list[DSCSymbol]: + """ + Load all symbols in the shared cache. This will block on the current thread waiting for processing to finish. + + While all functions in this API are synchronous, this function can be particularly slow due to the large number + of symbols in the shared cache. "and_wait" is appended to the function name to indicate that this function + will block until processing is complete, and for performant applications, you should consider calling this + function in a separate thread and waiting on its return. An example of this is provided in the shared cache + triage view. + + This may take several seconds if this is the first time this function is called. Subsequent calls will be faster. + + In UI-based API usage, it is likely that the triage view will have already performed this operation, and calls + to this function will be much faster. + + :return: A list of all symbols in the shared cache + """ count = ctypes.c_ulonglong() value = sccore.BNDSCViewLoadAllSymbolsAndWait(self.handle, count) if value is None: @@ -232,7 +301,11 @@ class SharedCache: return result @property - def image_names(self): + def image_names(self) -> list[str]: + """ + Get all image names in the shared cache + :return: + """ count = ctypes.c_ulonglong() value = sccore.BNDSCViewGetInstallNames(self.handle, count) if value is None: @@ -246,22 +319,71 @@ class SharedCache: return result @property - def state(self): + def state(self) -> DSCViewState: + """ + Get the current image state of the shared cache view. Useful for checking if images have been loaded yet or not. + :return: + """ return DSCViewState(sccore.BNDSCViewGetState(self.handle)) - def get_name_for_address(self, address): + def get_name_for_address(self, address) -> str: + """ + Get the "name" for the provided address. Specifically, the name of the memory region this address lies in. + + If this lies within an image segment, this will be in the format image_name + "::" + segment_name. + + It may also be the name of a branch pool or other non-image region. + + This is the API call utilized on the first dynamic entry in the right-click context menu. + + :param address: address to check + :return: + """ name = sccore.BNDSCViewGetNameForAddress(self.handle, address) if name is None: return "" result = name return result - def get_image_name_for_address(self, address): + def get_image_name_for_address(self, address) -> str: + """ + Return the install name for the image containing the provided address. + + If the address is not within an image, this will return an empty string. + + This is the API call used in the second dynamic entry in the right-click context menu. + + :param address: address to check + :return: + """ name = sccore.BNDSCViewGetImageNameForAddress(self.handle, address) if name is None: return "" result = name return result - def find_symbol_at_addr_and_apply_to_addr(self, symbolAddress, targetAddress, triggerReanalysis) -> None: - sccore.BNDSCFindSymbolAtAddressAndApplyToAddress(self.handle, symbolAddress, targetAddress, triggerReanalysis) + def find_symbol_at_addr_and_apply_to_addr(self, symbol_address, target_address, trigger_reanalysis) -> None: + """ + This is primarily a function utilized for automated backwards symbol propagation for stubs in the workflow, however + it is passed through here as well in the event you need to use it to do something similar, or want to create + your own version of the workflow. + + This is currently a blocking function. + + This will check the cache for a symbol located at symbol_address, and apply it to target_address, appending a + `j_` to the front of the symbol name copy at `target_address`. + + It will additionally backwards-propagate type information that was specifically applied via TypeLibrary to the stub. + + This includes calling conventions and can be seen in stubs pointing to objc_release_x[register] functions. + + This check will not run if: + - The symbol address and target address are the same + - The target address has already been given a name by this function + + :param symbol_address: Symbol address to check + :param target_address: Target address to apply symbol name and type to + :param trigger_reanalysis: Whether to reanalyze the function at target_address if the function already existed. + :return: None + """ + sccore.BNDSCFindSymbolAtAddressAndApplyToAddress(self.handle, symbol_address, target_address, trigger_reanalysis) |
