From 3be91f6407120d7821b5eacd653de92b246bce55 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 17:41:47 +0200 Subject: [PATCH 01/11] Implement ZwTerminateProcess --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index 364e6ea..e5547cf 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3232,3 +3232,22 @@ def RtlFreeHeap(self, emu, argv, ctx={}): self.mem_free(lpMem) return rv + + @apihook('ZwTerminateProcess', argc=2) + def ZwTerminateProcess(self, emu, argv, ctx={}): + ''' + NTSYSAPI NTSTATUS ZwTerminateProcess( + [in, optional] HANDLE ProcessHandle, + [in] NTSTATUS ExitStatus + ); + ''' + #Copied from TerminateProcess + hProcess, uExitCode = argv + rv = 0 + + proc = emu.get_object_from_handle(hProcess) + if not proc: + return rv + + emu.kill_process(proc) + rv = ddk.STATUS_SUCCESS From ca5b4a11d969554594785901ef8ce238f56e11d7 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 17:42:45 +0200 Subject: [PATCH 02/11] Implement ZwOpenProcess --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index e5547cf..b6437b0 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3251,3 +3251,26 @@ def ZwTerminateProcess(self, emu, argv, ctx={}): emu.kill_process(proc) rv = ddk.STATUS_SUCCESS + + @apihook('ZwOpenProcess', argc=4) + def ZwOpenProcess(self, emu, argv, ctx={}): + ''' + NTSYSAPI NTSTATUS ZwOpenProcess( + [out] PHANDLE ProcessHandle, + [in] ACCESS_MASK DesiredAccess, + [in] POBJECT_ATTRIBUTES ObjectAttributes, + [in, optional] PCLIENT_ID ClientId + + ); + ''' + rv = 0 + hnd, desAccess, pObject, pid = argv + proc = emu.get_object_from_handle(int.from_bytes(emu.mem_read(hnd, 4), "little")) + if proc: + emu.mem_write(hnd,(proc.get_id()).to_bytes(4, "little")) + rv = ddk.STATUS_SUCCESS + else: + emu.mem_write(hnd,(0).to_bytes(4, "little")) + rv = ddk.STATUS_INVALID_PARAMETER + return rv + From cbeaf2be815fa890cd699352b4bbbb51d9c501b8 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 17:43:50 +0200 Subject: [PATCH 03/11] Implement ZwDuplicateObject --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index b6437b0..97c65d8 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3274,3 +3274,35 @@ def ZwOpenProcess(self, emu, argv, ctx={}): rv = ddk.STATUS_INVALID_PARAMETER return rv + @apihook('ZwDuplicateObject', argc=7) + def ZwDuplicateObject (self, emu, argv, ctx={}): + ''' + NTSYSAPI NTSTATUS ZwDuplicateObject( + [in] HANDLE SourceProcessHandle, + [in] HANDLE SourceHandle, + [in, optional] HANDLE TargetProcessHandle, + [out, optional] PHANDLE TargetHandle, + [in] ACCESS_MASK DesiredAccess, + [in] ULONG HandleAttributes, + [in] ULONG Options + ); + ''' + #Based on DublicateTokenEx + (hsProccessHandle, hsHandle, htProcessHandle,htHandle, mask, attr, opt) = argv + rv = 0 + + obj = self.get_object_from_handle(hsHandle) + + if obj: + + new_token = emu.new_object(objman.Token) + hnd_new_token = new_token.get_handle() + + if phNewToken: + hnd = (htHandle).to_bytes(self.get_ptr_size(), 'little') + self.mem_write(htHandle, hnd) + rv = ddk.STATUS_SUCCESS + else: + rv = ddk.STATUS_INVALID_PARAMETER + + return rv \ No newline at end of file From 03fa133e68d5641bd126443a5e8f8793f9b83773 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 17:50:08 +0200 Subject: [PATCH 04/11] Multiple copies of basic string functions from msvcrt wcsstr towlower tolower strstr --- speakeasy/winenv/api/usermode/ntdll.py | 68 ++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/speakeasy/winenv/api/usermode/ntdll.py b/speakeasy/winenv/api/usermode/ntdll.py index 3371974..161076e 100644 --- a/speakeasy/winenv/api/usermode/ntdll.py +++ b/speakeasy/winenv/api/usermode/ntdll.py @@ -333,4 +333,72 @@ def LdrAccessResource(self, emu, argv, ctx={}): self.mem_write(Resource, offset.to_bytes(4, 'little')) return 0 + @apihook('wcsstr', argc=2,conv=e_arch.CALL_CONV_CDECL) + def wcsstr(self, emu, argv, ctx={}): + """ + wchar_t *wcsstr( + const wchar_t *str, + const wchar_t *strSearch + ); + """ + #Copied from msvcrt + hay, needle = argv + + if hay: + _hay = self.read_mem_string(hay, 2) + argv[0] = _hay + + if needle: + needle = self.read_mem_string(needle, 2) + argv[1] = needle + + ret = _hay.find(needle) + if ret != -1: + ret = hay + ret + else: + ret = 0 + return ret + + @apihook('towlower', argc=1,conv=e_arch.CALL_CONV_CDECL) + def towlower(self, emu, argv, ctx={}): + """ + int tolower ( int c ); + """ + #Copied from msvcrt + c, = argv + return c | 0x20 + + @apihook('tolower', argc=1,conv=e_arch.CALL_CONV_CDECL) + def tolower(self, emu, argv, ctx={}): + """ + int tolower ( int c ); + """ + #Copied from msvcrt + c, = argv + return c | 0x20 + + @apihook('strstr', argc=2, conv=e_arch.CALL_CONV_CDECL) + def strstr(self, emu, argv, ctx={}): + """ + char *strstr( + const char *str, + const char *strSearch + ); + """ + #Copied from msvcrt + hay, needle = argv + if hay: + _hay = self.read_mem_string(hay, 1) + argv[0] = _hay + + if needle: + needle = self.read_mem_string(needle, 1) + argv[1] = needle + + ret = _hay.find(needle) + if ret != -1: + ret = hay + ret + else: + ret = 0 + return ret From e202e05ab4e8263f00bcb9ef49b9c15d1e610a81 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 18:06:41 +0200 Subject: [PATCH 05/11] Multiple copies of basic string functions from msvcrt wcsstr towlower tolower strstr --- speakeasy/winenv/api/usermode/ntdll.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/speakeasy/winenv/api/usermode/ntdll.py b/speakeasy/winenv/api/usermode/ntdll.py index 161076e..c1fb308 100644 --- a/speakeasy/winenv/api/usermode/ntdll.py +++ b/speakeasy/winenv/api/usermode/ntdll.py @@ -8,7 +8,7 @@ import speakeasy.winenv.defs.nt.ddk as ddk import speakeasy.winenv.defs.nt.ntoskrnl as ntos import speakeasy.windows.common as winemu - +import speakeasy.winenv.arch as e_arch class Ntdll(api.ApiHandler): @@ -333,6 +333,7 @@ def LdrAccessResource(self, emu, argv, ctx={}): self.mem_write(Resource, offset.to_bytes(4, 'little')) return 0 + @apihook('wcsstr', argc=2,conv=e_arch.CALL_CONV_CDECL) def wcsstr(self, emu, argv, ctx={}): """ @@ -401,4 +402,4 @@ def strstr(self, emu, argv, ctx={}): else: ret = 0 return ret - + From 09ff9cad9e30cd3c9b439418a02027dcc3ac1640 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 18:10:54 +0200 Subject: [PATCH 06/11] Implement ShellExecuteExW based on ShellExecute --- speakeasy/winenv/api/usermode/shell32.py | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/speakeasy/winenv/api/usermode/shell32.py b/speakeasy/winenv/api/usermode/shell32.py index eb2b683..b447cc4 100644 --- a/speakeasy/winenv/api/usermode/shell32.py +++ b/speakeasy/winenv/api/usermode/shell32.py @@ -261,3 +261,45 @@ def SHGetFolderPath(self, emu, argv, ctx={}): emu.write_mem_string(path, pszPath, self.get_char_width(ctx)) return 0 + + + @apihook('ShellExecuteExW', argc=1) + def ShellExecuteExW(self, emu, argv, ctx={}): + ''' + BOOL ShellExecuteExW( + [in, out] SHELLEXECUTEINFOW *pExecInfo + ); + ''' + #Based on ShellExecute + pExecInfo, = argv + + cw = self.get_char_width(ctx) + + fn = '' + param = '' + dn = '' + + p_op = int.from_bytes(self.mem_read(pExecInfo + 0xC, 4), "little") + if p_op: + op = self.read_mem_string(p_op, cw) + print(op) + p_fn = int.from_bytes(self.mem_read(pExecInfo + 0x10, 4), "little") + if p_fn: + fn = self.read_mem_string(p_fn, cw) + print(fn) + p_param = int.from_bytes(self.mem_read(pExecInfo + 0x14, 4),"little") + if p_param: + param = self.read_mem_string(p_param, cw) + print(param) + p_dn = int.from_bytes(self.mem_read(pExecInfo + 0x18,4), "little") + if p_dn: + dn = self.read_mem_string(p_dn, cw) + print(dn) + + if dn and fn: + fn = '%s\\%s' % (dn, fn) + + proc = emu.create_process(path=fn, cmdline=param) + self.log_process_event(proc, PROC_CREATE) + + return 33 \ No newline at end of file From 6ce7c0b42bbd1484f0df16d5412fae0106e20023 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 19:43:06 +0200 Subject: [PATCH 07/11] fix tab --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index fbec9d4..2a4744b 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3263,7 +3263,7 @@ def ZwOpenProcess(self, emu, argv, ctx={}): ); ''' - rv = 0 + rv = 0 hnd, desAccess, pObject, pid = argv proc = emu.get_object_from_handle(int.from_bytes(emu.mem_read(hnd, 4), "little")) if proc: From d042fe0722ebebd143d99d67bd8a0ef890706a1c Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 19:45:32 +0200 Subject: [PATCH 08/11] Fix bug where if hnd is null the STATUS_INVALID_HANDLE is not returned leading to memory access errors --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index 2a4744b..745da03 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -2658,7 +2658,7 @@ def ZwOpenKey(self, emu, argv, ctx={}): hnd = self.reg_open_key(name, create=False) if not hnd: - rv = ddk.STATUS_INVALID_HANDLE + return ddk.STATUS_INVALID_HANDLE if phnd: self.mem_write(phnd, hnd.to_bytes(self.get_ptr_size(), 'little')) From fe5d6a979b7fc81f3835bd0a96dd144ab2d08ecf Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 19:51:23 +0200 Subject: [PATCH 09/11] fix error --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index 745da03..eb4e4e8 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -11,6 +11,7 @@ import speakeasy.winenv.defs.registry.reg as regdefs import speakeasy.winenv.defs.windows.windows as windefs import speakeasy.winenv.defs.nt.ntoskrnl as ntos +import speakeasy.windows.objman as objman from speakeasy.const import FILE_OPEN, FILE_WRITE, FILE_READ, MEM_WRITE from speakeasy.errors import ApiEmuError from speakeasy.winenv.api import api From f63524683884242b6841a399989b01c748740945 Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 19:58:04 +0200 Subject: [PATCH 10/11] fix error --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index eb4e4e8..9fd5b3a 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3299,7 +3299,7 @@ def ZwDuplicateObject (self, emu, argv, ctx={}): new_token = emu.new_object(objman.Token) hnd_new_token = new_token.get_handle() - if phNewToken: + if hnd_new_token: hnd = (htHandle).to_bytes(self.get_ptr_size(), 'little') self.mem_write(htHandle, hnd) rv = ddk.STATUS_SUCCESS From c0682c33236c2cc281998a6977bb45fd0d38bedb Mon Sep 17 00:00:00 2001 From: stonerhash Date: Fri, 17 Feb 2023 22:31:44 +0200 Subject: [PATCH 11/11] Fix for initial incorrect implementation of ZwOpenProcess. --- speakeasy/winenv/api/kernelmode/ntoskrnl.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/speakeasy/winenv/api/kernelmode/ntoskrnl.py b/speakeasy/winenv/api/kernelmode/ntoskrnl.py index 9fd5b3a..4b2a184 100644 --- a/speakeasy/winenv/api/kernelmode/ntoskrnl.py +++ b/speakeasy/winenv/api/kernelmode/ntoskrnl.py @@ -3264,11 +3264,15 @@ def ZwOpenProcess(self, emu, argv, ctx={}): ); ''' - rv = 0 - hnd, desAccess, pObject, pid = argv - proc = emu.get_object_from_handle(int.from_bytes(emu.mem_read(hnd, 4), "little")) - if proc: - emu.mem_write(hnd,(proc.get_id()).to_bytes(4, "little")) + (hnd, desAccess, pObject, cid) = argv + if not cid: + return ddk.STATUS_INVALID_PARAMETER + cid_obj = self.win.CLIENT_ID(emu.get_ptr_size()) + cid_obj = emu.mem_cast(cid_obj, cid) + oProc = emu.get_object_from_id(cid_obj.UniqueProcess) + hProc = emu.get_object_handle(oProc) + if hProc: + emu.mem_write(hnd,(hProc).to_bytes(4, "little")) rv = ddk.STATUS_SUCCESS else: emu.mem_write(hnd,(0).to_bytes(4, "little"))