Memory model objects (procmem)ο
ProcessMemory (procmem)ο
- malduck.procmemο
alias of
ProcessMemory
- class malduck.procmem.procmem.ProcessMemory(buf, base=0, regions=None, **_)[source]ο
Basic virtual memory representation
Short name: procmem
- Parameters:
buf (bytes, mmap, memoryview, bytearray or MemoryBuffer object) β Object with memory contents
base (int, optional (default: 0)) β Virtual address of the region of interest (or beginning of buf when no regions provided)
regions (List[
Region
]) β Regions mapping. If set to None (default), buf is mapped into single-region with VA specified in base argument
Letβs assume that notepad.exe_400000.bin contains raw memory dump starting at 0x400000 base address. We can easily load that file to
ProcessMemory
object, usingfrom_file()
method:from malduck import procmem with procmem.from_file("notepad.exe_400000.bin", base=0x400000) as p: mem = p.readv(...) ...
If your data are loaded yet into buffer, you can directly use procmem constructor:
from malduck import procmem with open("notepad.exe_400000.bin", "rb") as f: payload = f.read() p = procmem(payload, base=0x400000)
Then you can work with PE image contained in dump by creating
ProcessMemoryPE
object, using itsfrom_memory()
constructor methodfrom malduck import procmem, procmempe with open("notepad.exe_400000.bin", "rb") as f: payload = f.read() p = procmem(payload, base=0x400000) ppe = procmempe.from_memory(p) ppe.pe.resource("NPENCODINGDIALOG")
If you want to load PE file directly and work with it in a similar way as with memory-mapped files, just use image parameter. It also works with
ProcessMemoryPE.from_memory()
for embedded binaries. Your file will be loaded and relocated in similar way as itβs done by Windows loader.from malduck import procmempe with procmempe.from_file("notepad.exe", image=True) as p: p.pe.resource("NPENCODINGDIALOG")
- addr_region(addr)[source]ο
Returns
Region
object mapping specified virtual address- Parameters:
addr β Virtual address
- Return type:
- close(copy=False)[source]ο
Closes opened files referenced by ProcessMemory object owned by this object.
If copy is False (default): invalidates the object.
- Parameters:
copy (bool) β Copy data into string before closing the mmap object (default: False)
- disasmv(addr, size=None, x64=False, count=None)[source]ο
Disassembles code under specified address
Changed in version 4.0.0: Returns iterator instead of list of instructions
- Parameters:
addr (int) β Virtual address
size (int (optional)) β Size of disassembled buffer
count (int (optional)) β Number of instructions to disassemble
x64 (bool (optional)) β Assembly is 64bit
- Returns:
List[Instruction]
- extract(modules=None, extract_manager=None)[source]ο
Tries to extract config from ProcessMemory object
- Parameters:
modules (
malduck.extractor.ExtractorModules
) β Extractor modules object (optional, loads β~/.malduckβ by default)extract_manager (
malduck.extractor.ExtractManager
) β ExtractManager object (optional, creates ExtractManager by default)
- Returns:
Static configuration(s) (
malduck.extractor.ExtractManager.config
) or None if not extracted- Return type:
List[dict] or None
- findbytesp(query, offset=None, length=None)[source]ο
Search for byte sequences (e.g., 4? AA BB ?? DD). Uses
yarap()
internallyIf offset is None, looks for match from the beginning of memory
New in version 1.4.0: Query is passed to yarap as single hexadecimal string rule. Use Yara-compatible strings only
- Parameters:
query (str or bytes) β Sequence of wildcarded hexadecimal bytes, separated by spaces
offset (int (optional)) β Buffer offset where searching will be started
length (int (optional)) β Length of searched area
- Returns:
Iterator returning next offsets
- Return type:
Iterator[int]
- findbytesv(query, addr=None, length=None)[source]ο
Search for byte sequences (e.g., 4? AA BB ?? DD). Uses
yarav()
internallyIf addr is None, looks for match from the beginning of memory
New in version 1.4.0: Query is passed to yarav as single hexadecimal string rule. Use Yara-compatible strings only
- Parameters:
query (str or bytes) β Sequence of wildcarded hexadecimal bytes, separated by spaces
addr (int (optional)) β Virtual address where searching will be started
length (int (optional)) β Length of searched area
- Returns:
Iterator returning found virtual addresses
- Return type:
Iterator[int]
Usage example:
from malduck import hex findings = [] for va in mem.findbytesv("4? AA BB ?? DD"): if hex(mem.readv(va, 5)) == "4aaabbccdd": findings.append(va)
- findmz(addr)[source]ο
Tries to locate MZ header based on address inside PE image
- Parameters:
addr (int) β Virtual address inside image
- Returns:
Virtual address of found MZ header or None
- findp(query, offset=None, length=None)[source]ο
Find raw bytes in memory (non-region-wise).
If offset is None, looks for substring from the beginning of memory
- Parameters:
query (bytes) β Substring to find
offset (int (optional)) β Offset in buffer where searching starts
length (int (optional)) β Length of searched area
- Returns:
Generates offsets where bytes were found
- Return type:
Iterator[int]
- findv(query, addr=None, length=None)[source]ο
Find raw bytes in memory (region-wise)
If addr is None, looks for substring from the beginning of memory
- Parameters:
query (bytes) β Substring to find
addr (int (optional)) β Virtual address of region where searching starts
length (int (optional)) β Length of searched area
- Returns:
Generates offsets where regex was matched
- Return type:
Iterator[int]
- classmethod from_file(filename, **kwargs)[source]ο
Opens file and loads its contents into ProcessMemory object
- Parameters:
filename β File name to load
- Return type:
Itβs highly recommended to use context manager when operating on files:
from malduck import procmem with procmem.from_file("binary.dmp") as p: mem = p.readv(...) ...
- classmethod from_memory(memory, base=None, **kwargs)[source]ο
Makes new instance based on another ProcessMemory object.
Useful for specialized derived classes like
CuckooProcessMemory
- Parameters:
memory (
ProcessMemory
) β ProcessMemory object to be copiedbase (int (optional, default is provided by specialized class)) β Virtual address of region of interest (imgbase)
- Return type:
- is_addr(addr)[source]ο
Checks whether provided parameter is correct virtual address :param addr: Virtual address candidate :return: True if it is mapped by ProcessMemory object
- iter_regions(addr=None, offset=None, length=None, contiguous=False, trim=False)[source]ο
Iterates over Region objects starting at provided virtual address or offset
This method is used internally to enumerate regions using provided strategy.
Warning
If starting point is not provided, iteration will start from the first mapped region. This could be counter-intuitive when length is set. It literally means βget <length> of mapped bytesβ. If you want to look for regions from address 0, you need to explicitly provide this address as an argument.
New in version 3.0.0.
- Parameters:
addr (int (default: None)) β Virtual address of starting point
offset (int (default: None)) β Offset of starting point, which will be translated to virtual address
length (int (default: None, unlimited)) β Length of queried range in VM mapping context
contiguous (bool (default: False)) β If True, break after first gap. Starting point must be inside mapped region.
trim (bool (default: False)) β Trim Region objects to range boundaries (addr, addr+length)
- Return type:
Iterator[
Region
]
- property lengthο
Returns length of raw memory contents :rtype: int
- p2v(off, length=None)[source]ο
Buffer (physical) offset to virtual address translation
Changed in version 3.0.0: Added optional mapping length check
- Parameters:
off β Buffer offset
length β Expected minimal length of mapping (optional)
- Returns:
Virtual address or None if offset is not mapped
- patchp(offset, buf)[source]ο
Patch bytes under specified offset
Warning
Family of *p methods doesnβt care about contiguity of regions.
Use
p2v()
andpatchv()
if you want to operate on contiguous regions only- Parameters:
offset (int) β Buffer offset
buf (bytes) β Buffer with patch to apply
Usage example:
from malduck import procmempe, aplib with procmempe("mal1.exe.dmp") as ppe: # Decompress payload payload = aPLib().decompress( ppe.readv(ppe.imgbase + 0x8400, ppe.imgend) ) embed_pe = procmem(payload, base=0) # Fix headers embed_pe.patchp(0, b"MZ") embed_pe.patchp(embed_pe.uint32p(0x3C), b"PE") # Load patched image into procmempe embed_pe = procmempe.from_memory(embed_pe, image=True) assert embed_pe.asciiz(0x1000a410) == b"StrToIntExA"
- patchv(addr, buf)[source]ο
Patch bytes under specified virtual address
Patched address range must be within single region, ValueError is raised otherwise.
- Parameters:
addr (int) β Virtual address
buf (bytes) β Buffer with patch to apply
- readp(offset, length=None)[source]ο
Read a chunk of memory from the specified buffer offset.
Warning
Family of *p methods doesnβt care about contiguity of regions.
Use
p2v()
andreadv()
if you want to operate on contiguous regions only- Parameters:
offset β Buffer offset
length β Length of chunk (optional)
- Returns:
Chunk from specified location
- Return type:
bytes
- readv(addr, length=None)[source]ο
Read a chunk of memory from the specified virtual address
- Parameters:
addr (int) β Virtual address
length (int) β Length of chunk (optional)
- Returns:
Chunk from specified location
- Return type:
bytes
- readv_regions(addr=None, length=None, contiguous=True)[source]ο
Generate chunks of memory from next contiguous regions, starting from the specified virtual address, until specified length of read data is reached.
Used internally.
Changed in version 3.0.0: Contents of contiguous regions are merged into single string
- Parameters:
addr β Virtual address
length β Size of memory to read (optional)
contiguous β If True, readv_regions breaks after first gap
- Return type:
Iterator[Tuple[int, bytes]]
- readv_until(addr, s)[source]ο
Read a chunk of memory until the stop marker
- Parameters:
addr (int) β Virtual address
s (bytes) β Stop marker
- Return type:
bytes
- regexp(query, offset=None, length=None)[source]ο
Performs regex on the memory contents (non-region-wise)
If offset is None, looks for match from the beginning of memory
- Parameters:
query (bytes) β Regular expression to find
offset (int (optional)) β Offset in buffer where searching starts
length (int (optional)) β Length of searched area
- Returns:
Generates offsets where regex was matched
- Return type:
Iterator[int]
- regexv(query, addr=None, length=None)[source]ο
Performs regex on the memory contents (region-wise)
If addr is None, looks for match from the beginning of memory
- Parameters:
query (bytes) β Regular expression to find
addr (int (optional)) β Virtual address of region where searching starts
length (int (optional)) β Length of searched area
- Returns:
Generates offsets where regex was matched
- Return type:
Iterator[int]
Warning
Method doesnβt match bytes overlapping the border between regions
- utf16z(addr)[source]ο
Read a null-terminated UTF-16 ASCII string at address.
- Parameters:
addr β Virtual address of string
- Return type:
bytes
- v2p(addr, length=None)[source]ο
Virtual address to buffer (physical) offset translation
Changed in version 3.0.0: Added optional mapping length check
- Parameters:
addr β Virtual address
length β Expected minimal length of mapping (optional)
- Returns:
Buffer offset or None if virtual address is not mapped
- yarap(ruleset, offset=None, length=None, extended=False)[source]ο
Perform yara matching (non-region-wise)
If offset is None, looks for match from the beginning of memory
Changed in version 4.0.0: Added extended option which allows to get extended information about matched strings and rules. Default is False for backwards compatibility.
- Parameters:
ruleset (
malduck.yara.Yara
) β Yara object with loaded yara rulesoffset (int (optional)) β Offset in buffer where searching starts
length (int (optional)) β Length of searched area
extended (bool (optional, default False)) β Returns extended information about matched strings and rules
- Return type:
- yarav(ruleset, addr=None, length=None, extended=False)[source]ο
Perform yara matching (region-wise)
If addr is None, looks for match from the beginning of memory
Changed in version 4.0.0: Added extended option which allows to get extended information about matched strings and rules. Default is False for backwards compatibility.
- Parameters:
ruleset (
malduck.yara.Yara
) β Yara object with loaded yara rulesaddr (int (optional)) β Virtual address of region where searching starts
length (int (optional)) β Length of searched area
extended (bool (optional, default False)) β Returns extended information about matched strings and rules
- Return type:
malduck.yara.YaraRulesetOffsets
ormalduck.yara.YaraRulesetMatches
if extended is set to True
- class malduck.procmem.procmem.Region(addr: int, size: int, state: int, type_: int, protect: int, offset: int)[source]ο
Represents single mapped region in
ProcessMemory
- contains_offset(offset: int) bool [source]ο
Checks whether region contains provided physical offset
- property end: intο
Virtual address of region end (first unmapped byte)
- property end_offset: intο
Offset of region end (first unmapped byte)
- intersects_range(addr: int, length: int) bool [source]ο
Checks whether region mapping intersects with provided range
- property last: intο
Virtual address of last region byte
- property last_offset: intο
Offset of last region byte
- p2v(off: int) int [source]ο
Physical offset to translation. Assumes that offset is valid within Region. :param off: Physical offset :return: Virtual address
ProcessMemoryPE (procmempe)ο
- malduck.procmempeο
alias of
ProcessMemoryPE
- class malduck.procmem.procmempe.ProcessMemoryPE(buf: bytes | bytearray | mmap | MemoryBuffer, base: int = 0, regions: List[Region] | None = None, image: bool = False, detect_image: bool = False)[source]ο
Representation of memory-mapped PE file
Short name: procmempe
- Parameters:
buf (bytes, mmap, memoryview, bytearray or
MemoryBuffer()
object) β A memory object containing the PE to be loadedbase (int, optional (default: 0)) β Virtual address of the region of interest (or beginning of buf when no regions provided)
image (bool, optional (default: False)) β The memory object is a dump of memory-mapped PE
detect_image (bool, optional (default: False)) β Try to automatically detect if the input buffer is memory-mapped PE using some heuristics
File memory_dump contains a 64bit memory-aligned PE dumped from address 0x140000000, in order to load it into procmempe and access the pe field all we have to do is initialize a new object with the file data:
from malduck import procmempe with open("memory_dump", "rb") as f: data = f.read() pe_dump = procmempe(buf=data, base=0x140000000, image=True) print(pe_dump.pe.is64bit)
PE files can also be read directly using inherited
ProcessMemory.from_file()
with image argument set (look atfrom_memory()
method).pe_dump = procmempe.from_file("140000000_1d5bdc3dbe71a7bd", image=True) print(pe_dump.pe.sections)
- property imgend: intο
Address where PE image ends
- is_image_loaded_as_memdump() bool [source]ο
Checks whether memory region contains image incorrectly loaded as memory-mapped PE dump (image=False).
embed_pe = procmempe.from_memory(mem) if not embed_pe.is_image_loaded_as_memdump(): # Memory contains plain PE file - need to load it first embed_pe = procmempe.from_memory(mem, image=True)
ProcessMemoryELF (procmemelf)ο
- malduck.procmemelfο
alias of
ProcessMemoryELF
- class malduck.procmem.procmemelf.ProcessMemoryELF(buf: bytes | bytearray | mmap | MemoryBuffer, base: int = 0, regions: List[Region] | None = None, image: bool = False, detect_image: bool = False)[source]ο
Representation of memory-mapped ELF file
Short name: procmemelf
ELF files can be read directly using inherited
ProcessMemory.from_file()
with image argument set (look atfrom_memory()
method).- property elf: ELFFileο
Related
ELFFile
object
- property imgend: intο
Address where ELF image ends
CuckooProcessMemory (cuckoomem)ο
- malduck.cuckoomemο
alias of
CuckooProcessMemory
IDAProcessMemory (idamem)ο
- malduck.idamemο
alias of
IDAProcessMemory
- class malduck.procmem.idamem.IDAProcessMemory[source]ο
ProcessMemory representation operating in IDAPython context
Short name: idamem
Initialize by creating the object within IDAPython context and then use like a normal procmem object:
from malduck import idamem, xor ida = idamem() decrypted_data = xor(b"KEYZ", ida.readv(0x0040D320, 128)) some_wide_string = ida.utf16z(0x402010).decode("utf-8")