diff options
Diffstat (limited to 'src/miasm/os_dep/win_api_x86_32.py')
| -rw-r--r-- | src/miasm/os_dep/win_api_x86_32.py | 3595 |
1 files changed, 3595 insertions, 0 deletions
diff --git a/src/miasm/os_dep/win_api_x86_32.py b/src/miasm/os_dep/win_api_x86_32.py new file mode 100644 index 00000000..6e568abb --- /dev/null +++ b/src/miasm/os_dep/win_api_x86_32.py @@ -0,0 +1,3595 @@ +from __future__ import print_function +# +# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +from past.builtins import cmp +import struct +import os +import stat +import time +import string +import logging +from zlib import crc32 +from io import StringIO +import time +import datetime + +from future.utils import PY3, viewitems, viewvalues + +try: + from Crypto.Hash import MD5, SHA +except ImportError: + print("cannot find crypto, skipping") + +from miasm.jitter.csts import PAGE_READ, PAGE_WRITE, PAGE_EXEC +from miasm.core.utils import pck16, pck32, hexdump, whoami, int_to_byte +from miasm.os_dep.common import heap, windows_to_sbpath +from miasm.os_dep.common import set_win_str_w, set_win_str_a +from miasm.os_dep.common import get_fmt_args as _get_fmt_args +from miasm.os_dep.common import get_win_str_a, get_win_str_w +from miasm.os_dep.common import encode_win_str_a, encode_win_str_w +from miasm.os_dep.win_api_x86_32_seh import tib_address + +log = logging.getLogger("win_api_x86_32") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + +DATE_1601_TO_1970 = 116444736000000000 + +MAX_PATH = 260 + + +""" +typedef struct tagPROCESSENTRY32 { + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + TCHAR szExeFile[MAX_PATH]; +} PROCESSENTRY32, *PPROCESSENTRY32; +""" + + +ACCESS_DICT = {0x0: 0, + 0x1: 0, + 0x2: PAGE_READ, + 0x4: PAGE_READ | PAGE_WRITE, + 0x10: PAGE_EXEC, + 0x20: PAGE_EXEC | PAGE_READ, + 0x40: PAGE_EXEC | PAGE_READ | PAGE_WRITE, + 0x80: PAGE_EXEC | PAGE_READ | PAGE_WRITE, + # 0x80: PAGE_EXECUTE_WRITECOPY + 0x100: 0 + } + +ACCESS_DICT_INV = dict((x[1], x[0]) for x in viewitems(ACCESS_DICT)) + + +class whandle(object): + + def __init__(self, name, info): + self.name = name + self.info = info + + def __repr__(self): + return '<%r %r %r>' % (self.__class__.__name__, self.name, self.info) + + +class handle_generator(object): + + def __init__(self): + self.offset = 600 + self.all_handles = {} + + def add(self, name, info=None): + self.offset += 1 + h = whandle(name, info) + self.all_handles[self.offset] = h + + log.debug(repr(self)) + return self.offset + + def __repr__(self): + out = '<%r\n' % self.__class__.__name__ + ks = list(self.all_handles) + ks.sort() + + for k in ks: + out += " %r %r\n" % (k, self.all_handles[k]) + out += '>' + return out + + def __contains__(self, e): + return e in self.all_handles + + def __getitem__(self, item): + return self.all_handles.__getitem__(item) + + def __delitem__(self, item): + self.all_handles.__delitem__(item) + + +class c_winobjs(object): + + def __init__(self): + self.alloc_ad = 0x20000000 + self.alloc_align = 0x1000 + self.heap = heap() + self.handle_toolhelpsnapshot = 0xaaaa00 + self.toolhelpsnapshot_info = {} + self.handle_curprocess = 0xaaaa01 + self.dbg_present = 0 + self.tickcount = 0 + self.dw_pid_dummy1 = 0x111 + self.dw_pid_explorer = 0x222 + self.dw_pid_dummy2 = 0x333 + self.dw_pid_cur = 0x444 + self.module_fname_nux = None + self.module_name = "test.exe" + self.module_path = "c:\\mydir\\" + self.module_name + self.hcurmodule = None + self.module_filesize = None + self.getversion = 0x0A280105 + self.getforegroundwindow = 0x333333 + self.cryptcontext_hwnd = 0x44400 + self.cryptcontext_bnum = 0x44000 + self.cryptcontext_num = 0 + self.cryptcontext = {} + self.phhash_crypt_md5 = 0x55555 + # key used by EncodePointer and DecodePointer + # (kernel32) + self.ptr_encode_key = 0xabababab + self.files_hwnd = {} + self.windowlong_dw = 0x77700 + self.module_cur_hwnd = 0x88800 + self.module_file_nul = 0x999000 + self.runtime_dll = None + self.current_pe = None + self.tls_index = 0xf + self.tls_values = {} + self.handle_pool = handle_generator() + self.handle_mapped = {} + self.hkey_handles = { + 0x80000001: b"hkey_current_user", + 0x80000002: b"hkey_local_machine" + } + self.cur_dir = "c:\\tmp" + + self.nt_mdl = {} + self.nt_mdl_ad = None + self.nt_mdl_cur = 0 + self.win_event_num = 0x13370 + self.cryptdll_md5_h = {} + + self.lastwin32error = 0 + self.mutex = {} + self.env_variables = {} + self.events_pool = {} + self.find_data = None + + self.allocated_pages = {} + self.current_datetime = datetime.datetime( + year=2017, month=8, day=21, + hour=13, minute=37, + second=11, microsecond=123456 + ) + +winobjs = c_winobjs() + + +process_list = [ + [ + 0x40, # DWORD dwSize; + 0, # DWORD cntUsage; + winobjs.dw_pid_dummy1, # DWORD th32ProcessID; + 0x11111111, # ULONG_PTR th32DefaultHeapID; + 0x11111112, # DWORD th32ModuleID; + 1, # DWORD cntThreads; + winobjs.dw_pid_explorer, # DWORD th32ParentProcessID; + 0xbeef, # LONG pcPriClassBase; + 0x0, # DWORD dwFlags; + "dummy1.exe" # TCHAR szExeFile[MAX_PATH]; + ], + [ + 0x40, # DWORD dwSize; + 0, # DWORD cntUsage; + winobjs.dw_pid_explorer, # DWORD th32ProcessID; + 0x11111111, # ULONG_PTR th32DefaultHeapID; + 0x11111112, # DWORD th32ModuleID; + 1, # DWORD cntThreads; + 4, # DWORD th32ParentProcessID; + 0xbeef, # LONG pcPriClassBase; + 0x0, # DWORD dwFlags; + "explorer.exe" # TCHAR szExeFile[MAX_PATH]; + ], + + [ + 0x40, # DWORD dwSize; + 0, # DWORD cntUsage; + winobjs.dw_pid_dummy2, # DWORD th32ProcessID; + 0x11111111, # ULONG_PTR th32DefaultHeapID; + 0x11111112, # DWORD th32ModuleID; + 1, # DWORD cntThreads; + winobjs.dw_pid_explorer, # DWORD th32ParentProcessID; + 0xbeef, # LONG pcPriClassBase; + 0x0, # DWORD dwFlags; + "dummy2.exe" # TCHAR szExeFile[MAX_PATH]; + ], + + [ + 0x40, # DWORD dwSize; + 0, # DWORD cntUsage; + winobjs.dw_pid_cur, # DWORD th32ProcessID; + 0x11111111, # ULONG_PTR th32DefaultHeapID; + 0x11111112, # DWORD th32ModuleID; + 1, # DWORD cntThreads; + winobjs.dw_pid_explorer, # DWORD th32ParentProcessID; + 0xbeef, # LONG pcPriClassBase; + 0x0, # DWORD dwFlags; + winobjs.module_name # TCHAR szExeFile[MAX_PATH]; + ], + + +] + + +class hobj(object): + pass + + +class mdl(object): + + def __init__(self, ad, l): + self.ad = ad + self.l = l + + def __bytes__(self): + return struct.pack('LL', self.ad, self.l) + + def __str__(self): + if PY3: + return repr(self) + return self.__bytes__() + + +def kernel32_HeapAlloc(jitter): + ret_ad, args = jitter.func_args_stdcall(["heap", "flags", "size"]) + alloc_addr = winobjs.heap.alloc(jitter, args.size, cmt=hex(ret_ad)) + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def kernel32_HeapFree(jitter): + ret_ad, _ = jitter.func_args_stdcall(["heap", "flags", "pmem"]) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GlobalAlloc(jitter): + ret_ad, args = jitter.func_args_stdcall(["uflags", "msize"]) + alloc_addr = winobjs.heap.alloc(jitter, args.msize) + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def kernel32_LocalFree(jitter): + ret_ad, _ = jitter.func_args_stdcall(["lpvoid"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_LocalAlloc(jitter): + ret_ad, args = jitter.func_args_stdcall(["uflags", "msize"]) + alloc_addr = winobjs.heap.alloc(jitter, args.msize) + jitter.func_ret_stdcall(ret_ad, alloc_addr) + +def msvcrt_new(jitter): + ret_ad, args = jitter.func_args_cdecl(["size"]) + alloc_addr = winobjs.heap.alloc(jitter, args.size) + jitter.func_ret_cdecl(ret_ad, alloc_addr) + +globals()['msvcrt_??2@YAPAXI@Z'] = msvcrt_new + +def msvcrt_delete(jitter): + ret_ad, args = jitter.func_args_cdecl(["ptr"]) + jitter.func_ret_cdecl(ret_ad, 0) + +globals()['msvcrt_??3@YAXPAX@Z'] = msvcrt_delete + +def kernel32_GlobalFree(jitter): + ret_ad, _ = jitter.func_args_stdcall(["addr"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_IsDebuggerPresent(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.dbg_present) + + +def kernel32_CreateToolhelp32Snapshot(jitter): + ret_ad, _ = jitter.func_args_stdcall(["dwflags", "th32processid"]) + jitter.func_ret_stdcall(ret_ad, winobjs.handle_toolhelpsnapshot) + + +def kernel32_GetCurrentProcess(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.handle_curprocess) + + +def kernel32_GetCurrentProcessId(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.dw_pid_cur) + + +def kernel32_Process32First(jitter): + ret_ad, args = jitter.func_args_stdcall(["s_handle", "ad_pentry"]) + + pentry = struct.pack( + 'IIIIIIIII', *process_list[0][:-1] + ) + (process_list[0][-1] + '\x00').encode('utf8') + jitter.vm.set_mem(args.ad_pentry, pentry) + winobjs.toolhelpsnapshot_info[args.s_handle] = 0 + + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_Process32Next(jitter): + ret_ad, args = jitter.func_args_stdcall(["s_handle", "ad_pentry"]) + + winobjs.toolhelpsnapshot_info[args.s_handle] += 1 + if winobjs.toolhelpsnapshot_info[args.s_handle] >= len(process_list): + ret = 0 + else: + ret = 1 + n = winobjs.toolhelpsnapshot_info[args.s_handle] + pentry = struct.pack( + 'IIIIIIIII', *process_list[n][:-1]) + (process_list[n][-1]+ '\x00').encode('utf8') + jitter.vm.set_mem(args.ad_pentry, pentry) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetTickCount(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + winobjs.tickcount += 1 + jitter.func_ret_stdcall(ret_ad, winobjs.tickcount) + + +def kernel32_GetVersion(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.getversion) + + +def kernel32_GetVersionEx(jitter, str_size, encode_str): + ret_ad, args = jitter.func_args_stdcall(["ptr_struct"]) + + size = jitter.vm.get_u32(args.ptr_struct) + if size in [0x14+str_size, 0x1c+str_size]: + tmp = struct.pack( + "IIIII%dsHHHBB" % str_size, + 0x114, # struct size + 0x5, # maj vers + 0x2, # min vers + 0xa28, # build nbr + 0x2, # platform id + encode_str("Service pack 4"), + 3, # wServicePackMajor + 0, # wServicePackMinor + 0x100, # wSuiteMask + 1, # wProductType + 0 # wReserved + ) + tmp = tmp[:size] + jitter.vm.set_mem(args.ptr_struct, tmp) + ret = 1 + else: + ret = 0 + jitter.func_ret_stdcall(ret_ad, ret) + + +kernel32_GetVersionExA = lambda jitter: kernel32_GetVersionEx(jitter, 128, + encode_win_str_a) +kernel32_GetVersionExW = lambda jitter: kernel32_GetVersionEx(jitter, 256, + encode_win_str_w) + + +def kernel32_GetPriorityClass(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_SetPriorityClass(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd", "dwpclass"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_CloseHandle(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd"]) + jitter.func_ret_stdcall(ret_ad, 1) + +def kernel32_EncodePointer(jitter): + """ + PVOID EncodePointer( + _In_ PVOID Ptr + ); + + Encoding globally available pointers helps protect them from being + exploited. The EncodePointer function obfuscates the pointer value + with a secret so that it cannot be predicted by an external agent. + The secret used by EncodePointer is different for each process. + + A pointer must be decoded before it can be used. + + """ + ret, args = jitter.func_args_stdcall(1) + jitter.func_ret_stdcall(ret, args[0] ^ winobjs.ptr_encode_key) + return True + +def kernel32_DecodePointer(jitter): + """ + PVOID DecodePointer( + PVOID Ptr + ); + + The function returns the decoded pointer. + + """ + ret, args = jitter.func_args_stdcall(1) + jitter.func_ret_stdcall(ret, args[0] ^ winobjs.ptr_encode_key) + return True + +def user32_GetForegroundWindow(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.getforegroundwindow) + + +def user32_FindWindowA(jitter): + ret_ad, args = jitter.func_args_stdcall(["pclassname", "pwindowname"]) + if args.pclassname: + classname = get_win_str_a(jitter, args.pclassname) + log.info("FindWindowA classname %s", classname) + if args.pwindowname: + windowname = get_win_str_a(jitter, args.pwindowname) + log.info("FindWindowA windowname %s", windowname) + jitter.func_ret_stdcall(ret_ad, 0) + + +def user32_GetTopWindow(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def user32_BlockInput(jitter): + ret_ad, _ = jitter.func_args_stdcall(["blockit"]) + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptAcquireContext(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["phprov", "pszcontainer", + "pszprovider", "dwprovtype", + "dwflags"]) + prov = get_str(args.pszprovider) if args.pszprovider else "NONE" + log.debug('prov: %r', prov) + jitter.vm.set_u32(args.phprov, winobjs.cryptcontext_hwnd) + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptAcquireContextA(jitter): + advapi32_CryptAcquireContext(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def advapi32_CryptAcquireContextW(jitter): + advapi32_CryptAcquireContext(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def advapi32_CryptCreateHash(jitter): + ret_ad, args = jitter.func_args_stdcall(["hprov", "algid", "hkey", + "dwflags", "phhash"]) + + winobjs.cryptcontext_num += 1 + + if args.algid == 0x00008003: + log.debug('algo is MD5') + jitter.vm.set_u32( + args.phhash, + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num + ) + winobjs.cryptcontext[ + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num] = hobj() + winobjs.cryptcontext[ + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num].h = MD5.new() + elif args.algid == 0x00008004: + log.debug('algo is SHA1') + jitter.vm.set_u32( + args.phhash, + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num + ) + winobjs.cryptcontext[ + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num] = hobj() + winobjs.cryptcontext[ + winobjs.cryptcontext_bnum + winobjs.cryptcontext_num].h = SHA.new() + else: + raise ValueError('un impl algo1') + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptHashData(jitter): + ret_ad, args = jitter.func_args_stdcall(["hhash", "pbdata", "dwdatalen", + "dwflags"]) + + if not args.hhash in winobjs.cryptcontext: + raise ValueError("unknown crypt context") + + data = jitter.vm.get_mem(args.pbdata, args.dwdatalen) + log.debug('will hash %X', args.dwdatalen) + log.debug(repr(data[:0x10]) + "...") + winobjs.cryptcontext[args.hhash].h.update(data) + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptGetHashParam(jitter): + ret_ad, args = jitter.func_args_stdcall(["hhash", "param", "pbdata", + "dwdatalen", "dwflags"]) + + if not args.hhash in winobjs.cryptcontext: + raise ValueError("unknown crypt context") + + if args.param == 2: + # HP_HASHVAL + # XXX todo: save h state? + h = winobjs.cryptcontext[args.hhash].h.digest() + jitter.vm.set_mem(args.pbdata, h) + jitter.vm.set_u32(args.dwdatalen, len(h)) + elif args.param == 4: + # HP_HASHSIZE + ret = winobjs.cryptcontext[args.hhash].h.digest_size + jitter.vm.set_u32(args.pbdata, ret) + jitter.vm.set_u32(args.dwdatalen, 4) + else: + raise ValueError('not impl', args.param) + + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptReleaseContext(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hhash", "flags"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def advapi32_CryptDeriveKey(jitter): + ret_ad, args = jitter.func_args_stdcall(["hprov", "algid", "hbasedata", + "dwflags", "phkey"]) + + if args.algid == 0x6801: + log.debug('using DES') + else: + raise ValueError('un impl algo2') + h = winobjs.cryptcontext[args.hbasedata].h.digest() + log.debug('hash %r', h) + winobjs.cryptcontext[args.hbasedata].h_result = h + jitter.vm.set_u32(args.phkey, args.hbasedata) + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptDestroyHash(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hhash"]) + jitter.func_ret_stdcall(ret_ad, 1) + + +def advapi32_CryptDecrypt(jitter): + # ret_ad, _ = jitter.func_args_stdcall(["hkey", "hhash", "final", + # "dwflags", "pbdata", + # "pdwdatalen"]) + raise ValueError("Not implemented") + # jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_CreateFile(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["lpfilename", "access", + "dwsharedmode", + "lpsecurityattr", + "dwcreationdisposition", + "dwflagsandattr", + "htemplatefile"]) + if args.lpfilename == 0: + jitter.func_ret_stdcall(ret_ad, 0xffffffff) + return + + fname = get_str(args.lpfilename) + log.info('CreateFile fname %s', fname) + ret = 0xffffffff + + log.debug("%r %r", fname.lower(), winobjs.module_path.lower()) + is_original_file = fname.lower() == winobjs.module_path.lower() + + if fname.upper() in [r"\\.\SICE", r"\\.\NTICE", r"\\.\SIWVID", r'\\.\SIWDEBUG']: + pass + elif fname.upper() in ['NUL']: + ret = winobjs.module_cur_hwnd + else: + # sandbox path + sb_fname = windows_to_sbpath(fname) + if args.access & 0x80000000 or args.access == 1: + # read and maybe write + if args.dwcreationdisposition == 2: + # create_always + if os.access(sb_fname, os.R_OK): + # but file exist + pass + else: + raise NotImplementedError("Untested case") # to test + # h = open(sb_fname, 'rb+') + elif args.dwcreationdisposition == 3: + # open_existing + if os.access(sb_fname, os.R_OK): + s = os.stat(sb_fname) + if stat.S_ISDIR(s.st_mode): + ret = winobjs.handle_pool.add(sb_fname, 0x1337) + else: + open_mode = 'rb' + if (args.access & 0x40000000) or args.access == 2: + open_mode = 'r+b' + h = open(sb_fname, open_mode) + ret = winobjs.handle_pool.add(sb_fname, h) + else: + log.warning("FILE %r (%s) DOES NOT EXIST!", fname, sb_fname) + elif args.dwcreationdisposition == 1: + # create new + if os.access(sb_fname, os.R_OK): + # file exist + # ret = 80 + winobjs.lastwin32error = 80 + else: + # first create an empty file + open(sb_fname, 'wb').close() + # then open + h = open(sb_fname, 'r+b') + ret = winobjs.handle_pool.add(sb_fname, h) + elif args.dwcreationdisposition == 4: + # open_always + if os.access(sb_fname, os.R_OK): + s = os.stat(sb_fname) + if stat.S_ISDIR(s.st_mode): + ret = winobjs.handle_pool.add(sb_fname, 0x1337) + else: + h = open(sb_fname, 'r+b') + ret = winobjs.handle_pool.add(sb_fname, h) + else: + raise NotImplementedError("Untested case") + else: + raise NotImplementedError("Untested case") + elif (args.access & 0x40000000) or args.access == 2: + # write but not read + if args.dwcreationdisposition == 3: + # open existing + if is_original_file: + # cannot open self in write mode! + pass + elif os.access(sb_fname, os.R_OK): + s = os.stat(sb_fname) + if stat.S_ISDIR(s.st_mode): + # open dir + ret = winobjs.handle_pool.add(sb_fname, 0x1337) + else: + h = open(sb_fname, 'wb') + ret = winobjs.handle_pool.add(sb_fname, h) + else: + raise NotImplementedError("Untested case") # to test + elif args.dwcreationdisposition == 5: + # truncate_existing + if is_original_file: + pass + else: + raise NotImplementedError("Untested case") # to test + else: + # raise NotImplementedError("Untested case") # to test + h = open(sb_fname, 'wb') + ret = winobjs.handle_pool.add(sb_fname, h) + else: + raise NotImplementedError("Untested case") + + # h = open(sb_fname, 'rb+') + # ret = winobjs.handle_pool.add(sb_fname, h) + log.debug('CreateFile ret %x', ret) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_CreateFileA(jitter): + kernel32_CreateFile(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_CreateFileW(jitter): + kernel32_CreateFile(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_ReadFile(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpbuffer", + "nnumberofbytestoread", + "lpnumberofbytesread", + "lpoverlapped"]) + if args.hwnd == winobjs.module_cur_hwnd: + pass + elif args.hwnd in winobjs.handle_pool: + pass + else: + raise ValueError('unknown hwnd!') + + data = None + if args.hwnd in winobjs.files_hwnd: + data = winobjs.files_hwnd[ + winobjs.module_cur_hwnd].read(args.nnumberofbytestoread) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + data = wh.info.read(args.nnumberofbytestoread) + else: + raise ValueError('unknown filename') + + if data is not None: + if (args.lpnumberofbytesread): + jitter.vm.set_u32(args.lpnumberofbytesread, len(data)) + jitter.vm.set_mem(args.lpbuffer, data) + + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetFileSize(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpfilesizehight"]) + + if args.hwnd == winobjs.module_cur_hwnd: + ret = len(open(winobjs.module_fname_nux, "rb").read()) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + ret = len(open(wh.name, "rb").read()) + else: + raise ValueError('unknown hwnd!') + + if args.lpfilesizehight != 0: + jitter.vm.set_u32(args.lpfilesizehight, ret) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetFileSizeEx(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpfilesizehight"]) + + if args.hwnd == winobjs.module_cur_hwnd: + l = len(open(winobjs.module_fname_nux, "rb").read()) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + l = len(open(wh.name, "rb").read()) + else: + raise ValueError('unknown hwnd!') + + if args.lpfilesizehight == 0: + raise NotImplementedError("Untested case") + jitter.vm.set_mem(args.lpfilesizehight, pck32( + l & 0xffffffff) + pck32((l >> 32) & 0xffffffff)) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_FlushInstructionCache(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hprocess", "lpbasead", "dwsize"]) + jitter.func_ret_stdcall(ret_ad, 0x1337) + + +def kernel32_VirtualProtect(jitter): + ret_ad, args = jitter.func_args_stdcall(['lpvoid', 'dwsize', + 'flnewprotect', + 'lpfloldprotect']) + # XXX mask hpart + flnewprotect = args.flnewprotect & 0xFFF + if not flnewprotect in ACCESS_DICT: + raise ValueError('unknown access dw!') + + if args.lpfloldprotect: + old = jitter.vm.get_mem_access(args.lpvoid) + jitter.vm.set_u32(args.lpfloldprotect, ACCESS_DICT_INV[old]) + + paddr = args.lpvoid - (args.lpvoid % winobjs.alloc_align) + paddr_max = (args.lpvoid + args.dwsize + winobjs.alloc_align - 1) + paddr_max_round = paddr_max - (paddr_max % winobjs.alloc_align) + psize = paddr_max_round - paddr + for addr, items in list(winobjs.allocated_pages.items()): + alloc_addr, alloc_size = items + if (paddr + psize <= alloc_addr or + paddr > alloc_addr + alloc_size): + continue + size = jitter.vm.get_all_memory()[addr]["size"] + # Page is included in Protect area + if (paddr <= addr < addr + size <= paddr + psize): + log.warn("set page %x %x", addr, ACCESS_DICT[flnewprotect]) + jitter.vm.set_mem_access(addr, ACCESS_DICT[flnewprotect]) + continue + + # Page is partly in Protect area: splitting is needed + if (addr <= paddr < addr + size or + addr <= paddr + psize < addr + size): + + old_access = jitter.vm.get_mem_access(addr) + + # splits = [ + # addr -> max(paddr, addr) + # max(paddr, addr) -> min(addr + size, paddr + psize) + # min(addr + size, paddr + psize) -> addr + size + # ] + splits = [ + (addr, old_access, + jitter.vm.get_mem(addr, max(paddr, addr) - addr)), + (max(paddr, addr), ACCESS_DICT[flnewprotect], + jitter.vm.get_mem( + max(paddr, addr), + min(addr + size, paddr + psize) - max(paddr, addr))), + (min(addr + size, paddr + psize), old_access, + jitter.vm.get_mem( + min(addr + size, paddr + psize), + addr + size - min(addr + size, paddr + psize))) + ] + + jitter.vm.remove_memory_page(addr) + for split_addr, split_access, split_data in splits: + if not split_data: + continue + log.warn("create page %x %x", split_addr, + ACCESS_DICT[flnewprotect]) + jitter.vm.add_memory_page( + split_addr, split_access, split_data, + "VirtualProtect split ret 0x%X" % ret_ad) + winobjs.allocated_pages[split_addr] = (alloc_addr, alloc_size) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_VirtualAlloc(jitter): + ret_ad, args = jitter.func_args_stdcall(['lpvoid', 'dwsize', + 'alloc_type', 'flprotect']) + + + if not args.flprotect in ACCESS_DICT: + raise ValueError('unknown access dw!') + + if args.lpvoid == 0: + alloc_addr = winobjs.heap.next_addr(args.dwsize) + winobjs.allocated_pages[alloc_addr] = (alloc_addr, args.dwsize) + jitter.vm.add_memory_page( + alloc_addr, ACCESS_DICT[args.flprotect], b"\x00" * args.dwsize, + "Alloc in %s ret 0x%X" % (whoami(), ret_ad)) + else: + all_mem = jitter.vm.get_all_memory() + if args.lpvoid in all_mem: + alloc_addr = args.lpvoid + jitter.vm.set_mem_access(args.lpvoid, ACCESS_DICT[args.flprotect]) + else: + alloc_addr = winobjs.heap.next_addr(args.dwsize) + winobjs.allocated_pages[alloc_addr] = (alloc_addr, args.dwsize) + # alloc_addr = args.lpvoid + jitter.vm.add_memory_page( + alloc_addr, ACCESS_DICT[args.flprotect], b"\x00" * args.dwsize, + "Alloc in %s ret 0x%X" % (whoami(), ret_ad)) + + log.info('VirtualAlloc addr: 0x%x', alloc_addr) + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def kernel32_VirtualFree(jitter): + ret_ad, _ = jitter.func_args_stdcall(["lpvoid", "dwsize", "alloc_type"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def user32_GetWindowLongA(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd", "nindex"]) + jitter.func_ret_stdcall(ret_ad, winobjs.windowlong_dw) + + +def user32_SetWindowLongA(jitter): + ret_ad, _ = jitter.func_args_stdcall(["hwnd", "nindex", "newlong"]) + jitter.func_ret_stdcall(ret_ad, winobjs.windowlong_dw) + + +def kernel32_GetModuleFileName(jitter, funcname, set_str): + ret_ad, args = jitter.func_args_stdcall(["hmodule", "lpfilename", "nsize"]) + + if args.hmodule in [0, winobjs.hcurmodule]: + p = winobjs.module_path[:] + elif (winobjs.runtime_dll and + args.hmodule in viewvalues(winobjs.runtime_dll.name2off)): + name_inv = dict( + [ + (x[1], x[0]) + for x in viewitems(winobjs.runtime_dll.name2off) + ] + ) + p = name_inv[args.hmodule] + else: + log.warning(('Unknown module 0x%x.' + + 'Set winobjs.hcurmodule and retry'), args.hmodule) + p = None + + if p is None: + l = 0 + elif args.nsize < len(p): + p = p[:args.nsize] + l = len(p) + else: + l = len(p) + + if p: + set_str(args.lpfilename, p) + + jitter.func_ret_stdcall(ret_ad, l) + + +def kernel32_GetModuleFileNameA(jitter): + kernel32_GetModuleFileName(jitter, whoami(), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetModuleFileNameW(jitter): + kernel32_GetModuleFileName(jitter, whoami(), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_CreateMutex(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["mutexattr", "initowner", + "lpname"]) + + if args.lpname: + name = get_str(args.lpname) + log.info("CreateMutex %r", name) + else: + name = None + if args.initowner: + if name in winobjs.mutex: + raise NotImplementedError("Untested case") + # ret = 0 + else: + winobjs.mutex[name] = id(name) & 0xFFFFFFFF + ret = winobjs.mutex[name] + else: + if name in winobjs.mutex: + raise NotImplementedError("Untested case") + # ret = 0 + else: + winobjs.mutex[name] = id(name) & 0xFFFFFFFF + ret = winobjs.mutex[name] + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_CreateMutexA(jitter): + kernel32_CreateMutex(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_CreateMutexW(jitter): + kernel32_CreateMutex(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def shell32_SHGetSpecialFolderLocation(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwndowner", "nfolder", "ppidl"]) + jitter.vm.set_u32(args.ppidl, args.nfolder) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_SHGetPathFromIDList(jitter, funcname, set_str): + ret_ad, args = jitter.func_args_stdcall(["pidl", "ppath"]) + + if args.pidl == 7: # CSIDL_STARTUP: + s = "c:\\doc\\user\\startmenu\\programs\\startup" + set_str(args.ppath, s) + else: + raise ValueError('pidl not implemented', args.pidl) + jitter.func_ret_stdcall(ret_ad, 1) + + +def shell32_SHGetPathFromIDListW(jitter): + kernel32_SHGetPathFromIDList(jitter, whoami(), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def shell32_SHGetPathFromIDListA(jitter): + kernel32_SHGetPathFromIDList(jitter, whoami(), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetLastError(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, winobjs.lastwin32error) + + +def kernel32_SetLastError(jitter): + ret_ad, args = jitter.func_args_stdcall(["errcode"]) + # lasterr addr + # ad = tib_address + 0x34 + # jitter.vm.set_mem(ad, pck32(args.errcode)) + winobjs.lastwin32error = args.errcode + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_RestoreLastError(jitter): + kernel32_SetLastError(jitter) + + +def kernel32_LoadLibrary(jitter, get_str): + ret_ad, args = jitter.func_args_stdcall(["dllname"]) + + libname = get_str(args.dllname, 0x100) + ret = winobjs.runtime_dll.lib_get_add_base(libname) + log.info("Loading %r ret 0x%x", libname, ret) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_LoadLibraryA(jitter): + kernel32_LoadLibrary(jitter, lambda addr, max_char=None:get_win_str_a(jitter, addr, max_char)) + + +def kernel32_LoadLibraryW(jitter): + kernel32_LoadLibrary(jitter, lambda addr, max_char=None:get_win_str_w(jitter, addr, max_char)) + + +def kernel32_LoadLibraryEx(jitter, get_str): + ret_ad, args = jitter.func_args_stdcall(["dllname", "hfile", "flags"]) + + if args.hfile != 0: + raise NotImplementedError("Untested case") + libname = get_str(args.dllname, 0x100) + ret = winobjs.runtime_dll.lib_get_add_base(libname) + log.info("Loading %r ret 0x%x", libname, ret) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_LoadLibraryExA(jitter): + kernel32_LoadLibraryEx(jitter, lambda addr, max_char=None:get_win_str_a(jitter, addr, max_char)) + + +def kernel32_LoadLibraryExW(jitter): + kernel32_LoadLibraryEx(jitter, lambda addr, max_char=None:get_win_str_w(jitter, addr, max_char)) + + +def kernel32_GetProcAddress(jitter): + ret_ad, args = jitter.func_args_stdcall(["libbase", "fname"]) + fname = args.fname + if fname >= 0x10000: + fname = jitter.get_c_str(fname, 0x100) + if not fname: + fname = None + if fname is not None: + ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname) + else: + ad = 0 + log.info("GetProcAddress %r %r ret 0x%x", args.libbase, fname, ad) + jitter.add_breakpoint(ad, jitter.handle_lib) + jitter.func_ret_stdcall(ret_ad, ad) + + +def kernel32_GetModuleHandle(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["dllname"]) + + if args.dllname: + libname = get_str(args.dllname) + if libname: + ret = winobjs.runtime_dll.lib_get_add_base(libname) + else: + log.warning('unknown module!') + ret = 0 + log.info("GetModuleHandle %r ret 0x%x", libname, ret) + else: + ret = winobjs.current_pe.NThdr.ImageBase + log.info("GetModuleHandle default ret 0x%x", ret) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetModuleHandleA(jitter): + kernel32_GetModuleHandle(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_GetModuleHandleW(jitter): + kernel32_GetModuleHandle(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_VirtualLock(jitter): + ret_ad, _ = jitter.func_args_stdcall(["lpaddress", "dwsize"]) + jitter.func_ret_stdcall(ret_ad, 1) + + +class systeminfo(object): + oemId = 0 + dwPageSize = 0x1000 + lpMinimumApplicationAddress = 0x10000 + lpMaximumApplicationAddress = 0x7ffeffff + dwActiveProcessorMask = 0x1 + numberOfProcessors = 0x1 + ProcessorsType = 586 + dwAllocationgranularity = 0x10000 + wProcessorLevel = 0x6 + ProcessorRevision = 0xf0b + + def pack(self): + return struct.pack('IIIIIIIIHH', + self.oemId, + self.dwPageSize, + self.lpMinimumApplicationAddress, + self.lpMaximumApplicationAddress, + self.dwActiveProcessorMask, + self.numberOfProcessors, + self.ProcessorsType, + self.dwAllocationgranularity, + self.wProcessorLevel, + self.ProcessorRevision) + + +def kernel32_GetSystemInfo(jitter): + ret_ad, args = jitter.func_args_stdcall(["sys_ptr"]) + sysinfo = systeminfo() + jitter.vm.set_mem(args.sys_ptr, sysinfo.pack()) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_IsWow64Process(jitter): + ret_ad, args = jitter.func_args_stdcall(["process", "bool_ptr"]) + jitter.vm.set_u32(args.bool_ptr, 0) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetCommandLine(jitter, set_str): + ret_ad, _ = jitter.func_args_stdcall(0) + alloc_addr = winobjs.heap.alloc(jitter, 0x1000) + set_str(alloc_addr, '"%s"' % winobjs.module_path) + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def kernel32_GetCommandLineA(jitter): + kernel32_GetCommandLine(jitter, lambda addr, value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetCommandLineW(jitter): + kernel32_GetCommandLine(jitter, lambda addr, value: set_win_str_w(jitter, addr, value)) + + +def shell32_CommandLineToArgvW(jitter): + ret_ad, args = jitter.func_args_stdcall(["pcmd", "pnumargs"]) + cmd = get_win_str_w(jitter, args.pcmd) + if cmd.startswith('"') and cmd.endswith('"'): + cmd = cmd[1:-1] + log.info("CommandLineToArgv %r", cmd) + tks = cmd.split(' ') + addr = winobjs.heap.alloc(jitter, len(cmd) * 2 + 4 * len(tks)) + addr_ret = winobjs.heap.alloc(jitter, 4 * (len(tks) + 1)) + o = 0 + for i, t in enumerate(tks): + set_win_str_w(jitter, addr + o, t) + jitter.vm.set_u32(addr_ret + 4 * i, addr + o) + o += len(t)*2 + 2 + + jitter.vm.set_u32(addr_ret + 4 * (i+1), 0) + jitter.vm.set_u32(args.pnumargs, len(tks)) + jitter.func_ret_stdcall(ret_ad, addr_ret) + +def cryptdll_MD5Init(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_ctx"]) + index = len(winobjs.cryptdll_md5_h) + h = MD5.new() + winobjs.cryptdll_md5_h[index] = h + + jitter.vm.set_u32(args.ad_ctx, index) + jitter.func_ret_stdcall(ret_ad, 0) + + +def cryptdll_MD5Update(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_ctx", "ad_input", "inlen"]) + + index = jitter.vm.get_u32(args.ad_ctx) + if not index in winobjs.cryptdll_md5_h: + raise ValueError('unknown h context', index) + + data = jitter.vm.get_mem(args.ad_input, args.inlen) + winobjs.cryptdll_md5_h[index].update(data) + log.debug(hexdump(data)) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def cryptdll_MD5Final(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_ctx"]) + + index = jitter.vm.get_u32(args.ad_ctx) + if not index in winobjs.cryptdll_md5_h: + raise ValueError('unknown h context', index) + h = winobjs.cryptdll_md5_h[index].digest() + jitter.vm.set_mem(args.ad_ctx + 88, h) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlInitAnsiString(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_ctx", "ad_str"]) + + s = get_win_str_a(jitter, args.ad_str) + l = len(s) + jitter.vm.set_mem(args.ad_ctx, + pck16(l) + pck16(l + 1) + pck32(args.ad_str)) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlHashUnicodeString(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_ctxu", "case_i", "h_id", + "phout"]) + + if args.h_id != 1: + raise ValueError('unk hash unicode', args.h_id) + + l1, l2, ptra = struct.unpack('HHL', jitter.vm.get_mem(args.ad_ctxu, 8)) + s = jitter.vm.get_mem(ptra, l1) + s = s[:-1] + hv = 0 + + if args.case_i: + s = s.lower() + for c in s: + hv = ((65599 * hv) + ord(c)) & 0xffffffff + jitter.vm.set_u32(args.phout, hv) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_RtlMoveMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad_dst", "ad_src", "m_len"]) + data = jitter.vm.get_mem(args.ad_src, args.m_len) + jitter.vm.set_mem(args.ad_dst, data) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlAnsiCharToUnicodeChar(jitter): + ret_ad, args = jitter.func_args_stdcall(['ad_ad_ch']) + ad_ch = jitter.vm.get_u32(args.ad_ad_ch) + ch = ord(jitter.vm.get_mem(ad_ch, 1)) + jitter.vm.set_u32(args.ad_ad_ch, ad_ch + 1) + jitter.func_ret_stdcall(ret_ad, ch) + + +def ntdll_RtlFindCharInUnicodeString(jitter): + ret_ad, args = jitter.func_args_stdcall(["flags", "main_str_ad", + "search_chars_ad", "pos_ad"]) + + if args.flags != 0: + raise ValueError('unk flags') + + ml1, ml2, mptra = struct.unpack('HHL', + jitter.vm.get_mem(args.main_str_ad, 8)) + sl1, sl2, sptra = struct.unpack( + 'HHL', jitter.vm.get_mem(args.search_chars_ad, 8)) + main_data = jitter.vm.get_mem(mptra, ml1)[:-1] + search_data = jitter.vm.get_mem(sptra, sl1)[:-1] + + pos = None + for i, c in enumerate(main_data): + for s in search_data: + if s == c: + pos = i + break + if pos: + break + if pos is None: + ret = 0xC0000225 + jitter.vm.set_u32(args.pos_ad, 0) + else: + ret = 0 + jitter.vm.set_u32(args.pos_ad, pos) + + jitter.func_ret_stdcall(ret_ad, ret) + + +def ntdll_RtlComputeCrc32(jitter): + ret_ad, args = jitter.func_args_stdcall(["dwinit", "pdata", "ilen"]) + data = jitter.vm.get_mem(args.pdata, args.ilen) + crc_r = crc32(data, args.dwinit) + jitter.func_ret_stdcall(ret_ad, crc_r) + + +def ntdll_RtlExtendedIntegerMultiply(jitter): + ret_ad, args = jitter.func_args_stdcall(['multiplicand_low', + 'multiplicand_high', + 'multiplier']) + a = (args.multiplicand_high << 32) + args.multiplicand_low + a = a * args.multiplier + jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff) + + +def ntdll_RtlLargeIntegerAdd(jitter): + ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high', + 'b_low', 'b_high']) + a = (args.a_high << 32) + args.a_low + (args.b_high << 32) + args.b_low + jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff) + + +def ntdll_RtlLargeIntegerShiftRight(jitter): + ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high', 's_count']) + a = ((args.a_high << 32) + args.a_low) >> args.s_count + jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff) + + +def ntdll_RtlEnlargedUnsignedMultiply(jitter): + ret_ad, args = jitter.func_args_stdcall(['a', 'b']) + a = args.a * args.b + jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff) + + +def ntdll_RtlLargeIntegerSubtract(jitter): + ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high', + 'b_low', 'b_high']) + a = (args.a_high << 32) + args.a_low - (args.b_high << 32) + args.b_low + jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff) + + +def ntdll_RtlCompareMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(['ad1', 'ad2', 'm_len']) + data1 = jitter.vm.get_mem(args.ad1, args.m_len) + data2 = jitter.vm.get_mem(args.ad2, args.m_len) + + i = 0 + while data1[i] == data2[i]: + i += 1 + if i >= args.m_len: + break + + jitter.func_ret_stdcall(ret_ad, i) + + +def user32_GetMessagePos(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0x00110022) + + +def kernel32_Sleep(jitter): + ret_ad, _ = jitter.func_args_stdcall(['t']) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_ZwUnmapViewOfSection(jitter): + ret_ad, _ = jitter.func_args_stdcall(['h', 'ad']) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_IsBadReadPtr(jitter): + ret_ad, _ = jitter.func_args_stdcall(['lp', 'ucb']) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_KeInitializeEvent(jitter): + ret_ad, args = jitter.func_args_stdcall(['my_event', 'my_type', + 'my_state']) + jitter.vm.set_u32(args.my_event, winobjs.win_event_num) + winobjs.win_event_num += 1 + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_RtlGetVersion(jitter): + ret_ad, args = jitter.func_args_stdcall(['ptr_version']) + + s = struct.pack("IIIII", + 0x114, # struct size + 0x5, # maj vers + 0x2, # min vers + 0x666, # build nbr + 0x2, # platform id + ) + encode_win_str_w("Service pack 4") + + jitter.vm.set_mem(args.ptr_version, s) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_RtlVerifyVersionInfo(jitter): + ret_ad, args = jitter.func_args_stdcall(['ptr_version']) + + s = jitter.vm.get_mem(args.ptr_version, 0x5 * 4) + s_size, s_majv, s_minv, s_buildn, s_platform = struct.unpack('IIIII', s) + raise NotImplementedError("Untested case") + # jitter.vm.set_mem(args.ptr_version, s) + # jitter.func_ret_stdcall(ret_ad, 0) + + +def hal_ExAcquireFastMutex(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0) + + +def mdl2ad(n): + return winobjs.nt_mdl_ad + 0x10 * n + + +def ad2mdl(ad): + return ((ad - winobjs.nt_mdl_ad) & 0xFFFFFFFF) // 0x10 + + +def ntoskrnl_IoAllocateMdl(jitter): + ret_ad, args = jitter.func_args_stdcall(["v_addr", "l", "second_buf", + "chargequota", "pirp"]) + m = mdl(args.v_addr, args.l) + winobjs.nt_mdl[winobjs.nt_mdl_cur] = m + jitter.vm.set_mem(mdl2ad(winobjs.nt_mdl_cur), bytes(m)) + jitter.func_ret_stdcall(ret_ad, mdl2ad(winobjs.nt_mdl_cur)) + winobjs.nt_mdl_cur += 1 + + +def ntoskrnl_MmProbeAndLockPages(jitter): + ret_ad, args = jitter.func_args_stdcall(["p_mdl", "access_mode", "op"]) + + if not ad2mdl(args.p_mdl) in winobjs.nt_mdl: + raise ValueError('unk mdl', hex(args.p_mdl)) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_MmMapLockedPagesSpecifyCache(jitter): + ret_ad, args = jitter.func_args_stdcall(["p_mdl", "access_mode", + "cache_type", "base_ad", + "bugcheckonfailure", + "priority"]) + if not ad2mdl(args.p_mdl) in winobjs.nt_mdl: + raise ValueError('unk mdl', hex(args.p_mdl)) + + jitter.func_ret_stdcall(ret_ad, winobjs.nt_mdl[ad2mdl(args.p_mdl)].ad) + + +def ntoskrnl_MmProtectMdlSystemAddress(jitter): + ret_ad, args = jitter.func_args_stdcall(["p_mdl", "prot"]) + if not ad2mdl(args.p_mdl) in winobjs.nt_mdl: + raise ValueError('unk mdl', hex(args.p_mdl)) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_MmUnlockPages(jitter): + ret_ad, args = jitter.func_args_stdcall(['p_mdl']) + if not ad2mdl(args.p_mdl) in winobjs.nt_mdl: + raise ValueError('unk mdl', hex(args.p_mdl)) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_IoFreeMdl(jitter): + ret_ad, args = jitter.func_args_stdcall(['p_mdl']) + if not ad2mdl(args.p_mdl) in winobjs.nt_mdl: + raise ValueError('unk mdl', hex(args.p_mdl)) + del(winobjs.nt_mdl[ad2mdl(args.p_mdl)]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def hal_ExReleaseFastMutex(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_RtlQueryRegistryValues(jitter): + ret_ad, args = jitter.func_args_stdcall(["relativeto", "path", + "querytable", + "context", + "environ"]) + # path = get_win_str_w(jitter, args.path) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntoskrnl_ExAllocatePoolWithTagPriority(jitter): + ret_ad, args = jitter.func_args_stdcall(["pool_type", + "nbr_of_bytes", + "tag", "priority"]) + alloc_addr = winobjs.heap.next_addr(args.nbr_of_bytes) + jitter.vm.add_memory_page( + alloc_addr, PAGE_READ | PAGE_WRITE, b"\x00" * args.nbr_of_bytes, + "Alloc in %s ret 0x%X" % (whoami(), ret_ad)) + + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def my_lstrcmp(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2"]) + s1 = get_str(args.ptr_str1) + s2 = get_str(args.ptr_str2) + log.info("Compare %r with %r", s1, s2) + jitter.func_ret_stdcall(ret_ad, cmp(s1, s2)) + +def msvcrt_wcscmp(jitter): + ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"]) + s1 = get_win_str_w(jitter, args.ptr_str1) + s2 = get_win_str_w(jitter, args.ptr_str2) + log.debug("%s('%s','%s')" % (whoami(), s1, s2)) + jitter.func_ret_cdecl(ret_ad, cmp(s1, s2)) + +def msvcrt__wcsicmp(jitter): + ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"]) + s1 = get_win_str_w(jitter, args.ptr_str1) + s2 = get_win_str_w(jitter, args.ptr_str2) + log.debug("%s('%s','%s')" % (whoami(), s1, s2)) + jitter.func_ret_cdecl(ret_ad, cmp(s1.lower(), s2.lower())) + +def msvcrt__wcsnicmp(jitter): + ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2", "count"]) + s1 = get_win_str_w(jitter, args.ptr_str1) + s2 = get_win_str_w(jitter, args.ptr_str2) + log.debug("%s('%s','%s',%d)" % (whoami(), s1, s2, args.count)) + jitter.func_ret_cdecl(ret_ad, cmp(s1.lower()[:args.count], s2.lower()[:args.count])) + +def msvcrt_wcsncpy(jitter): + ret_ad, args = jitter.func_args_cdecl(["dst", "src", "n"]) + src = get_win_str_w(jitter, args.src) + dst = src[:args.n] + jitter.vm.set_mem(args.dst, b"\x00\x00" * args.n) + jitter.vm.set_mem(args.dst, dst.encode("utf-16le")) + jitter.func_ret_cdecl(ret_ad, args.dst) + +def kernel32_lstrcmpA(jitter): + my_lstrcmp(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_lstrcmpiA(jitter): + my_lstrcmp(jitter, whoami(), lambda x: get_win_str_a(jitter, x).lower()) + + +def kernel32_lstrcmpW(jitter): + my_lstrcmp(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_lstrcmpiW(jitter): + my_lstrcmp(jitter, whoami(), lambda x: get_win_str_w(jitter, x).lower()) + + +def kernel32_lstrcmpi(jitter): + my_lstrcmp(jitter, whoami(), lambda x: get_win_str_a(jitter, x).lower()) + + +def my_strcpy(jitter, funcname, get_str, set_str): + ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2"]) + s2 = get_str(args.ptr_str2) + set_str(args.ptr_str1, s2) + log.info("Copy '%r'", s2) + jitter.func_ret_stdcall(ret_ad, args.ptr_str1) + + +def kernel32_lstrcpyW(jitter): + my_strcpy(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_lstrcpyA(jitter): + my_strcpy(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_lstrcpy(jitter): + my_strcpy(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), lambda addr,value: set_win_str_a(jitter, addr, value)) + +def msvcrt__mbscpy(jitter): + ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"]) + s2 = get_win_str_w(jitter, args.ptr_str2) + set_win_str_w(jitter, args.ptr_str1, s2) + jitter.func_ret_cdecl(ret_ad, args.ptr_str1) + +def msvcrt_wcscpy(jitter): + return msvcrt__mbscpy(jitter) + + +def kernel32_lstrcpyn(jitter): + ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2", + "mlen"]) + s2 = get_win_str_a(jitter, args.ptr_str2) + if len(s2) >= args.mlen: + s2 = s2[:args.mlen - 1] + log.info("Copy '%r'", s2) + set_win_str_a(jitter, args.ptr_str1, s2) + jitter.func_ret_stdcall(ret_ad, args.ptr_str1) + + +def my_strlen(jitter, funcname, get_str, mylen): + ret_ad, args = jitter.func_args_stdcall(["src"]) + src = get_str(args.src) + length = mylen(src) + log.info("Len of '%r' -> 0x%x", src, length) + jitter.func_ret_stdcall(ret_ad, length) + + +def kernel32_lstrlenA(jitter): + my_strlen(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), len) + + +def kernel32_lstrlenW(jitter): + my_strlen(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr), len) + + +def kernel32_lstrlen(jitter): + my_strlen(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), len) + + +def my_lstrcat(jitter, funcname, get_str, set_str): + ret_ad, args = jitter.func_args_stdcall(['ptr_str1', 'ptr_str2']) + s1 = get_str(args.ptr_str1) + s2 = get_str(args.ptr_str2) + set_str(args.ptr_str1, s1 + s2) + jitter.func_ret_stdcall(ret_ad, args.ptr_str1) + + +def kernel32_lstrcatA(jitter): + my_lstrcat(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_lstrcatW(jitter): + my_lstrcat(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_GetUserGeoID(jitter): + ret_ad, args = jitter.func_args_stdcall(["geoclass"]) + if args.geoclass == 14: + ret = 12345678 + elif args.geoclass == 16: + ret = 55667788 + else: + raise ValueError('unknown geolcass') + jitter.func_ret_stdcall(ret_ad, ret) + + +def my_GetVolumeInformation(jitter, funcname, get_str, set_str): + ret_ad, args = jitter.func_args_stdcall(["lprootpathname", + "lpvolumenamebuffer", + "nvolumenamesize", + "lpvolumeserialnumber", + "lpmaximumcomponentlength", + "lpfilesystemflags", + "lpfilesystemnamebuffer", + "nfilesystemnamesize"]) + if args.lprootpathname: + s = get_str(args.lprootpathname) + log.info('GetVolumeInformation %r', s) + + + if args.lpvolumenamebuffer: + s = "volumename" + s = s[:args.nvolumenamesize] + set_str(args.lpvolumenamebuffer, s) + + if args.lpvolumeserialnumber: + jitter.vm.set_u32(args.lpvolumeserialnumber, 11111111) + if args.lpmaximumcomponentlength: + jitter.vm.set_u32(args.lpmaximumcomponentlength, 0xff) + if args.lpfilesystemflags: + jitter.vm.set_u32(args.lpfilesystemflags, 22222222) + + if args.lpfilesystemnamebuffer: + s = "filesystemname" + s = s[:args.nfilesystemnamesize] + set_str(args.lpfilesystemnamebuffer, s) + + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetVolumeInformationA(jitter): + my_GetVolumeInformation( + jitter, whoami(), lambda addr:get_win_str_a(jitter, addr), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetVolumeInformationW(jitter): + my_GetVolumeInformation(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_MultiByteToWideChar(jitter): + MB_ERR_INVALID_CHARS = 0x8 + CP_ACP = 0x000 + CP_1252 = 0x4e4 + + ret_ad, args = jitter.func_args_stdcall(["codepage", "dwflags", + "lpmultibytestr", + "cbmultibyte", + "lpwidecharstr", + "cchwidechar"]) + if args.codepage != CP_ACP and args.codepage != CP_1252: + raise NotImplementedError + # according to MSDN: + # "Note that, if cbMultiByte is 0, the function fails." + if args.cbmultibyte == 0: + raise ValueError + # according to MSDN: + # "Alternatively, this parameter can be set to -1 if the string is + # null-terminated." + if args.cbmultibyte == 0xffffffff: + src_len = 0 + while jitter.vm.get_mem(args.lpmultibytestr + src_len, 1) != b'\0': + src_len += 1 + src = jitter.vm.get_mem(args.lpmultibytestr, src_len) + else: + src = jitter.vm.get_mem(args.lpmultibytestr, args.cbmultibyte) + if args.dwflags & MB_ERR_INVALID_CHARS: + # will raise an exception if decoding fails + s = src.decode("cp1252", errors="replace").encode("utf-16le") + else: + # silently replace undecodable chars with U+FFFD + s = src.decode("cp1252", errors="replace").encode("utf-16le") + if args.cchwidechar > 0: + # return value is number of bytes written + retval = min(args.cchwidechar, len(s)) + jitter.vm.set_mem(args.lpwidecharstr, s[:retval]) + else: + # return value is number of bytes to write + # i.e., size of dest. buffer to allocate + retval = len(s) + jitter.func_ret_stdcall(ret_ad, retval) + + +def kernel32_WideCharToMultiByte(jitter): + """ + int WideCharToMultiByte( + UINT CodePage, + DWORD dwFlags, + _In_NLS_string_(cchWideChar)LPCWCH lpWideCharStr, + int cchWideChar, + LPSTR lpMultiByteStr, + int cbMultiByte, + LPCCH lpDefaultChar, + LPBOOL lpUsedDefaultChar + ); + + """ + CP_ACP = 0x000 + CP_1252 = 0x4e4 + + ret, args = jitter.func_args_stdcall([ + 'CodePage', 'dwFlags', 'lpWideCharStr', 'cchWideChar', + 'lpMultiByteStr', 'cbMultiByte', 'lpDefaultChar', 'lpUsedDefaultChar', + ]) + if args.CodePage != CP_ACP and args.CodePage != CP_1252: + raise NotImplementedError + cchWideChar = args.cchWideChar + if cchWideChar == 0xffffffff: + cchWideChar = len(get_win_str_w(jitter, args.lpWideCharStr)) + 1 + src = jitter.vm.get_mem(args.lpWideCharStr, cchWideChar * 2) + dst = src.decode("utf-16le").encode("cp1252", errors="replace") + if args.cbMultiByte > 0: + # return value is the number of bytes written + retval = min(args.cbMultiByte, len(dst)) + jitter.vm.set_mem(args.lpMultiByteStr, dst[:retval]) + else: + # return value is the size of the buffer to allocate + # to get the multibyte string + retval = len(dst) + jitter.func_ret_stdcall(ret, retval) + + +def my_GetEnvironmentVariable(jitter, funcname, get_str, set_str, mylen): + ret_ad, args = jitter.func_args_stdcall(["lpname", "lpbuffer", + "nsize"]) + + s = get_str(args.lpname) + log.info('GetEnvironmentVariable %r', s) + if s in winobjs.env_variables: + v = winobjs.env_variables[s] + else: + log.warning('WARNING unknown env variable %r', s) + v = "" + set_str(args.lpbuffer, v) + jitter.func_ret_stdcall(ret_ad, mylen(v)) + + +def kernel32_GetEnvironmentVariableA(jitter): + my_GetEnvironmentVariable(jitter, whoami(), + lambda addr:get_win_str_a(jitter, addr), + lambda addr,value: set_win_str_a(jitter, addr, value), + len) + + +def kernel32_GetEnvironmentVariableW(jitter): + my_GetEnvironmentVariable(jitter, whoami(), + lambda addr:get_win_str_w(jitter, addr), + lambda addr,value: set_win_str_w(jitter, addr, value), + len) + + +def my_GetSystemDirectory(jitter, funcname, set_str): + ret_ad, args = jitter.func_args_stdcall(["lpbuffer", "usize"]) + s = "c:\\windows\\system32" + l = len(s) + set_str(args.lpbuffer, s) + jitter.func_ret_stdcall(ret_ad, l) + + + +def kernel32_GetSystemDirectoryA(jitter): + my_GetSystemDirectory(jitter, whoami(), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetSystemDirectoryW(jitter): + my_GetSystemDirectory(jitter, whoami(), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def my_CreateDirectory(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(['lppath', 'secattrib']) + # path = get_str(jitter, args.lppath) + jitter.func_ret_stdcall(ret_ad, 0x1337) + + +def kernel32_CreateDirectoryW(jitter): + my_CreateDirectory(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_CreateDirectoryA(jitter): + my_CreateDirectory(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + + +def my_CreateEvent(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["lpeventattributes", + "bmanualreset", + "binitialstate", + "lpname"]) + s = get_str(args.lpname) if args.lpname else None + if not s in winobjs.events_pool: + winobjs.events_pool[s] = (args.bmanualreset, args.binitialstate) + else: + log.warning('WARNING: known event') + jitter.func_ret_stdcall(ret_ad, id(s) & 0xFFFFFFFF) + + +def kernel32_CreateEventA(jitter): + my_CreateEvent(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_CreateEventW(jitter): + my_CreateEvent(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_WaitForSingleObject(jitter): + ret_ad, args = jitter.func_args_stdcall(['handle', 'dwms']) + + t_start = time.time() * 1000 + found = False + while True: + if args.dwms and args.dwms + t_start > time.time() * 1000: + ret = 0x102 + break + for key, value in viewitems(winobjs.events_pool): + if key != args.handle: + continue + found = True + if value[1] == 1: + ret = 0 + break + if not found: + log.warning('unknown handle') + ret = 0xffffffff + break + time.sleep(0.1) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_SetFileAttributesA(jitter): + ret_ad, args = jitter.func_args_stdcall(["lpfilename", + "dwfileattributes"]) + if args.lpfilename: + # fname = get_win_str_a(jitter, args.lpfilename) + ret = 1 + else: + ret = 0 + jitter.vm.set_u32(tib_address + 0x34, 3) + + jitter.func_ret_stdcall(ret_ad, ret) + + +def ntdll_RtlMoveMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(["dst", "src", "l"]) + s = jitter.vm.get_mem(args.src, args.l) + jitter.vm.set_mem(args.dst, s) + jitter.func_ret_stdcall(ret_ad, 1) + + +def ntdll_ZwQuerySystemInformation(jitter): + ret_ad, args = jitter.func_args_stdcall(["systeminformationclass", + "systeminformation", + "systeminformationl", + "returnl"]) + if args.systeminformationclass == 2: + # SYSTEM_PERFORMANCE_INFORMATION + o = struct.pack('II', 0x22222222, 0x33333333) + o += b"\x00" * args.systeminformationl + o = o[:args.systeminformationl] + jitter.vm.set_mem(args.systeminformation, o) + else: + raise ValueError('unknown sysinfo class', + args.systeminformationclass) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_ZwProtectVirtualMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid", + "pdwsize", + "flnewprotect", + "lpfloldprotect"]) + + ad = jitter.vm.get_u32(args.lppvoid) + # dwsize = upck32(jitter.vm.get_mem(args.pdwsize, 4)) + # XXX mask hpart + flnewprotect = args.flnewprotect & 0xFFF + + if not flnewprotect in ACCESS_DICT: + raise ValueError('unknown access dw!') + jitter.vm.set_mem_access(ad, ACCESS_DICT[flnewprotect]) + + # XXX todo real old protect + jitter.vm.set_u32(args.lpfloldprotect, 0x40) + + jitter.func_ret_stdcall(ret_ad, 1) + + +def ntdll_ZwAllocateVirtualMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid", + "zerobits", "pdwsize", + "alloc_type", + "flprotect"]) + + # ad = upck32(jitter.vm.get_mem(args.lppvoid, 4)) + dwsize = jitter.vm.get_u32(args.pdwsize) + + if not args.flprotect in ACCESS_DICT: + raise ValueError('unknown access dw!') + + alloc_addr = winobjs.heap.next_addr(dwsize) + jitter.vm.add_memory_page( + alloc_addr, ACCESS_DICT[args.flprotect], b"\x00" * dwsize, + "Alloc in %s ret 0x%X" % (whoami(), ret_ad)) + jitter.vm.set_u32(args.lppvoid, alloc_addr) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_ZwFreeVirtualMemory(jitter): + ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid", + "pdwsize", "alloc_type"]) + # ad = upck32(jitter.vm.get_mem(args.lppvoid, 4)) + # dwsize = upck32(jitter.vm.get_mem(args.pdwsize, 4)) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlInitString(jitter): + ret_ad, args = jitter.func_args_stdcall(["pstring", "source"]) + s = get_win_str_a(jitter, args.source) + l = len(s) + 1 + o = struct.pack('HHI', l, l, args.source) + jitter.vm.set_mem(args.pstring, o) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlAnsiStringToUnicodeString(jitter): + ret_ad, args = jitter.func_args_stdcall(["dst", "src", "alloc_str"]) + + l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.src, 0x8)) + s = get_win_str_a(jitter, p_src) + l = (len(s) + 1) * 2 + if args.alloc_str: + alloc_addr = winobjs.heap.next_addr(l) + jitter.vm.add_memory_page( + alloc_addr, PAGE_READ | PAGE_WRITE, b"\x00" * l, + "Alloc in %s ret 0x%X" % (whoami(), ret_ad)) + else: + alloc_addr = p_src + set_win_str_w(jitter, alloc_addr, s) + o = struct.pack('HHI', l, l, alloc_addr) + jitter.vm.set_mem(args.dst, o) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_LdrLoadDll(jitter): + ret_ad, args = jitter.func_args_stdcall(["path", "flags", + "modname", "modhandle"]) + + l1, l2, p_src = struct.unpack('HHI', + jitter.vm.get_mem(args.modname, 0x8)) + s = get_win_str_w(jitter, p_src) + libname = s.lower() + + ad = winobjs.runtime_dll.lib_get_add_base(libname) + log.info("Loading %r ret 0x%x", s, ad) + jitter.vm.set_u32(args.modhandle, ad) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_RtlFreeUnicodeString(jitter): + ret_ad, args = jitter.func_args_stdcall(['src']) + # l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.src, 0x8)) + # s = get_win_str_w(jitter, p_src) + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_LdrGetProcedureAddress(jitter): + ret_ad, args = jitter.func_args_stdcall(["libbase", "pfname", + "opt", "p_ad"]) + + l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.pfname, 0x8)) + fname = get_win_str_a(jitter, p_src) + + ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname) + jitter.add_breakpoint(ad, jitter.handle_lib) + + jitter.vm.set_u32(args.p_ad, ad) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def ntdll_memset(jitter): + ret_ad, args = jitter.func_args_cdecl(['addr', 'c', 'size']) + jitter.vm.set_mem(args.addr, int_to_byte(args.c) * args.size) + jitter.func_ret_cdecl(ret_ad, args.addr) + + +def msvcrt_memset(jitter): + ret_ad, args = jitter.func_args_cdecl(['addr', 'c', 'size']) + jitter.vm.set_mem(args.addr, int_to_byte(args.c) * args.size) + jitter.func_ret_cdecl(ret_ad, args.addr) + +def msvcrt_strrchr(jitter): + ret_ad, args = jitter.func_args_cdecl(['pstr','c']) + s = get_win_str_a(jitter, args.pstr) + c = int_to_byte(args.c).decode() + ret = args.pstr + s.rfind(c) + log.info("strrchr(%x '%s','%s') = %x" % (args.pstr,s,c,ret)) + jitter.func_ret_cdecl(ret_ad, ret) + +def msvcrt_wcsrchr(jitter): + ret_ad, args = jitter.func_args_cdecl(['pstr','c']) + s = get_win_str_w(jitter, args.pstr) + c = int_to_byte(args.c).decode() + ret = args.pstr + (s.rfind(c)*2) + log.info("wcsrchr(%x '%s',%s) = %x" % (args.pstr,s,c,ret)) + jitter.func_ret_cdecl(ret_ad, ret) + +def msvcrt_memcpy(jitter): + ret_ad, args = jitter.func_args_cdecl(['dst', 'src', 'size']) + s = jitter.vm.get_mem(args.src, args.size) + jitter.vm.set_mem(args.dst, s) + jitter.func_ret_cdecl(ret_ad, args.dst) + +def msvcrt_realloc(jitter): + ret_ad,args = jitter.func_args_cdecl(['ptr','new_size']) + if args.ptr == 0: + addr = winobjs.heap.alloc(jitter, args.new_size) + else: + addr = winobjs.heap.alloc(jitter, args.new_size) + size = winobjs.heap.get_size(jitter.vm, args.ptr) + data = jitter.vm.get_mem(args.ptr, size) + jitter.vm.set_mem(addr, data) + jitter.func_ret_cdecl(ret_ad, addr) + +def msvcrt_memcmp(jitter): + ret_ad, args = jitter.func_args_cdecl(['ps1', 'ps2', 'size']) + s1 = jitter.vm.get_mem(args.ps1, args.size) + s2 = jitter.vm.get_mem(args.ps2, args.size) + ret = cmp(s1, s2) + jitter.func_ret_cdecl(ret_ad, ret) + + +def shlwapi_PathFindExtensionA(jitter): + ret_ad, args = jitter.func_args_stdcall(['path_ad']) + path = get_win_str_a(jitter, args.path_ad) + i = path.rfind('.') + if i == -1: + i = args.path_ad + len(path) + else: + i = args.path_ad + i + jitter.func_ret_stdcall(ret_ad, i) + + +def shlwapi_PathRemoveFileSpecW(jitter): + ret_ad, args = jitter.func_args_stdcall(['path_ad']) + path = get_win_str_w(jitter, args.path_ad) + i = path.rfind('\\') + if i == -1: + i = 0 + jitter.vm.set_mem(args.path_ad + i * 2, b"\x00\x00") + path = get_win_str_w(jitter, args.path_ad) + jitter.func_ret_stdcall(ret_ad, 1) + + +def shlwapi_PathIsPrefixW(jitter): + ret_ad, args = jitter.func_args_stdcall(['ptr_prefix', 'ptr_path']) + prefix = get_win_str_w(jitter, args.ptr_prefix) + path = get_win_str_w(jitter, args.ptr_path) + + if path.startswith(prefix): + ret = 1 + else: + ret = 0 + jitter.func_ret_stdcall(ret_ad, ret) + + +def shlwapi_PathIsDirectoryW(jitter): + ret_ad, args = jitter.func_args_stdcall(['ptr_path']) + fname = get_win_str_w(jitter, args.ptr_path) + + sb_fname = windows_to_sbpath(fname) + + s = os.stat(sb_fname) + ret = 0 + if stat.S_ISDIR(s.st_mode): + ret = 1 + + jitter.func_ret_cdecl(ret_ad, ret) + + +def shlwapi_PathIsFileSpec(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(['path_ad']) + path = get_str(args.path_ad) + if path.find(':') != -1 and path.find('\\') != -1: + ret = 0 + else: + ret = 1 + + jitter.func_ret_stdcall(ret_ad, ret) + + +def shlwapi_PathGetDriveNumber(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(['path_ad']) + path = get_str(args.path_ad) + l = ord(path[0].upper()) - ord('A') + if 0 <= l <= 25: + ret = l + else: + ret = -1 + + jitter.func_ret_stdcall(ret_ad, ret) + + +def shlwapi_PathGetDriveNumberA(jitter): + shlwapi_PathGetDriveNumber(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def shlwapi_PathGetDriveNumberW(jitter): + shlwapi_PathGetDriveNumber(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def shlwapi_PathIsFileSpecA(jitter): + shlwapi_PathIsFileSpec(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def shlwapi_PathIsFileSpecW(jitter): + shlwapi_PathIsFileSpec(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def shlwapi_StrToIntA(jitter): + ret_ad, args = jitter.func_args_stdcall(['i_str_ad']) + i_str = get_win_str_a(jitter, args.i_str_ad) + try: + i = int(i_str) + except: + log.warning('WARNING cannot convert int') + i = 0 + + jitter.func_ret_stdcall(ret_ad, i) + + +def shlwapi_StrToInt64Ex(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(['pstr', 'flags', 'pret']) + i_str = get_str(args.pstr) + + if args.flags == 0: + r = int(i_str) + elif args.flags == 1: + r = int(i_str, 16) + else: + raise ValueError('cannot decode int') + + jitter.vm.set_mem(args.pret, struct.pack('q', r)) + jitter.func_ret_stdcall(ret_ad, 1) + + +def shlwapi_StrToInt64ExA(jitter): + shlwapi_StrToInt64Ex(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def shlwapi_StrToInt64ExW(jitter): + shlwapi_StrToInt64Ex(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def user32_IsCharAlpha(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["c"]) + try: + c = int_to_byte(args.c) + except: + log.error('bad char %r', args.c) + c = "\x00" + if c.isalpha(jitter): + ret = 1 + else: + ret = 0 + jitter.func_ret_stdcall(ret_ad, ret) + + +def user32_IsCharAlphaA(jitter): + user32_IsCharAlpha(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def user32_IsCharAlphaW(jitter): + user32_IsCharAlpha(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def user32_IsCharAlphaNumericA(jitter): + ret_ad, args = jitter.func_args_stdcall(["c"]) + c = int_to_byte(args.c) + if c.isalnum(jitter): + ret = 1 + else: + ret = 0 + jitter.func_ret_stdcall(ret_ad, ret) + +def get_fmt_args(jitter, fmt, cur_arg, get_str): + return _get_fmt_args(fmt, cur_arg, get_str, jitter.get_arg_n_cdecl) + +def msvcrt_sprintf_str(jitter, get_str): + ret_ad, args = jitter.func_args_cdecl(['string', 'fmt']) + cur_arg, fmt = 2, args.fmt + return ret_ad, args, get_fmt_args(jitter, fmt, cur_arg, get_str) + +def msvcrt_sprintf(jitter): + ret_ad, args, output = msvcrt_sprintf_str(jitter, lambda addr:get_win_str_a(jitter, addr)) + ret = len(output) + log.info("sprintf() = '%s'" % (output)) + jitter.vm.set_mem(args.string, (output + '\x00').encode('utf8')) + return jitter.func_ret_cdecl(ret_ad, ret) + +def msvcrt_swprintf(jitter): + ret_ad, args = jitter.func_args_cdecl(['string', 'fmt']) + cur_arg, fmt = 2, args.fmt + output = get_fmt_args(jitter, fmt, cur_arg, lambda addr:get_win_str_w(jitter, addr)) + ret = len(output) + log.info("swprintf('%s') = '%s'" % (get_win_str_w(jitter, args.fmt), output)) + jitter.vm.set_mem(args.string, output.encode("utf-16le") + b'\x00\x00') + return jitter.func_ret_cdecl(ret_ad, ret) + +def msvcrt_fprintf(jitter): + ret_addr, args = jitter.func_args_cdecl(['file', 'fmt']) + cur_arg, fmt = 2, args.fmt + output = get_fmt_args(jitter, fmt, cur_arg, lambda addr:get_win_str_a(jitter, addr)) + ret = len(output) + log.info("fprintf(%x, '%s') = '%s'" % (args.file, lambda addr:get_win_str_a(jitter, addr)(args.fmt), output)) + + fd = jitter.vm.get_u32(args.file + 0x10) + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + winobjs.handle_pool[fd].info.write(output) + + return jitter.func_ret_cdecl(ret_addr, ret) + +def shlwapi_StrCmpNIA(jitter): + ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2", + "nchar"]) + s1 = get_win_str_a(jitter, args.ptr_str1).lower() + s2 = get_win_str_a(jitter, args.ptr_str2).lower() + s1 = s1[:args.nchar] + s2 = s2[:args.nchar] + jitter.func_ret_stdcall(ret_ad, cmp(s1, s2)) + + +def advapi32_RegCreateKeyW(jitter): + ret_ad, args = jitter.func_args_stdcall(["hkey", "subkey", + "phandle"]) + s_subkey = get_win_str_w(jitter, args.subkey).lower() if args.subkey else "" + + ret_hkey = 0 + ret = 2 + if args.hkey in winobjs.hkey_handles: + ret = 0 + if s_subkey: + ret_hkey = hash(s_subkey) & 0xffffffff + winobjs.hkey_handles[ret_hkey] = s_subkey + else: + ret_hkey = args.hkey + + log.info("RegCreateKeyW(%x, '%s') = (%x,%d)" % (args.hkey, s_subkey, ret_hkey, ret)) + jitter.vm.set_u32(args.phandle, ret_hkey) + + jitter.func_ret_stdcall(ret_ad, ret) + +def kernel32_GetCurrentDirectoryA(jitter): + ret_ad, args = jitter.func_args_stdcall(["size","buf"]) + dir_ = winobjs.cur_dir + log.debug("GetCurrentDirectory() = '%s'" % dir_) + set_win_str_a(jitter, args.buf, dir_[:args.size-1]) + ret = len(dir_) + if args.size <= len(dir_): + ret += 1 + jitter.func_ret_stdcall(ret_ad, ret) + +def advapi32_RegOpenKeyEx(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["hkey", "subkey", + "reserved", "access", + "phandle"]) + s_subkey = get_str(args.subkey).lower() if args.subkey else "" + + ret_hkey = 0 + ret = 2 + if args.hkey in winobjs.hkey_handles: + if s_subkey: + h = hash(s_subkey) & 0xffffffff + if h in winobjs.hkey_handles: + ret_hkey = h + ret = 0 + else: + log.error('unknown skey') + + jitter.vm.set_u32(args.phandle, ret_hkey) + + jitter.func_ret_stdcall(ret_ad, ret) + + +def advapi32_RegOpenKeyExA(jitter): + advapi32_RegOpenKeyEx(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def advapi32_RegOpenKeyExW(jitter): + advapi32_RegOpenKeyEx(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def advapi32_RegSetValue(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["hkey", "psubkey", + "valuetype", "pvalue", + "vlen"]) + if args.psubkey: + log.info("Subkey %s", get_str(args.psubkey)) + if args.pvalue: + log.info("Value %s", get_str(args.pvalue)) + jitter.func_ret_stdcall(ret_ad, 0) + +def advapi32_RegSetValueEx(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["hkey", "lpvaluename", + "reserved", "dwtype", + "lpdata", "cbData"]) + hkey = winobjs.hkey_handles.get(args.hkey, "unknown HKEY") + value_name = get_str(args.lpvaluename) if args.lpvaluename else "" + data = get_str(args.lpdata) if args.lpdata else "" + log.info("%s('%s','%s'='%s',%x)" % (funcname, hkey, value_name, data, args.dwtype)) + jitter.func_ret_stdcall(ret_ad, 0) + +def advapi32_RegCloseKey(jitter): + ret_ad, args = jitter.func_args_stdcall(["hkey"]) + del winobjs.hkey_handles[args.hkey] + log.info("RegCloseKey(%x)" % args.hkey) + jitter.func_ret_stdcall(ret_ad, 0) + +def advapi32_RegSetValueExA(jitter): + advapi32_RegSetValueEx(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def advapi32_RegSetValueExW(jitter): + advapi32_RegOpenKeyEx(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def advapi32_RegSetValueA(jitter): + advapi32_RegSetValue(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def advapi32_RegSetValueW(jitter): + advapi32_RegSetValue(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_GetThreadLocale(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0x40c) + +def kernel32_SetCurrentDirectory(jitter, get_str): + ret_ad, args = jitter.func_args_stdcall(['dir']) + dir_ = get_str(args.dir) + log.debug("SetCurrentDirectory('%s') = 1" % dir_) + winobjs.cur_dir = dir_ + jitter.func_ret_stdcall(ret_ad, 1) + +def kernel32_SetCurrentDirectoryW(jitter): + return kernel32_SetCurrentDirectory(jitter, lambda addr:get_win_str_w(jitter, addr)) + +def kernel32_SetCurrentDirectoryA(jitter): + return kernel32_SetCurrentDirectory(jitter, lambda addr:get_win_str_a(jitter, addr)) + +def msvcrt_wcscat(jitter): + ret_ad, args = jitter.func_args_cdecl(['ptr_str1', 'ptr_str2']) + s1 = get_win_str_w(jitter, args.ptr_str1) + s2 = get_win_str_w(jitter, args.ptr_str2) + log.info("strcat('%s','%s')" % (s1,s2)) + set_win_str_w(jitter, args.ptr_str1, s1 + s2) + jitter.func_ret_cdecl(ret_ad, args.ptr_str1) + + +def kernel32_GetLocaleInfo(jitter, funcname, set_str): + ret_ad, args = jitter.func_args_stdcall(["localeid", "lctype", + "lplcdata", "cchdata"]) + + buf = None + ret = 0 + if args.localeid == 0x40c: + if args.lctype == 0x3: + buf = "ENGLISH" + buf = buf[:args.cchdata - 1] + set_str(args.lplcdata, buf) + ret = len(buf) + else: + raise ValueError('unimpl localeid') + + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetLocaleInfoA(jitter): + kernel32_GetLocaleInfo(jitter, whoami(), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetLocaleInfoW(jitter): + kernel32_GetLocaleInfo(jitter, whoami(), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_TlsAlloc(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + winobjs.tls_index += 1 + jitter.func_ret_stdcall(ret_ad, winobjs.tls_index) + + +def kernel32_TlsFree(jitter): + ret_ad, _ = jitter.func_args_stdcall(["tlsindex"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_TlsSetValue(jitter): + ret_ad, args = jitter.func_args_stdcall(["tlsindex", "tlsvalue"]) + winobjs.tls_values[args.tlsindex] = args.tlsvalue + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_TlsGetValue(jitter): + ret_ad, args = jitter.func_args_stdcall(["tlsindex"]) + if not args.tlsindex in winobjs.tls_values: + raise ValueError("unknown tls val", repr(args.tlsindex)) + jitter.func_ret_stdcall(ret_ad, winobjs.tls_values[args.tlsindex]) + + +def user32_GetKeyboardType(jitter): + ret_ad, args = jitter.func_args_stdcall(["typeflag"]) + + ret = 0 + if args.typeflag == 0: + ret = 4 + else: + raise ValueError('unimpl keyboard type') + + jitter.func_ret_stdcall(ret_ad, ret) + + +class startupinfo(object): + """ + typedef struct _STARTUPINFOA { + /* 00000000 */ DWORD cb; + /* 00000004 */ LPSTR lpReserved; + /* 00000008 */ LPSTR lpDesktop; + /* 0000000C */ LPSTR lpTitle; + /* 00000010 */ DWORD dwX; + /* 00000014 */ DWORD dwY; + /* 00000018 */ DWORD dwXSize; + /* 0000001C */ DWORD dwYSize; + /* 00000020 */ DWORD dwXCountChars; + /* 00000024 */ DWORD dwYCountChars; + /* 00000028 */ DWORD dwFillAttribute; + /* 0000002C */ DWORD dwFlags; + /* 00000030 */ WORD wShowWindow; + /* 00000032 */ WORD cbReserved2; + /* 00000034 */ LPBYTE lpReserved2; + /* 00000038 */ HANDLE hStdInput; + /* 0000003C */ HANDLE hStdOutput; + /* 00000040 */ HANDLE hStdError; + } STARTUPINFOA, *LPSTARTUPINFOA; + + """ + # TODO: fill with relevant values + # for now, struct is just a placeholder + cb = 0x0 + lpReserved = 0x0 + lpDesktop = 0x0 + lpTitle = 0x0 + dwX = 0x0 + dwY = 0x0 + dwXSize = 0x0 + dwYSize = 0x0 + dwXCountChars = 0x0 + dwYCountChars = 0x0 + dwFillAttribute = 0x0 + dwFlags = 0x0 + wShowWindow = 0x0 + cbReserved2 = 0x0 + lpReserved2 = 0x0 + hStdInput = 0x0 + hStdOutput = 0x0 + hStdError = 0x0 + + def pack(self): + return struct.pack('IIIIIIIIIIIIHHIIII', + self.cb, + self.lpReserved, + self.lpDesktop, + self.lpTitle, + self.dwX, + self.dwY, + self.dwXSize, + self.dwYSize, + self.dwXCountChars, + self.dwYCountChars, + self.dwFillAttribute, + self.dwFlags, + self.wShowWindow, + self.cbReserved2, + self.lpReserved2, + self.hStdInput, + self.hStdOutput, + self.hStdError) + + +def kernel32_GetStartupInfo(jitter, funcname, set_str): + """ + void GetStartupInfo( + LPSTARTUPINFOW lpStartupInfo + ); + + Retrieves the contents of the STARTUPINFO structure that was specified + when the calling process was created. + + https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getstartupinfow + + """ + ret_ad, args = jitter.func_args_stdcall(["ptr"]) + jitter.vm.set_mem(args.ptr, startupinfo().pack()) + jitter.func_ret_stdcall(ret_ad, args.ptr) + + +def kernel32_GetStartupInfoA(jitter): + kernel32_GetStartupInfo(jitter, whoami(), lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetStartupInfoW(jitter): + kernel32_GetStartupInfo(jitter, whoami(), lambda addr,value: set_win_str_w(jitter, addr, value)) + + +def kernel32_GetCurrentThreadId(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0x113377) + + +def kernel32_InitializeCriticalSection(jitter): + ret_ad, _ = jitter.func_args_stdcall(["lpcritic"]) + jitter.func_ret_stdcall(ret_ad, 0) + + +def user32_GetSystemMetrics(jitter): + ret_ad, args = jitter.func_args_stdcall(["nindex"]) + + ret = 0 + if args.nindex in [0x2a, 0x4a]: + ret = 0 + else: + raise ValueError('unimpl index') + jitter.func_ret_stdcall(ret_ad, ret) + + +def wsock32_WSAStartup(jitter): + ret_ad, args = jitter.func_args_stdcall(["version", "pwsadata"]) + jitter.vm.set_mem(args.pwsadata, b"\x01\x01\x02\x02WinSock 2.0\x00") + jitter.func_ret_stdcall(ret_ad, 0) + + +def get_current_filetime(): + """ + Get current filetime + https://msdn.microsoft.com/en-us/library/ms724228 + """ + curtime = winobjs.current_datetime + unixtime = int(time.mktime(curtime.timetuple())) + filetime = (int(unixtime * 1000000 + curtime.microsecond) * 10 + + DATE_1601_TO_1970) + return filetime + + +def unixtime_to_filetime(unixtime): + """ + Convert unixtime to filetime + https://msdn.microsoft.com/en-us/library/ms724228 + """ + return (unixtime * 10000000) + DATE_1601_TO_1970 + + +def filetime_to_unixtime(filetime): + """ + Convert filetime to unixtime + # https://msdn.microsoft.com/en-us/library/ms724228 + """ + return int((filetime - DATE_1601_TO_1970) // 10000000) + + +def datetime_to_systemtime(curtime): + + s = struct.pack('HHHHHHHH', + curtime.year, # year + curtime.month, # month + curtime.weekday(), # dayofweek + curtime.day, # day + curtime.hour, # hour + curtime.minute , # minutes + curtime.second, # seconds + int(curtime.microsecond // 1000), # millisec + ) + return s + + +def kernel32_GetSystemTimeAsFileTime(jitter): + ret_ad, args = jitter.func_args_stdcall(["lpSystemTimeAsFileTime"]) + + current_filetime = get_current_filetime() + filetime = struct.pack('II', + current_filetime & 0xffffffff, + (current_filetime>>32) & 0xffffffff) + + jitter.vm.set_mem(args.lpSystemTimeAsFileTime, filetime) + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_GetLocalTime(jitter): + ret_ad, args = jitter.func_args_stdcall(["lpsystemtime"]) + systemtime = datetime_to_systemtime(winobjs.current_datetime) + jitter.vm.set_mem(args.lpsystemtime, systemtime) + jitter.func_ret_stdcall(ret_ad, args.lpsystemtime) + + +def kernel32_GetSystemTime(jitter): + ret_ad, args = jitter.func_args_stdcall(["lpsystemtime"]) + systemtime = datetime_to_systemtime(winobjs.current_datetime) + jitter.vm.set_mem(args.lpsystemtime, systemtime) + jitter.func_ret_stdcall(ret_ad, args.lpsystemtime) + + +def kernel32_CreateFileMapping(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["hfile", "lpattr", "flprotect", + "dwmaximumsizehigh", + "dwmaximumsizelow", "lpname"]) + + if args.hfile == 0xffffffff: + # Create null mapping + if args.dwmaximumsizehigh: + raise NotImplementedError("Untested case") + hmap = StringIO("\x00" * args.dwmaximumsizelow) + hmap_handle = winobjs.handle_pool.add('filemem', hmap) + + ret = winobjs.handle_pool.add('filemapping', hmap_handle) + else: + if not args.hfile in winobjs.handle_pool: + raise ValueError('unknown handle') + ret = winobjs.handle_pool.add('filemapping', args.hfile) + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_CreateFileMappingA(jitter): + kernel32_CreateFileMapping(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_CreateFileMappingW(jitter): + kernel32_CreateFileMapping(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_MapViewOfFile(jitter): + ret_ad, args = jitter.func_args_stdcall(["hfile", "flprotect", + "dwfileoffsethigh", + "dwfileoffsetlow", + "length"]) + + if not args.hfile in winobjs.handle_pool: + raise ValueError('unknown handle') + hmap = winobjs.handle_pool[args.hfile] + if not hmap.info in winobjs.handle_pool: + raise ValueError('unknown file handle') + + hfile_o = winobjs.handle_pool[hmap.info] + fd = hfile_o.info + fd.seek((args.dwfileoffsethigh << 32) | args.dwfileoffsetlow) + data = fd.read(args.length) if args.length else fd.read() + length = len(data) + + log.debug('MapViewOfFile len: %x', len(data)) + + if not args.flprotect in ACCESS_DICT: + raise ValueError('unknown access dw!') + + alloc_addr = winobjs.heap.alloc(jitter, len(data)) + jitter.vm.set_mem(alloc_addr, data) + + winobjs.handle_mapped[alloc_addr] = (hfile_o, args.dwfileoffsethigh, + args.dwfileoffsetlow, length) + + jitter.func_ret_stdcall(ret_ad, alloc_addr) + + +def kernel32_UnmapViewOfFile(jitter): + ret_ad, args = jitter.func_args_stdcall(['ad']) + + if not args.ad in winobjs.handle_mapped: + raise NotImplementedError("Untested case") + """ + hfile_o, dwfileoffsethigh, dwfileoffsetlow, length = winobjs.handle_mapped[ad] + off = (dwfileoffsethigh<<32) | dwfileoffsetlow + s = jitter.vm.get_mem(ad, length) + hfile_o.info.seek(off) + hfile_o.info.write(s) + hfile_o.info.close() + """ + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetDriveType(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(['pathname']) + + p = get_str(args.pathname) + p = p.upper() + + log.debug('Drive: %r', p) + + ret = 0 + if p[0] == "C": + ret = 3 + + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetDriveTypeA(jitter): + kernel32_GetDriveType(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_GetDriveTypeW(jitter): + kernel32_GetDriveType(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_GetDiskFreeSpace(jitter, funcname, get_str): + ret_ad, args = jitter.func_args_stdcall(["lprootpathname", + "lpsectorpercluster", + "lpbytespersector", + "lpnumberoffreeclusters", + "lptotalnumberofclusters"]) + jitter.vm.set_u32(args.lpsectorpercluster, 8) + jitter.vm.set_u32(args.lpbytespersector, 0x200) + jitter.vm.set_u32(args.lpnumberoffreeclusters, 0x222222) + jitter.vm.set_u32(args.lptotalnumberofclusters, 0x333333) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetDiskFreeSpaceA(jitter): + kernel32_GetDiskFreeSpace(jitter, whoami(), lambda addr:get_win_str_a(jitter, addr)) + + +def kernel32_GetDiskFreeSpaceW(jitter): + kernel32_GetDiskFreeSpace(jitter, whoami(), lambda addr:get_win_str_w(jitter, addr)) + + +def kernel32_VirtualQuery(jitter): + ret_ad, args = jitter.func_args_stdcall(["ad", "lpbuffer", "dwl"]) + + all_mem = jitter.vm.get_all_memory() + found = None + for basead, m in viewitems(all_mem): + if basead <= args.ad < basead + m['size']: + found = args.ad, m + break + if not found: + raise ValueError('cannot find mem', hex(args.ad)) + + if args.dwl != 0x1c: + raise ValueError('strange mem len', hex(args.dwl)) + s = struct.pack('IIIIIII', + args.ad, + basead, + ACCESS_DICT_INV[m['access']], + m['size'], + 0x1000, + ACCESS_DICT_INV[m['access']], + 0x01000000) + jitter.vm.set_mem(args.lpbuffer, s) + jitter.func_ret_stdcall(ret_ad, args.dwl) + + +def kernel32_GetProcessAffinityMask(jitter): + ret_ad, args = jitter.func_args_stdcall(["hprocess", + "procaffmask", + "systemaffmask"]) + jitter.vm.set_u32(args.procaffmask, 1) + jitter.vm.set_u32(args.systemaffmask, 1) + jitter.func_ret_stdcall(ret_ad, 1) + + +def msvcrt_rand(jitter): + ret_ad, _ = jitter.func_args_cdecl(0) + jitter.func_ret_stdcall(ret_ad, 0x666) + +def msvcrt_srand(jitter): + ret_ad, _ = jitter.func_args_cdecl(['seed']) + jitter.func_ret_stdcall(ret_ad, 0) + +def msvcrt_wcslen(jitter): + ret_ad, args = jitter.func_args_cdecl(["pwstr"]) + s = get_win_str_w(jitter, args.pwstr) + jitter.func_ret_cdecl(ret_ad, len(s)) + +def kernel32_SetFilePointer(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "dinstance", + "p_dinstance_high", + "movemethod"]) + + if args.hwnd == winobjs.module_cur_hwnd: + pass + elif args.hwnd in winobjs.handle_pool: + pass + else: + raise ValueError('unknown hwnd!') + + # data = None + if args.hwnd in winobjs.files_hwnd: + winobjs.files_hwnd[winobjs.module_cur_hwnd].seek(args.dinstance, args.movemethod) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + wh.info.seek(args.dinstance, args.movemethod) + else: + raise ValueError('unknown filename') + jitter.func_ret_stdcall(ret_ad, args.dinstance) + + +def kernel32_SetFilePointerEx(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "dinstance_l", + "dinstance_h", + "pnewfileptr", + "movemethod"]) + dinstance = args.dinstance_l | (args.dinstance_h << 32) + if dinstance: + raise ValueError('Not implemented') + if args.pnewfileptr: + raise ValueError('Not implemented') + if args.hwnd == winobjs.module_cur_hwnd: + pass + elif args.hwnd in winobjs.handle_pool: + pass + else: + raise ValueError('unknown hwnd!') + + # data = None + if args.hwnd in winobjs.files_hwnd: + winobjs.files_hwnd[winobjs.module_cur_hwnd].seek(dinstance, args.movemethod) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + wh.info.seek(dinstance, args.movemethod) + else: + raise ValueError('unknown filename') + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_SetEndOfFile(jitter): + ret_ad, args = jitter.func_args_stdcall(['hwnd']) + if args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + wh.info.seek(0, 2) + else: + raise ValueError('unknown filename') + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_FlushFileBuffers(jitter): + ret_ad, args = jitter.func_args_stdcall(['hwnd']) + if args.hwnd in winobjs.handle_pool: + pass + else: + raise ValueError('unknown filename') + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_WriteFile(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpbuffer", + "nnumberofbytestowrite", + "lpnumberofbyteswrite", + "lpoverlapped"]) + data = jitter.vm.get_mem(args.lpbuffer, args.nnumberofbytestowrite) + + if args.hwnd == winobjs.module_cur_hwnd: + pass + elif args.hwnd in winobjs.handle_pool: + pass + else: + raise ValueError('unknown hwnd!') + + if args.hwnd in winobjs.files_hwnd: + winobjs.files_hwnd[winobjs.module_cur_hwnd].write(data) + elif args.hwnd in winobjs.handle_pool: + wh = winobjs.handle_pool[args.hwnd] + wh.info.write(data) + else: + raise ValueError('unknown filename') + + if (args.lpnumberofbyteswrite): + jitter.vm.set_u32(args.lpnumberofbyteswrite, len(data)) + + jitter.func_ret_stdcall(ret_ad, 1) + + +def user32_IsCharUpperA(jitter): + ret_ad, args = jitter.func_args_stdcall(["c"]) + ret = 0 if args.c & 0x20 else 1 + jitter.func_ret_stdcall(ret_ad, ret) + + +def user32_IsCharLowerA(jitter): + ret_ad, args = jitter.func_args_stdcall(["c"]) + ret = 1 if args.c & 0x20 else 0 + jitter.func_ret_stdcall(ret_ad, ret) + + +def kernel32_GetSystemDefaultLangID(jitter): + ret_ad, _ = jitter.func_args_stdcall(0) + jitter.func_ret_stdcall(ret_ad, 0x409) # encglish + + +def msvcrt_malloc(jitter): + ret_ad, args = jitter.func_args_cdecl(["msize"]) + addr = winobjs.heap.alloc(jitter, args.msize) + jitter.func_ret_cdecl(ret_ad, addr) + + +def msvcrt_free(jitter): + ret_ad, _ = jitter.func_args_cdecl(["ptr"]) + jitter.func_ret_cdecl(ret_ad, 0) + + +def msvcrt_fseek(jitter): + ret_ad, args = jitter.func_args_cdecl(['stream', 'offset', 'orig']) + fd = jitter.vm.get_u32(args.stream + 0x10) + + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + o = winobjs.handle_pool[fd] + o.info.seek(args.offset, args.orig) + jitter.func_ret_cdecl(ret_ad, 0) + + +def msvcrt_ftell(jitter): + ret_ad, args = jitter.func_args_cdecl(["stream"]) + fd = jitter.vm.get_u32(args.stream + 0x10) + + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + o = winobjs.handle_pool[fd] + off = o.info.tell() + jitter.func_ret_cdecl(ret_ad, off) + + +def msvcrt_rewind(jitter): + ret_ad, args = jitter.func_args_cdecl(["stream"]) + fd = jitter.vm.get_u32(args.stream + 0x10) + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + o = winobjs.handle_pool[fd] + # off = o.info.seek(0, 0) + jitter.func_ret_cdecl(ret_ad, 0) + + +def msvcrt_fread(jitter): + ret_ad, args = jitter.func_args_cdecl(["buf", "size", "nmemb", "stream"]) + fd = jitter.vm.get_u32(args.stream + 0x10) + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + + data = winobjs.handle_pool[fd].info.read(args.size * args.nmemb) + jitter.vm.set_mem(args.buf, data) + jitter.func_ret_cdecl(ret_ad, args.nmemb) + + +def msvcrt_fwrite(jitter): + ret_ad, args = jitter.func_args_cdecl(["buf", "size", "nmemb", "stream"]) + fd = jitter.vm.get_u32(args.stream + 0x10) + if not fd in winobjs.handle_pool: + raise NotImplementedError("Unknown file handle!") + + data = jitter.vm.get_mem(args.buf, args.size*args.nmemb) + winobjs.handle_pool[fd].info.write(data) + jitter.func_ret_cdecl(ret_ad, args.nmemb) + + +def msvcrt_fclose(jitter): + ret_ad, args = jitter.func_args_cdecl(['stream']) + fd = jitter.vm.get_u32(args.stream + 0x10) + + if not fd in winobjs.handle_pool: + raise NotImplementedError("Untested case") + o = winobjs.handle_pool[fd] + # off = o.info.close() + jitter.func_ret_cdecl(ret_ad, 0) + + +def msvcrt_atexit(jitter): + ret_ad, _ = jitter.func_args_cdecl(["func"]) + jitter.func_ret_cdecl(ret_ad, 0) + + +def user32_MessageBoxA(jitter): + ret_ad, args = jitter.func_args_stdcall(["hwnd", "lptext", + "lpcaption", "utype"]) + + text = get_win_str_a(jitter, args.lptext) + caption = get_win_str_a(jitter, args.lpcaption) + + log.info('Caption: %r Text: %r', caption, text) + + jitter.func_ret_stdcall(ret_ad, 0) + + +def kernel32_myGetTempPath(jitter, set_str): + ret_ad, args = jitter.func_args_stdcall(["l", "buf"]) + l = 'c:\\temp\\' + if len(l) < args.l: + set_str(args.buf, l) + jitter.func_ret_stdcall(ret_ad, len(l)) + + +def kernel32_GetTempPathA(jitter): + kernel32_myGetTempPath(jitter, lambda addr,value: set_win_str_a(jitter, addr, value)) + + +def kernel32_GetTempPathW(jitter): + kernel32_myGetTempPath(jitter, lambda addr,value: set_win_str_w(jitter, addr, value)) + + +temp_num = 0 + + +def kernel32_GetTempFileNameA(jitter): + global temp_num + ret_ad, args = jitter.func_args_stdcall(["path", "ext", "unique", "buf"]) + + temp_num += 1 + ext = get_win_str_a(jitter, args.ext) if args.ext else 'tmp' + path = get_win_str_a(jitter, args.path) if args.path else "xxx" + fname = path + "\\" + "temp%.4d" % temp_num + "." + ext + jitter.vm.set_mem(args.buf, fname.encode('utf-8')) + + jitter.func_ret_stdcall(ret_ad, 0) + + +class win32_find_data(object): + fileattrib = 0 + creationtime = 0 + lastaccesstime = 0 + lastwritetime = 0 + filesizehigh = 0 + filesizelow = 0 + dwreserved0 = 0 + dwreserved1 = 0x1337beef + cfilename = "" + alternamefilename = "" + + def __init__(self, **kargs): + for k, v in viewitems(kargs): + setattr(self, k, v) + + def toStruct(self, encode_str=encode_win_str_w): + s = struct.pack('=IQQQIIII', + self.fileattrib, + self.creationtime, + self.lastaccesstime, + self.lastwritetime, + self.filesizehigh, + self.filesizelow, + self.dwreserved0, + self.dwreserved1) + fname = encode_str(self.cfilename) + b'\x00' * MAX_PATH + fname = fname[:MAX_PATH] + s += fname + fname = encode_str(self.alternamefilename) + b'\x00' * 14 + fname = fname[:14] + s += fname + return s + + +class find_data_mngr(object): + + def __init__(self): + self.patterns = {} + self.flist = [] + # handle number -> (flist index, current index in list) + self.handles = {} + + def add_list(self, pattern, flist): + index = len(self.flist) + self.flist.append(flist) + + self.patterns[pattern] = index + + def findfirst(self, pattern): + assert(pattern in self.patterns) + findex = self.patterns[pattern] + h = len(self.handles) + 1 + self.handles[h] = [findex, 0] + return h + + def findnext(self, h): + assert(h in self.handles) + findex, index = self.handles[h] + if index >= len(self.flist[findex]): + return None + fname = self.flist[findex][index] + self.handles[h][1] += 1 + + return fname + +def my_FindFirstFile(jitter, pfilepattern, pfindfiledata, get_win_str, encode_str): + filepattern = get_win_str(jitter, pfilepattern) + h = winobjs.find_data.findfirst(filepattern) + + fname = winobjs.find_data.findnext(h) + fdata = win32_find_data(cfilename=fname) + + jitter.vm.set_mem(pfindfiledata, fdata.toStruct(encode_str=encode_str)) + return h + +def kernel32_FindFirstFileA(jitter): + ret_ad, args = jitter.func_args_stdcall(["pfilepattern", "pfindfiledata"]) + h = my_FindFirstFile(jitter, args.pfilepattern, args.pfindfiledata, + get_win_str_a, encode_win_str_a) + jitter.func_ret_stdcall(ret_ad, h) + +def kernel32_FindFirstFileW(jitter): + ret_ad, args = jitter.func_args_stdcall(["pfilepattern", "pfindfiledata"]) + h = my_FindFirstFile(jitter, args.pfilepattern, args.pfindfiledata, + get_win_str_w, encode_win_str_w) + jitter.func_ret_stdcall(ret_ad, h) + +def kernel32_FindFirstFileExA(jitter): + ret_ad, args = jitter.func_args_stdcall([ + "lpFileName", + "fInfoLevelId", + "lpFindFileData", + "fSearchOp", + "lpSearchFilter", + "dwAdditionalFlags"]) + h = my_FindFirstFile(jitter, args.lpFileName, args.lpFindFileData, + get_win_str_a, encode_win_str_a) + jitter.func_ret_stdcall(ret_ad, h) + +def kernel32_FindFirstFileExW(jitter): + ret_ad, args = jitter.func_args_stdcall([ + "lpFileName", + "fInfoLevelId", + "lpFindFileData", + "fSearchOp", + "lpSearchFilter", + "dwAdditionalFlags"]) + h = my_FindFirstFile(jitter, args.lpFileName, args.lpFindFileData, + get_win_str_w, encode_win_str_w) + jitter.func_ret_stdcall(ret_ad, h) + +def my_FindNextFile(jitter, encode_str): + ret_ad, args = jitter.func_args_stdcall(["handle", "pfindfiledata"]) + fname = winobjs.find_data.findnext(args.handle) + if fname is None: + winobjs.lastwin32error = 0x12 # ERROR_NO_MORE_FILES + ret = 0 + else: + ret = 1 + fdata = win32_find_data(cfilename=fname) + jitter.vm.set_mem(args.pfindfiledata, fdata.toStruct(encode_str=encode_str)) + jitter.func_ret_stdcall(ret_ad, ret) + +kernel32_FindNextFileA = lambda jitter: my_FindNextFile(jitter, encode_win_str_a) +kernel32_FindNextFileW = lambda jitter: my_FindNextFile(jitter, encode_win_str_w) + +def kernel32_GetNativeSystemInfo(jitter): + ret_ad, args = jitter.func_args_stdcall(["sys_ptr"]) + sysinfo = systeminfo() + jitter.vm.set_mem(args.sys_ptr, sysinfo.pack()) + jitter.func_ret_stdcall(ret_ad, 0) + + +def raw2guid(r): + o = struct.unpack('IHHHBBBBBB', r) + return '{%.8X-%.4X-%.4X-%.4X-%.2X%.2X%.2X%.2X%.2X%.2X}' % o + + +digs = string.digits + string.ascii_lowercase + + +def int2base(x, base): + if x < 0: + sign = -1 + elif x == 0: + return '0' + else: + sign = 1 + x *= sign + digits = [] + while x: + digits.append(digs[x % base]) + x /= base + if sign < 0: + digits.append('-') + digits.reverse() + return ''.join(digits) + + +def msvcrt__ultow(jitter): + ret_ad, args = jitter.func_args_cdecl(["value", "p", "radix"]) + + value = args.value & 0xFFFFFFFF + if not args.radix in [10, 16, 20]: + raise ValueError("Not tested") + s = int2base(value, args.radix) + set_win_str_w(jitter, args.p, s) + jitter.func_ret_cdecl(ret_ad, args.p) + + +def msvcrt_myfopen(jitter, get_str): + ret_ad, args = jitter.func_args_cdecl(["pfname", "pmode"]) + + fname = get_str(args.pfname) + rw = get_str(args.pmode) + log.info("fopen %r, %r", fname, rw) + + if rw in ['r', 'rb', 'wb+','wb','wt']: + sb_fname = windows_to_sbpath(fname) + h = open(sb_fname, rw) + eax = winobjs.handle_pool.add(sb_fname, h) + dwsize = 0x20 + alloc_addr = winobjs.heap.alloc(jitter, dwsize) + pp = pck32(0x11112222) + pck32(0) + pck32(0) + pck32(0) + pck32(eax) + jitter.vm.set_mem(alloc_addr, pp) + + else: + raise ValueError('unknown access mode %s' % rw) + + jitter.func_ret_cdecl(ret_ad, alloc_addr) + + +def msvcrt__wfopen(jitter): + msvcrt_myfopen(jitter, lambda addr:get_win_str_w(jitter, addr)) + + +def msvcrt_fopen(jitter): + msvcrt_myfopen(jitter, lambda addr:get_win_str_a(jitter, addr)) + + +def msvcrt_strlen(jitter): + ret_ad, args = jitter.func_args_cdecl(["src"]) + + s = get_win_str_a(jitter, args.src) + jitter.func_ret_cdecl(ret_ad, len(s)) + + +def kernel32_QueryPerformanceCounter(jitter): + ret_ad, args = jitter.func_args_stdcall(["lpPerformanceCount"]) + jitter.vm.set_mem(args.lpPerformanceCount, struct.pack('<Q', 0x1)) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_InitializeCriticalSectionEx(jitter): + ''' + LPCRITICAL_SECTION lpCriticalSection, + DWORD dwSpinCount, + DWORD Flags + ''' + ret_ad, args = jitter.func_args_stdcall(["lpCriticalSection", "dwSpinCount", "Flags"]) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_EnterCriticalSection(jitter): + ''' + void EnterCriticalSection( + LPCRITICAL_SECTION lpCriticalSection + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["lpCriticalSection"]) + jitter.func_ret_stdcall(ret_ad, 0x0) + + +def kernel32_LeaveCriticalSection(jitter): + ''' + void LeaveCriticalSection( + LPCRITICAL_SECTION lpCriticalSection + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["lpCriticalSection"]) + jitter.func_ret_stdcall(ret_ad, 0x0) + + +class FLS(object): + def __init__(self): + self.slots = [] + + def kernel32_FlsAlloc(self, jitter): + ''' + DWORD FlsAlloc( + PFLS_CALLBACK_FUNCTION lpCallback + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["lpCallback"]) + index = len(self.slots) + self.slots.append(0x0) + jitter.func_ret_stdcall(ret_ad, index) + + def kernel32_FlsSetValue(self, jitter): + ''' + BOOL FlsSetValue( + DWORD dwFlsIndex, + PVOID lpFlsData + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["dwFlsIndex", "lpFlsData"]) + self.slots[args.dwFlsIndex] = args.lpFlsData + jitter.func_ret_stdcall(ret_ad, 1) + + def kernel32_FlsGetValue(self, jitter): + ''' + PVOID FlsGetValue( + DWORD dwFlsIndex + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["dwFlsIndex"]) + jitter.func_ret_stdcall(ret_ad, self.slots[args.dwFlsIndex]) + +fls = FLS() + + +def kernel32_GetProcessHeap(jitter): + ''' + HANDLE GetProcessHeap(); + ''' + ret_ad, args = jitter.func_args_stdcall([]) + hHeap = 0x67676767 + jitter.func_ret_stdcall(ret_ad, hHeap) + + +STD_INPUT_HANDLE = 0xfffffff6 +STD_OUTPUT_HANDLE = 0xfffffff5 +STD_ERROR_HANDLE = 0xfffffff4 + + +def kernel32_GetStdHandle(jitter): + ''' + HANDLE WINAPI GetStdHandle( + _In_ DWORD nStdHandle + ); + + STD_INPUT_HANDLE (DWORD)-10 + The standard input device. Initially, this is the console input buffer, CONIN$. + + STD_OUTPUT_HANDLE (DWORD)-11 + The standard output device. Initially, this is the active console screen buffer, CONOUT$. + + STD_ERROR_HANDLE (DWORD)-12 + The standard error device. Initially, this is the active console screen buffer, CONOUT$. + ''' + ret_ad, args = jitter.func_args_stdcall(["nStdHandle"]) + jitter.func_ret_stdcall(ret_ad, { + STD_OUTPUT_HANDLE: 1, + STD_ERROR_HANDLE: 2, + STD_INPUT_HANDLE: 3, + }[args.nStdHandle]) + + +FILE_TYPE_UNKNOWN = 0x0000 +FILE_TYPE_CHAR = 0x0002 + + +def kernel32_GetFileType(jitter): + ''' + DWORD GetFileType( + HANDLE hFile + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["hFile"]) + jitter.func_ret_stdcall(ret_ad, { + # STD_OUTPUT_HANDLE + 1: FILE_TYPE_CHAR, + # STD_ERROR_HANDLE + 2: FILE_TYPE_CHAR, + # STD_INPUT_HANDLE + 3: FILE_TYPE_CHAR, + }.get(args.hFile, FILE_TYPE_UNKNOWN)) + + +def kernel32_IsProcessorFeaturePresent(jitter): + ''' + BOOL IsProcessorFeaturePresent( + DWORD ProcessorFeature + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["ProcessorFeature"]) + jitter.func_ret_stdcall(ret_ad, { + # PF_ARM_64BIT_LOADSTORE_ATOMIC + 25: False, + # PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE + 24: False, + # PF_ARM_EXTERNAL_CACHE_AVAILABLE + 26: False, + # PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE + 27: False, + # PF_ARM_VFP_32_REGISTERS_AVAILABLE + 18: False, + # PF_3DNOW_INSTRUCTIONS_AVAILABLE + 7: False, + # PF_CHANNELS_ENABLED + 16: True, + # PF_COMPARE_EXCHANGE_DOUBLE + 2: False, + # PF_COMPARE_EXCHANGE128 + 14: False, + # PF_COMPARE64_EXCHANGE128 + 15: False, + # PF_FASTFAIL_AVAILABLE + 23: False, + # PF_FLOATING_POINT_EMULATED + 1: False, + # PF_FLOATING_POINT_PRECISION_ERRATA + 0: True, + # PF_MMX_INSTRUCTIONS_AVAILABLE + 3: True, + # PF_NX_ENABLED + 12: True, + # PF_PAE_ENABLED + 9: True, + # PF_RDTSC_INSTRUCTION_AVAILABLE + 8: True, + # PF_RDWRFSGSBASE_AVAILABLE + 22: True, + # PF_SECOND_LEVEL_ADDRESS_TRANSLATION + 20: True, + # PF_SSE3_INSTRUCTIONS_AVAILABLE + 13: True, + # PF_VIRT_FIRMWARE_ENABLED + 21: False, + # PF_XMMI_INSTRUCTIONS_AVAILABLE + 6: True, + # PF_XMMI64_INSTRUCTIONS_AVAILABLE + 10: True, + # PF_XSAVE_ENABLED + 17: False, + }[args.ProcessorFeature]) + + +def kernel32_GetACP(jitter): + ''' + UINT GetACP(); + ''' + ret_ad, args = jitter.func_args_stdcall([]) + # Windows-1252: Latin 1 / Western European Superset of ISO-8859-1 (without C1 controls). + jitter.func_ret_stdcall(ret_ad, 1252) + + +# ref: https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers +VALID_CODE_PAGES = { + 37,437,500,708,709,710,720,737,775,850,852,855,857,858,860,861,862,863,864,865,866,869,870,874,875, + 932,936,949,950,1026,1047,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1200,1201,1250,1251,1252, + 1253,1254,1255,1256,1257,1258,1361,10000,10001,10002,10003,10004,10005,10006,10007,10008,10010,10017, + 10021,10029,10079,10081,10082,12000,12001,20000,20001,20002,20003,20004,20005,20105,20106,20107,20108, + 20127,20261,20269,20273,20277,20278,20280,20284,20285,20290,20297,20420,20423,20424,20833,20838,20866, + 20871,20880,20905,20924,20932,20936,20949,21025,21027,21866,28591,28592,28593,28594,28595,28596,28597, + 28598,28599,28603,28605,29001,38598,50220,50221,50222,50225,50227,50229,50930,50931,50933,50935,50936, + 50937,50939,51932,51936,51949,51950,52936,54936,57002,57003,57004,57005,57006,57007,57008,57009,57010, + 57011,65000,65001 +} + + +def kernel32_IsValidCodePage(jitter): + ''' + BOOL IsValidCodePage( + UINT CodePage + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["CodePage"]) + jitter.func_ret_stdcall(ret_ad, args.CodePage in VALID_CODE_PAGES) + + +def kernel32_GetCPInfo(jitter): + ''' + BOOL GetCPInfo( + UINT CodePage, + LPCPINFO lpCPInfo + ); + ''' + ret_ad, args = jitter.func_args_stdcall(["CodePage", "lpCPInfo"]) + assert args.CodePage == 1252 + # ref: http://www.rensselaer.org/dept/cis/software/g77-mingw32/include/winnls.h + #define MAX_LEADBYTES 12 + #define MAX_DEFAULTCHAR 2 + jitter.vm.set_mem(args.lpCPInfo, struct.pack('<I', 0x1) + b'??' + b'\x00' * 12) + jitter.func_ret_stdcall(ret_ad, 1) + + +def kernel32_GetStringTypeW(jitter): + """ + BOOL GetStringTypeW( + DWORD dwInfoType, + _In_NLS_string_(cchSrc)LPCWCH lpSrcStr, + int cchSrc, + LPWORD lpCharType + ); + + Retrieves character type information for the characters in the specified + Unicode source string. For each character in the string, the function + sets one or more bits in the corresponding 16-bit element of the output + array. Each bit identifies a given character type, for example, letter, + digit, or neither. + + """ + # These types support ANSI C and POSIX (LC_CTYPE) character typing + # functions.A bitwise-OR of these values is retrieved in the array in the + # output buffer when dwInfoType is set to CT_CTYPE1. For DBCS locales, the + # type attributes apply to both narrow characters and wide characters. The + # Japanese hiragana and katakana characters, and the kanji ideograph + # characters all have the C1_ALPHA attribute. + CT_TYPE1 = 0x01 + # TODO handle other types of information + # (CT_TYPE2, CT_TYPE3) + # for now, they raise NotImplemented + CT_TYPE2 = 0x02 + CT_TYPE3 = 0x03 + + C1_UPPER = 0x0001 # Uppercase + C1_LOWER = 0x0002 # Lowercase + C1_DIGIT = 0x0004 # Decimal digits + C1_SPACE = 0x0008 # Space characters + C1_PUNCT = 0x0010 # Punctuation + C1_CNTRL = 0x0020 # Control characters + C1_BLANK = 0x0040 # Blank characters + C1_XDIGIT = 0x0080 # Hexadecimal digits + C1_ALPHA = 0x0100 # Any linguistic character: alphabetical, syllabary, or ideographic + C1_DEFINED = 0x0200 # A defined character, but not one of the other C1_* types + + # the following sets have been generated from the Linux python library curses + # e.g., C1_PUNCT_SET = [chr(i) for i in range(256) if curses.ascii.ispunct(chr(i))] + C1_PUNCT_SET = ['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', + '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', + '^', '_', '`', '{', '|', '}', '~'] + C1_CNTRL_SET = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', + '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', + '\x7f'] + C1_BLANK_SET = ['\t', ' '] + C1_XDIGIT_SET = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', + 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f'] + + ret, args = jitter.func_args_stdcall(['dwInfoType', 'lpSrcStr', 'cchSrc', + 'lpCharType']) + s = jitter.vm.get_mem(args.lpSrcStr, args.cchSrc).decode("utf-16") + if args.dwInfoType == CT_TYPE1: + # iterate over characters from the decoded W string + for i, c in enumerate(s): + # TODO handle non-ascii characters + if not c.isascii(): + continue + val = 0 + if c.isupper(): + val |= C1_UPPER + if c.islower(): + val |= C1_LOWER + if c.isdigit(): + val |= C1_DIGIT + if c.isspace(): + val |= C1_SPACE + if c in C1_PUNCT_SET: + val |= C1_PUNCT + if c in C1_CNTRL_SET: + val |= C1_CNTRL + if c in C1_BLANK_SET: + val |= C1_BLANK + if c in C1_XDIGIT_SET: + val |= C1_XDIGIT + if c.isalpha(): + val |= C1_ALPHA + if val == 0: + val = C1_DEFINED + jitter.vm.set_u16(args.lpCharType + i * 2, val) + elif args.dwInfoType == CT_TYPE2: + raise NotImplemented + elif args.dwInfoType == CT_TYPE3: + raise NotImplemented + else: + raise ValueError("CT_TYPE unknown: %i" % args.dwInfoType) + jitter.func_ret_stdcall(ret, 1) + return True |