Address mapping (analysis.map)

analysis.map: MappingAnnotation

The analysis.map object is a MappingAnnotation instance that allows you to access the File layout and convert addresses between three forms (see Addressing in Malcat).

Addressing in Malcat

Malcat can manipulate addresses in three different forms:

  • Physical addresses: a file offset, used within the analysis.file object for instance

  • Virtual addresses: an absolute memory address

  • Effective addresses: a contiguous address space which contains both physical and virtual address spaces.

Unless specified differently, most of Malcat python methods manipulate effective addresses. But what is exactly this effective address space? Think of a PE file organized as follow:

  • a 0x200 bytes header

  • a .bss purely virtual section, loaded at address 0x401000-0x402000

  • a .text section, loaded at address 0x402000-0x404300 and stored at file offset 0x200 - 0x2200 (the last 0x300 bytes are not file-backed)

  • an overlay which won’t be loaded in memory, stored at file offset 0x2200-0x3000

Some of Malcat’s analyses are only interested in the physical representation of the file, like the Entropy computation and do not care about the virtual space. Some analyses want to take the virtual space into account (e.g. the Cross References Scanner), some want both. Having to juggle constantly between physical and virtual addresses is difficult. A solution is to use an effective address space which is the concatenation of both address space:

  • it starts with the header at address [0x0-0x200[

  • then maps the .bss section at address [0x200-0x1200[

  • then maps the .text section at address [0x1200-0x3500[

  • and finally maps the overlay at address [0x3500-0x4300[

This make most analysis work much easier because the effective address space is contiguous. We can describe all the parts of a file (physical and virtual spaces) by using an integer in the range [0x0-0x4300[.

Note

For simple file types (i.e. files formats which don’t specify any specific mapping), the three address spaces are equivalent, i.e. physical address = virtual address = effective address

Mapping object

class malcat.MappingAnnotation

This class contains region layout information for a file.

base: int

the file’s imagebase, i.e. the virtual address it will be loaded in memory. Will be 0 if the file is not loaded into memory.

end: int

the maximum effective address valid for this file

regions: List[malcat.Region]

the list of the file’s regions

__iter__()

Iterate over the file’s regions

Returns:

iterator over the list of regions

Return type:

iterator

__contains__(address)

Check if an effective address belongs to the file’s mapping

Parameters:

address (int) – an effective address

Returns:

true iff address <= end

Return type:

bool

__contains__(name)

Check if the file contains any region named name. Example:

has_reloc = ".reloc" in analysis.map
Parameters:

name (str) – a section/region name

Returns:

true iff there is a region such as malcat.Region.name == name

Return type:

bool

get_region(address)

Get the region containing a given effective address

Parameters:

address (int) – an effective address

Returns:

the region containing address or None if none

Return type:

malcat.Region or None

__getitem__(address)

Return the region containing a given effective address. Example:

ep_rva = analysis.struct["OptionalHeader"]["AddressOfEntryPoint"]
ep_region = analysis.map[analysis.map.r2a(ep_rva)]
print("EP located inside section {}".format(ep_region.name))
Parameters:

address (int) – an effective address

Returns:

the region containing address

Return type:

malcat.Region

Raises:

KeyError if address does not belong to any region

__getitem__(name)

Get the first region named name. Example:

if ".rsrc" in analysis.map:
    rsrc_offset = analysis.map[".rsrc"].phys
    rsrc_size = analysis.map[".rsrc"].phys_size
    rsrc_data = analysis.file[rsrc_offset : rsrc_offset + rsrc_size]
Parameters:

name (str) – name of the region

Returns:

the first region named name

Return type:

malcat.Region

Raises:

KeyError if no region could be found

Conversion functions

The analysis.map object allows you to convert addresses to and from the three different address spaces. Note that not all addresses may be converted. Physical address may not lay in the file, and virtual addresses may not be valid for a given mapping. In this case, the conversion functions will return None.

Offsets

from_phys(offset)

converts a file offset to an effective address. Example:

offset = 0x1000
va = analysis.map.to_virt(analysis.map.from_phys(offset))
Parameters:

offset (int) – a file offset, e.g. 0x10.

Returns:

the corresponding effective address or None if the file offset is greater or equal than the file size

Return type:

int

to_phys(effective_address)

converts an effective address to a file offset. Example:

va = 0x401000
offset = analysis.map.to_phys(analysis.map.from_virt(va))
Parameters:

effective_address (int) – an effective address.

Returns:

the corresponding file offset or None if the effective address belongs to a purely virtual address space.

Return type:

int

Also if you don’t like typing:

p2a(offset)

shortcut for analysis.map.from_phys().

a2p(effective_address)

shortcut for analysis.map.to_phys().

Virtual address

from_virt(virtual_address)

converts a virtual address to an effective address. Example:

va = 0x401000
offset = analysis.map.to_phys(analysis.map.from_virt(va))
Parameters:

virtual_address (int) – a virtual memory address, e.g. 0x401000.

Returns:

the corresponding effective address or None if the virtual address is not mapped.

Return type:

int

to_virt(effective_address)

converts an effective address to a virtual address. Example:

offset = 0x1000
va = analysis.map.to_virt(analysis.map.from_phys(offset))
Parameters:

effective_address (int) – an effective address.

Returns:

the corresponding virtual address or None if the effective address does not belong to a virtual-mapped space.

Return type:

int

Also if you don’t like typing:

v2a(virtual_address)

shortcut for analysis.map.from_virt().

a2v(effective_address)

shortcut for analysis.map.to_virt().

RVA

from_rva(rva)

converts a Relative Virtual Address to an effective address. This is strictly equivalent to analysis.map.from_virt(malct.map.base + rva).

Parameters:

offset (int) – a relative virtual address, e.g. 0x1000.

Returns:

the corresponding effective address or None if the RVA does not belong to a virtual-mapped space.

Return type:

int

to_rva(effective_address)

converts an effective address to a Relative Virtual Address

Parameters:

effective_address – an effective address.

Returns:

the corresponding Relative Virtual Address or None if the effective address does not belong to a virtual-mapped space.

Return type:

int

Also if you don’t like typing:

r2a(rva)

shortcut for analysis.map.from_rva().

a2r(effective_address)

shortcut for analysis.map.to_rva().

File layout and regions

The analysis.map object allows you also to list all the regions of the file. A region is a contiguous memory interval which has a physical and/or a virtual address and a name. It does not have to be a 1:1 mapping to a program’s section. For instance, a PE file will feature, in addition to the PE sections, a “header” region and (maybe) an “overlay” region. For an ELF file, the regions are computed using both segments AND sections information.

You can get the list of regions from the MappingAnnotation.regions list or using other query methods from analysis.map. A region is an instance of Region which is decribed below:

class malcat.Region

A region is a contiguous memory interval which has a physical and/or a virtual address and a name.

name: str

name of region (e.g. “.text”)

address: int

effective address of the first byte of the region

size: int

size of region in the effective address space. This is the maximum size between its physical and virtual size.

__len__()
Return type:

int

Returns:

same as size

start: int

same as address

end: int

same as address + size

phys: int

file offset of first bit of region

phys_size: int

size of region on disk

virt: int

address of region in memory

virt_size: int

size of region in memory

read: bool

True iff region has read rights

write: bool

True iff region has write rights

exec: bool

True iff region has exec rights