Module refinery.units.formats.pe.dotnet.dnsfx
Expand source code Browse git
from __future__ import annotations
from refinery.lib.dotnet.header import DotNetStructReader
from refinery.lib.id import buffer_contains
from refinery.lib.meta import SizeInt
from refinery.units.compression.zl import zl
from refinery.units.formats import PathExtractorUnit, UnpackResult
class dnsfx(PathExtractorUnit, docs='{0}{p}{PathExtractorUnit}'):
"""
Extracts files from .NET single file applications.
"""
_SIGNATURE = bytes([
# 32 bytes represent the bundle signature: SHA-256 for '.net core bundle'
0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38,
0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32,
0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18,
0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae
])
def unpack(self, data):
reader = DotNetStructReader(memoryview(data))
reader.seek(self._find_bundle_manifest_offset(data))
major_version = reader.u32()
minor_version = reader.u32()
self.log_info(F'version {major_version}.{minor_version}')
count = reader.u32()
bhash = reader.read_dn_string_primitive()
self.log_info(F'bundle {bhash} contains {count} files')
if major_version >= 2:
reader.u64() # depsOffset
reader.u64() # depsSize
reader.u64() # runtimeConfigOffset
reader.u64() # runtimeConfigSize
reader.u64() # flags
for _ in range(count):
try:
offset = reader.u64()
size = reader.u64()
compressed_size = 0
if major_version >= 6:
compressed_size = reader.u64()
type = reader.u8()
path = reader.read_dn_string_primitive()
def _logmsg():
_log = F'read item at offset 0x{offset:08X}, type 0x{type:02X}, size {SizeInt(size)!r}'
if compressed_size:
return F'{_log}, compressed to size {SizeInt(compressed_size)!r}'
return F'{_log}, uncompressed'
self.log_debug(_logmsg)
with reader.detour():
reader.seek(offset)
if compressed_size:
item_data = reader.read(compressed_size) | zl | bytearray
else:
item_data = reader.read(size)
yield UnpackResult(path, item_data)
except EOFError:
self.log_warn('unexpected EOF while parsing bundle, terminating')
break
def _find_bundle_manifest_offset(self, data: bytearray) -> int:
bundle_sig_offset = data.find(self._SIGNATURE, 0)
if bundle_sig_offset < 0:
raise ValueError('Cannot find valid Bundle Manifest offset. Is this a .NET Bundle?')
return int.from_bytes(data[bundle_sig_offset - 8:bundle_sig_offset], 'little')
@classmethod
def handles(cls, data):
return buffer_contains(data, cls._SIGNATURE)
Classes
class dnsfx (*paths, exclude=None, list=False, join_path=False, drop_path=False, fuzzy=0, exact=False, regex=False, path=b'path')-
Extracts files from .NET single file applications.
This unit extracts items with an associated virtual path from a container; each extracted item is emitted as a separate chunk with a corresponding meta variable named "path".
Positional arguments to dnsfx are patterns to filter the extracted items. Use the
-xflag to add an exclusion pattern. To extract all files with a foo or bar extension, but none that has the word "temp" in its path:dnsfx .foo .bar -x tempTo view only the paths of all chunks, use the listing switch:
emit data | ... | dnsfx -lOtherwise, extracted items are written to the standard output port and usually require a frame to properly process. In order to dump all extracted data to disk, the following pipeline can be used:
emit data | ... | dnsfx [| dump extracted/{path} ]The value
{path}is a placeholder which is substituted by the virtual path of the extracted item. When using dnsfx to unpack a file on disk, the following pattern can be useful:ef pack.bin [| dnsfx -j | d2p ]The unit
efis also a path extractor. By specifying-j(or--join), the paths of extracted items are combined. Here,d2pis a shortcut fordump {path}. It deconflicts the joined paths with the local file system: Ifpack.bincontains itemsone.txtandtwo.txt, the following local file tree would be the result:pack.bin pack/one.txt pack/two.txtFinally, the
-d(or--drop) switch can be used to not create (or alter) the path metadata at all, which is useful in cases where path metadata from a previous unit should be preserved.Expand source code Browse git
class dnsfx(PathExtractorUnit, docs='{0}{p}{PathExtractorUnit}'): """ Extracts files from .NET single file applications. """ _SIGNATURE = bytes([ # 32 bytes represent the bundle signature: SHA-256 for '.net core bundle' 0x8b, 0x12, 0x02, 0xb9, 0x6a, 0x61, 0x20, 0x38, 0x72, 0x7b, 0x93, 0x02, 0x14, 0xd7, 0xa0, 0x32, 0x13, 0xf5, 0xb9, 0xe6, 0xef, 0xae, 0x33, 0x18, 0xee, 0x3b, 0x2d, 0xce, 0x24, 0xb3, 0x6a, 0xae ]) def unpack(self, data): reader = DotNetStructReader(memoryview(data)) reader.seek(self._find_bundle_manifest_offset(data)) major_version = reader.u32() minor_version = reader.u32() self.log_info(F'version {major_version}.{minor_version}') count = reader.u32() bhash = reader.read_dn_string_primitive() self.log_info(F'bundle {bhash} contains {count} files') if major_version >= 2: reader.u64() # depsOffset reader.u64() # depsSize reader.u64() # runtimeConfigOffset reader.u64() # runtimeConfigSize reader.u64() # flags for _ in range(count): try: offset = reader.u64() size = reader.u64() compressed_size = 0 if major_version >= 6: compressed_size = reader.u64() type = reader.u8() path = reader.read_dn_string_primitive() def _logmsg(): _log = F'read item at offset 0x{offset:08X}, type 0x{type:02X}, size {SizeInt(size)!r}' if compressed_size: return F'{_log}, compressed to size {SizeInt(compressed_size)!r}' return F'{_log}, uncompressed' self.log_debug(_logmsg) with reader.detour(): reader.seek(offset) if compressed_size: item_data = reader.read(compressed_size) | zl | bytearray else: item_data = reader.read(size) yield UnpackResult(path, item_data) except EOFError: self.log_warn('unexpected EOF while parsing bundle, terminating') break def _find_bundle_manifest_offset(self, data: bytearray) -> int: bundle_sig_offset = data.find(self._SIGNATURE, 0) if bundle_sig_offset < 0: raise ValueError('Cannot find valid Bundle Manifest offset. Is this a .NET Bundle?') return int.from_bytes(data[bundle_sig_offset - 8:bundle_sig_offset], 'little') @classmethod def handles(cls, data): return buffer_contains(data, cls._SIGNATURE)Ancestors
Subclasses
Class variables
var reverse-
The type of the None singleton.
Methods
def unpack(self, data)-
Expand source code Browse git
def unpack(self, data): reader = DotNetStructReader(memoryview(data)) reader.seek(self._find_bundle_manifest_offset(data)) major_version = reader.u32() minor_version = reader.u32() self.log_info(F'version {major_version}.{minor_version}') count = reader.u32() bhash = reader.read_dn_string_primitive() self.log_info(F'bundle {bhash} contains {count} files') if major_version >= 2: reader.u64() # depsOffset reader.u64() # depsSize reader.u64() # runtimeConfigOffset reader.u64() # runtimeConfigSize reader.u64() # flags for _ in range(count): try: offset = reader.u64() size = reader.u64() compressed_size = 0 if major_version >= 6: compressed_size = reader.u64() type = reader.u8() path = reader.read_dn_string_primitive() def _logmsg(): _log = F'read item at offset 0x{offset:08X}, type 0x{type:02X}, size {SizeInt(size)!r}' if compressed_size: return F'{_log}, compressed to size {SizeInt(compressed_size)!r}' return F'{_log}, uncompressed' self.log_debug(_logmsg) with reader.detour(): reader.seek(offset) if compressed_size: item_data = reader.read(compressed_size) | zl | bytearray else: item_data = reader.read(size) yield UnpackResult(path, item_data) except EOFError: self.log_warn('unexpected EOF while parsing bundle, terminating') break
Inherited members
PathExtractorUnit:CustomJoinBehaviourCustomPathSeparatorFilterEverythingRequiresactassemblecodecconsolefilterfinishhandlesis_quietis_reversibleisattylabelledleniencylog_alwayslog_debuglog_detachlog_faillog_infolog_levellog_warnloggernamenozzleoptional_dependenciesreadread1required_dependenciesresetrunsourcesuperinit
UnitBase: