From f2f683ebf52a32e97a20e1f63c346cfc68d75995 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 21 Feb 2024 02:49:30 +0200 Subject: [PATCH] Introduced 'as_signed' utility method for turning unsigned values into signed ones --- qiling/os/posix/syscall/mman.py | 2 +- qiling/os/posix/syscall/unistd.py | 5 ++--- qiling/os/posix/syscall/wait.py | 18 +++++++----------- qiling/os/utils.py | 21 ++++++++++++++++++++- qiling/os/windows/dlls/kernel32/fileapi.py | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/qiling/os/posix/syscall/mman.py b/qiling/os/posix/syscall/mman.py index 0adcd5871..81d53564f 100755 --- a/qiling/os/posix/syscall/mman.py +++ b/qiling/os/posix/syscall/mman.py @@ -161,7 +161,7 @@ class mmap_flags(IntFlag): label = '[mmap anonymous]' else: - fd = ql.unpacks(ql.pack(fd)) + fd = ql.os.utils.as_signed(fd, 32) if fd not in range(NR_OPEN): return -EBADF diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index babc9e0ef..62eab143c 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -266,7 +266,7 @@ def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int): def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): - offset = ql.unpacks(ql.pack(offset)) + offset = ql.os.utils.as_signed(offset, 32) f = get_opened_fd(ql.os, fd) @@ -285,8 +285,7 @@ def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, result: int, whence: int): - # treat offset as a signed value - offset = ql.unpack64s(ql.pack64((offset_high << 32) | offset_low)) + offset = ql.os.utils.as_signed((offset_high << 32) | offset_low, 64) f = get_opened_fd(ql.os, fd) diff --git a/qiling/os/posix/syscall/wait.py b/qiling/os/posix/syscall/wait.py index 51102f877..a936e3b54 100644 --- a/qiling/os/posix/syscall/wait.py +++ b/qiling/os/posix/syscall/wait.py @@ -9,19 +9,15 @@ from qiling.os.posix.const import ECHILD def ql_syscall_wait4(ql: Qiling, pid: int, wstatus: int, options: int, rusage: int): - # convert to signed (pid_t is 32bit) - pid = ql.unpack32s(ql.pack32(pid)) - # python expects options to be a signed 32bit int - options = ql.unpack32s(ql.pack32(options)) + pid = ql.os.utils.as_signed(pid, 32) + options = ql.os.utils.as_signed(options, 32) try: spid, status, _ = os.wait4(pid, options) - - if wstatus: - ql.mem.write_ptr(wstatus, status, 4) - - retval = spid except ChildProcessError: - retval = -ECHILD + return -ECHILD + + if wstatus: + ql.mem.write_ptr(wstatus, status, 4) - return retval + return spid diff --git a/qiling/os/utils.py b/qiling/os/utils.py index a9241ee6f..eaddb64da 100644 --- a/qiling/os/utils.py +++ b/qiling/os/utils.py @@ -23,6 +23,25 @@ class QlOsUtils: def __init__(self, ql: Qiling): self.ql = ql + @staticmethod + def as_signed(value: int, nbits: int) -> int: + """Transform an unsigned integer value into its 2's complement signed value + equivalent. This method has no effect on signed integers. + + Args: + value: an unsigned integer to transform + nbits: value bit size + + Returns: a signed integer + """ + + # truncate value to specified bit size + value &= (1 << nbits) - 1 + + msb = 1 << (nbits - 1) + + return -(value & ~(msb - 1)) | value + def read_string(self, address: int, encoding: str, maxlen: int = 0) -> str: """Read a null-terminated string from memory. @@ -244,4 +263,4 @@ def __update_ellipsis(self, args: Iterable[int]) -> Callable[[MutableMapping], N def __do_update(params: MutableMapping) -> None: params.update((f'{QlOsUtils.ELLIPSIS_PREF}{i}', a) for i, a in enumerate(args)) - return __do_update \ No newline at end of file + return __do_update diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index 81a41d562..1ea43e316 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -698,7 +698,7 @@ def _CreateFileMapping(ql: Qiling, address: int, params): req_size = (dwMaximumSizeHigh << 32) | dwMaximumSizeLow - if hFile == ql.unpack(ql.packs(INVALID_HANDLE_VALUE)): + if hFile == ql.os.utils.as_signed(INVALID_HANDLE_VALUE, ql.arch.bits): fmobj = FileMappingMem() else: