from __future__ import print_function # # Copyright (C) 2011 EADS France, Fabrice Desclaux # # 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('', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'] 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