Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/mem_invalid_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
def mem_crash(ql: Qiling, access: int, address: int, size: int, value: int):
print(f'got crash')

PAGE_SIZE = 0x1000
aligned = address & ~(PAGE_SIZE - 1)
PAGE_SIZE = ql.mem.pagesize
aligned = ql.mem.align(address)

# map the entire page containing the invalid address and fill it with 'Q's
ql.mem.map(aligned, PAGE_SIZE)
Expand Down
18 changes: 9 additions & 9 deletions qiling/extensions/idaplugin/qilingida.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from PyQt5.QtWidgets import (QPushButton, QHBoxLayout)

# Qiling
from qiling import *
from qiling import Qiling
from qiling.const import *
from qiling.arch.x86_const import reg_map_32 as x86_reg_map_32
from qiling.arch.x86_const import reg_map_64 as x86_reg_map_64
Expand Down Expand Up @@ -1269,7 +1269,7 @@ def ql_show_mem_view(self, addr=get_screen_ea(), size=0x10):
ok = ask_yn(1, "Memory [%X:%X] is not mapped!\nDo you want to map it?\n YES - Load Binary\n NO - Fill page with zeroes\n Cancel - Close dialog" % (mem_addr, mem_addr + mem_size))
if ok == 0:
self.qlemu.ql.mem.map(mem_addr, mem_size)
self.qlemu.ql.mem.write(self.qlemu.ql.mem.align(mem_addr), b"\x00"*mem_size)
self.qlemu.ql.mem.write(mem_addr, b"\x00"*mem_size)
elif ok == 1:
# TODO: map_binary
return
Expand Down Expand Up @@ -1568,16 +1568,16 @@ def _guide_hook(self, ql, addr, size):
self.paths[start_bb_id].append(cur_bb.id)
ql.emu_stop()

def _skip_unmapped_rw(self, ql, type, addr, size, value):
alignment = 0x1000
# Round down
map_addr = addr & (~(alignment - 1))
# Round up
map_size = ((size + (alignment - 1)) & (~(alignment - 1)))
def _skip_unmapped_rw(self, ql: Qiling, type, addr, size, value):
map_addr = ql.mem.align(addr)
map_size = ql.mem.align_up(size)

if not ql.mem.is_mapped(map_addr, map_size):
logging.warning(f"Invalid memory R/W, trying to map {hex(map_size)} at {hex(map_addr)}")

ql.mem.map(map_addr, map_size)
ql.mem.write(map_addr, b'\x00'*map_size)
ql.mem.write(map_addr, b'\x00' * map_size)

return True

def _find_branch_in_real_block(self, bb):
Expand Down
8 changes: 4 additions & 4 deletions qiling/loader/pe.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def load_dll(self, name: bytes, driver: bool = False) -> int:
data = cached.data

image_base = cached.ba
image_size = self.ql.mem.align(len(data), 0x1000)
image_size = self.ql.mem.align_up(len(data))

# verify whether we can load the dll to the same address it was loaded when it was cached.
# if not, the dll will have to be realoded in order to have its symbols relocated using the
Expand Down Expand Up @@ -126,7 +126,7 @@ def load_dll(self, name: bytes, driver: bool = False) -> int:
data = bytearray(dll.get_memory_mapped_image())

image_base = dll.OPTIONAL_HEADER.ImageBase or self.dll_last_address
image_size = self.ql.mem.align(len(data), 0x1000)
image_size = self.ql.mem.align_up(len(data))

self.ql.log.debug(f'DLL preferred base address: {image_base:#x}')

Expand Down Expand Up @@ -514,7 +514,7 @@ def load(self):
if self.path and not self.ql.code:
# for simplicity, no image base relocation
self.pe_image_address = self.pe.OPTIONAL_HEADER.ImageBase
self.pe_image_address_size = self.ql.mem.align(self.pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)
self.pe_image_address_size = self.ql.mem.align_up(self.pe.OPTIONAL_HEADER.SizeOfImage)

if self.pe_image_address + self.pe_image_address_size > self.ql.os.heap_base_address:
# pe reloc
Expand Down Expand Up @@ -599,7 +599,7 @@ def load(self):
self.ql.os.fcall.writeParams(((POINTER, self.ql.loader.driver_object_address), (POINTER, self.ql.loader.regitry_path_address)))

# mmap PE file into memory
self.ql.mem.map(self.pe_image_address, self.align(self.pe_image_address_size, 0x1000), info="[PE]")
self.ql.mem.map(self.pe_image_address, self.ql.mem.align_up(self.pe_image_address_size), info="[PE]")
self.pe.parse_data_directories()
data = bytearray(self.pe.get_memory_mapped_image())
self.ql.mem.write(self.pe_image_address, bytes(data))
Expand Down
4 changes: 2 additions & 2 deletions qiling/loader/pe_uefi.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ def map_and_load(self, path: str, exec_now: bool=False):

# use image base only if it does not point to NULL
image_base = pe.OPTIONAL_HEADER.ImageBase or self.next_image_base
image_size = ql.mem.align(pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)
image_size = ql.mem.align_up(pe.OPTIONAL_HEADER.SizeOfImage)

assert (image_base % 0x1000) == 0, 'image base is expected to be page-aligned'
assert (image_base % ql.mem.pagesize) == 0, 'image base is expected to be page-aligned'

if image_base != pe.OPTIONAL_HEADER.ImageBase:
pe.relocate_image(image_base)
Expand Down
49 changes: 37 additions & 12 deletions qiling/os/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,21 +195,45 @@ def show_mapinfo(self):
def get_lib_base(self, filename: str) -> int:
return next((s for s, _, _, info, _ in self.map_info if os.path.split(info)[1] == filename), -1)

def align(self, addr: int, alignment: int = None) -> int:
"""Round up to nearest alignment.
def align(self, value: int, alignment: int = None) -> int:
"""Align a value down to the specified alignment boundary.

Args:
addr: address to align
alignment: alignment granularity, must be a power of 2
value: a value to align
alignment: alignment boundary; must be a power of 2. if not specified
value will be aligned to page size

Returns: aligned value
"""

if alignment is None:
alignment = self.pagesize

# make sure alignment is a power of 2
assert alignment & (alignment - 1) == 0

# round down to nearest alignment
return value & ~(alignment - 1)

def align_up(self, value: int, alignment: int = None) -> int:
"""Align a value up to the specified alignment boundary.

Args:
value: value to align
alignment: alignment boundary; must be a power of 2. if not specified
value will be aligned to page size

Returns: aligned value
"""

if alignment is None:
alignment = self.pagesize

# rounds up to nearest alignment
mask = self.max_mem_addr & -alignment
# make sure alignment is a power of 2
assert alignment & (alignment - 1) == 0

return (addr + (alignment - 1)) & mask
# round up to nearest alignment
return (value + alignment - 1) & ~(alignment - 1)

def save(self):
"""Save entire memory content.
Expand Down Expand Up @@ -431,7 +455,7 @@ def find_free_space(self, size: int, minaddr: int = None, maxaddr: int = None, a
gaps = zip(gaps_lbounds, gaps_ubounds)

for lbound, ubound in gaps:
addr = self.align(lbound, align)
addr = self.align_up(lbound, align)
end = addr + size

# is aligned range within gap and satisfying min / max requirements?
Expand All @@ -457,18 +481,19 @@ def map_anywhere(self, size: int, minaddr: int = None, maxaddr: int = None, alig
if align is None:
align = self.pagesize

size = self.align_up(size)
addr = self.find_free_space(size, minaddr, maxaddr, align)

self.map(addr, self.align(size), perms, info)
self.map(addr, size, perms, info)

return addr

def protect(self, addr: int, size: int, perms):
# mask off perms bits that are not supported by unicorn
perms &= UC_PROT_ALL

aligned_address = addr & ~(self.pagesize - 1)
aligned_size = self.align((addr & (self.pagesize - 1)) + size)
aligned_address = self.align(addr)
aligned_size = self.align_up((addr & (self.pagesize - 1)) + size)

self.ql.uc.mem_protect(aligned_address, aligned_size, perms)
self.change_mapinfo(aligned_address, aligned_address + aligned_size, mem_p = perms)
Expand Down Expand Up @@ -590,7 +615,7 @@ def alloc(self, size: int) -> int:
# is new chunk going to exceed currently allocated heap space?
# in case it does, allocate additional heap space
if self.current_use + size > self.current_alloc:
real_size = self.ql.mem.align(size)
real_size = self.ql.mem.align_up(size)

# if that additional allocation is going to exceed heap upper bound, fail
if self.start_address + self.current_use + real_size > self.end_address:
Expand Down
7 changes: 4 additions & 3 deletions qiling/os/posix/syscall/mman.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,12 @@ def syscall_mmap_impl(ql: Qiling, addr: int, mlen: int, prot: int, flags: int, f

need_mmap = True
mmap_base = addr
mmap_size = (mlen - (addr & (pagesize - 1)) + pagesize - 1) & ~(pagesize - 1)
mmap_size = ql.mem.align_up(mlen - (addr & (pagesize - 1)))

if ql.ostype != QL_OS.QNX:
mmap_base &= ~(pagesize - 1)
if (flags & MAP_FIXED) > 0 and mmap_base != addr:
mmap_base = ql.mem.align(mmap_base)

if (flags & MAP_FIXED) and mmap_base != addr:
return MAP_FAILED

# initial ql.loader.mmap_address
Expand Down