Change is_mapped semantics

This commit is contained in:
elicn
2022-05-12 22:19:38 +03:00
parent 7dc2e9713a
commit 6f3ccb1f2f
4 changed files with 51 additions and 15 deletions
+5 -3
View File
@@ -4,7 +4,7 @@ from abc import abstractmethod
from qiling import Qiling
from qiling.arch.x86 import QlArchIntel
from qiling.arch.x86_const import *
from qiling.exception import QlGDTError
from qiling.exception import QlGDTError, QlMemoryMappedError
from qiling.os.memory import QlMemoryManager
class GDTArray:
@@ -50,8 +50,10 @@ class GDTManager:
def __init__(self, ql: Qiling, base = QL_X86_GDT_ADDR, limit = QL_X86_GDT_LIMIT, num_entries = 16):
ql.log.debug(f'Mapping GDT at {base:#x} with limit {limit:#x}')
if not ql.mem.is_mapped(base, limit):
ql.mem.map(base, limit, info="[GDT]")
if not ql.mem.is_available(base, limit):
raise QlMemoryMappedError('cannot map GDT, memory location is taken')
ql.mem.map(base, limit, info="[GDT]")
# setup GDT by writing to GDTR
ql.arch.regs.write(UC_X86_REG_GDTR, (0, base, limit, 0x0))
+1 -1
View File
@@ -368,7 +368,7 @@ class QlLoaderELF(QlLoader):
_vsyscall_addr = int(self.profile.get('vsyscall_address'), 0)
_vsyscall_size = int(self.profile.get('vsyscall_size'), 0)
if not self.ql.mem.is_mapped(_vsyscall_addr, _vsyscall_size):
if self.ql.mem.is_available(_vsyscall_addr, _vsyscall_size):
# initialize with int3 instructions then insert syscall entry
# each syscall should be 1KiB away
self.ql.mem.map(_vsyscall_addr, _vsyscall_size, info="[vsyscall]")
+36 -6
View File
@@ -280,7 +280,7 @@ class QlMemoryManager:
self.ql.log.debug(f'restoring memory range: {lbound:#08x} {ubound:#08x} {label}')
size = ubound - lbound
if not self.is_mapped(lbound, size):
if self.is_available(lbound, size):
self.ql.log.debug(f'mapping {lbound:#08x} {ubound:#08x}, mapsize = {size:#x}')
self.map(lbound, size, perms, label)
@@ -420,9 +420,34 @@ class QlMemoryManager:
for begin, end, _ in self.ql.uc.mem_regions():
self.unmap(begin, end - begin + 1)
def __mapped_regions(self) -> Iterator[Tuple[int, int]]:
"""Iterate through all mapped memory regions, consolidating adjacent regions
together to a continuous one. Protection bits and labels are ignored.
"""
if not self.map_info:
return
iter_memmap = iter(self.map_info)
p_lbound, p_ubound, _, _, _ = next(iter_memmap)
# map_info is assumed to contain non-overlapping regions sorted by lbound
for lbound, ubound, _, _, _ in iter_memmap:
if lbound == p_ubound:
p_ubound = ubound
else:
yield (p_lbound, p_ubound)
p_lbound = lbound
p_ubound = ubound
yield (p_lbound, p_ubound)
def is_available(self, addr: int, size: int) -> bool:
"""Query whether the memory range starting at `addr` and is of length of `size` bytes
can be allocated.
is available for allocation.
Returns: True if it can be allocated, False otherwise
"""
@@ -433,16 +458,21 @@ class QlMemoryManager:
end = addr + size
# make sure neither begin nor end are enclosed within a mapped range, or entirely enclosing one
return not any((lbound <= begin < ubound) or (lbound < end <= ubound) or (begin <= lbound < ubound <= end) for lbound, ubound, _, _, _ in self.map_info)
return not any((lbound <= begin < ubound) or (lbound < end <= ubound) or (begin <= lbound < ubound <= end) for lbound, ubound in self.__mapped_regions())
def is_mapped(self, addr: int, size: int) -> bool:
"""Query whether the memory range starting at `addr` and is of length of `size` bytes
is mapped, either partially or entirely.
is fully mapped.
Returns: True if any part of the specified memory range is taken, False otherwise
Returns: True if the specified memory range is taken fully, False otherwise
"""
return not self.is_available(addr, size)
assert size > 0, 'expected a positive size value'
begin = addr
end = addr + size
return any((lbound <= begin < end <= ubound) for lbound, ubound in self.__mapped_regions())
def find_free_space(self, size: int, minaddr: int = None, maxaddr: int = None, align: int = None) -> int:
"""Locate an unallocated memory that is large enough to contain a range in size of
+9 -5
View File
@@ -13,7 +13,7 @@ from qiling.arch.x86_const import GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, FS_SEGMENT_A
from qiling.arch.x86_utils import GDTManager, SegmentManager86, SegmentManager64
from qiling.cc import intel
from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT
from qiling.exception import QlErrorSyscallError, QlErrorSyscallNotFound
from qiling.exception import QlErrorSyscallError, QlErrorSyscallNotFound, QlMemoryMappedError
from qiling.os.fcall import QlFunctionCall
from qiling.os.memory import QlMemoryHeap
from qiling.os.os import QlOs
@@ -116,11 +116,15 @@ class QlOsWindows(QlOs):
segm.setup_fs(FS_SEGMENT_ADDR, FS_SEGMENT_SIZE)
segm.setup_gs(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE)
if not self.ql.mem.is_mapped(FS_SEGMENT_ADDR, FS_SEGMENT_SIZE):
self.ql.mem.map(FS_SEGMENT_ADDR, FS_SEGMENT_SIZE, info='[FS]')
if not self.ql.mem.is_available(FS_SEGMENT_ADDR, FS_SEGMENT_SIZE):
raise QlMemoryMappedError('cannot map FS segment, memory location is taken')
if not self.ql.mem.is_mapped(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE):
self.ql.mem.map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, info='[GS]')
self.ql.mem.map(FS_SEGMENT_ADDR, FS_SEGMENT_SIZE, info='[FS]')
if not self.ql.mem.is_available(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE):
raise QlMemoryMappedError('cannot map GS segment, memory location is taken')
self.ql.mem.map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, info='[GS]')
def __setup_components(self):