Files
cea-sec-miasm/doc/locationdb/locationdb.ipynb
T

12 KiB

LocationDB object

The LocationDB is the Miasm object responsible of the symbols' management. A Location is an object representing a code or data (or anywhere else) position. As the name says, the LocationDB is a database of locations. Here are some rules:

  • each location has exactly one associated LocKey
  • a LocKey is linked to a unique LocationDB (and must not be used in another LocationDB)
  • a LocKey is very similar to primary key object in a database.
  • a LocKey can have an optional offset.
  • a LocKey can have multiple symbol names
  • two Lockeys cannot share an identical offset
  • two LocKeys cannot share a symbol name

Below are manipulations of the LocationDB

In [1]:
# Import and create a locationDB
from miasm.core.locationdb import LocationDB
loc_db = LocationDB()
print(repr(loc_db))
In [2]:
# Create a location with default attributes (no offset, no symbol name)
loc_a = loc_db.add_location()
print(loc_a)
# Create a second location with an offset
loc_b = loc_db.add_location(offset=112233)
print(loc_b)
In [3]:
# Add a location with a name
loc_c = loc_db.add_location(name="main")
# Add another alias name to this location
loc_db.add_location_name(loc_c, "_main_")
# Add another location
loc_d = loc_db.add_location()
In [4]:
# Display LocationDB
print(loc_db)
In [5]:
# Associate an offset to an existing location
loc_db.set_location_offset(loc_a, 0x5678)
print(loc_db)
In [6]:
# Remove a name from an existing location
loc_db.remove_location_name(loc_c, "_main_")
print(loc_db)
In [7]:
# Get the offset of a location
hex(loc_db.get_location_offset(loc_a))
In [8]:
# Location with no offset
print(loc_db.get_location_offset(loc_c))
None
In [9]:
# Display locations
loc_db.pretty_str(loc_a)
Out [9]:
'loc_5678'
In [10]:
loc_db.pretty_str(loc_b)
Out [10]:
'loc_1b669'
In [11]:
loc_db.pretty_str(loc_c)
Out [11]:
'main'
In [12]:
loc_db.pretty_str(loc_d)
Out [12]:
'loc_key_3'

Note that:

  • if a location doesn't have an offset neither a name, its pretty form is loc_key_XXX
  • if a location has an offset but no name, its pretty form is loc_OFFSET
  • if a location has a name, its pretty form is name

Locations usage in Miasm

The locations are used everywhere in miasm. For example, let disassemble a simple shellcode:

In [13]:
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine

# Create a LocationDB
loc_db = LocationDB()

# Create a container of bytes
cont = Container.from_string(
    b"\x83\xf8\x10\x74\x07\x89\xc6\x0f\x47\xc3\xeb\x08\x89\xc8\xe8\x31\x33\x22\x11\x40\xc3",
    loc_db
)

# Instantiate a x86 32 bit architecture
machine = Machine("x86_32")

# Instantiate a disassembler engine, using the previous bin_stream and its
# associated location DB.
mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)

# Run a recursive traversal disassembling from address 0
asmcfg = mdis.dis_multiblock(0)

# Display each basic blocks
for block in asmcfg.blocks:
    print(block)
loc_0
CMP        EAX, 0x10
JZ         loc_c
->	c_next:loc_5 	c_to:loc_c 
loc_c
MOV        EAX, ECX
CALL       loc_11223344
->	c_next:loc_13 
loc_5
MOV        ESI, EAX
CMOVA      EAX, EBX
JMP        loc_14
->	c_to:loc_14 
loc_13
INC        EAX
->	c_next:loc_14 
loc_14
RET        
In [14]:
block = asmcfg.getby_offset(0)
print(block)
loc_0
CMP        EAX, 0x10
JZ         loc_c
->	c_next:loc_5 	c_to:loc_c 
In [15]:
# The basic block is placed at a location, which can be retrieved using `.loc_key`
print(block.loc_key)
loc_key_0
In [16]:
# We can add a name to this first location
loc_db.add_location_name(block.loc_key, "entry")
print(loc_db)
loc_key_0: 0x0 - entry
loc_key_1: 0xc - 
loc_key_2: 0x5 - 
loc_key_3: 0x11223344 - 
loc_key_4: 0x13 - 
loc_key_5: 0x14 - 
In [17]:
# And we can re-display the block:
print(block)
entry
CMP        EAX, 0x10
JZ         loc_c
->	c_next:loc_5 	c_to:loc_c 
In [18]:
# We will give an arbitrary name to location at offset 0xC
loc_c = loc_db.get_offset_location(0xc)
loc_db.add_location_name(loc_c, "quiche")
print(block)
entry
CMP        EAX, 0x10
JZ         quiche
->	c_next:loc_5 	c_to:quiche 

Those locations are also used in intermediate representation:

In [19]:
# Get a lifter
lifter = machine.lifter_model_call(loc_db)
In [20]:
# Get the intermediate representation of the asmcfg
ircfg = lifter.new_ircfg_from_asmcfg(asmcfg)
In [21]:
# Get location at 0
loc_entry = loc_db.get_offset_location(0)
# Get irblock at this location
irblock = ircfg.blocks[loc_entry]
# Display IRBlock
print(irblock)
b'entry':

zf = FLAG_EQ_CMP(EAX, 0x10)

nf = FLAG_SIGN_SUB(EAX, 0x10)

pf = parity((EAX + -0x10) & 0xFF)

cf = FLAG_SUB_CF(EAX, 0x10)

of = FLAG_SUB_OF(EAX, 0x10)

af = ((EAX ^ 0x10) ^ (EAX + -0x10))[4:5]

EIP = CC_EQ(zf)?(b'quiche',loc_5)

IRDst = CC_EQ(zf)?(b'quiche',loc_5)

In miasm, each expression embeds its size. The location doesn't have a size. To use a location in IR code, you have to wrap it in the Miasm word ExprLoc

In [22]:
# Get the irblock destination (IRDst value)
dst = irblock.dst
print(dst)
CC_EQ(zf)?(loc_key_1,loc_key_2)
In [23]:
print(repr(dst))
ExprCond(ExprOp('CC_EQ', ExprId('zf', 1)), ExprLoc(<LocKey 1>, 32), ExprLoc(<LocKey 2>, 32))
In [24]:
# It's an ExprCond. We retrieve here the possible values
src1, src2 = dst.src1, dst.src2
print(repr(src1), repr(src2))
ExprLoc(<LocKey 1>, 32) ExprLoc(<LocKey 2>, 32)
In [25]:
# Retrieve the location of the ExprLoc
loc = src1.loc_key
print(loc)
loc_key_1