From 38b1baa98cf6ceb9ee15f00c93f3cd754435b989 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Wed, 7 Oct 2026 16:39:15 +0100 Subject: [PATCH] Migrate API handlers to ctx.args Handlers set the report display of an argument through ctx.args, by parameter name where the signature is usable on x86 and x64 and by slot index otherwise. argv holds the raw slots, and the transitional copy of argv writes in handle_import_func is gone. Variadic handlers use ctx.args.clear() and append(); delegating handlers pass ctx, so the inner handler's displays apply to the outer call. The display setter ignores values that are not strings, such as None from a failed constant lookup or the raw pointer of a NULL string argument. API hooks get raw argv. WindowsEmulator.get_api_args() returns the arguments of the hooked call as the report shows them, and the emu_dll and dbgview examples use it. --- doc/api-handlers.md | 2 +- doc/library.md | 11 + examples/dbgview.py | 4 +- examples/emu_dll.py | 3 +- speakeasy/windows/winemu.py | 43 ++-- speakeasy/winenv/api/api.py | 8 +- speakeasy/winenv/api/kernelmode/ndis.py | 6 +- speakeasy/winenv/api/kernelmode/netio.py | 2 +- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 157 +++++++------ speakeasy/winenv/api/kernelmode/wdfldr.py | 6 +- speakeasy/winenv/api/usermode/advapi32.py | 108 ++++----- speakeasy/winenv/api/usermode/bcrypt.py | 24 +- speakeasy/winenv/api/usermode/com_api.py | 6 +- speakeasy/winenv/api/usermode/crypt32.py | 2 +- speakeasy/winenv/api/usermode/dnsapi.py | 2 +- speakeasy/winenv/api/usermode/kernel32.py | 232 +++++++++++--------- speakeasy/winenv/api/usermode/mpr.py | 8 +- speakeasy/winenv/api/usermode/msvcrt.py | 149 +++++++------ speakeasy/winenv/api/usermode/ncrypt.py | 22 +- speakeasy/winenv/api/usermode/netapi32.py | 8 +- speakeasy/winenv/api/usermode/ntdll.py | 8 +- speakeasy/winenv/api/usermode/ole32.py | 10 +- speakeasy/winenv/api/usermode/oleaut32.py | 8 +- speakeasy/winenv/api/usermode/secur32.py | 6 +- speakeasy/winenv/api/usermode/shell32.py | 12 +- speakeasy/winenv/api/usermode/shlwapi.py | 38 ++-- speakeasy/winenv/api/usermode/urlmon.py | 9 +- speakeasy/winenv/api/usermode/user32.py | 42 ++-- speakeasy/winenv/api/usermode/winhttp.py | 37 ++-- speakeasy/winenv/api/usermode/wininet.py | 38 ++-- speakeasy/winenv/api/usermode/wkscli.py | 6 +- speakeasy/winenv/api/usermode/ws2_32.py | 40 ++-- tests/test_handler_args.py | 11 + 33 files changed, 542 insertions(+), 526 deletions(-) diff --git a/doc/api-handlers.md b/doc/api-handlers.md index 560a0c7..4c4c0de 100644 --- a/doc/api-handlers.md +++ b/doc/api-handlers.md @@ -30,7 +30,7 @@ def HeapAlloc(self, emu, argv, ctx: api.ApiContext = api.NO_CONTEXT): Imports that have no `@apihook` are not necessarily fatal. Speakeasy ships a signature database generated from Microsoft's [win32metadata](https://github.com/microsoft/win32metadata) (via the [win32json](https://github.com/marlersoft/win32json) export, vendored as the `deps/win32json` submodule). When an import misses every handler, `Win32Emulator.handle_import_func` looks the function up there and, if it is declared, emulates the call from its prototype: it reads the right number of argument slots, decodes `PSTR`/`PWSTR`/`BOOL` arguments for the trace, renders enum and flag parameters symbolically (`dwCreationDisposition: CREATE_ALWAYS`, `dwShareMode: FILE_SHARE_WRITE|FILE_SHARE_READ`), expands pointers to known structs into a JSON-like rendering with typed fields (`lpSecurityAttributes: {nLength: 0xc, lpSecurityDescriptor: 0x0, bInheritHandle: TRUE}`, following nested pointers one level so `OBJECT_ATTRIBUTES.ObjectName` shows its string), zero-fills `Out` buffers whose size the prototype declares, returns a type-appropriate success value, and cleans up the stack according to the calling convention. Each argument in the event of such a call has the parameter name, its type, the raw value, and the rendering (see [reporting](reporting.md)). -Calls served by a handler use the same signature to name and render their arguments when its slot count equals the handler's `argc`. The arguments are rendered before the handler runs. `ctx.args` gives the handler one entry per parameter, by name (`ctx.args["hKey"]`) or by parameter index. A handler that sets `display` replaces the rendering of that parameter. The type of the argument becomes `str` if the parameter is declared as a string, and `text` otherwise. A display for a parameter that the signature renders as an enum or flags does not replace that rendering, so all such values have one format. +Calls served by a handler use the same signature to name and render their arguments when its slot count equals the handler's `argc`. The arguments are rendered before the handler runs. `ctx.args` gives the handler one entry per parameter, by name (`ctx.args["hKey"]`) or by parameter index. A handler that sets `display` replaces the rendering of that parameter. The type of the argument becomes `str` if the parameter is declared as a string, and `text` otherwise. A display for a parameter that the signature renders as an enum or flags does not replace that rendering, so all such values have one format. A value that is not a string, such as `None` from a failed lookup or a NULL pointer the handler did not decode, keeps the current display. Handlers without a matching signature (the C runtime, kernel-mode APIs, COM methods) record one unnamed argument per slot. These handlers use the slot index (`ctx.args[0]`), because a name finds no argument. A name or index that matches no argument gives a detached entry, and its changes are not recorded. Variadic handlers add entries with `ctx.args.append(text)` and remove all entries with `ctx.args.clear()`. `tests/test_handler_arg_access.py` checks that each name a handler uses is a parameter of every signature of that function, and that each index means the same parameter on x86 and x64. diff --git a/doc/library.md b/doc/library.md index f1c64af..91b7492 100644 --- a/doc/library.md +++ b/doc/library.md @@ -38,6 +38,17 @@ se.shutdown() - pass `volumes=` to mount host paths into emulated filesystem - pass `gdb_port=` to block for GDB attach before execution; `gdb_host=` controls the bind address and defaults to `127.0.0.1` +## API hooks + +`se.add_api_hook(cb, "user32", "MessageBox*")` calls `cb(emu, api_name, func, params)` in place of the handler. `params` holds the raw argument slots, and `func(params)` runs the handler. After that call, `emu.get_api_args()` returns the arguments as the report shows them, with the values the handler decoded: + +```python +def hook_messagebox(emu, api_name, func, params): + rv = func(params) + print(emu.get_api_args()[1].display) # the lpText string + return rv +``` + For runnable scripts, see [../examples](../examples/). ## Related docs diff --git a/examples/dbgview.py b/examples/dbgview.py index 24a74fc..a6094e5 100644 --- a/examples/dbgview.py +++ b/examples/dbgview.py @@ -15,7 +15,7 @@ class DbgView(speakeasy.Speakeasy): # Call the DbgPrint* function and print the formatted string to the console rv = func(params) - formatted_str = params[0] + formatted_str = emu.get_api_args()[-1].display print(formatted_str) return rv @@ -24,7 +24,7 @@ class DbgView(speakeasy.Speakeasy): # Call the DbgPrintEx function and print the formatted string to the console rv = func(params) - formatted_str = params[2] + formatted_str = emu.get_api_args()[-1].display print(formatted_str) return rv diff --git a/examples/emu_dll.py b/examples/emu_dll.py index 7e600ba..7c9009a 100644 --- a/examples/emu_dll.py +++ b/examples/emu_dll.py @@ -18,7 +18,8 @@ def hook_messagebox(emu, api_name, func, params): # Call the MessageBox function and print its text string data rv = func(params) - hWnd, lpText, lpCaption, uType = params + # params holds the raw arguments; the handler's decoded values are in get_api_args() + lpText = emu.get_api_args()[1].display msg = f"{api_name} text: {lpText}" logger.info(msg) diff --git a/speakeasy/windows/winemu.py b/speakeasy/windows/winemu.py index 2a6cda9..21619df 100644 --- a/speakeasy/windows/winemu.py +++ b/speakeasy/windows/winemu.py @@ -32,7 +32,7 @@ from speakeasy.windows.netman import NetworkManager from speakeasy.windows.objman import HandleAllocator from speakeasy.windows.regman import RegistryManager from speakeasy.winenv.api import sigdb, sigfmt -from speakeasy.winenv.api.api import ApiContext, HandlerArgs +from speakeasy.winenv.api.api import NO_CONTEXT, ApiContext, HandlerArgs # When disassembling, a minimum instruction size needs to be supplied # This number is arbitrary and just needs to be large enough to cover @@ -115,6 +115,7 @@ class WindowsEmulator(BinaryEmulator): self._setup_done: bool = False self.bootstrap_phase: BootstrapPhase = BootstrapPhase.INITIALIZED self.curr_run: Run | None = None + self.api_ctx: ApiContext = NO_CONTEXT self.restart_curr_run: bool = False self._stop_on_faults: bool = False self._pending_fault_stop: StopReason | None = None @@ -1964,27 +1965,15 @@ class WindowsEmulator(BinaryEmulator): self.enable_code_hook() return rv - def _apply_argv_writes(self, ctx: ApiContext, sig: sigdb.FuncSig | None, before: list[int], after: list) -> None: - """Show the values that a handler wrote into argv in place of the rendering of their arguments.""" - if sig is not None and len(before) == len(after): - pos = 0 - for index, count in enumerate(sig.slot_layout(self.get_ptr_size())): - changed = [after[i] for i in range(pos, pos + count) if after[i] != before[i]] - pos += count - if changed: - arg = ctx.args[index] - if isinstance(changed[0], int): - arg.display, arg.type = hex(changed[0]), arg.type - else: - arg.display = str(changed[0]) - return - if sig is not None: - ctx.args = HandlerArgs.from_slots(before) - for i, slot in enumerate(after): - if i >= len(before): - ctx.args.append(hex(slot) if isinstance(slot, int) else str(slot)) - elif slot != before[i]: - ctx.args[i].display = hex(slot) if isinstance(slot, int) else str(slot) + def get_api_args(self) -> list[ApiArg]: + """ + Get the arguments of the hooked API call in progress, as the report shows them. + + An API hook calls this after it calls the original handler to see the + values the handler decoded, such as the strings behind pointer arguments. + Outside an API hook the list is empty. + """ + return self.api_ctx.args.get_report_args() def handle_import_func(self, dll, name): """ @@ -2016,7 +2005,6 @@ class WindowsEmulator(BinaryEmulator): else: args = HandlerArgs.from_slots(argv) ctx = ApiContext(func_name=imp_api, args=args) - raw_argv = list(argv) self.hammer.handle_import_func(imp_api, conv, argc) hooks = self.get_api_hooks(dll, name) @@ -2027,8 +2015,12 @@ class WindowsEmulator(BinaryEmulator): orig = lambda args: hooked_func(self, args, ctx) # noqa # Hooks execute in FIFO order (first registered, first called). # All hooks run; the last hook's return value is used. - for hook in hooks: - rv = hook.cb(self, imp_api, orig, argv) + prev_ctx, self.api_ctx = self.api_ctx, ctx + try: + for hook in hooks: + rv = hook.cb(self, imp_api, orig, argv) + finally: + self.api_ctx = prev_ctx else: try: rv = self.api.call_api_func(mod, func, argv, ctx=ctx) # type: ignore[union-attr] @@ -2048,7 +2040,6 @@ class WindowsEmulator(BinaryEmulator): self._fire_dyn_code_hooks(ret) # Log the API args and return value - self._apply_argv_writes(ctx, sig, raw_argv, argv) self.log_api(call_pc, imp_api, rv, ctx.args.get_report_args()) if not self.run_complete and ret == oret and pc == opc: diff --git a/speakeasy/winenv/api/api.py b/speakeasy/winenv/api/api.py index 64c6a5c..ebd6a2e 100644 --- a/speakeasy/winenv/api/api.py +++ b/speakeasy/winenv/api/api.py @@ -48,14 +48,16 @@ class HandlerArg: return self._arg.display @display.setter - def display(self, text: str) -> None: + def display(self, text: object) -> None: """ Show ``text`` for this argument. The type becomes ``str`` on a parameter declared as a string, and ``text`` otherwise. A parameter that the signature renders as an enum or flags keeps that rendering, - so all such values have one format. + so all such values have one format. A value that is not a string, + such as ``None`` from a failed lookup or a NULL pointer the handler + did not decode, keeps the current display. """ - if self._param is not None and self._arg.type in ("enum", "flags"): + if not isinstance(text, str) or (self._param is not None and self._arg.type in ("enum", "flags")): return self._arg.display = text self._arg.type = "str" if self._param is not None and self._param.kind in sigdb.STRING_KINDS else "text" diff --git a/speakeasy/winenv/api/kernelmode/ndis.py b/speakeasy/winenv/api/kernelmode/ndis.py index 4b432f4..9ae0fc2 100644 --- a/speakeasy/winenv/api/kernelmode/ndis.py +++ b/speakeasy/winenv/api/kernelmode/ndis.py @@ -85,7 +85,7 @@ class Ndis(api.ApiHandler): fn = self.read_unicode_string(NdisRoutineName) addr = emu.get_proc("ndis", fn) - argv[0] = fn + ctx.args[0].display = fn return addr @apihook("NdisMRegisterMiniportDriver", argc=5) @@ -224,7 +224,7 @@ class Ndis(api.ApiHandler): ptr = 0 stag = self.convert_pool_tag(tag) - argv[1] = stag + ctx.args[1].display = stag go = self.ndis.NDIS_GENERIC_OBJECT(emu.get_ptr_size()) go.DriverObject = drv @@ -249,7 +249,7 @@ class Ndis(api.ApiHandler): rv = ddk.STATUS_SUCCESS stag = self.convert_pool_tag(tag) - argv[2] = stag + ctx.args[2].display = stag ptr = self.mem_alloc(size=size, tag=f"api.ndis_pool.{stag}") self.mem_write(va, ptr.to_bytes(emu.get_ptr_size(), "little")) diff --git a/speakeasy/winenv/api/kernelmode/netio.py b/speakeasy/winenv/api/kernelmode/netio.py index 753d176..f7eff8a 100644 --- a/speakeasy/winenv/api/kernelmode/netio.py +++ b/speakeasy/winenv/api/kernelmode/netio.py @@ -320,7 +320,7 @@ class Netio(api.ApiHandler): raddr = inet_ntoa(sock_addr.sin_addr.to_bytes(4, "little")) rport = ntohs(sock_addr.sin_port) - argv[1] = f"{raddr}:{rport}" + ctx.args[1].display = f"{raddr}:{rport}" return rv diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index f90d6ad..19ead3c 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -137,8 +137,8 @@ class Ntoskrnl(api.ApiHandler): _argv = emu.get_func_argv(_arch.CALL_CONV_CDECL, 1 + fmt_cnt)[1:] fin = self.do_str_format(fmt_str, _argv) - argv.clear() - argv.append(fin) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @@ -162,10 +162,10 @@ class Ntoskrnl(api.ApiHandler): fin = self.do_str_format(fmt_str, _argv) - argv.clear() - argv.append(cid) - argv.append(level) - argv.append(fin) + ctx.args.clear() + ctx.args.append(hex(cid)) + ctx.args.append(hex(level)) + ctx.args.append(fin) return len(fin) @@ -192,8 +192,8 @@ class Ntoskrnl(api.ApiHandler): rv = len(fin) self.mem_write(buffer, fin.encode("utf-8")) - argv[0] = fin.replace("\x00", "") - argv[1] = fmt_str + ctx.args[0].display = fin.replace("\x00", "") + ctx.args[1].display = fmt_str return rv @@ -241,7 +241,7 @@ class Ntoskrnl(api.ApiHandler): data = self.get_bytes(us) self.mem_write(dest, data) - argv[1] = ansi_str + ctx.args["SourceString"].display = ansi_str return nts @@ -266,7 +266,7 @@ class Ntoskrnl(api.ApiHandler): data = self.get_bytes(ansi) self.mem_write(dest, data) - argv[1] = ansi_str + ctx.args["SourceString"].display = ansi_str @apihook("RtlInitUnicodeString", argc=2) def RtlInitUnicodeString(self, emu, argv, ctx: api.ApiContext = api.NO_CONTEXT): @@ -294,7 +294,7 @@ class Ntoskrnl(api.ApiHandler): data = self.get_bytes(us) self.mem_write(dest, data) - argv[1] = uni_str + ctx.args["SourceString"].display = uni_str @apihook("RtlFreeUnicodeString", argc=1) def RtlFreeUnicodeString(self, emu, argv, ctx: api.ApiContext = api.NO_CONTEXT): @@ -306,7 +306,7 @@ class Ntoskrnl(api.ApiHandler): (UnicodeString,) = argv us_str = self.read_unicode_string(UnicodeString) - argv[0] = us_str + ctx.args["UnicodeString"].display = us_str us = self.win.UNICODE_STRING(emu.get_ptr_size()) us = self.mem_cast(us, UnicodeString) @@ -327,9 +327,9 @@ class Ntoskrnl(api.ApiHandler): if Tag: try: Tag = Tag.to_bytes(4, "little").decode("utf-8") + ctx.args[2].display = Tag except Exception as e: logger.exception(str(e)) - argv[2] = Tag chunk = self.pool_alloc(PoolType, NumberOfBytes, Tag) return chunk @@ -347,9 +347,9 @@ class Ntoskrnl(api.ApiHandler): if Tag: try: Tag = Tag.to_bytes(4, "little").decode("utf-8") + ctx.args[1].display = Tag except Exception as e: logger.exception(str(e)) - argv[1] = Tag self.mem_free(P) @apihook("ExAllocatePool", argc=2) @@ -379,9 +379,9 @@ class Ntoskrnl(api.ApiHandler): if Tag: try: Tag = Tag.to_bytes(4, "little").decode("utf-8") + ctx.args[2].display = Tag except Exception as e: logger.exception(str(e)) - argv[2] = Tag if not Size: return 0 @@ -445,6 +445,7 @@ class Ntoskrnl(api.ApiHandler): if name: name = self.read_unicode_string(name).replace("\x00", "") + ctx.args[2].display = name driver_obj = self.get_object_from_addr(drv) if not driver_obj: @@ -454,7 +455,6 @@ class Ntoskrnl(api.ApiHandler): self.mem_write(out_addr, dev.address.to_bytes(self.get_ptr_size(), byteorder="little")) - argv[2] = name return nts @apihook("IoCreateDeviceSecure", argc=9) @@ -478,6 +478,7 @@ class Ntoskrnl(api.ApiHandler): if name: name = self.read_unicode_string(name).replace("\x00", "") + ctx.args[2].display = name driver_obj = self.get_object_from_addr(drv) @@ -485,7 +486,6 @@ class Ntoskrnl(api.ApiHandler): self.mem_write(out_addr, dev.address.to_bytes(self.get_ptr_size(), byteorder="little")) - argv[2] = name return nts @apihook("IoCreateSymbolicLink", argc=2) @@ -502,8 +502,8 @@ class Ntoskrnl(api.ApiHandler): emu.add_symlink(link_name, dev_name) nts = ddk.STATUS_SUCCESS - argv[0] = link_name - argv[1] = dev_name + ctx.args[0].display = link_name + ctx.args[1].display = dev_name return nts @@ -517,7 +517,7 @@ class Ntoskrnl(api.ApiHandler): """ pIrp, boost = argv - argv[1] = 0xFF & argv[1] + ctx.args[1].display = hex(0xFF & boost) return @apihook("IoDeleteSymbolicLink", argc=1) @@ -531,7 +531,7 @@ class Ntoskrnl(api.ApiHandler): SymbolicLinkName = argv[0] link_name = self.read_unicode_string(SymbolicLinkName).replace("\x00", "") - argv[0] = link_name + ctx.args[0].display = link_name return nts @apihook("KeInitializeMutex", argc=2) @@ -720,7 +720,7 @@ class Ntoskrnl(api.ApiHandler): ws = self.read_wide_string(src) self.write_wide_string(ws, dest) - argv[1] = ws + ctx.args[1].display = ws return len(ws) @@ -737,7 +737,7 @@ class Ntoskrnl(api.ApiHandler): ws = self.read_wide_string(src) self.write_wide_string(ws, dest) - argv[1] = ws + ctx.args[1].display = ws return len(ws) @apihook("RtlMoveMemory", argc=3) @@ -801,8 +801,8 @@ class Ntoskrnl(api.ApiHandler): fin = self.do_str_format(fmt_str, _argv) self.write_string(fin, buf) - argv.clear() - argv.append(fin) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @apihook("_snprintf", argc=_arch.VAR_ARGS, conv=_arch.CALL_CONV_CDECL) @@ -826,8 +826,8 @@ class Ntoskrnl(api.ApiHandler): fin = self.do_str_format(fmt_str, _argv) self.write_string(fin, buf) - argv.clear() - argv.append(fin) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @apihook("wcslen", argc=1, conv=_arch.CALL_CONV_CDECL) @@ -841,7 +841,7 @@ class Ntoskrnl(api.ApiHandler): string = argv[0] ws = self.read_wide_string(string) if isinstance(ws, str): - argv[0] = ws + ctx.args[0].display = ws slen = len(ws) else: slen = int(len(ws) / 2) @@ -867,8 +867,8 @@ class Ntoskrnl(api.ApiHandler): else: rv = wstr + offset - argv[0] = ws - argv[1] = needle.decode("utf-16le") + ctx.args[0].display = ws + ctx.args[1].display = needle.decode("utf-16le") return rv @@ -891,8 +891,8 @@ class Ntoskrnl(api.ApiHandler): new = (dws + sws).encode("utf-16le") self.mem_write(dest, new) - argv[0] = dws - argv[1] = sws + ctx.args[0].display = dws + ctx.args[1].display = sws return dest @apihook("strrchr", argc=2, conv=_arch.CALL_CONV_CDECL) @@ -914,8 +914,8 @@ class Ntoskrnl(api.ApiHandler): else: rv = cstr + offset - argv[0] = cs - argv[1] = needle.decode("utf-8") + ctx.args[0].display = cs + ctx.args[1].display = needle.decode("utf-8") return rv @@ -938,8 +938,8 @@ class Ntoskrnl(api.ApiHandler): else: rv = cstr + offset - argv[0] = cs - argv[1] = needle.decode("utf-8") + ctx.args[0].display = cs + ctx.args[1].display = needle.decode("utf-8") return rv @@ -958,8 +958,8 @@ class Ntoskrnl(api.ApiHandler): ws1 = self.read_wide_string(string1, max_chars=count) ws2 = self.read_wide_string(string2, max_chars=count) - argv[0] = ws1 - argv[1] = ws2 + ctx.args[0].display = ws1 + ctx.args[1].display = ws2 if ws1.lower() == ws2.lower(): rv = 0 @@ -983,8 +983,8 @@ class Ntoskrnl(api.ApiHandler): cs1 = self.read_string(string1) cs2 = self.read_string(string2) - argv[0] = cs1 - argv[1] = cs2 + ctx.args[0].display = cs1 + ctx.args[1].display = cs2 if cs1.lower() == cs2.lower(): rv = 0 @@ -1005,8 +1005,8 @@ class Ntoskrnl(api.ApiHandler): ws1 = self.read_wide_string(string1) ws2 = self.read_wide_string(string2) - argv[0] = ws1 - argv[1] = ws2 + ctx.args[0].display = ws1 + ctx.args[1].display = ws2 if ws1.lower() == ws2.lower(): rv = 0 @@ -1071,7 +1071,7 @@ class Ntoskrnl(api.ApiHandler): to_copy = src.Length data = self.mem_read(src.Buffer, to_copy) - argv[1] = data.decode("utf-16le") + ctx.args["SourceString"].display = data.decode("utf-16le") self.mem_write(dest.Buffer, data) self.mem_write(dest_str, self.get_bytes(dest)) @@ -1100,8 +1100,8 @@ class Ntoskrnl(api.ApiHandler): else: rv = s1 == s2 - argv[0] = s1 - argv[1] = s2 + ctx.args["String1"].display = s1 + ctx.args["String2"].display = s2 return int(rv) @apihook("IoAllocateIrp", argc=2) @@ -1119,7 +1119,7 @@ class Ntoskrnl(api.ApiHandler): irp = emu.new_irp() rv = irp.address - argv[0] = StackSize + ctx.args[0].display = hex(StackSize) return rv @@ -1229,7 +1229,7 @@ class Ntoskrnl(api.ApiHandler): if EventHandle: self.mem_write(EventHandle, hnd.to_bytes(4, "little")) - argv[0] = name + ctx.args[0].display = name return evt.address @apihook("KeInitializeEvent", argc=3) @@ -1387,11 +1387,11 @@ class Ntoskrnl(api.ApiHandler): if base: addr = self.mem_read(base, emu.get_ptr_size()) addr = int.from_bytes(addr, "little") - argv[1] = addr + ctx.args["BaseAddress"].display = hex(addr) if byte_len: size = self.mem_read(byte_len, emu.get_ptr_size()) size = int.from_bytes(size, "little") - argv[2] = size + ctx.args["RegionSize"].display = hex(size) rv = ddk.STATUS_SUCCESS return rv @@ -1414,8 +1414,7 @@ class Ntoskrnl(api.ApiHandler): else: obj = self.get_object_from_handle(hProcess) - proc_path = obj.path - argv[0] = proc_path + ctx.args["ProcessHandle"].display = obj.path data = b"" if lpBuffer and lpBaseAddress: @@ -1630,7 +1629,7 @@ class Ntoskrnl(api.ApiHandler): else: name = self.read_unicode_string(ObjectName) name = name.replace("\x00", "") - argv[0] = name + ctx.args[0].display = name obj = self.get_object_from_name(name) if not obj: @@ -1659,7 +1658,7 @@ class Ntoskrnl(api.ApiHandler): rv = ddk.STATUS_INVALID_PARAMETER s1 = self.read_unicode_string(ObjectName).replace("\x00", "") - argv[0] = s1 + ctx.args[0].display = s1 obj = self.get_object_from_name(s1) if obj: @@ -1732,7 +1731,7 @@ class Ntoskrnl(api.ApiHandler): fn = self.read_unicode_string(SystemRoutineName) addr = emu.get_proc("ntoskrnl", fn) - argv[0] = fn + ctx.args[0].display = fn return addr @apihook("KeQuerySystemTime", argc=1) @@ -1835,7 +1834,7 @@ class Ntoskrnl(api.ApiHandler): guid = self.mem_read(ProviderId, 16) guid = uuid.UUID(bytes_le=guid) - argv[0] = str(guid) + ctx.args[0].display = str(guid) return rv @@ -1852,7 +1851,7 @@ class Ntoskrnl(api.ApiHandler): Base, MappedAsImage, DirectoryEntry, Size = argv MappedAsImage &= 0xFF - argv[1] = MappedAsImage + ctx.args["MappedAsImage"].display = hex(MappedAsImage) rv = 0 @@ -1884,7 +1883,7 @@ class Ntoskrnl(api.ApiHandler): self.mem_write(EventHandle, hnd.to_bytes(self.ptr_size, "little")) rv = ddk.STATUS_SUCCESS - argv[2] = name + ctx.args["ObjectAttributes"].display = name return rv @apihook("ZwCreateEvent", argc=5) @@ -1909,8 +1908,8 @@ class Ntoskrnl(api.ApiHandler): self.mem_write(EventHandle, hnd.to_bytes(self.ptr_size, "little")) rv = ddk.STATUS_SUCCESS - argv[2] = name - argv[4] = 0xFF & state + ctx.args["ObjectAttributes"].display = name + ctx.args["InitialState"].display = hex(0xFF & state) return rv @@ -2316,8 +2315,6 @@ class Ntoskrnl(api.ApiHandler): self.write_wide_string(fin, buf) - argv = [buf, cnt, fmt] + argv - argv[2] = fmt_str return len(fin) @apihook("ObReferenceObjectByHandle", argc=6) @@ -2469,7 +2466,7 @@ class Ntoskrnl(api.ApiHandler): src, num_elements = argv ws = self.read_wide_string(src) - argv[0] = ws + ctx.args[0].display = ws return len(ws) @@ -2690,7 +2687,7 @@ class Ntoskrnl(api.ApiHandler): rv = 0 mb = self.read_string(mbstr) - argv[1] = mb + ctx.args[1].display = mb wide = mb.encode("utf-16le") if not wcstr: rv = len(mb) @@ -2716,7 +2713,7 @@ class Ntoskrnl(api.ApiHandler): oa = self.mem_cast(oa, objattr) name = self.read_unicode_string(oa.ObjectName) - argv[2] = name + ctx.args["ObjectAttributes"].display = name hnd = self.reg_open_key(name, create=False) if not hnd: @@ -2746,7 +2743,7 @@ class Ntoskrnl(api.ApiHandler): if val: name = self.read_unicode_string(val) - argv[1] = name + ctx.args["ValueName"].display = name key = self.reg_get_key(hnd) if key: @@ -2807,14 +2804,14 @@ class Ntoskrnl(api.ApiHandler): create_disp = 0xFFFFFFFF & create_disp - argv[3] = name + ctx.args["IoStatusBlock"].display = name cd = ddk.get_create_disposition(create_disp) if cd: - argv[7] = cd + ctx.args["CreateDisposition"].display = cd ad = ddk.get_file_access_defines(access) if ad: - argv[1] = " | ".join(ad) + ctx.args["DesiredAccess"].display = " | ".join(ad) npath = name if name.startswith("\\??\\"): @@ -2883,10 +2880,10 @@ class Ntoskrnl(api.ApiHandler): oa = self.mem_cast(oa, objattr) path = self.read_unicode_string(oa.ObjectName) - argv[3] = path + ctx.args["IoStatusBlock"].display = path ad = ddk.get_file_access_defines(access) if ad: - argv[1] = " | ".join(ad) + ctx.args["DesiredAccess"].display = " | ".join(ad) obj = self.get_object_from_name(path) if obj: @@ -2986,7 +2983,7 @@ class Ntoskrnl(api.ApiHandler): } path_str = self.read_wide_string(Path) - argv[1] = path_str + ctx.args["Path"].display = path_str return rv @@ -3013,7 +3010,7 @@ class Ntoskrnl(api.ApiHandler): if _file and buf and length: path = _file.path - argv[0] = path + ctx.args["FileHandle"].display = path data = self.mem_read(buf, length) if data: @@ -3026,7 +3023,7 @@ class Ntoskrnl(api.ApiHandler): data = data.decode("utf-8") except UnicodeDecodeError: data = data.hex() - argv[6] = data[:0x10] + ctx.args["Length"].display = data[:0x10] nts = ddk.STATUS_SUCCESS return nts @@ -3053,7 +3050,7 @@ class Ntoskrnl(api.ApiHandler): if _file and buf: path = _file.path - argv[0] = path + ctx.args["FileHandle"].display = path data = _file.get_data() @@ -3115,7 +3112,7 @@ class Ntoskrnl(api.ApiHandler): oa = self.mem_cast(oa, ObjectAttributes) if oa.ObjectName: name = self.read_unicode_string(oa.ObjectName) - argv[2] = name + ctx.args["ObjectAttributes"].display = name size = 0 if MaximumSize: @@ -3123,7 +3120,7 @@ class Ntoskrnl(api.ApiHandler): size = int.from_bytes(size, "little") hmap = fm.file_create_mapping(FileHandle, name, size, SectionPageProtection) self.mem_write(SectionHandle, hmap.to_bytes(self.get_ptr_size(), byteorder="little")) - argv[0] = hmap + ctx.args["SectionHandle"].display = hex(hmap) return ddk.STATUS_SUCCESS @@ -3210,8 +3207,8 @@ class Ntoskrnl(api.ApiHandler): self.mem_write(buf, data) if ViewSize: self.mem_write(ViewSize, size.to_bytes(self.get_ptr_size(), "little")) - argv[2] = buf - argv[6] = size + ctx.args["BaseAddress"].display = hex(buf) + ctx.args["ViewSize"].display = hex(size) elif not pref_address: if bytes_to_map == 0: bytes_to_map = sect.size @@ -3221,8 +3218,8 @@ class Ntoskrnl(api.ApiHandler): mm.tag = f"{tag_prefix}.0x{buf:x}" if ViewSize: self.mem_write(ViewSize, size.to_bytes(self.get_ptr_size(), "little")) - argv[2] = buf - argv[6] = size + ctx.args["BaseAddress"].display = hex(buf) + ctx.args["ViewSize"].display = hex(size) sect.add_view(buf, full_offset, size, access) else: buf = pref_address diff --git a/speakeasy/winenv/api/kernelmode/wdfldr.py b/speakeasy/winenv/api/kernelmode/wdfldr.py index e8ecb5c..6be3f0a 100644 --- a/speakeasy/winenv/api/kernelmode/wdfldr.py +++ b/speakeasy/winenv/api/kernelmode/wdfldr.py @@ -390,7 +390,7 @@ class Wdfldr(api.ApiHandler): wkey = emu.reg_get_key(Key) if wkey: val_name = self.read_unicode_string(ValueName) - argv[2] = val_name + ctx.args[2].display = val_name value = wkey.get_value(val_name) if value: ulong = value.get_data() @@ -449,11 +449,11 @@ class Wdfldr(api.ApiHandler): if InterfaceClassGUID: guid = self.mem_read(InterfaceClassGUID, 16) guid = uuid.UUID(bytes_le=guid) - argv[2] = str(guid) + ctx.args[2].display = str(guid) if ReferenceString: ref = self.read_unicode_string(ReferenceString) - argv[3] = ref + ctx.args[3].display = ref return rv diff --git a/speakeasy/winenv/api/usermode/advapi32.py b/speakeasy/winenv/api/usermode/advapi32.py index 50329a7..b7cfd63 100644 --- a/speakeasy/winenv/api/usermode/advapi32.py +++ b/speakeasy/winenv/api/usermode/advapi32.py @@ -63,7 +63,7 @@ class AdvApi32(api.ApiHandler): hkey_name = regdefs.get_hkey_type(hKey) if hkey_name: - argv[0] = hkey_name + ctx.args["hKey"].display = hkey_name if not hnd and not lpSubKey: hnd = hKey else: @@ -75,7 +75,7 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) if lpSubKey: lpSubKey = self.read_mem_string(lpSubKey, cw) - argv[1] = lpSubKey + ctx.args["lpSubKey"].display = lpSubKey if hkey_name and lpSubKey: if not lpSubKey.startswith("\\"): @@ -112,14 +112,14 @@ class AdvApi32(api.ApiHandler): hkey_name = regdefs.get_hkey_type(hKey) if hkey_name: - argv[0] = hkey_name + ctx.args["hKey"].display = hkey_name if not hnd and not lpSubKey: hnd = hKey cw = self.get_char_width(ctx) if lpSubKey: lpSubKey = self.read_mem_string(lpSubKey, cw) - argv[1] = lpSubKey + ctx.args["lpSubKey"].display = lpSubKey if hkey_name and lpSubKey: if not lpSubKey.startswith("\\"): @@ -156,17 +156,17 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) if lpValueName: lpValueName = self.read_mem_string(lpValueName, cw) - argv[1] = lpValueName + ctx.args["lpValueName"].display = lpValueName type_name = regdefs.get_value_type(lpType) if type_name: - argv[3] = type_name + ctx.args["lpType"].display = type_name length = 0 if lpcbData: length = self.mem_read(lpcbData, 4) length = int.from_bytes(length, "little") - argv[5] = length + ctx.args["lpcbData"].display = hex(length) key = self.reg_get_key(hKey) if key: @@ -237,7 +237,7 @@ class AdvApi32(api.ApiHandler): value_name = "" if lpValueName: value_name = self.read_mem_string(lpValueName, cw) - argv[1] = value_name + ctx.args["lpValueName"].display = value_name value_data = "" if lpData and cbData: @@ -304,7 +304,6 @@ class AdvApi32(api.ApiHandler): _argv = argv + [0, 0, 0, 0] rv = self.RegEnumKeyEx(emu, _argv, ctx) - argv[:] = _argv[:4] return rv @@ -329,7 +328,7 @@ class AdvApi32(api.ApiHandler): rv = windefs.ERROR_INVALID_HANDLE if hKey: key = self.reg_get_key(hKey) - argv[0] = key.get_path() + ctx.args["hKey"].display = key.get_path() if not key: rv = windefs.ERROR_INVALID_HANDLE else: @@ -362,14 +361,14 @@ class AdvApi32(api.ApiHandler): rv = windefs.ERROR_INVALID_HANDLE if hkey: key = self.reg_get_key(hkey) - argv[0] = key.get_path() + ctx.args["hKey"].display = key.get_path() if not key: rv = windefs.ERROR_INVALID_HANDLE else: cw = self.get_char_width(ctx) if lpSubKey: lpSubKey = self.read_mem_string(lpSubKey, cw) - argv[1] = lpSubKey + ctx.args["lpSubKey"].display = lpSubKey sub_key_path = key.get_path() + "\\" + lpSubKey self.emu.reg_create_key(sub_key_path) self.record_registry_access_event(sub_key_path, REG_CREATE) @@ -399,7 +398,7 @@ class AdvApi32(api.ApiHandler): key_path = "" hkey_name = regdefs.get_hkey_type(hKey) if hkey_name: - argv[0] = hkey_name + ctx.args["hKey"].display = hkey_name key_path = hkey_name else: key_obj = self.reg_get_key(hKey) @@ -410,7 +409,7 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) if lpSubKey: sub_key = self.read_mem_string(lpSubKey, cw) - argv[1] = sub_key + ctx.args["lpSubKey"].display = sub_key if key_path and sub_key: if not sub_key.startswith("\\"): sub_key = "\\" + sub_key @@ -449,7 +448,7 @@ class AdvApi32(api.ApiHandler): value_name = "" if lpValueName: value_name = self.read_mem_string(lpValueName, cw) - argv[1] = value_name + ctx.args["lpValueName"].display = value_name value = key.get_value(value_name) if not value: @@ -497,7 +496,7 @@ class AdvApi32(api.ApiHandler): hkey_name = regdefs.get_hkey_type(hKey) if hkey_name: - argv[0] = hkey_name + ctx.args["hKey"].display = hkey_name key = self.reg_get_key(hKey) if not key: @@ -636,29 +635,30 @@ class AdvApi32(api.ApiHandler): ste = self.win.SERVICE_TABLE_ENTRY(emu.get_ptr_size()) entry = self.mem_cast(ste, lpServiceStartTable) - argv[0] = "lpServiceStartTable=[" + table = "lpServiceStartTable=[" while entry.lpServiceName != windefs.NULL or entry.lpServiceProc != windefs.NULL: service_name = "Service" if entry.lpServiceName != windefs.NULL: service_name = self.read_mem_string(entry.lpServiceName, cw) - argv[0] += f" {{ lpServiceName={service_name}" + table += f" {{ lpServiceName={service_name}" else: - argv[0] += " { lpServiceName=NULL" + table += " { lpServiceName=NULL" if entry.lpServiceProc != windefs.NULL: service_main = entry.lpServiceProc - argv[0] += f", lpServiceProc={hex(service_main)} }} " + table += f", lpServiceProc={hex(service_main)} }} " argc, svc_argv = emu.build_service_main_args(service_name, char_width=cw) self.queue_run("thread.service", service_main, [argc, svc_argv]) else: - argv[0] += ", lpServiceProc=NULL } " + table += ", lpServiceProc=NULL } " lpServiceStartTable += self.sizeof(ste) ste = self.win.SERVICE_TABLE_ENTRY(emu.get_ptr_size()) entry = self.mem_cast(ste, lpServiceStartTable) - argv[0] += "]" + table += "]" + ctx.args["lpServiceStartTable"].display = table rv = True emu.set_last_error(windefs.ERROR_SUCCESS) @@ -782,13 +782,13 @@ class AdvApi32(api.ApiHandler): if svc_name: _sname = self.read_mem_string(svc_name, cw) - argv[1] = _sname + ctx.args["lpServiceName"].display = _sname if disp_name: _dname = self.read_mem_string(disp_name, cw) - argv[2] = _dname + ctx.args["lpDisplayName"].display = _dname if bin_path: _bpname = self.read_mem_string(bin_path, cw) - argv[7] = _bpname + ctx.args["lpBinaryPathName"].display = _bpname hSvc = self.mem_alloc(size=8) emu.set_last_error(windefs.ERROR_SUCCESS) @@ -956,17 +956,17 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) if lpBinaryPathName: - argv[4] = self.read_mem_string(lpBinaryPathName, cw) + ctx.args["lpBinaryPathName"].display = self.read_mem_string(lpBinaryPathName, cw) if lpLoadOrderGroup: - argv[5] = self.read_mem_string(lpLoadOrderGroup, cw) + ctx.args["lpLoadOrderGroup"].display = self.read_mem_string(lpLoadOrderGroup, cw) if lpDependencies: - argv[7] = self.read_mem_string(lpDependencies, cw) + ctx.args["lpDependencies"].display = self.read_mem_string(lpDependencies, cw) if lpServiceStartName: - argv[8] = self.read_mem_string(lpServiceStartName, cw) + ctx.args["lpServiceStartName"].display = self.read_mem_string(lpServiceStartName, cw) if lpPassword: - argv[9] = self.read_mem_string(lpPassword, cw) + ctx.args["lpPassword"].display = self.read_mem_string(lpPassword, cw) if lpDisplayName: - argv[10] = self.read_mem_string(lpDisplayName, cw) + ctx.args["lpDisplayName"].display = self.read_mem_string(lpDisplayName, cw) emu.set_last_error(windefs.ERROR_SUCCESS) return 1 @@ -1024,10 +1024,10 @@ class AdvApi32(api.ApiHandler): if szContainer: cont_str = self.read_mem_string(szContainer, cw) - argv[1] = cont_str + ctx.args["szContainer"].display = cont_str if szProvider: prov_str = self.read_mem_string(szProvider, cw) - argv[2] = prov_str + ctx.args["szProvider"].display = prov_str cm = emu.get_crypt_manager() hnd = cm.crypt_open(cname=cont_str, pname=prov_str, ptype=dwProvType, flags=dwFlags) @@ -1179,7 +1179,7 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) user_name = emu.config.user.name - argv[0] = user_name + ctx.args["lpBuffer"].display = user_name if lpBuffer: if cw == 2: @@ -1208,10 +1208,10 @@ class AdvApi32(api.ApiHandler): if sysname: sysname = self.read_mem_string(sysname, cw) - argv[0] = sysname + ctx.args["lpSystemName"].display = sysname if name: name = self.read_mem_string(name, cw) - argv[1] = name + ctx.args["lpName"].display = name rv = True return rv @@ -1337,13 +1337,13 @@ class AdvApi32(api.ApiHandler): if ptr_sysname: sn = self.read_mem_string(ptr_sysname, cw) - argv[0] = sn + ctx.args["lpSystemName"].display = sn if not ptr_acctname: return rv acctname = self.read_mem_string(ptr_acctname, cw) - argv[1] = acctname + ctx.args["lpAccountName"].display = acctname user = emu.config.user.name # Currently only supporting user SIDs specified in the config @@ -1354,13 +1354,13 @@ class AdvApi32(api.ApiHandler): if not str_sid: return rv - argv[2] = str_sid + ctx.args["Sid"].display = str_sid sid_struct = windefs.convert_sid_str_to_struct(emu.get_ptr_size(), str_sid) side_struct_size = sid_struct.sizeof() cbsid = self.mem_read(ptr_cbsid, 4) cbsid = int.from_bytes(cbsid, "little") - argv[3] = cbsid + ctx.args["cbSid"].display = hex(cbsid) if not cbsid: self.mem_write(ptr_cbsid, side_struct_size.to_bytes(4, "little")) return rv @@ -1371,7 +1371,7 @@ class AdvApi32(api.ApiHandler): domain = emu.config.domain cchdomname = self.mem_read(ptr_cchdomname, 4) cbcchdomname = int.from_bytes(cchdomname, "little") - argv[5] = cbcchdomname + ctx.args["cchReferencedDomainName"].display = hex(cbcchdomname) if not cbcchdomname: buf_size = len(domain) + 1 self.mem_write(ptr_cchdomname, buf_size.to_bytes(4, "little")) @@ -1382,11 +1382,11 @@ class AdvApi32(api.ApiHandler): self.mem_write(ptr_sid, self.get_bytes(sid_struct)) self.write_mem_string(domain, ptr_domname, cw) - argv[4] = domain + ctx.args["ReferencedDomainName"].display = domain # Currently only supporting user SIDs (SidTypeUser = 1) self.mem_write(ptr_peuse, (1).to_bytes(4, "little")) - argv[6] = 1 + ctx.args["peUse"].display = hex(1) return rv @@ -1423,7 +1423,7 @@ class AdvApi32(api.ApiHandler): if sysname: sn = self.read_mem_string(sysname, cw) - argv[0] = sn + ctx.args["lpSystemName"].display = sn return rv @@ -1451,12 +1451,12 @@ class AdvApi32(api.ApiHandler): appstr = "" if app: appstr = self.read_mem_string(app, cw) - argv[1] = appstr + ctx.args["lpApplicationName"].display = appstr if cmd: cmdstr = self.read_mem_string(cmd, cw) if not appstr: appstr = cmdstr.split(" ")[0] - argv[2] = cmdstr + ctx.args["lpCommandLine"].display = cmdstr proc = emu.create_process(path=appstr, cmdline=cmdstr) proc_hnd = self.get_object_handle(proc) @@ -1499,7 +1499,7 @@ class AdvApi32(api.ApiHandler): } hProv, Algid, hKey, dwFlags, phHash = argv - argv[1] = hash_algs.get(Algid, Algid)[0] + ctx.args["Algid"].display = hash_algs.get(Algid, Algid)[0] if hKey != 0: return 0 @@ -1553,7 +1553,7 @@ class AdvApi32(api.ApiHandler): param_enums = {1: "HP_ALGID", 2: "HP_HASHVAL", 4: "HP_HASHSIZE", 5: "HP_HMAC_INFO"} if dwParam in param_enums.keys(): - argv[1] = param_enums[dwParam] + ctx.args["dwParam"].display = param_enums[dwParam] return 1 @@ -1679,15 +1679,15 @@ class AdvApi32(api.ApiHandler): cw = self.get_char_width(ctx) if lpSubKey: lpSubKey = self.read_mem_string(lpSubKey, cw) - argv[1] = lpSubKey + ctx.args["lpSubKey"].display = lpSubKey if lpValue: lpValue = self.read_mem_string(lpValue, cw) - argv[2] = lpValue + ctx.args["lpValue"].display = lpValue type_name = regdefs.get_value_type(lpType) if type_name: - argv[4] = type_name + ctx.args["pdwType"].display = type_name length = 0 if lpcbData: @@ -1753,11 +1753,11 @@ class AdvApi32(api.ApiHandler): service_type_str = adv32.get_define_int(dwServiceType, "SERVICE_") if service_type_str: - argv[1] = service_type_str + ctx.args["dwServiceType"].display = service_type_str service_state_str = adv32.get_define_int(dwServiceState, "SERVICE_") if service_state_str: - argv[2] = service_state_str + ctx.args["dwServiceState"].display = service_state_str # TODO: Populate service status output return 1 @@ -1774,7 +1774,7 @@ class AdvApi32(api.ApiHandler): hSCManager, lpServiceName, dwDesiredAccess = argv cw = self.get_char_width(ctx) svcname = self.read_mem_string(lpServiceName, cw) - argv[1] = svcname + ctx.args["lpServiceName"].display = svcname return self.get_handle() @apihook("DeleteService", argc=1, conv=_arch.CALL_CONV_STDCALL) diff --git a/speakeasy/winenv/api/usermode/bcrypt.py b/speakeasy/winenv/api/usermode/bcrypt.py index a0b2e90..1749548 100644 --- a/speakeasy/winenv/api/usermode/bcrypt.py +++ b/speakeasy/winenv/api/usermode/bcrypt.py @@ -38,19 +38,19 @@ class Bcrypt(api.ApiHandler): algid = self.read_wide_string(pszAlgId) if algid: - argv[1] = algid + ctx.args["pszAlgId"].display = algid implementation = "" if pszImplementation: implementation = self.read_wide_string(pszImplementation) if implementation: - argv[2] = implementation + ctx.args["pszImplementation"].display = implementation cm = emu.get_crypt_manager() hnd = cm.crypt_open(pname=implementation, ptype=algid, flags=dwFlags) if hnd: self.mem_write(phAlgorithm, hnd.to_bytes(emu.get_ptr_size(), "little")) - argv[0] = hnd + ctx.args["phAlgorithm"].display = hex(hnd) return ntdefs.STATUS_SUCCESS @@ -70,19 +70,19 @@ class Bcrypt(api.ApiHandler): hAlgorithm, hImportKey, pszBlobType, phKey, pbInput, cbInput, dwFlags = argv blob_type = self.read_wide_string(pszBlobType) - argv[2] = blob_type + ctx.args["pszBlobType"].display = blob_type cbInput = cbInput & 0xFFFFFFFF blob = self.mem_read(pbInput, cbInput) - argv[4] = base64.b64encode(blob).decode("utf-8") + ctx.args["pbInput"].display = base64.b64encode(blob).decode("utf-8") cm = emu.get_crypt_manager() if hAlgorithm and phKey: - ctx = cm.crypt_get(hAlgorithm) - hnd = ctx.import_key(blob_type=blob_type, blob=blob, blob_len=cbInput, flags=dwFlags) + alg_ctx = cm.crypt_get(hAlgorithm) + hnd = alg_ctx.import_key(blob_type=blob_type, blob=blob, blob_len=cbInput, flags=dwFlags) if hnd: self.mem_write(phKey, hnd.to_bytes(emu.get_ptr_size(), "little")) - argv[3] = hnd + ctx.args["phKey"].display = hex(hnd) return ntdefs.STATUS_SUCCESS @@ -118,7 +118,7 @@ class Bcrypt(api.ApiHandler): property = self.read_wide_string(pszProperty) if property: - argv[1] = property + ctx.args["pszProperty"].display = property # TODO: implement property retrieval @@ -133,10 +133,10 @@ class Bcrypt(api.ApiHandler): """ (hKey,) = argv cm = emu.get_crypt_manager() - for hnd, ctx in cm.ctx_handles.items(): - hnd_key = ctx.get_key(hKey) + for hnd, crypt_ctx in cm.ctx_handles.items(): + hnd_key = crypt_ctx.get_key(hKey) if hnd_key: - ctx.delete_key(hKey) + crypt_ctx.delete_key(hKey) return ntdefs.STATUS_SUCCESS return ntdefs.STATUS_INVALID_HANDLE diff --git a/speakeasy/winenv/api/usermode/com_api.py b/speakeasy/winenv/api/usermode/com_api.py index e1fb482..83546bd 100644 --- a/speakeasy/winenv/api/usermode/com_api.py +++ b/speakeasy/winenv/api/usermode/com_api.py @@ -65,7 +65,7 @@ class ComApi(api.ApiHandler): ); """ ptr, strNetworkResource, strUser, strPassword, strLocale, lSecurityFlags, strAuthority, pCtx, ppNamespace = argv - argv[1] = self.read_wide_string(strNetworkResource) + ctx.args[1].display = self.read_wide_string(strNetworkResource) if ppNamespace: ci = emu.com.get_interface(emu, emu.get_ptr_size(), "IWbemServices") @@ -87,8 +87,8 @@ class ComApi(api.ApiHandler): ); """ ptr, strQueryLanguage, strQuery, lFlags, pCtx, ppEnum = argv - argv[1] = self.read_wide_string(strQueryLanguage) - argv[2] = self.read_wide_string(strQuery) + ctx.args[1].display = self.read_wide_string(strQueryLanguage) + ctx.args[2].display = self.read_wide_string(strQuery) # not implemented so returning -1 return -1 diff --git a/speakeasy/winenv/api/usermode/crypt32.py b/speakeasy/winenv/api/usermode/crypt32.py index 55dbce3..8fafc2c 100644 --- a/speakeasy/winenv/api/usermode/crypt32.py +++ b/speakeasy/winenv/api/usermode/crypt32.py @@ -56,7 +56,7 @@ class Crypt32(api.ApiHandler): if not isinstance(s, str): s = s.decode("utf8") - argv[0] = s + ctx.args["pszString"].display = s try: decoded = base64.b64decode(s) diff --git a/speakeasy/winenv/api/usermode/dnsapi.py b/speakeasy/winenv/api/usermode/dnsapi.py index 8cdab6d..33b5594 100644 --- a/speakeasy/winenv/api/usermode/dnsapi.py +++ b/speakeasy/winenv/api/usermode/dnsapi.py @@ -69,7 +69,7 @@ class DnsApi(api.ApiHandler): rec.pName = pszName rec.wType = wType if wType == DNS_TYPE_TEXT: - argv[1] = "DNS_TYPE_TEXT" + ctx.args["wType"].display = "DNS_TYPE_TEXT" text = self.netman.get_dns_txt(name) if not text: diff --git a/speakeasy/winenv/api/usermode/kernel32.py b/speakeasy/winenv/api/usermode/kernel32.py index 9c13884..c2bc958 100644 --- a/speakeasy/winenv/api/usermode/kernel32.py +++ b/speakeasy/winenv/api/usermode/kernel32.py @@ -277,7 +277,7 @@ class Kernel32(api.ApiHandler): """ (_str,) = argv cw = self.get_char_width(ctx) - argv[0] = self.read_mem_string(_str, cw) + ctx.args["lpOutputString"].display = self.read_mem_string(_str, cw) @apihook("GetThreadTimes", argc=5) def GetThreadTimes(self, emu, argv, ctx: api.ApiContext = api.NO_CONTEXT): @@ -363,7 +363,7 @@ class Kernel32(api.ApiHandler): emu.set_last_error(windefs.ERROR_SUCCESS) hnd, evt = emu.create_mutant(name) - argv[2] = name + ctx.args["lpName"].display = name return hnd @apihook("CreateMutexEx", argc=4) @@ -393,7 +393,7 @@ class Kernel32(api.ApiHandler): emu.set_last_error(windefs.ERROR_SUCCESS) hnd, evt = emu.create_mutant(name) - argv[1] = name + ctx.args["lpName"].display = name return hnd @apihook("LoadLibrary", argc=1) @@ -410,7 +410,7 @@ class Kernel32(api.ApiHandler): lib = winemu.normalize_dll_name(req_lib) hmod = emu.load_library(lib) - argv[0] = req_lib + ctx.args["lpLibFileName"].display = req_lib return hmod @@ -488,7 +488,7 @@ class Kernel32(api.ApiHandler): cap_def = k32types.get_flag_defines(dwFlags, "TH32CS") if cap_def: cap_def = "|".join(cap_def) - argv[0] = cap_def + ctx.args["dwFlags"].display = cap_def return hnd @@ -777,7 +777,7 @@ class Kernel32(api.ApiHandler): if name: obj_name = self.read_mem_string(name, cw) - argv[2] = obj_name + ctx.args["lpName"].display = obj_name obj = self.get_object_from_name(obj_name) @@ -842,7 +842,7 @@ class Kernel32(api.ApiHandler): if lpCmdLine: cmd = self.read_mem_string(lpCmdLine, 1) - argv[0] = cmd + ctx.args["lpCmdLine"].display = cmd app = cmd.split()[0] proc = emu.create_process(path=app, cmdline=cmd) self.record_process_event(proc, PROC_CREATE) @@ -884,9 +884,8 @@ class Kernel32(api.ApiHandler): pretty_flags = " | ".join([name for bit, name in flags.items() if dwFlags & bit]) - argv[0] = req_lib - argv[1] = argv[1] - argv[2] = pretty_flags + ctx.args["lpLibFileName"].display = req_lib + ctx.args["dwFlags"].display = pretty_flags if not hmod: emu.set_last_error(windefs.ERROR_MOD_NOT_FOUND) @@ -914,7 +913,15 @@ class Kernel32(api.ApiHandler): # Args are the same as CreateProcess except for argv[0] and argv[-1] _argv = argv[1:-1] rv = self.CreateProcess(emu, _argv, ctx) - argv[1:-1] = _argv + app, cmd, flags = _argv[0], _argv[1], _argv[5] + cw = self.get_char_width(ctx) + if app: + ctx.args[1].display = self.read_mem_string(app, cw) + if cmd: + ctx.args[2].display = self.read_mem_string(cmd, cw) + def_flags = windefs.get_creation_flags(flags) + if def_flags: + ctx.args[6].display = " | ".join(def_flags) return rv @apihook("CreateProcess", argc=10) @@ -938,15 +945,15 @@ class Kernel32(api.ApiHandler): appstr = "" if app: appstr = self.read_mem_string(app, cw) - argv[0] = appstr + ctx.args["lpApplicationName"].display = appstr if cmd: cmdstr = self.read_mem_string(cmd, cw) - argv[1] = cmdstr + ctx.args["lpCommandLine"].display = cmdstr def_flags = windefs.get_creation_flags(flags) if def_flags: def_flags = " | ".join(def_flags) - argv[5] = def_flags + ctx.args["dwCreationFlags"].display = def_flags proc = emu.create_process(path=appstr, cmdline=cmdstr, child=True) proc_hnd = self.get_object_handle(proc) @@ -984,10 +991,12 @@ class Kernel32(api.ApiHandler): buf = 0 tag_prefix = "api.VirtualAlloc" + protect = flProtect prot_def = windefs.get_page_rights(flProtect) if prot_def: prot_def = "|".join(prot_def) - argv[3] = prot_def + ctx.args["flProtect"].display = prot_def + protect = prot_def # Was this address already commited? mm = emu.get_address_map(lpAddress) @@ -1013,7 +1022,7 @@ class Kernel32(api.ApiHandler): proc = emu.get_current_process() if proc: self.record_process_event( - proc, MEM_ALLOC, base=buf, size=dwSize, type=flAllocationType, protect=argv[3] + proc, MEM_ALLOC, base=buf, size=dwSize, type=flAllocationType, protect=protect ) emu._set_dyn_code_hook(buf, size) @@ -1053,16 +1062,18 @@ class Kernel32(api.ApiHandler): return windefs.NULL proc_path = obj.path - argv[0] = proc_path + ctx.args["hProcess"].display = proc_path proc_path = ntpath.basename(proc_path) proc_path = proc_path.replace(".", "_") tag_prefix = f"api.VirtualAllocEx.{proc_path}.{obj.pid}" + protect = flProtect prot_def = windefs.get_page_rights(flProtect) if prot_def: prot_def = "|".join(prot_def) - argv[4] = prot_def + ctx.args["flProtect"].display = prot_def + protect = prot_def # Was this address already commited? mm = emu.get_address_map(lpAddress) @@ -1086,7 +1097,7 @@ class Kernel32(api.ApiHandler): ) mm = emu.get_address_map(buf) - self.record_process_event(obj, MEM_ALLOC, base=buf, size=dwSize, type=flAllocationType, protect=argv[4]) + self.record_process_event(obj, MEM_ALLOC, base=buf, size=dwSize, type=flAllocationType, protect=protect) emu._set_dyn_code_hook(buf, size) @@ -1112,7 +1123,7 @@ class Kernel32(api.ApiHandler): obj = self.get_object_from_handle(hProcess) proc_path = obj.path - argv[0] = proc_path + ctx.args["hProcess"].display = proc_path data = b"" if lpBuffer and lpBaseAddress: @@ -1150,7 +1161,7 @@ class Kernel32(api.ApiHandler): obj = self.get_object_from_handle(hProcess) proc_path = obj.path - argv[0] = proc_path + ctx.args["hProcess"].display = proc_path data = b"" if lpBuffer and lpBaseAddress: @@ -1195,7 +1206,7 @@ class Kernel32(api.ApiHandler): proc_obj = self.get_object_from_handle(hProcess) proc_path = proc_obj.path - argv[0] = proc_path + ctx.args["hProcess"].display = proc_path proc_path = ntpath.basename(proc_path) proc_path = proc_path.replace(".", "_") @@ -1238,7 +1249,7 @@ class Kernel32(api.ApiHandler): def_flags = windefs.get_creation_flags(dwCreationFlags) if def_flags: def_flags = " | ".join(def_flags) - argv[4] = def_flags + ctx.args["dwCreationFlags"].display = def_flags is_suspended = False if dwCreationFlags & windefs.CREATE_SUSPENDED: @@ -1457,7 +1468,7 @@ class Kernel32(api.ApiHandler): prot_def = windefs.get_page_rights(flNewProtect) if prot_def: prot_def = " | ".join(prot_def) - argv[3] = prot_def + ctx.args["flNewProtect"].display = prot_def self.record_process_event(proc_obj, MEM_PROTECT, base=lpAddress, size=dwSize, protect=prot_def) @@ -1682,7 +1693,7 @@ class Kernel32(api.ApiHandler): if lpConsoleTitle: cw = self.get_char_width(ctx) cs1 = self.read_mem_string(lpConsoleTitle, cw) - argv[0] = cs1 + ctx.args["lpConsoleTitle"].display = cs1 return True @apihook("GetLocalTime", argc=1) @@ -1813,7 +1824,7 @@ class Kernel32(api.ApiHandler): } rv = lookup[argv[0]]["return"] - argv[0] = lookup[argv[0]]["name"] + ctx.args["ProcessorFeature"].display = lookup[argv[0]]["name"] return rv @@ -1831,8 +1842,8 @@ class Kernel32(api.ApiHandler): cs1 = self.read_mem_string(string1, cw) cs2 = self.read_mem_string(string2, cw) - argv[0] = cs1 - argv[1] = cs2 + ctx.args["lpString1"].display = cs1 + ctx.args["lpString2"].display = cs2 if cs1.lower() == cs2.lower(): rv = 0 @@ -1853,8 +1864,8 @@ class Kernel32(api.ApiHandler): cs1 = self.read_mem_string(string1, cw) cs2 = self.read_mem_string(string2, cw) - argv[0] = cs1 - argv[1] = cs2 + ctx.args["lpString1"].display = cs1 + ctx.args["lpString2"].display = cs2 if cs1 == cs2: rv = 0 @@ -1913,7 +1924,7 @@ class Kernel32(api.ApiHandler): cw = 1 s = self.read_mem_string(src, cw) - argv[0] = s + ctx.args["lpString"].display = s return len(s) @@ -1950,7 +1961,7 @@ class Kernel32(api.ApiHandler): rv = proc.base else: lib = self.read_mem_string(mod_name, cw) - argv[0] = lib + ctx.args["lpModuleName"].display = lib sname, _ = os.path.splitext(lib) sname = winemu.normalize_dll_name(sname) mods = emu.get_peb_modules() @@ -1980,7 +1991,7 @@ class Kernel32(api.ApiHandler): else: try: proc = self.read_mem_string(proc_name, 1) - argv[1] = proc + ctx.args["lpProcName"].display = proc except Exception: pass @@ -2183,8 +2194,8 @@ class Kernel32(api.ApiHandler): s1 = self.read_mem_string(lpString1, cw) s2 = self.read_mem_string(lpString2, cw) - argv[0] = s1 - argv[1] = s2 + ctx.args["lpString1"].display = s1 + ctx.args["lpString2"].display = s2 if cw == 2: new = (s1 + s2).encode("utf-16le") @@ -2209,7 +2220,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) s = self.read_mem_string(src, cw) - argv[1] = s + ctx.args["lpString2"].display = s s = s[: iMaxLength - 1] s += "\x00" @@ -2229,7 +2240,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) s = self.read_mem_string(src, cw) - argv[1] = s + ctx.args["lpString2"].display = s s += "\x00" self.write_mem_string(s, dest, cw) @@ -2615,7 +2626,7 @@ class Kernel32(api.ApiHandler): if lpSrc: src = self.read_mem_string(lpSrc, cw) dst = src - argv[0] = src + ctx.args["lpSrc"].display = src for k, v in emu.get_env().items(): ev = f"%{k.lower()}%" if ev in dst.lower(): @@ -2626,7 +2637,7 @@ class Kernel32(api.ApiHandler): if lpDst: self.write_mem_string(dst, lpDst, cw) rv = len(dst) - argv[1] = dst + ctx.args["lpDst"].display = dst return rv @@ -2936,11 +2947,11 @@ class Kernel32(api.ApiHandler): if cchWideChar == 0: if cbMultiByte == 0xFFFFFFFF: mbs = self.read_mem_string(lpMultiByteStr, 1) - argv[2] = mbs + ctx.args["lpMultiByteStr"].display = mbs rv = len(mbs) + 1 else: mbs = self.read_mem_string(lpMultiByteStr, 1) - argv[2] = mbs + ctx.args["lpMultiByteStr"].display = mbs rv = len(mbs) + 1 elif lpMultiByteStr == 0 or cbMultiByte == 0: emu.set_last_error(windefs.ERROR_INSUFFICIENT_BUFFER) @@ -2948,7 +2959,7 @@ class Kernel32(api.ApiHandler): elif lpWideCharStr != 0: if cbMultiByte == 0xFFFFFFFF: mbs = self.read_mem_string(lpMultiByteStr, 1) - argv[2] = mbs + ctx.args["lpMultiByteStr"].display = mbs mbs += "\x00" ws = mbs.encode("utf-16le") @@ -3140,7 +3151,7 @@ class Kernel32(api.ApiHandler): filename = mod.emu_path if filename: - argv[1] = filename + ctx.args["lpFilename"].display = filename if cw == 2: out = filename.encode("utf-16le") elif cw == 1: @@ -3235,7 +3246,7 @@ class Kernel32(api.ApiHandler): else: sysroot = "C:\\Windows\\system32" - argv[0] = sysroot + ctx.args["lpBuffer"].display = sysroot sysroot += "\x00" if cw == 2: out = sysroot.encode("utf-16le") @@ -3273,8 +3284,8 @@ class Kernel32(api.ApiHandler): if lpName and lpValue: name = self.read_mem_string(lpName, cw) val = self.read_mem_string(lpValue, cw) - argv[0] = name - argv[1] = val + ctx.args["lpName"].display = name + ctx.args["lpValue"].display = val emu.set_env(name, val) return True @@ -3290,7 +3301,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) if path: path = self.read_mem_string(path, cw) - argv[0] = path + ctx.args["lpPathName"].display = path return True @apihook("GetWindowsDirectory", argc=2) @@ -3325,7 +3336,7 @@ class Kernel32(api.ApiHandler): name = "" if map_name: name = self.read_mem_string(map_name, cw) - argv[5] = name + ctx.args["lpName"].display = name hmap = self.file_create_mapping(hfile, name, size, prot) @@ -3457,7 +3468,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) rv = windefs.INVALID_FILE_ATTRIBUTES target = self.read_mem_string(fn, cw) - argv[0] = target + ctx.args["lpFileName"].display = target if self.does_file_exist(target): rv = windefs.FILE_ATTRIBUTE_NORMAL return rv @@ -3476,13 +3487,13 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) filename = self.read_mem_string(lpFileName, cw) - argv[0] = filename + ctx.args["lpFileName"].display = filename level_id = k32types.get_define(fInfoLevelId, "GetFileExInfo") if not level_id: return False - argv[1] = level_id + ctx.args["fInfoLevelId"].display = level_id file_data = k32types.WIN32_FILE_ATTRIBUTE_DATA(emu.get_ptr_size()) @@ -3571,7 +3582,7 @@ class Kernel32(api.ApiHandler): if pn: target = self.read_mem_string(pn, cw) - argv[0] = target + ctx.args["lpPathName"].display = target return True @apihook("RemoveDirectory", argc=1) @@ -3586,7 +3597,7 @@ class Kernel32(api.ApiHandler): if pn: target = self.read_mem_string(pn, cw) - argv[0] = target + ctx.args["lpPathName"].display = target return True @@ -3604,10 +3615,10 @@ class Kernel32(api.ApiHandler): if src: src = self.read_mem_string(src, cw) - argv[0] = src + ctx.args["lpExistingFileName"].display = src if dst: dst = self.read_mem_string(dst, cw) - argv[1] = dst + ctx.args["lpNewFileName"].display = dst if not src or not dst: emu.set_last_error(windefs.ERROR_INVALID_PARAMETER) @@ -3656,10 +3667,10 @@ class Kernel32(api.ApiHandler): if src: src = self.read_mem_string(src, cw) - argv[0] = src + ctx.args["lpExistingFileName"].display = src if dst: dst = self.read_mem_string(dst, cw) - argv[1] = dst + ctx.args["lpNewFileName"].display = dst if not src or not dst: emu.set_last_error(windefs.ERROR_INVALID_PARAMETER) @@ -3721,17 +3732,17 @@ class Kernel32(api.ApiHandler): return hnd target = self.read_mem_string(fname, cw) - argv[0] = target + ctx.args["lpFileName"].display = target ad = ddk.get_access_defines(access) if ad: - argv[1] = " | ".join(ad) + ctx.args["dwDesiredAccess"].display = " | ".join(ad) disp_bytes = disp.to_bytes(8, "little") disp = int(int.from_bytes(disp_bytes[0:4], "little")) cd = windefs.get_create_disposition(disp) if cd: - argv[4] = cd + ctx.args["dwCreationDisposition"].display = cd obj = self.get_object_from_name(target) if obj: @@ -3792,7 +3803,7 @@ class Kernel32(api.ApiHandler): return 0 target = self.read_mem_string(lpFileName, cw) - argv[0] = target + ctx.args["lpFileName"].display = target if emu.does_file_exist(target): # FIXME : does not handle read-only attribute @@ -3879,7 +3890,7 @@ class Kernel32(api.ApiHandler): self.record_file_access_event(path, FILE_WRITE, data=data, buffer=lpBuffer, size=num_bytes) data_hex = data.hex() - argv[1] = f"{hex(lpBuffer)} ({data_hex[:0x20]})" + ctx.args["lpBuffer"].display = f"{hex(lpBuffer)} ({data_hex[:0x20]})" if bytes_written: self.mem_write(bytes_written, len(data).to_bytes(4, "little")) @@ -4078,7 +4089,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) if root: root_name = self.read_mem_string(root, cw) - argv[0] = root_name + ctx.args["lpRootPathName"].display = root_name return True @@ -4099,7 +4110,7 @@ class Kernel32(api.ApiHandler): obj = None if name: evt_name = self.read_mem_string(name, cw) - argv[3] = evt_name + ctx.args["lpName"].display = evt_name obj = self.get_object_from_name(evt_name) if obj: @@ -4126,7 +4137,7 @@ class Kernel32(api.ApiHandler): obj = None if name: timer_name = self.read_mem_string(name, cw) - argv[2] = timer_name + ctx.args["lpTimerName"].display = timer_name obj = self.get_object_from_name(timer_name) if obj: @@ -4155,7 +4166,7 @@ class Kernel32(api.ApiHandler): obj = None if name: timer_name = self.read_mem_string(name, cw) - argv[1] = timer_name + ctx.args["lpTimerName"].display = timer_name obj = self.get_object_from_name(timer_name) if obj: @@ -4183,7 +4194,7 @@ class Kernel32(api.ApiHandler): hnd = 0 if name: timer_name = self.read_mem_string(name, cw) - argv[2] = timer_name + ctx.args["lpTimerName"].display = timer_name obj = self.get_object_from_name(timer_name) @@ -4250,7 +4261,7 @@ class Kernel32(api.ApiHandler): hnd = 0 if name: evt_name = self.read_mem_string(name, cw) - argv[2] = evt_name + ctx.args["lpName"].display = evt_name obj = self.get_object_from_name(evt_name) @@ -4575,7 +4586,7 @@ class Kernel32(api.ApiHandler): pipe_name = "" if lpName: pipe_name = self.read_mem_string(lpName, cw) - argv[0] = pipe_name + ctx.args["lpName"].display = pipe_name hnd = emu.pipe_open(pipe_name, dwOpenMode, nMaxInstances, nOutBufferSize, nInBufferSize) if not hnd: @@ -4682,11 +4693,11 @@ class Kernel32(api.ApiHandler): lcid = k32types.get_define(Locale, "LOCALE_") if lcid: - argv[0] = lcid + ctx.args["Locale"].display = lcid lctype = k32types.get_define(LCType, "LOCALE_") if lctype: - argv[1] = lctype + ctx.args["LCType"].display = lctype locale_data = "" if lctype == "LOCALE_SENGLISHCOUNTRYNAME": locale_data = "United States" @@ -4747,8 +4758,8 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) host = emu.config.hostname - argv[0] = host - argv[1] = len(host) + ctx.args["lpBuffer"].display = host + ctx.args["nSize"].display = hex(len(host)) if lpBuffer and host: if cw == 2: @@ -4805,7 +4816,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) name = self.read_mem_string(lpName, cw) - argv[0] = name + ctx.args["lpName"].display = name env = emu.get_env() var = env.get(name.lower()) @@ -4860,7 +4871,6 @@ class Kernel32(api.ApiHandler): _argv = [lpFileName, lpFindFileData] rv = self.FindFirstFile(emu, _argv, ctx) - argv[0] = _argv[0] return rv @@ -4881,7 +4891,7 @@ class Kernel32(api.ApiHandler): return windefs.INVALID_HANDLE_VALUE srch = self.read_mem_string(lpFileName, cw) - argv[0] = srch + ctx.args["lpFileName"].display = srch if srch.startswith("\\\\?\\"): srch = srch.replace("\\\\?\\", "") @@ -4934,7 +4944,7 @@ class Kernel32(api.ApiHandler): except StopIteration: return 0 - argv[1] = name + ctx.args["lpFindFileData"].display = name if cw == 2: cfn = name.encode("utf-16le") @@ -5090,9 +5100,11 @@ class Kernel32(api.ApiHandler): return 0 name = self.normalize_res_identifier(emu, cw, lpName) - argv[1] = name + if name != lpName: + ctx.args["lpName"].display = name if isinstance(name, str) else hex(name) type_ = self.normalize_res_identifier(emu, cw, lpType) - argv[2] = type_ + if type_ != lpType: + ctx.args["lpType"].display = type_ if isinstance(type_, str) else hex(type_) res = self.find_resource(pe, name, type_) if res is None: return 0 @@ -5126,9 +5138,11 @@ class Kernel32(api.ApiHandler): return 0 name = self.normalize_res_identifier(emu, cw, lpName) - argv[1] = name + if name != lpName: + ctx.args["lpType"].display = name if isinstance(name, str) else hex(name) type_ = self.normalize_res_identifier(emu, cw, lpType) - argv[2] = type_ + if type_ != lpType: + ctx.args["lpName"].display = type_ if isinstance(type_, str) else hex(type_) res = self.find_resource(pe, name, type_) if res is None: return 0 @@ -5271,7 +5285,7 @@ class Kernel32(api.ApiHandler): if path: cw = self.get_char_width(ctx) path_str = self.read_mem_string(path, cw) - argv[0] = path_str + ctx.args["lpPathName"].display = path_str emu.set_cd(path_str) return True @@ -5423,7 +5437,7 @@ class Kernel32(api.ApiHandler): new = (tempdir).encode("utf-8") + b"\x00" rv = len(tempdir) if lpBuffer: - argv[1] = tempdir + ctx.args["lpBuffer"].display = tempdir self.mem_write(lpBuffer, new) return rv @@ -5460,7 +5474,7 @@ class Kernel32(api.ApiHandler): cw = self.get_char_width(ctx) name = self.read_mem_string(lpRootPathName, cw) if name: - argv[0] = name + ctx.args["lpRootPathName"].display = name if name.startswith("\\\\?\\"): name = name.replace("\\\\?\\", "") @@ -5516,7 +5530,7 @@ class Kernel32(api.ApiHandler): lpszLongPath, lpszShortPath, cchBuffer = argv cw = self.get_char_width(ctx) s = self.read_mem_string(lpszLongPath, cw) - argv[0] = s + ctx.args["lpszLongPath"].display = s files = s.split("\\") out = files[0] + "\\" for i, file in enumerate(files): @@ -5547,7 +5561,7 @@ class Kernel32(api.ApiHandler): out += "\\" if lpszShortPath and len(out) + 1 <= cchBuffer: - argv[1] = out + ctx.args["lpszShortPath"].display = out self.write_mem_string(out, lpszShortPath, cw) return len(out) + 1 @@ -5566,10 +5580,10 @@ class Kernel32(api.ApiHandler): # Not an accurate implementation, just a placeholder for now cw = self.get_char_width(ctx) s = self.read_mem_string(lpszShortPath, cw) - argv[0] = s + ctx.args["lpszShortPath"].display = s self.write_mem_string(s, lpszLongPath, cw) - argv[1] = s + ctx.args["lpszLongPath"].display = s return len(s) * cw + 1 @@ -5672,7 +5686,7 @@ class Kernel32(api.ApiHandler): emu.set_last_error(windefs.ERROR_INVALID_PARAMETER) return 0 - argv[0] = s + ctx.args["lpString"].display = s if s[0] == "#" and int(s[1:]) < ATOM_RESERVED: return int(s[1:]) @@ -5693,7 +5707,7 @@ class Kernel32(api.ApiHandler): emu.set_last_error(windefs.ERROR_INVALID_PARAMETER) return 0 - argv[0] = s + ctx.args["lpString"].display = s if s[0] == "#" and int(s[1:]) < ATOM_RESERVED: return int(s[1:]) @@ -5724,7 +5738,7 @@ class Kernel32(api.ApiHandler): else: s = self.get_local_atom_name(nAtom) - argv[1] = s + ctx.args["lpBuffer"].display = s s += "\0" if len(s) > nSize: s = s[: nSize - 1] + "\0" @@ -5827,7 +5841,7 @@ class Kernel32(api.ApiHandler): curr_drive = next(dw) if curr_drive: volume_guid_path = curr_drive.get("volume_guid_path") - argv[0] = volume_guid_path + ctx.args["lpszVolumeName"].display = volume_guid_path self.write_mem_string(volume_guid_path + "\x00", lpszVolumeName, cw) @@ -5859,7 +5873,7 @@ class Kernel32(api.ApiHandler): return 0 volume_guid_path = next_drive.get("volume_guid_path") - argv[1] = volume_guid_path + ctx.args["lpszVolumeName"].display = volume_guid_path self.write_mem_string(volume_guid_path + "\x00", lpszVolumeName, cw) return 1 @@ -5913,7 +5927,7 @@ class Kernel32(api.ApiHandler): volume_guid_path = self.read_mem_string(lpszVolumeName, cw) if volume_guid_path: - argv[0] = volume_guid_path + ctx.args["lpszVolumeName"].display = volume_guid_path ERROR_MORE_DATA = 234 @@ -5922,11 +5936,11 @@ class Kernel32(api.ApiHandler): drive = dm.get_drive(volume_guid_path=volume_guid_path) if drive: root_path = drive.get("root_path") - argv[1] = root_path + ctx.args["lpszVolumePathNames"].display = root_path root_path += "\x00\x00" # additional NULL to terminate list root_path_len = len(root_path) - argv[3] = root_path_len + ctx.args["lpcchReturnLength"].display = hex(root_path_len) if lpszVolumePathNames and cchBufferLength >= root_path_len: self.write_mem_string(root_path, lpszVolumePathNames, cw) @@ -6050,13 +6064,13 @@ class Kernel32(api.ApiHandler): name_type = k32types.get_define(NameType, prefix="ComputerName") if name_type: - argv[0] = name_type + ctx.args["NameType"].display = name_type hostname = emu.config.hostname - argv[1] = hostname + ctx.args["lpBuffer"].display = hostname hostname_len = len(hostname) - argv[2] = hostname_len + ctx.args["nSize"].display = hex(hostname_len) self.write_mem_string(hostname, lpBuffer, cw) self.mem_write(nSize, hostname_len.to_bytes(4, "little")) @@ -6081,7 +6095,7 @@ class Kernel32(api.ApiHandler): locale = k32types.get_define(Locale, prefix="LOCALE_") if locale: - argv[0] = locale + ctx.args["Locale"].display = locale if lpDate == 0: self.GetSystemTimeAsFileTime(emu, [lpDate], ctx) @@ -6091,7 +6105,7 @@ class Kernel32(api.ApiHandler): date_format = self.read_mem_string(lpFormat, cw) if date_format: - argv[3] = date_format + ctx.args["lpFormat"].display = date_format # Working from example "ddd, dd MMM yyyy "; TODO: expand this date = datetime.date(sys_time.wYear, sys_time.wMonth, sys_time.wDay) @@ -6109,7 +6123,7 @@ class Kernel32(api.ApiHandler): return len(date_str) + 1 self.write_mem_string(date_str + "\x00" * cw, lpDateStr, cw) - argv[4] = date_str + ctx.args["lpDateStr"].display = date_str return 1 @@ -6185,7 +6199,7 @@ class Kernel32(api.ApiHandler): locale = k32types.get_define(Locale, prefix="LOCALE_") if locale: - argv[0] = locale + ctx.args["Locale"].display = locale if lpTime == 0: self.GetSystemTimeAsFileTime(emu, [lpTime], ctx) @@ -6196,7 +6210,7 @@ class Kernel32(api.ApiHandler): if lpFormat: time_format = self.read_mem_string(lpFormat, cw) if time_format: - argv[3] = time_format + ctx.args["lpFormat"].display = time_format else: # Using this as default; TODO: use proper string based on locale time_format = "hh:mm:ss" @@ -6217,7 +6231,7 @@ class Kernel32(api.ApiHandler): return len(time_str) + 1 self.write_mem_string(time_str + "\x00" * cw, lpTimeStr, cw) - argv[4] = time_str + ctx.args["lpTimeStr"].display = time_str return 1 @@ -6489,7 +6503,7 @@ class Kernel32(api.ApiHandler): out = path + f"\\{prefix}_{int(time.time_ns())}.tmp" else: out = path + f"{int(time.time_ns())}.tmp" - argv[1] = out + ctx.args["lpPrefixString"].display = out self.write_mem_string(out, lpTempFileName, cw) return len(out) + 1 @@ -6564,8 +6578,8 @@ class Kernel32(api.ApiHandler): else: temp_title = temp_title.encode("utf-8") + b"\x00" - argv[0] = temp_title - argv[1] = len(temp_title) + ctx.args["lpConsoleTitle"].display = str(temp_title) + ctx.args["nSize"].display = hex(len(temp_title)) if lpConsoleTitle and temp_title: self.mem_write(lpConsoleTitle, temp_title) @@ -6655,7 +6669,7 @@ class Kernel32(api.ApiHandler): obj = None if name: timer_name = self.read_mem_string(name, 2) - argv[1] = timer_name + ctx.args["lpTimerName"].display = timer_name obj = self.get_object_from_name(timer_name) if obj: diff --git a/speakeasy/winenv/api/usermode/mpr.py b/speakeasy/winenv/api/usermode/mpr.py index 8934854..58426c8 100644 --- a/speakeasy/winenv/api/usermode/mpr.py +++ b/speakeasy/winenv/api/usermode/mpr.py @@ -30,15 +30,15 @@ class Mpr(api.ApiHandler): scope = mpr.get_define_int(dwScope, "RESOURCE_") if scope: - argv[0] = scope + ctx.args["dwScope"].display = scope type = mpr.get_define_int(dwType, "RESOURCETYPE_") if type: - argv[1] = type + ctx.args["dwType"].display = type usage = mpr.get_define_int(dwUsage, "RESOURCEUSAGE_") if usage: - argv[2] = usage + ctx.args["dwUsage"].display = usage return mpr.ERROR_NO_NETWORK @@ -81,6 +81,6 @@ class Mpr(api.ApiHandler): local_name = self.read_mem_string(lpLocalName, cw) if local_name: - argv[0] = local_name + ctx.args["lpLocalName"].display = local_name return mpr.ERROR_NO_NETWORK diff --git a/speakeasy/winenv/api/usermode/msvcrt.py b/speakeasy/winenv/api/usermode/msvcrt.py index cb485d2..73cb881 100644 --- a/speakeasy/winenv/api/usermode/msvcrt.py +++ b/speakeasy/winenv/api/usermode/msvcrt.py @@ -135,7 +135,7 @@ class Msvcrt(api.ApiHandler): else: # Convert the string mbs = self.read_mem_string(mbstr, 1) - argv[3] = mbs + ctx.args[3].display = mbs mbs += "\x00" ws = mbs.encode("utf-16le") @@ -170,8 +170,8 @@ class Msvcrt(api.ApiHandler): ws1 = self.read_wide_string(string1, max_chars=count) ws2 = self.read_wide_string(string2, max_chars=count) - argv[0] = ws1 - argv[1] = ws2 + ctx.args[0].display = ws1 + ctx.args[1].display = ws2 if ws1.lower() == ws2.lower(): rv = 0 @@ -545,11 +545,11 @@ class Msvcrt(api.ApiHandler): if hay: _hay = self.read_mem_string(hay, 1) - argv[0] = _hay + ctx.args[0].display = _hay if needle: needle = self.read_mem_string(needle, 1) - argv[1] = needle + ctx.args[1].display = needle ret = _hay.find(needle) if ret != -1: @@ -571,11 +571,11 @@ class Msvcrt(api.ApiHandler): if hay: _hay = self.read_mem_string(hay, 2) - argv[0] = _hay + ctx.args[0].display = _hay if needle: needle = self.read_mem_string(needle, 2) - argv[1] = needle + ctx.args[1].display = needle ret = _hay.find(needle) if ret != -1: @@ -604,8 +604,8 @@ class Msvcrt(api.ApiHandler): else: is_truncated = False - argv[0] = self.read_mem_string(strDest, 1) - argv[2] = self.read_mem_string(src, 1) + ctx.args[0].display = self.read_mem_string(strDest, 1) + ctx.args[2].display = self.read_mem_string(src, 1) slen1 = self.mem_string_len(strDest, 1) rem = num - slen1 @@ -639,7 +639,10 @@ class Msvcrt(api.ApiHandler): vargs = self.va_args(va_list, fmt_cnt) fin = self.do_str_format(fmt_str, vargs) - argv[:] = [opts, stream, fin] + ctx.args.clear() + ctx.args.append(hex(opts)) + ctx.args.append(hex(stream)) + ctx.args.append(fin) rv = len(fin) return rv @@ -658,14 +661,16 @@ class Msvcrt(api.ApiHandler): fmt_cnt = self.get_va_arg_count(fmt_str) if not fmt_cnt: - argv.clear() - argv.extend([stream, fmt_str]) + ctx.args.clear() + ctx.args.append(hex(stream)) + ctx.args.append(fmt_str) return len(fmt_str) _argv = emu.get_func_argv(e_arch.CALL_CONV_CDECL, 2 + fmt_cnt)[2:] fin = self.do_str_format(fmt_str, _argv) - argv.clear() - argv.extend([stream, fin]) + ctx.args.clear() + ctx.args.append(hex(stream)) + ctx.args.append(fin) return len(fin) @apihook("printf", argc=e_arch.VAR_ARGS, conv=e_arch.CALL_CONV_CDECL) @@ -681,14 +686,14 @@ class Msvcrt(api.ApiHandler): fmt_cnt = self.get_va_arg_count(fmt_str) if not fmt_cnt: - argv.clear() - argv.extend([fmt_str]) + ctx.args.clear() + ctx.args.append(fmt_str) return len(fmt_str) fmt_argv = emu.get_func_argv(e_arch.CALL_CONV_CDECL, 1 + fmt_cnt)[1:] fin = self.do_str_format(fmt_str, fmt_argv) - argv.clear() - argv.extend([fin]) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @apihook("memset", argc=3, conv=e_arch.CALL_CONV_CDECL) @@ -782,8 +787,8 @@ class Msvcrt(api.ApiHandler): fin = self.do_str_format(fmt_str, _argv) self.write_string(fin, buf) - argv.clear() - argv.append(fin) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @apihook("_snprintf", argc=e_arch.VAR_ARGS, conv=e_arch.CALL_CONV_CDECL) @@ -807,8 +812,8 @@ class Msvcrt(api.ApiHandler): fin = self.do_str_format(fmt_str, _argv) self.write_string(fin, buf) - argv.clear() - argv.append(fin) + ctx.args.clear() + ctx.args.append(fin) return len(fin) @apihook("atoi", argc=1, conv=e_arch.CALL_CONV_CDECL) @@ -822,7 +827,7 @@ class Msvcrt(api.ApiHandler): (_str,) = argv i = self.read_string(_str) - argv[0] = i + ctx.args[0].display = i try: rv = int(i) @@ -898,7 +903,7 @@ class Msvcrt(api.ApiHandler): s = self.read_string(src) self.write_string(s, dest) - argv[1] = s + ctx.args[1].display = s return dest @apihook("wcscpy", argc=2, conv=e_arch.CALL_CONV_CDECL) @@ -912,7 +917,7 @@ class Msvcrt(api.ApiHandler): dest, src = argv ws = self.read_wide_string(src) self.write_wide_string(ws, dest) - argv[1] = ws + ctx.args[1].display = ws return dest @apihook("strncpy", argc=3, conv=e_arch.CALL_CONV_CDECL) @@ -929,7 +934,7 @@ class Msvcrt(api.ApiHandler): if len(s) < length: s += "\x00" * (length - len(s)) self.write_string(s, dest) - argv[1] = s + ctx.args[1].display = s return dest @apihook("wcsncpy", argc=3, conv=e_arch.CALL_CONV_CDECL) @@ -946,7 +951,7 @@ class Msvcrt(api.ApiHandler): if len(ws) < count: ws += "\x00" * (count - len(ws)) self.write_wide_string(ws, dest) - argv[1] = ws + ctx.args[1].display = ws return dest @apihook("memcpy", argc=3, conv=e_arch.CALL_CONV_CDECL) @@ -1118,7 +1123,7 @@ class Msvcrt(api.ApiHandler): (s,) = argv string = self.read_mem_string(s, 1) - argv[0] = string + ctx.args[0].display = string rv = len(string) return rv @@ -1233,7 +1238,7 @@ class Msvcrt(api.ApiHandler): (s,) = argv string = self.read_mem_string(s, 1) - argv[0] = string + ctx.args[0].display = string rv = len(string) return rv @@ -1246,7 +1251,6 @@ class Msvcrt(api.ApiHandler): ); """ (c,) = argv - argv[0] = c if 0x00 <= c <= 0x7F: c = ord(chr(c).upper()) else: @@ -1263,7 +1267,7 @@ class Msvcrt(api.ApiHandler): (s,) = argv string = self.read_mem_string(s, 1) - argv[0] = string + ctx.args[0].display = string rv = len(string) return rv @@ -1279,8 +1283,8 @@ class Msvcrt(api.ApiHandler): _str1, _str2 = argv s1 = self.read_mem_string(_str1, 1) s2 = self.read_mem_string(_str2, 1) - argv[0] = s1 - argv[1] = s2 + ctx.args[0].display = s1 + ctx.args[1].display = s2 new = (s1 + s2).encode("utf-8") self.mem_write(_str1, new + b"\x00") return _str1 @@ -1298,7 +1302,7 @@ class Msvcrt(api.ApiHandler): return 0 string = self.read_string(string_ptr) - argv[0] = string + ctx.args[0].display = string self.write_string(string.lower(), string_ptr) return string_ptr @@ -1314,8 +1318,8 @@ class Msvcrt(api.ApiHandler): dest, src, count = argv s1 = self.read_mem_string(dest, 1) s2 = self.read_string(src, max_chars=count) - argv[0] = s1 - argv[1] = s2 + ctx.args[0].display = s1 + ctx.args[1].display = s2 new = (s1 + s2).encode("utf-8") self.mem_write(dest, new + b"\x00") return dest @@ -1331,8 +1335,8 @@ class Msvcrt(api.ApiHandler): _str1, _str2 = argv s1 = self.read_mem_string(_str1, 2) s2 = self.read_mem_string(_str2, 2) - argv[0] = s1 - argv[1] = s2 + ctx.args[0].display = s1 + ctx.args[1].display = s2 new = (s1 + s2).encode("utf-16le") self.mem_write(_str1, new + b"\x00\x00") return _str1 @@ -1346,7 +1350,7 @@ class Msvcrt(api.ApiHandler): """ (s,) = argv string = self.read_wide_string(s) - argv[0] = string + ctx.args[0].display = string rv = len(string) return rv @@ -1420,8 +1424,8 @@ class Msvcrt(api.ApiHandler): string2 = self.read_mem_string(s2, 1) if string1 == string2: rv = 0 - argv[0] = string1 - argv[1] = string2 + ctx.args[0].display = string1 + ctx.args[1].display = string2 return rv @@ -1440,8 +1444,8 @@ class Msvcrt(api.ApiHandler): string2 = self.read_mem_string(s2, 1) if string1 == string2: rv = 0 - argv[0] = string1 - argv[1] = string2 + ctx.args[0].display = string1 + ctx.args[1].display = string2 return rv @@ -1464,8 +1468,8 @@ class Msvcrt(api.ApiHandler): else: rv = cstr + offset - argv[0] = cs - argv[1] = needle.decode("utf-8") + ctx.args[0].display = cs + ctx.args[1].display = needle.decode("utf-8") return rv @@ -1528,8 +1532,8 @@ class Msvcrt(api.ApiHandler): else: rv = cstr + offset - argv[0] = cs - argv[1] = needle.decode("utf-8") + ctx.args[0].display = cs + ctx.args[1].display = needle.decode("utf-8") return rv @@ -1585,8 +1589,8 @@ class Msvcrt(api.ApiHandler): rv = len(fin) self.mem_write(buffer, fin.encode("utf-8")) - argv[0] = fin.replace("\x00", "") - argv[1] = fmt_str + ctx.args[0].display = fin.replace("\x00", "") + ctx.args[1].display = fmt_str return rv @@ -1614,8 +1618,8 @@ class Msvcrt(api.ApiHandler): rv = len(fin) self.mem_write(buffer, fin.encode("utf-8")) - argv[0] = fin.replace("\x00", "") - argv[1] = fmt_str + ctx.args[0].display = fin.replace("\x00", "") + ctx.args[1].display = fmt_str return rv @@ -1636,8 +1640,8 @@ class Msvcrt(api.ApiHandler): cs1 = self.read_string(string1) cs2 = self.read_string(string2) - argv[0] = cs1 - argv[1] = cs2 + ctx.args[0].display = cs1 + ctx.args[1].display = cs2 if cs1.lower() == cs2.lower(): rv = 0 @@ -1661,8 +1665,8 @@ class Msvcrt(api.ApiHandler): cs1 = self.read_wide_string(string1) cs2 = self.read_wide_string(string2) - argv[0] = cs1 - argv[1] = cs2 + ctx.args[0].display = cs1 + ctx.args[1].display = cs2 if cs1.lower() == cs2.lower(): rv = 0 @@ -1817,8 +1821,8 @@ class Msvcrt(api.ApiHandler): cs1 = self.read_string(string1) cs2 = self.read_string(string2) - argv[0] = cs1 - argv[1] = cs2 + ctx.args[0].display = cs1 + ctx.args[1].display = cs2 if cs1.lower() == cs2.lower(): rv = 0 @@ -1843,8 +1847,8 @@ class Msvcrt(api.ApiHandler): cs1 = self.read_string(string1) cs2 = self.read_string(string2) - argv[0] = cs1 - argv[1] = cs2 + ctx.args[0].display = cs1 + ctx.args[1].display = cs2 if cs1[:count].lower() == cs2[:count].lower(): rv = 0 @@ -1865,8 +1869,8 @@ class Msvcrt(api.ApiHandler): ws1 = self.read_wide_string(string1) ws2 = self.read_wide_string(string2) - argv[0] = ws1 - argv[1] = ws2 + ctx.args[0].display = ws1 + ctx.args[1].display = ws2 if ws1.lower() == ws2.lower(): rv = 0 @@ -1888,8 +1892,8 @@ class Msvcrt(api.ApiHandler): string2 = self.read_wide_string(s2) if string1 == string2: rv = 0 - argv[0] = string1 - argv[1] = string2 + ctx.args[0].display = string1 + ctx.args[1].display = string2 return rv @@ -1917,9 +1921,6 @@ class Msvcrt(api.ApiHandler): fin = self.do_str_format(fmt_str, argv) self.write_wide_string(fin, buf) - - argv = [buf, cnt, fmt] + argv - argv[2] = fmt_str return len(fin) @apihook("_errno", argc=0) @@ -1949,8 +1950,8 @@ class Msvcrt(api.ApiHandler): path = self.read_string(filename) mode_str = self.read_string(mode) - argv[0] = path - argv[1] = mode_str + ctx.args[0].display = path + ctx.args[1].display = mode_str create = any(flag in mode_str for flag in ("w", "a", "+")) truncate = "w" in mode_str and "a" not in mode_str @@ -1980,8 +1981,8 @@ class Msvcrt(api.ApiHandler): path = self.read_wide_string(filename) mode_str = self.read_wide_string(mode) - argv[0] = path - argv[1] = mode_str + ctx.args[0].display = path + ctx.args[1].display = mode_str create = any(flag in mode_str for flag in ("w", "a", "+")) truncate = "w" in mode_str and "a" not in mode_str @@ -2022,9 +2023,7 @@ class Msvcrt(api.ApiHandler): """ stream, offset, origin = argv hfile = self.file_streams.get(stream) - argv[0] = hfile or 0 - argv[1] = offset - argv[2] = origin + ctx.args[0].display = hex(hfile or 0) if hfile is None: return -1 @@ -2044,7 +2043,7 @@ class Msvcrt(api.ApiHandler): """ (stream,) = argv hfile = self.file_streams.get(stream) - argv[0] = hfile or 0 + ctx.args[0].display = hex(hfile or 0) if hfile is None: return -1 @@ -2069,7 +2068,7 @@ class Msvcrt(api.ApiHandler): """ ptr, size, count, stream = argv hfile = self.file_streams.get(stream) - argv[3] = hfile or 0 + ctx.args[3].display = hex(hfile or 0) if not ptr or size == 0 or count == 0 or hfile is None: return 0 diff --git a/speakeasy/winenv/api/usermode/ncrypt.py b/speakeasy/winenv/api/usermode/ncrypt.py index b124515..8d99234 100644 --- a/speakeasy/winenv/api/usermode/ncrypt.py +++ b/speakeasy/winenv/api/usermode/ncrypt.py @@ -36,7 +36,7 @@ class Ncrypt(api.ApiHandler): phProvider, pszProviderName, dwFlags = argv if pszProviderName: prov_str = self.read_wide_string(pszProviderName) - argv[1] = prov_str + ctx.args["pszProviderName"].display = prov_str cm = emu.get_crypt_manager() hnd = cm.crypt_open(pname=prov_str, flags=dwFlags) @@ -61,15 +61,15 @@ class Ncrypt(api.ApiHandler): """ hProvider, hImportKey, pszBlobType, pParameterList, phKey, pbData, cbData, dwFlags = argv blob_type = self.read_wide_string(pszBlobType) - argv[2] = blob_type + ctx.args["pszBlobType"].display = blob_type blob = self.mem_read(pbData, cbData) - argv[5] = base64.b64encode(blob).decode("utf-8") + ctx.args["pbData"].display = base64.b64encode(blob).decode("utf-8") cm = emu.get_crypt_manager() if hProvider and phKey: - ctx = cm.crypt_get(hProvider) - hnd = ctx.import_key( + prov_ctx = cm.crypt_get(hProvider) + hnd = prov_ctx.import_key( blob_type=blob_type, blob=blob, blob_len=cbData, @@ -92,10 +92,10 @@ class Ncrypt(api.ApiHandler): """ hKey, dwFlags = argv cm = emu.get_crypt_manager() - for hnd, ctx in cm.ctx_handles.items(): - hnd_key = ctx.get_key(hKey) + for hnd, crypt_ctx in cm.ctx_handles.items(): + hnd_key = crypt_ctx.get_key(hKey) if hnd_key: - ctx.delete_key(hKey) + crypt_ctx.delete_key(hKey) break return windefs.ERROR_SUCCESS @@ -111,12 +111,12 @@ class Ncrypt(api.ApiHandler): cm = emu.get_crypt_manager() # hObject can be a handle to a provider or key - for hnd, ctx in cm.ctx_handles.items(): + for hnd, crypt_ctx in cm.ctx_handles.items(): if hnd == hObject: cm.crypt_close(hObject) break - elif ctx.get_key(hObject): - ctx.delete_key(hObject) + elif crypt_ctx.get_key(hObject): + crypt_ctx.delete_key(hObject) break return windefs.ERROR_SUCCESS diff --git a/speakeasy/winenv/api/usermode/netapi32.py b/speakeasy/winenv/api/usermode/netapi32.py index 1d8170e..ef7ffcc 100644 --- a/speakeasy/winenv/api/usermode/netapi32.py +++ b/speakeasy/winenv/api/usermode/netapi32.py @@ -32,16 +32,16 @@ class NetApi32(api.ApiHandler): if lpServer: server = self.read_wide_string(lpServer) - argv[0] = server + ctx.args["lpServer"].display = server # Assumes the server being queried is the local computer domain = emu.config.domain - argv[1] = domain + ctx.args["lpNameBuffer"].display = domain namebuf = self.mem_alloc(emu.get_ptr_size()) self.write_wide_string(domain, namebuf) self.mem_write(lpNameBuffer, namebuf.to_bytes(emu.get_ptr_size(), "little")) - argv[2] = netapi32defs.NetSetupDomainName + ctx.args["BufferType"].display = hex(netapi32defs.NetSetupDomainName) self.mem_write(BufferType, netapi32defs.NetSetupDomainName.to_bytes(4, "little")) return netapi32defs.NERR_Success @@ -120,7 +120,7 @@ class NetApi32(api.ApiHandler): if servername: server = self.read_wide_string(servername) - argv[0] = server + ctx.args["servername"].display = server return netapi32defs.NERR_Success diff --git a/speakeasy/winenv/api/usermode/ntdll.py b/speakeasy/winenv/api/usermode/ntdll.py index 0b8cb79..cc966a6 100644 --- a/speakeasy/winenv/api/usermode/ntdll.py +++ b/speakeasy/winenv/api/usermode/ntdll.py @@ -116,10 +116,10 @@ class Ntdll(api.ApiHandler): pretty_flags = " | ".join([name for bit, name in flags.items() if LoadFlags & bit]) if SearchPath: - argv[0] = self.read_mem_string(SearchPath, 2) + ctx.args["DllPath"].display = self.read_mem_string(SearchPath, 2) - argv[2] = req_lib - argv[1] = pretty_flags + ctx.args["DllName"].display = req_lib + ctx.args["DllCharacteristics"].display = pretty_flags if not hmod: STATUS_DLL_NOT_FOUND = 0xC0000135 @@ -149,7 +149,7 @@ class Ntdll(api.ApiHandler): fn = self.mem_cast(fn, proc_name) proc = self.read_mem_string(fn.Buffer, 1, max_chars=fn.Length) - argv[1] = proc + ctx.args["ProcedureName"].display = proc elif ordinal: proc = f"ordinal_{proc_name}" diff --git a/speakeasy/winenv/api/usermode/ole32.py b/speakeasy/winenv/api/usermode/ole32.py index 19726f2..a0b7882 100644 --- a/speakeasy/winenv/api/usermode/ole32.py +++ b/speakeasy/winenv/api/usermode/ole32.py @@ -86,11 +86,11 @@ class Ole32(api.ApiHandler): authn_level = com.get_define_int(argv[4]) if authn_level: - argv[4] = authn_level + ctx.args["dwAuthnLevel"].display = authn_level imp_level = com.get_define_int(argv[5]) if imp_level: - argv[5] = imp_level + ctx.args["dwImpLevel"].display = imp_level return rv @@ -112,12 +112,12 @@ class Ole32(api.ApiHandler): clsid_str = com.convert_guid_bytes_to_str(clsid_bytes) clsid_name = com.get_clsid(clsid_str) if clsid_name: - argv[0] = clsid_name + ctx.args["rclsid"].display = clsid_name riid_bytes = self.mem_read(riid, self.sizeof(windefs.GUID())) riid_str = com.convert_guid_bytes_to_str(riid_bytes) iid_name = com.get_iid(riid_str) if iid_name: - argv[3] = iid_name + ctx.args["riid"].display = iid_name if ppv: ci = emu.com.get_interface(emu, emu.get_ptr_size(), iid_name.replace("IID_", "")) pv = self.mem_alloc(emu.get_ptr_size(), tag=f"emu.COM.pv_{iid_name}") @@ -160,7 +160,7 @@ class Ole32(api.ApiHandler): guid = self.mem_read(rclsid, self.sizeof(windefs.GUID())) u = com.convert_guid_bytes_to_str(guid) - argv[1] = u + ctx.args["lplpsz"].display = u u = (u + "\x00").encode("utf-16le") ptr = self.mem_alloc(len(u), tag="api.StringFromCLSID") diff --git a/speakeasy/winenv/api/usermode/oleaut32.py b/speakeasy/winenv/api/usermode/oleaut32.py index dc93872..36e3410 100644 --- a/speakeasy/winenv/api/usermode/oleaut32.py +++ b/speakeasy/winenv/api/usermode/oleaut32.py @@ -24,7 +24,7 @@ class OleAut32(api.ApiHandler): (psz,) = argv alloc_str = self.read_mem_string(psz, 2) if alloc_str: - argv[0] = alloc_str + ctx.args["psz"].display = alloc_str alloc_str += "\x00" ws = alloc_str.encode("utf-16le") ws_len = len(ws) @@ -58,7 +58,7 @@ class OleAut32(api.ApiHandler): else: alloc_str = self.read_mem_string(strin, 2) if alloc_str: - argv[0] = alloc_str + ctx.args["strIn"].display = alloc_str alloc_str = alloc_str[:ui] alloc_str += "\x00" ws = alloc_str.encode("utf-16le") @@ -86,7 +86,7 @@ class OleAut32(api.ApiHandler): ws = b"\x00" * (ui * 2) if psz: ws = self.mem_read(psz, ui * 2) - argv[1] = ws.decode("utf-16le", errors="replace") + ctx.args["psz"].display = ws.decode("utf-16le", errors="replace") bstr = self.mem_alloc(4 + ui * 2 + 2) self.mem_write(bstr, struct.pack("= required: self.write_mem_string(cache_name, szFileName, cw) self.record_file_access_event(cache_name, FILE_CREATE) diff --git a/speakeasy/winenv/api/usermode/user32.py b/speakeasy/winenv/api/usermode/user32.py index 4db753e..0485748 100644 --- a/speakeasy/winenv/api/usermode/user32.py +++ b/speakeasy/winenv/api/usermode/user32.py @@ -335,12 +335,12 @@ class User32(api.ApiHandler): _, cn, wn, _, x, y, width, height, parent, menu, inst, param = argv if cn: cn = self.read_mem_string(cn, cw) - argv[1] = cn + ctx.args["lpClassName"].display = cn else: cn = None if wn: wn = self.read_mem_string(wn, cw) - argv[2] = wn + ctx.args["lpWindowName"].display = wn else: wn = None hnd = self.sessman.create_window(wn, cn) @@ -373,10 +373,10 @@ class User32(api.ApiHandler): if lpText: text = self.read_mem_string(lpText, cw) - argv[1] = text + ctx.args["lpText"].display = text if lpCaption: cap = self.read_mem_string(lpCaption, cw) - argv[2] = cap + ctx.args["lpCaption"].display = cap rv = IDCANCEL return rv @@ -394,7 +394,6 @@ class User32(api.ApiHandler): """ av = argv[:-1] rv = self.MessageBox(emu, av, ctx) - argv[:4] = av return rv @apihook("LoadString", argc=4) @@ -446,10 +445,7 @@ class User32(api.ApiHandler): encoded = encoded[: ccBufferMax * cw] emu.mem_write(lpBuffer, encoded) - if cw == 1: - argv[2] = s - else: - argv[2] = s + ctx.args["lpBuffer"].display = s return len(encoded) @@ -542,7 +538,7 @@ class User32(api.ApiHandler): cw = self.get_char_width(ctx) s = self.read_mem_string(lpString, cw) - argv[0] = s + ctx.args["lpString"].display = s return rv @@ -570,8 +566,8 @@ class User32(api.ApiHandler): self.write_mem_string(fin, buf, cw) - argv.append(fin) - argv.append(fmt_str) + ctx.args.append(fin) + ctx.args.append(fmt_str) return len(fin) @apihook("PeekMessage", argc=5) @@ -643,7 +639,7 @@ class User32(api.ApiHandler): hname = windefs.get_windowhook_flags(idHook) if hname: hname = hname[0] - argv[0] = hname + ctx.args["idHook"].display = hname hnd = self.get_handle() self.window_hooks.update({hnd: (idHook, lpfn, hmod)}) @@ -770,10 +766,10 @@ class User32(api.ApiHandler): cw = self.get_char_width(ctx) if lpClassName: cn = self.read_mem_string(lpClassName, cw) - argv[0] = cn + ctx.args["lpClassName"].display = cn if lpWindowName: wn = self.read_mem_string(lpWindowName, cw) - argv[1] = wn + ctx.args["lpWindowName"].display = wn return 0 @apihook("GetWindowText", argc=3) @@ -817,9 +813,9 @@ class User32(api.ApiHandler): vargs = self.va_args(va_list, fmt_cnt) fin = self.do_str_format(fmt_str, vargs) self.write_string(fin, buf) - argv.clear() - argv.append(fin) - argv.append(fmt_str) + ctx.args.clear() + ctx.args.append(fin) + ctx.args.append(fmt_str) return len(fin) @apihook("ReleaseDC", argc=2) @@ -963,7 +959,7 @@ class User32(api.ApiHandler): cw = self.get_char_width(ctx) if lpTemplateName: tname = self.read_mem_string(lpTemplateName, cw) - argv[1] = tname + ctx.args["lpTemplateName"].display = tname return rv @@ -1277,8 +1273,7 @@ class User32(api.ApiHandler): _str, cchLength = argv cw = self.get_char_width(ctx) val = self.read_mem_string(_str, cw, max_chars=cchLength) - argv[0] = val - argv[1] = cchLength + ctx.args["lpsz"].display = val self.write_mem_string(val.lower(), _str, cw) return cchLength @@ -1293,8 +1288,7 @@ class User32(api.ApiHandler): _str, cchLength = argv cw = self.get_char_width(ctx) val = self.read_mem_string(_str, cw, max_chars=cchLength) - argv[0] = val - argv[1] = cchLength + ctx.args["lpsz"].display = val self.write_mem_string(val.upper(), _str, cw) return cchLength @@ -1379,7 +1373,7 @@ class User32(api.ApiHandler): lpszDesktop, dwFlags, fInherit, dwDesiredAccess = argv cw = self.get_char_width(ctx) desktop = self.read_mem_string(lpszDesktop, cw) - argv[0] = desktop + ctx.args["lpszDesktop"].display = desktop return self.get_handle() @apihook("SetThreadDesktop", argc=1) diff --git a/speakeasy/winenv/api/usermode/winhttp.py b/speakeasy/winenv/api/usermode/winhttp.py index c943ad5..1fd3458 100644 --- a/speakeasy/winenv/api/usermode/winhttp.py +++ b/speakeasy/winenv/api/usermode/winhttp.py @@ -53,13 +53,13 @@ class WinHttp(api.ApiHandler): if ua: ua = self.read_mem_string(ua, 2) - argv[0] = ua + ctx.args["pszAgentW"].display = ua if proxy: proxy = self.read_mem_string(proxy, 2) - argv[2] = proxy + ctx.args["pszProxyW"].display = proxy if bypass: bypass = self.read_mem_string(bypass, 2) - argv[3] = bypass + ctx.args["pszProxyBypassW"].display = bypass conn = self.netman.new_wininet_inst(ua, access, proxy, bypass, flags) hnd = conn.get_handle() @@ -79,7 +79,7 @@ class WinHttp(api.ApiHandler): if server: server = self.read_mem_string(server, 2) - argv[1] = server + ctx.args["pswzServerName"].display = server wini = self.netman.get_wininet_object(hnd) @@ -107,22 +107,22 @@ class WinHttp(api.ApiHandler): if verb: verb = self.read_mem_string(verb, 2) - argv[1] = verb + ctx.args["pwszVerb"].display = verb if objname: objname = self.read_mem_string(objname, 2) - argv[2] = objname + ctx.args["pwszObjectName"].display = objname if ver: ver = self.read_mem_string(ver, 2) - argv[3] = ver + ctx.args["pwszVersion"].display = ver if ref: ref = self.read_mem_string(ref, 2) - argv[4] = ref + ctx.args["pwszReferrer"].display = ref if accepts: accepts = self.read_mem_string(accepts, 2) - argv[5] = accepts + ctx.args["ppwszAcceptTypes"].display = accepts defs = windefs.get_flag_defines(flags) - argv[6] = " | ".join(defs) + ctx.args["dwFlags"].display = " | ".join(defs) sess = self.netman.get_wininet_object(hnd) req = sess.new_request(verb, objname, ver, ref, accepts, defs, None) @@ -160,7 +160,7 @@ class WinHttp(api.ApiHandler): if url: url = self.read_mem_string(url, 2) - argv[1] = url + ctx.args["lpcwszUrl"].display = url return True @@ -200,7 +200,7 @@ class WinHttp(api.ApiHandler): if headers: headers = self.read_mem_string(headers, 2) - argv[1] = headers + ctx.args["lpszHeaders"].display = headers if lpOptional and dwOptionalLength: body = self.mem_read(lpOptional, dwOptionalLength) @@ -273,7 +273,7 @@ class WinHttp(api.ApiHandler): # url = self.read_mem_string(pwszUrl, dwUrlLength) if pwszUrl and lpUrlComponents: url = self.read_mem_string(pwszUrl, cw) - argv[0] = url + ctx.args["pwszUrl"].display = url rv = True uc = windefs.URL_COMPONENTS(emu.get_ptr_size()) @@ -312,9 +312,9 @@ class WinHttp(api.ApiHandler): hnd, headers, dwHeaderlen, dwModfier = argv headers = self.read_wide_string(headers, dwHeaderlen) - argv[1] = headers + ctx.args["lpszHeaders"].display = headers flags = windefs.get_header_info_winhttp(dwModfier) - argv[3] = " | ".join(flags) + ctx.args["dwModifiers"].display = " | ".join(flags) rv = 1 return rv @@ -334,7 +334,8 @@ class WinHttp(api.ApiHandler): hnd, dwInfoLevel, name, buffer, bufferLen, index = argv header_query = windefs.get_header_query(dwInfoLevel) - argv[2] = header_query + if header_query: + ctx.args["pwszName"].display = header_query if buffer == 0: emu.set_last_error(windefs.ERROR_INSUFFICIENT_BUFFER) @@ -343,11 +344,9 @@ class WinHttp(api.ApiHandler): # If program checks for WINHTTP_QUERY_STATUS_CODE and the buffer is set, write '200' to buffer if (header_query == windefs.WINHTTP_QUERY_STATUS_CODE) and (buffer != 0): self.mem_write(buffer, b"\x32\x00\x30\x00\x30\x00\x00\x00") - argv[3] = buffer self.mem_write(bufferLen, 8) - argv[4] = bufferLen - argv[5] = 0 + ctx.args["lpdwIndex"].display = hex(0) rv = 1 return rv diff --git a/speakeasy/winenv/api/usermode/wininet.py b/speakeasy/winenv/api/usermode/wininet.py index 9f970c8..7220851 100644 --- a/speakeasy/winenv/api/usermode/wininet.py +++ b/speakeasy/winenv/api/usermode/wininet.py @@ -53,13 +53,13 @@ class Wininet(api.ApiHandler): cw = self.get_char_width(ctx) if ua: ua = self.read_mem_string(ua, cw) - argv[0] = ua + ctx.args["lpszAgent"].display = ua if proxy: proxy = self.read_mem_string(proxy, cw) - argv[2] = proxy + ctx.args["lpszProxy"].display = proxy if bypass: bypass = self.read_mem_string(bypass, cw) - argv[3] = bypass + ctx.args["lpszProxyBypass"].display = bypass conn = self.netman.new_wininet_inst(ua, access, proxy, bypass, flags) hnd = conn.get_handle() @@ -84,13 +84,13 @@ class Wininet(api.ApiHandler): cw = self.get_char_width(ctx) if server: server = self.read_mem_string(server, cw) - argv[1] = server + ctx.args["lpszServerName"].display = server if user: user = self.read_mem_string(user, cw) - argv[3] = user + ctx.args["lpszUserName"].display = user if password: password = self.read_mem_string(password, cw) - argv[4] = password + ctx.args["lpszPassword"].display = password wini = self.netman.get_wininet_object(hnd) @@ -120,19 +120,19 @@ class Wininet(api.ApiHandler): cw = self.get_char_width(ctx) if verb: verb = self.read_mem_string(verb, cw) - argv[1] = verb + ctx.args["lpszVerb"].display = verb if objname: objname = self.read_mem_string(objname, cw) - argv[2] = objname + ctx.args["lpszObjectName"].display = objname if ver: ver = self.read_mem_string(ver, cw) - argv[3] = ver + ctx.args["lpszVersion"].display = ver if ref: ref = self.read_mem_string(ref, cw) - argv[4] = ref + ctx.args["lpszReferrer"].display = ref defs = windefs.get_flag_defines(flags) - argv[6] = " | ".join(defs) + ctx.args["dwFlags"].display = " | ".join(defs) sess = self.netman.get_wininet_object(hnd) req = sess.new_request(verb, objname, ver, ref, accepts, defs, dwctx) @@ -156,7 +156,7 @@ class Wininet(api.ApiHandler): if lpszUrl and lpUrlComponents: url = self.read_mem_string(lpszUrl, cw) - argv[0] = url + ctx.args["lpszUrl"].display = url rv = True uc = windefs.URL_COMPONENTS(emu.get_ptr_size()) @@ -213,7 +213,7 @@ class Wininet(api.ApiHandler): if lpdwFlags: self.mem_write(lpdwFlags, flags.to_bytes(4, "little")) - argv[0] = "INTERNET_CONNECTION_LAN" + ctx.args["lpdwFlags"].display = "INTERNET_CONNECTION_LAN" return rv @@ -235,7 +235,7 @@ class Wininet(api.ApiHandler): cw = self.get_char_width(ctx) if headers: headers = self.read_mem_string(headers, cw) - argv[1] = headers + ctx.args["lpszHeaders"].display = headers if lpOptional: body = self.mem_read(lpOptional, dwOptionalLength) @@ -282,7 +282,7 @@ class Wininet(api.ApiHandler): rv = False opt = windefs.get_option_define(dwOption) if opt: - argv[1] = opt + ctx.args["dwOption"].display = opt if dwOption == windefs.INTERNET_OPTION_SECURITY_FLAGS: if lpBuffer: @@ -335,7 +335,7 @@ class Wininet(api.ApiHandler): rv = False info_str = windefs.get_header_query(dwInfoLevel) if info_str: - argv[1] = info_str + ctx.args["dwInfoLevel"].display = info_str if not lpBuffer: emu.set_last_error(windefs.ERROR_INSUFFICIENT_BUFFER) if windefs.WINHTTP_QUERY_STATUS_CODE == dwInfoLevel: @@ -405,13 +405,13 @@ class Wininet(api.ApiHandler): cw = self.get_char_width(ctx) if lpszUrl: url = self.read_mem_string(lpszUrl, cw) - argv[1] = url + ctx.args["lpszUrl"].display = url if lpszHeaders: headers = self.read_mem_string(lpszHeaders, cw) - argv[2] = headers + ctx.args["lpszHeaders"].display = headers defs = windefs.get_flag_defines(dwFlags) - argv[4] = " | ".join(defs) + ctx.args["dwFlags"].display = " | ".join(defs) wini = self.netman.get_wininet_object(hInternet) if not wini: diff --git a/speakeasy/winenv/api/usermode/wkscli.py b/speakeasy/winenv/api/usermode/wkscli.py index ccb6372..d8195f3 100644 --- a/speakeasy/winenv/api/usermode/wkscli.py +++ b/speakeasy/winenv/api/usermode/wkscli.py @@ -31,16 +31,16 @@ class Wkscli(api.ApiHandler): if lpServer: server = self.read_wide_string(lpServer) - argv[0] = server + ctx.args["lpServer"].display = server # Assumes the server being queried is the local computer domain = emu.config.domain - argv[1] = domain + ctx.args["lpNameBuffer"].display = domain namebuf = self.mem_alloc(emu.get_ptr_size()) self.write_wide_string(domain, namebuf) self.mem_write(lpNameBuffer, namebuf.to_bytes(emu.get_ptr_size(), "little")) - argv[2] = netapi32defs.NetSetupDomainName + ctx.args["BufferType"].display = hex(netapi32defs.NetSetupDomainName) self.mem_write(BufferType, netapi32defs.NetSetupDomainName.to_bytes(4, "little")) return netapi32defs.NERR_Success diff --git a/speakeasy/winenv/api/usermode/ws2_32.py b/speakeasy/winenv/api/usermode/ws2_32.py index e72fa30..27ea0bf 100644 --- a/speakeasy/winenv/api/usermode/ws2_32.py +++ b/speakeasy/winenv/api/usermode/ws2_32.py @@ -90,8 +90,8 @@ class Ws2_32(api.ApiHandler): fd = sock.fd - argv[0] = fam_str - argv[1] = sock_str + ctx.args["af"].display = fam_str + ctx.args["type"].display = sock_str return fd @@ -151,8 +151,8 @@ class Ws2_32(api.ApiHandler): fd = sock.fd - argv[0] = fam_str - argv[1] = sock_str + ctx.args["af"].display = fam_str + ctx.args["type"].display = sock_str return fd @@ -167,7 +167,7 @@ class Ws2_32(api.ApiHandler): if a: a = self.read_mem_string(a, 1) - argv[0] = a + ctx.args["cp"].display = a try: rv = inet_aton(a) rv = int.from_bytes(rv, "little") @@ -227,15 +227,15 @@ class Ws2_32(api.ApiHandler): opt_level = winsock.get_define(level, "SOL_") if opt_level: - argv[1] = opt_level + ctx.args["level"].display = opt_level opt_name = winsock.get_define(optname, "SO_") if opt_name: - argv[2] = opt_name + ctx.args["optname"].display = opt_name if opt_name == "SO_RCVBUF" or opt_name == "SO_SNDBUF": opt_val = self.mem_read(optval, optlen) - argv[3] = struct.unpack(" None: ] +def test_handler_display_non_string_keeps_rendering() -> None: + args = _signature_args() + args["p2"].display = None + args["p0"].display = 0 + assert [(a.type, a.display) for a in args.get_report_args()] == [ + ("ptr", "0x1000"), + ("flags", "F_ONE"), + ("handle", "0x44"), + ] + + def test_handler_type_is_settable() -> None: args = api.HandlerArgs.from_slots([0x1000]) args[0].display = "C:\\x"