about summary refs log tree commit diff stats
path: root/src/miasm/os_dep
diff options
context:
space:
mode:
Diffstat (limited to 'src/miasm/os_dep')
-rw-r--r--src/miasm/os_dep/__init__.py1
-rw-r--r--src/miasm/os_dep/common.py169
-rw-r--r--src/miasm/os_dep/linux/__init__.py1
-rw-r--r--src/miasm/os_dep/linux/environment.py993
-rw-r--r--src/miasm/os_dep/linux/syscall.py1129
-rw-r--r--src/miasm/os_dep/linux_stdlib.py213
-rw-r--r--src/miasm/os_dep/win_32_structs.py231
-rw-r--r--src/miasm/os_dep/win_api_x86_32.py3595
-rw-r--r--src/miasm/os_dep/win_api_x86_32_seh.py705
9 files changed, 7037 insertions, 0 deletions
diff --git a/src/miasm/os_dep/__init__.py b/src/miasm/os_dep/__init__.py
new file mode 100644
index 00000000..6aa660d8
--- /dev/null
+++ b/src/miasm/os_dep/__init__.py
@@ -0,0 +1 @@
+"Operating System specific methods"
diff --git a/src/miasm/os_dep/common.py b/src/miasm/os_dep/common.py
new file mode 100644
index 00000000..74100817
--- /dev/null
+++ b/src/miasm/os_dep/common.py
@@ -0,0 +1,169 @@
+import os
+
+from future.utils import viewitems
+
+from miasm.core.utils import force_bytes, force_str
+from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
+from miasm.core.utils import get_caller_name
+from miasm.core.utils import pck64, upck64
+
+BASE_SB_PATH = "file_sb"
+WIN_CODEPAGE = "cp1252"
+
+def get_win_str_a(jitter, ad_str, max_char=None):
+    l = 0
+    tmp = ad_str
+    while ((max_char is None or l < max_char) and
+           jitter.vm.get_mem(tmp, 1) != b"\x00"):
+        tmp += 1
+        l += 1
+    data = jitter.vm.get_mem(ad_str, l)
+    ret = data.decode(WIN_CODEPAGE)
+    return ret
+
+
+def get_win_str_w(jitter, ad_str, max_char=None):
+    l = 0
+    tmp = ad_str
+    while ((max_char is None or l < max_char) and
+           jitter.vm.get_mem(tmp, 2) != b"\x00\x00"):
+        tmp += 2
+        l += 2
+    s = jitter.vm.get_mem(ad_str, l)
+    s = s.decode("utf-16le")
+    return s
+
+def encode_win_str_a(value):
+    value = value.encode(WIN_CODEPAGE) + b"\x00"
+    return value
+
+def encode_win_str_w(value):
+    value = value.encode("utf-16le") + b'\x00' * 2
+    return value
+
+
+def set_win_str_a(jitter, addr, value):
+    value = encode_win_str_a(value)
+    jitter.vm.set_mem(addr, value)
+
+
+def set_win_str_w(jitter, addr, value):
+    value = encode_win_str_w(value)
+    jitter.vm.set_mem(addr, value)
+
+
+class heap(object):
+
+    "Light heap simulation"
+
+    addr = 0x20000000
+    align = 0x1000
+    size = 32
+    mask = (1 << size) - 1
+
+    def next_addr(self, size):
+        """
+        @size: the size to allocate
+        return the future checnk address
+        """
+        ret = self.addr
+        self.addr = (self.addr + size + self.align - 1)
+        self.addr &= self.mask ^ (self.align - 1)
+        return ret
+
+    def alloc(self, jitter, size, perm=PAGE_READ | PAGE_WRITE, cmt=""):
+        """
+        @jitter: a jitter instance
+        @size: the size to allocate
+        @perm: permission flags (see vm_alloc doc)
+        """
+        return self.vm_alloc(jitter.vm, size, perm=perm, cmt=cmt)
+
+    def vm_alloc(self, vm, size, perm=PAGE_READ | PAGE_WRITE, cmt=""):
+        """
+        @vm: a VmMngr instance
+        @size: the size to allocate
+        @perm: permission flags (PAGE_READ, PAGE_WRITE, PAGE_EXEC or any `|`
+            combination of them); default is PAGE_READ|PAGE_WRITE
+        """
+        addr = self.next_addr(size)
+        vm.add_memory_page(
+            addr,
+            perm,
+            b"\x00" * (size),
+            "Heap alloc by %s %s" % (get_caller_name(2), cmt)
+        )
+        return addr
+
+    def get_size(self, vm, ptr):
+        """
+        @vm: a VmMngr instance
+        @size: ptr to get the size of the associated allocation.
+
+        `ptr` can be the base address of a previous allocation, or an address
+        within the allocated range. The size of the whole allocation is always
+        returned, regardless ptr is the base address or not.
+        """
+        assert vm.is_mapped(ptr, 1)
+        data = vm.get_all_memory()
+        ptr_page = data.get(ptr, None)
+        if ptr_page is None:
+            for address, page_info in viewitems(data):
+                if address <= ptr < address + page_info["size"]:
+                    ptr_page = page_info
+                    break
+            else:
+                raise RuntimeError("Must never happen (unmapped but mark as mapped by API)")
+        return ptr_page["size"]
+
+
+def windows_to_sbpath(path):
+    """Convert a Windows path to a valid filename within the sandbox
+    base directory.
+
+    """
+    path = [elt for elt in path.lower().replace('/', '_').split('\\') if elt]
+    return os.path.join(BASE_SB_PATH, *path)
+
+
+def unix_to_sbpath(path):
+    """Convert a POSIX path to a valid filename within the sandbox
+    base directory.
+
+    """
+    path = [elt for elt in path.split('/') if elt]
+    return os.path.join(BASE_SB_PATH, *path)
+
+def get_fmt_args(fmt, cur_arg, get_str, get_arg_n):
+    idx = 0
+    fmt = get_str(fmt)
+    chars_format = '%cdfsuxX'
+    char_percent = '%'
+    char_string = 's'
+    output = ""
+
+    while True:
+        if idx == len(fmt):
+            break
+        char = fmt[idx:idx+1]
+        idx += 1
+        if char == char_percent:
+            token = char_percent
+            while True:
+                char = fmt[idx:idx+1]
+                idx += 1
+                token += char
+                if char in chars_format:
+                    break
+            if char == char_percent:
+                output += char
+                continue
+            if token.endswith(char_string):
+                addr = get_arg_n(cur_arg)
+                arg = get_str(addr)
+            else:
+                arg = get_arg_n(cur_arg)
+            char = token % arg
+            cur_arg += 1
+        output += char
+    return output
diff --git a/src/miasm/os_dep/linux/__init__.py b/src/miasm/os_dep/linux/__init__.py
new file mode 100644
index 00000000..4434ce50
--- /dev/null
+++ b/src/miasm/os_dep/linux/__init__.py
@@ -0,0 +1 @@
+# Linux emulation
diff --git a/src/miasm/os_dep/linux/environment.py b/src/miasm/os_dep/linux/environment.py
new file mode 100644
index 00000000..3ba4382f
--- /dev/null
+++ b/src/miasm/os_dep/linux/environment.py
@@ -0,0 +1,993 @@
+from __future__ import print_function
+from collections import namedtuple
+import functools
+import logging
+import os
+import re
+import struct
+import termios
+
+from future.utils import viewitems
+
+from miasm.core.interval import interval
+from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
+
+
+REGEXP_T = type(re.compile(r''))
+
+StatInfo = namedtuple("StatInfo", [
+    "st_dev", "st_ino", "st_nlink", "st_mode", "st_uid", "st_gid", "st_rdev",
+    "st_size", "st_blksize", "st_blocks", "st_atime", "st_atimensec",
+    "st_mtime", "st_mtimensec", "st_ctime", "st_ctimensec"
+])
+StatFSInfo = namedtuple("StatFSInfo", [
+    "f_type", "f_bsize", "f_blocks", "f_bfree", "f_bavail", "f_files",
+    "f_ffree", "f_fsid", "f_namelen", "f_frsize", "f_flags", "f_spare",
+])
+
+log = logging.getLogger("environment")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.WARNING)
+
+class FileDescriptor(object):
+    """Stand for a file descriptor on a system
+
+    According to inode(7), following types are possibles:
+     - socket
+     - symbolic link
+     - regular file
+     - block device
+     - directory
+     - character device
+     - FIFO
+    """
+
+    # st_mode's file type
+    file_type = None
+    # st_mode's file mode (9 least bits are file permission bits)
+    file_mode = 0o0777
+    # st_dev / st_rdev
+    cont_device_id = None
+    device_id = 0
+    # inode number (st_ino)
+    inode = None
+    # Number of hardlink (st_nlink)
+    nlink = 0
+    # Owner / group
+    uid = None
+    gid = None
+    # Size (st_size / st_blksize / st_blocks)
+    size = 0
+    blksize = 0
+    blocks = 0
+    # Times
+    atime = 0
+    atimensec = 0
+    mtime = 0
+    mtimensec = 0
+    ctime = 0
+    ctimensec = 0
+
+    def __init__(self, number):
+        self.number = number
+        self.is_closed = False
+
+    def stat(self):
+        mode = self.file_type | self.file_mode
+        return StatInfo(
+            st_dev=self.cont_device_id, st_ino=self.inode,
+            st_nlink=self.nlink, st_mode=mode,
+            st_uid=self.uid, st_gid=self.gid,
+            st_rdev=self.device_id, st_size=self.size,
+            st_blksize=self.blksize, st_blocks=self.blocks,
+            st_atime=self.atime, st_atimensec=self.atimensec,
+            st_mtime=self.mtime, st_mtimensec=self.mtimensec,
+            st_ctime=self.ctime, st_ctimensec=self.ctimensec
+        )
+
+    def close(self):
+        self.is_closed = True
+
+
+class FileDescriptorCharDevice(FileDescriptor):
+    file_type = 0o0020000 # S_IFCHR
+    file_mode = 0o0620
+    cont_device_id = 1
+    device_id = 1
+
+
+class FileDescriptorSTDIN(FileDescriptorCharDevice):
+    """Special file descriptor standinf for STDIN"""
+    inode = 0
+
+    def read(self, count):
+        raise RuntimeError("Not implemented")
+
+
+class FileDescriptorSTDOUT(FileDescriptorCharDevice):
+    """Special file descriptor standinf for STDOUT"""
+    inode = 1
+
+    def write(self, data):
+        print("[STDOUT] %s" % data.rstrip())
+
+
+class FileDescriptorSTDERR(FileDescriptorCharDevice):
+    """Special file descriptor standinf for STDERR"""
+    inode = 2
+
+    def write(self, data):
+        print("[STDERR] %s" % data.rstrip())
+
+
+class FileDescriptorDirectory(FileDescriptor):
+    """FileDescription designing a directory"""
+
+    file_type = 0o0040000 # S_IFDIR
+
+    def __init__(self, number, flags, filesystem, real_path):
+        super(FileDescriptorDirectory, self).__init__(number)
+        self.filesystem = filesystem
+        self.real_path = real_path
+        self.cur_listdir = None
+        self.flags = flags
+
+    def listdir(self):
+        if self.cur_listdir is None:
+            self.cur_listdir = os.listdir(self.real_path)
+        while self.cur_listdir:
+            yield self.cur_listdir.pop()
+
+
+class FileDescriptorRegularFile(FileDescriptor):
+    """FileDescriptor designing a regular file"""
+
+    file_type = 0o0100000 # S_IFREG
+
+    def __init__(self, number, flags, filesystem, real_fd):
+        super(FileDescriptorRegularFile, self).__init__(number)
+        self.flags = flags
+        self.filesystem = filesystem
+        self.real_fd = real_fd
+
+    def write(self, data):
+        raise RuntimeError("Not implemented")
+
+    def read(self, count):
+        return os.read(self.real_fd, count)
+
+    def close(self):
+        super(FileDescriptorRegularFile, self).close()
+        return os.close(self.real_fd)
+
+    def lseek(self, offset, whence):
+        return os.lseek(self.real_fd, offset, whence) # SEEK_SET
+
+    def tell(self):
+        return self.lseek(0, 1) # SEEK_CUR
+
+    def seek(self, offset):
+        return self.lseek(offset, 0) # SEEK_SET
+
+
+class FileDescriptorSocket(FileDescriptor):
+    """FileDescription standing for a socket"""
+
+    file_type = 0o0140000 # S_IFSOCK
+
+    def __init__(self, number, family, type_, protocol):
+        super(FileDescriptorSocket, self).__init__(number)
+        self.family = family
+        self.type_ = type_
+        self.protocol = protocol
+
+
+class FileSystem(object):
+    """File system abstraction
+    Provides standard operations on the filesystem, (a bit like FUSE)
+
+    API using FileSystem only used sandbox-side path. FileSystem should be the
+    only object able to interact with real path, outside the sandbox.
+
+    Thus, if `resolve_path` is correctly implemented and used, it should not be
+    possible to modify files outside the sandboxed path
+    """
+
+    device_id = 0x1234 # ID of device containing file (stat.st_dev)
+    blocksize = 0x1000 # Size of block on this filesystem
+    f_type = 0xef53 # (Type of filesystem) EXT4_SUPER_MAGIC
+    nb_total_block = 0x1000
+    nb_free_block = 0x100
+    nb_avail_block = nb_free_block # Available to unprivileged user
+    nb_total_fnode = 100 # Total file nodes in filesystem
+    nb_free_fnode = 50
+    max_filename_len = 256
+    fragment_size = 0
+    mount_flags = 0
+
+    def __init__(self, base_path, linux_env):
+        self.base_path = base_path
+        self.linux_env = linux_env
+        self.passthrough = []
+        self.path_to_inode = {} # Real path (post-resolution) -> inode number
+
+    def resolve_path(self, path, follow_link=True):
+        """Resolve @path to the corresponding sandboxed path"""
+
+        # path_bytes is used for Python 2 / Python 3 compatibility
+        path_bytes = not isinstance(path, str)
+        path_sep = os.path.sep.encode() if path_bytes else os.path.sep
+
+        if path_bytes:
+            def _convert(subpath):
+                if not isinstance(subpath, str):
+                    return subpath
+                return subpath.encode()
+            def _convert_re(expr):
+                if isinstance(expr.pattern, str):
+                    try:
+                        return re.compile(
+                            expr.pattern.encode(),
+                            flags=expr.flags & ~re.UNICODE
+                        )
+                    except UnicodeEncodeError:
+                        # Will never match
+                        log.warning(
+                            'Cannot convert regexp to bytes %r %r',
+                            expr.pattern,
+                            expr.flags,
+                            exc_info=True,
+                        )
+                        return re.compile(b'$X')
+                return expr
+        else:
+            def _convert(subpath):
+                if not isinstance(subpath, str):
+                    return subpath.decode()
+                return subpath
+            def _convert_re(expr):
+                if not isinstance(expr.pattern, str):
+                    try:
+                        return re.compile(
+                            expr.pattern.decode(),
+                            flags=expr.flags & re.UNICODE
+                        )
+                    except UnicodeDecodeError:
+                        # Will never match
+                        log.warning(
+                            'Cannot convert regexp to str %r %r',
+                            expr.pattern,
+                            expr.flags,
+                            exc_info=True,
+                        )
+                        return re.compile(r'$X')
+                return expr
+
+        # Remove '../', etc.
+        path = os.path.normpath(path)
+
+        # Passthrough
+        for passthrough in self.passthrough:
+            if isinstance(passthrough, REGEXP_T):
+                if _convert_re(passthrough).match(path):
+                    return path
+            elif _convert(passthrough) == path:
+                return path
+
+        # Remove leading '/' if any
+        path = path.lstrip(path_sep)
+
+        base_path = os.path.abspath(_convert(self.base_path))
+        out_path = os.path.join(base_path, path)
+        assert out_path.startswith(base_path + path_sep)
+        if os.path.islink(out_path):
+            link_target = os.readlink(out_path)
+            # Link can be absolute or relative -> absolute
+            link = os.path.normpath(os.path.join(os.path.dirname(path), link_target))
+            if follow_link:
+                out_path = self.resolve_path(link)
+            else:
+                out_path = link
+        return out_path
+
+    def get_path_inode(self, real_path):
+        inode = self.path_to_inode.setdefault(real_path, len(self.path_to_inode))
+        return inode
+
+    def exists(self, path):
+        sb_path = self.resolve_path(path)
+        return os.path.exists(sb_path)
+
+    def readlink(self, path):
+        sb_path = self.resolve_path(path, follow_link=False)
+        if not os.path.islink(sb_path):
+            return None
+        return os.readlink(sb_path)
+
+    def statfs(self):
+        return StatFSInfo(
+            f_type=self.f_type, f_bsize=self.blocksize,
+            f_blocks=self.nb_total_block, f_bfree=self.nb_free_block,
+            f_bavail=self.nb_avail_block, f_files=self.nb_total_fnode,
+            f_ffree=self.nb_free_fnode, f_fsid=self.device_id,
+            f_namelen=self.max_filename_len,
+            f_frsize=self.fragment_size, f_flags=self.mount_flags, f_spare=0)
+
+    def getattr_(self, path, follow_link=True):
+        sb_path = self.resolve_path(path, follow_link=follow_link)
+        flags = self.linux_env.O_RDONLY
+        if os.path.isdir(sb_path):
+            flags |= self.linux_env.O_DIRECTORY
+
+        fd = self.open_(path, flags, follow_link=follow_link)
+        info = self.linux_env.fstat(fd)
+        self.linux_env.close(fd)
+        return info
+
+    def open_(self, path, flags, follow_link=True):
+        path = self.resolve_path(path, follow_link=follow_link)
+        if not os.path.exists(path):
+            # ENOENT (No such file or directory)
+            return -1
+        fd = self.linux_env.next_fd()
+        acc_mode = flags & self.linux_env.O_ACCMODE
+
+        if os.path.isdir(path):
+            assert flags & self.linux_env.O_DIRECTORY == self.linux_env.O_DIRECTORY
+            if acc_mode == self.linux_env.O_RDONLY:
+                fdesc = FileDescriptorDirectory(fd, flags, self, path)
+            else:
+                raise RuntimeError("Not implemented")
+        elif os.path.isfile(path):
+            if acc_mode == os.O_RDONLY:
+                # Read only
+                real_fd = os.open(path, os.O_RDONLY)
+            else:
+                raise RuntimeError("Not implemented")
+            fdesc = FileDescriptorRegularFile(fd, flags, self, real_fd)
+
+        elif os.path.islink(path):
+            raise RuntimeError("Not implemented")
+        else:
+            raise RuntimeError("Unknown file type for %r" % path)
+
+        self.linux_env.file_descriptors[fd] = fdesc
+        # Set stat info
+        fdesc.cont_device_id = self.device_id
+        fdesc.inode = self.get_path_inode(path)
+        fdesc.uid = self.linux_env.user_uid
+        fdesc.gid = self.linux_env.user_gid
+        size = os.path.getsize(path)
+        fdesc.size = size
+        fdesc.blksize = self.blocksize
+        fdesc.blocks = (size + ((512 - (size % 512)) % 512)) // 512
+        return fd
+
+
+class Networking(object):
+    """Network abstraction"""
+
+    def __init__(self, linux_env):
+        self.linux_env = linux_env
+
+    def socket(self, family, type_, protocol):
+        fd = self.linux_env.next_fd()
+        fdesc = FileDescriptorSocket(fd, family, type_, protocol)
+        self.linux_env.file_descriptors[fd] = fdesc
+        return fd
+
+
+class LinuxEnvironment(object):
+    """A LinuxEnvironment regroups information to simulate a Linux-like
+    environment"""
+
+    # To be overridden
+    platform_arch = None
+
+    # User information
+    user_uid = 1000
+    user_euid = 1000
+    user_gid = 1000
+    user_egid = 1000
+    user_name = b"user"
+
+    # Memory mapping information
+    brk_current = 0x74000000
+    mmap_current = 0x75000000
+
+    # System information
+    sys_sysname = b"Linux"
+    sys_nodename = b"user-pc"
+    sys_release = b"4.13.0-19-generic"
+    sys_version = b"#22-Ubuntu"
+    sys_machine = None
+
+    # Filesystem
+    filesystem_base = "file_sb"
+    file_descriptors = None
+
+    # Current process
+    process_tid = 1000
+    process_pid = 1000
+
+    # Syscall restrictions
+    ioctl_allowed = None # list of (fd, cmd), None value for wildcard
+    ioctl_disallowed = None # list of (fd, cmd), None value for wildcard
+
+    # Time
+    base_time = 1531900000
+
+    # Arch specific constant
+    O_ACCMODE = None
+    O_CLOEXEC = None
+    O_DIRECTORY = None
+    O_LARGEFILE = None
+    O_NONBLOCK = None
+    O_RDONLY = None
+
+    def __init__(self):
+        stdin = FileDescriptorSTDIN(0)
+        stdout = FileDescriptorSTDOUT(1)
+        stderr = FileDescriptorSTDERR(2)
+        for std in [stdin, stdout, stderr]:
+            std.uid = self.user_uid
+            std.gid = self.user_gid
+        self.file_descriptors = {
+            0: stdin,
+            1: stdout,
+            2: stderr,
+        }
+        self.ioctl_allowed = [
+            (0, termios.TCGETS),
+            (0, termios.TIOCGWINSZ),
+            (0, termios.TIOCSWINSZ),
+            (1, termios.TCGETS),
+            (1, termios.TIOCGWINSZ),
+            (1, termios.TIOCSWINSZ),
+        ]
+        self.ioctl_disallowed = [
+            (2, termios.TCGETS),
+            (0, termios.TCSETSW),
+        ]
+        self.filesystem = FileSystem(self.filesystem_base, self)
+        self.network = Networking(self)
+
+    def next_fd(self):
+        return len(self.file_descriptors)
+
+    def clock_gettime(self):
+        out = self.base_time
+        self.base_time += 1
+        return out
+
+    def open_(self, path, flags, follow_link=True):
+        """Stub for 'open' syscall"""
+        return self.filesystem.open_(path, flags, follow_link=follow_link)
+
+    def socket(self, family, type_, protocol):
+        """Stub for 'socket' syscall"""
+        return self.network.socket(family, type_, protocol)
+
+    def fstat(self, fd):
+        """Get file status through fd"""
+        fdesc = self.file_descriptors.get(fd)
+        if fdesc is None:
+            return None
+        return fdesc.stat()
+
+    def stat(self, path):
+        """Get file status through path"""
+        return self.filesystem.getattr_(path)
+
+    def lstat(self, path):
+        """Get file status through path (not following links)"""
+        return self.filesystem.getattr_(path, follow_link=False)
+
+    def close(self, fd):
+        """Stub for 'close' syscall"""
+        fdesc = self.file_descriptors.get(fd)
+        if fdesc is None:
+            return None
+        return fdesc.close()
+
+    def write(self, fd, data):
+        """Stub for 'write' syscall"""
+        fdesc = self.file_descriptors.get(fd)
+        if fdesc is None:
+            return None
+        fdesc.write(data)
+        return len(data)
+
+    def read(self, fd, count):
+        """Stub for 'read' syscall"""
+        fdesc = self.file_descriptors.get(fd)
+        if fdesc is None:
+            return None
+        return fdesc.read(count)
+
+    def getdents(self, fd, count, packing_callback):
+        """Stub for 'getdents' syscall
+
+        'getdents64' must be handled by caller (only the structure layout is
+        modified)
+
+        @fd: getdents' fd argument
+        @count: getdents' count argument
+        @packing_callback(cur_len, d_ino, d_type, name) -> entry
+        """
+        fdesc = self.file_descriptors[fd]
+        if not isinstance(fdesc, FileDescriptorDirectory):
+            raise RuntimeError("Not implemented")
+
+        out = b""
+        # fdesc.listdir continues from where it stopped
+        for name in fdesc.listdir():
+            d_ino = 1 # Not the real one
+            d_type = 0 # DT_UNKNOWN (getdents(2) "All applications must properly
+                       # handle a return of DT_UNKNOWN.")
+            entry = packing_callback(len(out), d_ino, d_type, name)
+
+            if len(out) + len(entry) > count:
+                # Report to a further call
+                fdesc.cur_listdir.append(name)
+                break
+            out = out + entry
+        return out
+
+    def ioctl(self, fd, cmd, arg):
+        """Stub for 'ioctl' syscall
+        Return the list of element to pack back depending on target ioctl
+        If the ioctl is disallowed, return False
+        """
+        allowed = False
+        disallowed = False
+        for test in [(fd, cmd), (None, cmd), (fd, None)]:
+            if test in self.ioctl_allowed:
+                allowed = True
+            if test in self.ioctl_disallowed:
+                disallowed = True
+
+        if allowed and disallowed:
+            raise ValueError("fd: %x, cmd: %x is allowed and disallowed" % (fd, cmd))
+
+        if allowed:
+            if cmd == termios.TCGETS:
+                return 0, 0, 0, 0
+            elif cmd == termios.TIOCGWINSZ:
+                # struct winsize
+                # {
+                #   unsigned short ws_row;	/* rows, in characters */
+                #   unsigned short ws_col;	/* columns, in characters */
+                #   unsigned short ws_xpixel;	/* horizontal size, pixels */
+                #   unsigned short ws_ypixel;	/* vertical size, pixels */
+                # };
+                return 1000, 360, 1000, 1000
+            elif cmd == termios.TIOCSWINSZ:
+                # Ignore it
+                return
+            else:
+                raise RuntimeError("Not implemented")
+
+        elif disallowed:
+            return False
+
+        else:
+            raise KeyError("Unknown ioctl fd:%x cmd:%x" % (fd, cmd))
+
+    def mmap(self, addr, len_, prot, flags, fd, off, vmmngr):
+        """Stub for 'mmap' syscall
+
+        'mmap2' must be implemented by calling this function with off * 4096
+        """
+        if addr == 0:
+            addr = self.mmap_current
+            self.mmap_current += (len_ + 0x1000) & ~0xfff
+
+        all_mem = vmmngr.get_all_memory()
+        mapped = interval(
+            [
+                (start, start + info["size"] - 1)
+                for start, info in viewitems(all_mem)
+            ]
+        )
+
+        MAP_FIXED = 0x10
+        if flags & MAP_FIXED:
+            # Alloc missing and override
+            missing = interval([(addr, addr + len_ - 1)]) - mapped
+            for start, stop in missing:
+                vmmngr.add_memory_page(
+                    start,
+                    PAGE_READ|PAGE_WRITE,
+                    b"\x00" * (stop - start + 1),
+                    "mmap allocated"
+                )
+        else:
+            # Find first candidate segment nearby addr
+            for start, stop in mapped:
+                if stop < addr:
+                    continue
+                rounded = (stop + 1 + 0x1000) & ~0xfff
+                if (interval([(rounded, rounded + len_)]) & mapped).empty:
+                    addr = rounded
+                    break
+            else:
+                assert (interval([(addr, addr + len_)]) & mapped).empty
+
+            vmmngr.add_memory_page(
+                addr,
+                PAGE_READ|PAGE_WRITE,
+                b"\x00" * len_,
+                "mmap allocated"
+            )
+
+        if fd == 0xffffffff:
+            MAP_ANONYMOUS = 0x20    # mman.h
+            # fd and offset are ignored if MAP_ANONYMOUS flag is present
+            if not(flags & MAP_ANONYMOUS) and off != 0:
+                raise RuntimeError("Not implemented")
+            data = b"\x00" * len_
+        else:
+            fdesc = self.file_descriptors[fd]
+            cur_pos = fdesc.tell()
+            fdesc.seek(off)
+            data = fdesc.read(len_)
+            fdesc.seek(cur_pos)
+
+        vmmngr.set_mem(addr, data)
+        return addr
+
+    def brk(self, addr, vmmngr):
+        """Stub for 'brk' syscall"""
+        if addr == 0:
+            addr = self.brk_current
+        else:
+            all_mem = vmmngr.get_all_memory()
+            mapped = interval(
+                [
+                    (start, start + info["size"] - 1)
+                    for start, info in viewitems(all_mem)
+                ]
+            )
+
+            # Alloc missing and override
+            missing = interval([(self.brk_current, addr)]) - mapped
+            for start, stop in missing:
+                vmmngr.add_memory_page(
+                    start,
+                    PAGE_READ|PAGE_WRITE,
+                    b"\x00" * (stop - start + 1),
+                    "BRK"
+                )
+
+            self.brk_current = addr
+        return addr
+
+
+class LinuxEnvironment_x86_32(LinuxEnvironment):
+    platform_arch = b"x86_32"
+    sys_machine = b"x86_32"
+
+    # TODO FIXME
+    ## O_ACCMODE = 0x3
+    ## O_CLOEXEC = 0x80000
+    ## O_DIRECTORY = 0x10000
+    ## O_LARGEFILE = 0x8000
+    ## O_NONBLOCK = 0x800
+    ## O_RDONLY = 0
+
+
+class LinuxEnvironment_x86_64(LinuxEnvironment):
+    platform_arch = b"x86_64"
+    sys_machine = b"x86_64"
+
+    O_ACCMODE = 0x3
+    O_CLOEXEC = 0x80000
+    O_DIRECTORY = 0x10000
+    O_LARGEFILE = 0x8000
+    O_NONBLOCK = 0x800
+    O_RDONLY = 0
+
+
+class LinuxEnvironment_arml(LinuxEnvironment):
+    platform_arch = b"arml"
+    sys_machine = b"arml"
+
+    O_ACCMODE = 0x3
+    O_CLOEXEC = 0x80000
+    O_DIRECTORY = 0x4000
+    O_LARGEFILE = 0x20000
+    O_NONBLOCK = 0x800
+    O_RDONLY = 0
+
+    # ARM specific
+    tls = 0
+    # get_tls: __kuser_helper_version >= 1
+    # cmpxchg: __kuser_helper_version >= 2
+    # memory_barrier: __kuser_helper_version >= 3
+    kuser_helper_version = 3
+
+
+class LinuxEnvironment_mips32b(LinuxEnvironment):
+    platform_arch = b"mips32b"
+    sys_machine = b"mips32b"
+
+
+class AuxVec(object):
+    """Auxiliary vector abstraction, filled with default values
+    (mainly based on https://lwn.net/Articles/519085)
+
+    # Standard usage
+    >>> auxv = AuxVec(elf_base_addr, cont_target.entry_point, linux_env)
+
+    # Enable AT_SECURE
+    >>> auxv = AuxVec(..., AuxVec.AT_SECURE=1)
+    # Modify AT_RANDOM
+    >>> auxv = AuxVec(..., AuxVec.AT_RANDOM="\x00"*0x10)
+
+    # Using AuxVec instance for stack preparation
+    # First, fill memory with vectors data
+    >>> for AT_number, data in auxv.data_to_map():
+            dest_ptr = ...
+            copy_to_dest(data, dest_ptr)
+            auxv.ptrs[AT_number] = dest_ptr
+    # Then, get the key: value (with value being sometime a pointer)
+    >>> for auxid, auxval in auxv.iteritems():
+            ...
+    """
+
+    AT_PHDR = 3
+    AT_PHNUM = 5
+    AT_PAGESZ = 6
+    AT_ENTRY = 9
+    AT_UID = 11
+    AT_EUID = 12
+    AT_GID = 13
+    AT_EGID = 14
+    AT_PLATFORM = 15
+    AT_HWCAP = 16
+    AT_SECURE = 23
+    AT_RANDOM = 25
+    AT_SYSINFO_EHDR = 33
+
+    def __init__(self, elf_phdr_vaddr, entry_point, linux_env, **kwargs):
+        """Instantiate an AuxVec, with required elements:
+        - elf_phdr_vaddr: virtual address of the ELF's PHDR in memory
+        - entry_point: virtual address of the ELF entry point
+        - linux_env: LinuxEnvironment instance, used to provides some of the
+          option values
+
+        Others options can be overridden by named arguments
+
+        """
+        self.info = {
+            self.AT_PHDR: elf_phdr_vaddr,
+            self.AT_PHNUM: 9,
+            self.AT_PAGESZ: 0x1000,
+            self.AT_ENTRY: entry_point,
+            self.AT_UID: linux_env.user_uid,
+            self.AT_EUID: linux_env.user_euid,
+            self.AT_GID: linux_env.user_gid,
+            self.AT_EGID: linux_env.user_egid,
+            self.AT_PLATFORM: linux_env.platform_arch,
+            self.AT_HWCAP: 0,
+            self.AT_SECURE: 0,
+            self.AT_RANDOM: b"\x00" * 0x10,
+            # vDSO is not mandatory
+            self.AT_SYSINFO_EHDR: None,
+        }
+        self.info.update(kwargs)
+        self.ptrs = {} # info key -> corresponding virtual address
+
+    def data_to_map(self):
+        """Iterator on (AT_number, data)
+        Once the data has been mapped, the corresponding ptr must be set in
+        'self.ptrs[AT_number]'
+        """
+        for AT_number in [self.AT_PLATFORM, self.AT_RANDOM]:
+            yield (AT_number, self.info[AT_number])
+
+    def iteritems(self):
+        """Iterator on auxiliary vector id and values"""
+        for AT_number, value in viewitems(self.info):
+            if AT_number in self.ptrs:
+                value = self.ptrs[AT_number]
+            if value is None:
+                # AT to ignore
+                continue
+            yield (AT_number, value)
+
+    items = iteritems
+
+def prepare_loader_x86_64(jitter, argv, envp, auxv, linux_env,
+                          hlt_address=0x13371acc):
+    """Fill the environment with enough information to run a linux loader
+
+    @jitter: Jitter instance
+    @argv: list of strings
+    @envp: dict of environment variables names to their values
+    @auxv: AuxVec instance
+    @hlt_address (default to 0x13371acc): stopping address
+
+    Example of use:
+    >>> jitter = machine.jitter()
+    >>> jitter.init_stack()
+    >>> linux_env = LinuxEnvironment_x86_64()
+    >>> argv = ["/bin/ls", "-lah"]
+    >>> envp = {"PATH": "/usr/local/bin", "USER": linux_env.user_name}
+    >>> auxv = AuxVec(elf_base_addr, entry_point, linux_env)
+    >>> prepare_loader_x86_64(jitter, argv, envp, auxv, linux_env)
+    # One may want to enable syscall handling here
+    # The program can now run from the loader
+    >>> jitter.init_run(ld_entry_point)
+    >>> jitter.continue_run()
+    """
+    # Stack layout looks like
+    # [data]
+    #  - auxv values
+    #  - envp name=value
+    #  - argv arguments
+    # [auxiliary vector]
+    # [environment pointer]
+    # [argument vector]
+
+    for AT_number, data in auxv.data_to_map():
+        data += b"\x00"
+        jitter.cpu.RSP -= len(data)
+        ptr = jitter.cpu.RSP
+        jitter.vm.set_mem(ptr, data)
+        auxv.ptrs[AT_number] = ptr
+
+    env_ptrs = []
+    for name, value in viewitems(envp):
+        env = b"%s=%s\x00" % (name, value)
+        jitter.cpu.RSP -= len(env)
+        ptr = jitter.cpu.RSP
+        jitter.vm.set_mem(ptr, env)
+        env_ptrs.append(ptr)
+
+    argv_ptrs = []
+    for arg in argv:
+        arg += b"\x00"
+        jitter.cpu.RSP -= len(arg)
+        ptr = jitter.cpu.RSP
+        jitter.vm.set_mem(ptr, arg)
+        argv_ptrs.append(ptr)
+
+    jitter.push_uint64_t(hlt_address)
+    jitter.push_uint64_t(0)
+    jitter.push_uint64_t(0)
+    for auxid, auxval in viewitems(auxv):
+        jitter.push_uint64_t(auxval)
+        jitter.push_uint64_t(auxid)
+    jitter.push_uint64_t(0)
+    for ptr in reversed(env_ptrs):
+        jitter.push_uint64_t(ptr)
+    jitter.push_uint64_t(0)
+    for ptr in reversed(argv_ptrs):
+        jitter.push_uint64_t(ptr)
+    jitter.push_uint64_t(len(argv))
+
+
+
+def _arml__kuser_get_tls(linux_env, jitter):
+    # __kuser_get_tls
+    jitter.pc = jitter.cpu.LR
+    jitter.cpu.R0 = linux_env.tls
+    return True
+
+def _arml__kuser_cmpxchg(jitter):
+    oldval = jitter.cpu.R0
+    newval = jitter.cpu.R1
+    ptr = jitter.cpu.R2
+
+    value = struct.unpack("<I", jitter.vm.get_mem(ptr, 4))[0]
+    if value == oldval:
+        jitter.vm.set_mem(ptr, struct.pack("<I", newval))
+        jitter.cpu.R0 = 0
+        jitter.cpu.cf = 1
+    else:
+        jitter.cpu.R0 = -1
+        jitter.cpu.cf = 0
+
+    jitter.pc = jitter.cpu.LR
+    return True
+
+def _arml__kuser_memory_barrier(jitter):
+    # __kuser_memory_barrier
+    jitter.pc = jitter.cpu.LR
+    return True
+
+def _arml__kuser_helper_version(linux_env, jitter):
+    jitter.pc = jitter.cpu.LR
+    jitter.cpu.R0 = linux_env.kuser_helper_version
+    return True
+
+
+def prepare_loader_arml(jitter, argv, envp, auxv, linux_env,
+                        hlt_address=0x13371acc):
+    """Fill the environment with enough information to run a linux loader
+
+    @jitter: Jitter instance
+    @argv: list of strings
+    @envp: dict of environment variables names to their values
+    @auxv: AuxVec instance
+    @hlt_address (default to 0x13371acc): stopping address
+
+    Example of use:
+    >>> jitter = machine.jitter()
+    >>> jitter.init_stack()
+    >>> linux_env = LinuxEnvironment_arml()
+    >>> argv = ["/bin/ls", "-lah"]
+    >>> envp = {"PATH": "/usr/local/bin", "USER": linux_env.user_name}
+    >>> auxv = AuxVec(elf_base_addr, entry_point, linux_env)
+    >>> prepare_loader_arml(jitter, argv, envp, auxv, linux_env)
+    # One may want to enable syscall handling here
+    # The program can now run from the loader
+    >>> jitter.init_run(ld_entry_point)
+    >>> jitter.continue_run()
+    """
+    # Stack layout looks like
+    # [data]
+    #  - auxv values
+    #  - envp name=value
+    #  - argv arguments
+    # [auxiliary vector]
+    # [environment pointer]
+    # [argument vector]
+
+    for AT_number, data in auxv.data_to_map():
+        data += b"\x00"
+        jitter.cpu.SP -= len(data)
+        ptr = jitter.cpu.SP
+        jitter.vm.set_mem(ptr, data)
+        auxv.ptrs[AT_number] = ptr
+
+    env_ptrs = []
+    for name, value in viewitems(envp):
+        env = b"%s=%s\x00" % (name, value)
+        jitter.cpu.SP -= len(env)
+        ptr = jitter.cpu.SP
+        jitter.vm.set_mem(ptr, env)
+        env_ptrs.append(ptr)
+
+    argv_ptrs = []
+    for arg in argv:
+        arg += b"\x00"
+        jitter.cpu.SP -= len(arg)
+        ptr = jitter.cpu.SP
+        jitter.vm.set_mem(ptr, arg)
+        argv_ptrs.append(ptr)
+
+    jitter.push_uint32_t(hlt_address)
+    jitter.push_uint32_t(0)
+    jitter.push_uint32_t(0)
+    for auxid, auxval in viewitems(auxv):
+        jitter.push_uint32_t(auxval)
+        jitter.push_uint32_t(auxid)
+    jitter.push_uint32_t(0)
+    for ptr in reversed(env_ptrs):
+        jitter.push_uint32_t(ptr)
+    jitter.push_uint32_t(0)
+    for ptr in reversed(argv_ptrs):
+        jitter.push_uint32_t(ptr)
+    jitter.push_uint32_t(len(argv))
+
+    # Add kernel user helpers
+    # from Documentation/arm/kernel_user_helpers.txt
+
+    if linux_env.kuser_helper_version >= 1:
+        jitter.add_breakpoint(
+            0xFFFF0FE0,
+            functools.partial(_arml__kuser_get_tls, linux_env)
+        )
+
+    if linux_env.kuser_helper_version >= 2:
+        jitter.add_breakpoint(0XFFFF0FC0, _arml__kuser_cmpxchg)
+
+    if linux_env.kuser_helper_version >= 3:
+        jitter.add_breakpoint(0xFFFF0FA0, _arml__kuser_memory_barrier)
+
+    jitter.add_breakpoint(0xffff0ffc, _arml__kuser_helper_version)
diff --git a/src/miasm/os_dep/linux/syscall.py b/src/miasm/os_dep/linux/syscall.py
new file mode 100644
index 00000000..bbaae1bc
--- /dev/null
+++ b/src/miasm/os_dep/linux/syscall.py
@@ -0,0 +1,1129 @@
+from builtins import range
+import fcntl
+import functools
+import logging
+import struct
+import termios
+
+from miasm.jitter.csts import EXCEPT_INT_XX, EXCEPT_SYSCALL
+from miasm.core.utils import pck64
+
+log = logging.getLogger('syscalls')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.WARNING)
+
+
+def _dump_struct_stat_x86_64(info):
+    data = struct.pack(
+        "QQQIIIIQQQQQQQQQQQQQ",
+        info.st_dev,
+        info.st_ino,
+        info.st_nlink,
+        info.st_mode,
+        info.st_uid,
+        info.st_gid,
+        0, # 32 bit padding
+        info.st_rdev,
+        info.st_size,
+        info.st_blksize,
+        info.st_blocks,
+        info.st_atime,
+        info.st_atimensec,
+        info.st_mtime,
+        info.st_mtimensec,
+        info.st_ctime,
+        info.st_ctimensec,
+        0, # unused
+        0, # unused
+        0, # unused
+    )
+    return data
+
+
+def _dump_struct_stat_arml(info):
+    data = struct.pack(
+        "QIIIIIIIIIIIIIIIIII",
+        info.st_dev,
+        0, # pad
+        info.st_ino,
+        info.st_mode,
+        info.st_nlink,
+        info.st_uid,
+        info.st_gid,
+        info.st_rdev,
+        info.st_size,
+        info.st_blksize,
+        info.st_blocks,
+        info.st_atime,
+        info.st_atimensec,
+        info.st_mtime,
+        info.st_mtimensec,
+        info.st_ctime,
+        info.st_ctimensec,
+        0, # unused
+        0, # unused
+    )
+    return data
+
+
+def sys_x86_64_rt_sigaction(jitter, linux_env):
+    # Parse arguments
+    sig, act, oact, sigsetsize = jitter.syscall_args_systemv(4)
+    log.debug("sys_rt_sigaction(%x, %x, %x, %x)", sig, act, oact, sigsetsize)
+
+    # Stub
+    if oact != 0:
+        # Return an empty old action
+        jitter.vm.set_mem(oact, b"\x00" * sigsetsize)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_generic_brk(jitter, linux_env):
+    # Parse arguments
+    addr, = jitter.syscall_args_systemv(1)
+    log.debug("sys_brk(%d)", addr)
+
+    # Stub
+    jitter.syscall_ret_systemv(linux_env.brk(addr, jitter.vm))
+
+
+def sys_x86_32_newuname(jitter, linux_env):
+    # struct utsname {
+    #     char sysname[];    /* Operating system name (e.g., "Linux") */
+    #     char nodename[];   /* Name within "some implementation-defined
+    #                            network" */
+    #     char release[];    /* Operating system release (e.g., "2.6.28") */
+    #     char version[];    /* Operating system version */
+    #     char machine[];    /* Hardware identifier */
+    # }
+
+    # Parse arguments
+    nameptr, = jitter.syscall_args_systemv(1)
+    log.debug("sys_newuname(%x)", nameptr)
+
+    # Stub
+    info = [
+        linux_env.sys_sysname,
+        linux_env.sys_nodename,
+        linux_env.sys_release,
+        linux_env.sys_version,
+        linux_env.sys_machine
+    ]
+    # TODO: Elements start at 0x41 multiples on my tests...
+    output = b""
+    for elem in info:
+        output += elem
+        output += b"\x00" * (0x41 - len(elem))
+    jitter.vm.set_mem(nameptr, output)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_x86_64_newuname(jitter, linux_env):
+    # struct utsname {
+    #     char sysname[];    /* Operating system name (e.g., "Linux") */
+    #     char nodename[];   /* Name within "some implementation-defined
+    #                            network" */
+    #     char release[];    /* Operating system release (e.g., "2.6.28") */
+    #     char version[];    /* Operating system version */
+    #     char machine[];    /* Hardware identifier */
+    # }
+
+    # Parse arguments
+    nameptr, = jitter.syscall_args_systemv(1)
+    log.debug("sys_newuname(%x)", nameptr)
+
+    # Stub
+    info = [
+        linux_env.sys_sysname,
+        linux_env.sys_nodename,
+        linux_env.sys_release,
+        linux_env.sys_version,
+        linux_env.sys_machine
+    ]
+    # TODO: Elements start at 0x41 multiples on my tests...
+    output = b""
+    for elem in info:
+        output += elem
+        output += b"\x00" * (0x41 - len(elem))
+    jitter.vm.set_mem(nameptr, output)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_arml_newuname(jitter, linux_env):
+    # struct utsname {
+    #     char sysname[];    /* Operating system name (e.g., "Linux") */
+    #     char nodename[];   /* Name within "some implementation-defined
+    #                            network" */
+    #     char release[];    /* Operating system release (e.g., "2.6.28") */
+    #     char version[];    /* Operating system version */
+    #     char machine[];    /* Hardware identifier */
+    # }
+
+    # Parse arguments
+    nameptr, = jitter.syscall_args_systemv(1)
+    log.debug("sys_newuname(%x)", nameptr)
+
+    # Stub
+    info = [
+        linux_env.sys_sysname,
+        linux_env.sys_nodename,
+        linux_env.sys_release,
+        linux_env.sys_version,
+        linux_env.sys_machine
+    ]
+    # TODO: Elements start at 0x41 multiples on my tests...
+    output = b""
+    for elem in info:
+        output += elem
+        output += b"\x00" * (0x41 - len(elem))
+    jitter.vm.set_mem(nameptr, output)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_generic_access(jitter, linux_env):
+    # Parse arguments
+    pathname, mode = jitter.syscall_args_systemv(2)
+    rpathname = jitter.get_c_str(pathname)
+    rmode = mode
+    if mode == 1:
+        rmode = "F_OK"
+    elif mode == 2:
+        rmode = "R_OK"
+    log.debug("sys_access(%s, %s)", rpathname, rmode)
+
+    # Stub
+    # Do not check the mode
+    if linux_env.filesystem.exists(rpathname):
+        jitter.syscall_ret_systemv(0)
+    else:
+        jitter.syscall_ret_systemv(-1)
+
+
+def sys_x86_64_openat(jitter, linux_env):
+    # Parse arguments
+    dfd, filename, flags, mode = jitter.syscall_args_systemv(4)
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_openat(%x, %r, %x, %x)", dfd, rpathname, flags, mode)
+
+    # Stub
+    # flags, openat particularity over 'open' are ignored
+    jitter.syscall_ret_systemv(linux_env.open_(rpathname, flags))
+
+
+def sys_x86_64_newstat(jitter, linux_env):
+    # Parse arguments
+    filename, statbuf = jitter.syscall_args_systemv(2)
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_newstat(%r, %x)", rpathname, statbuf)
+
+    # Stub
+    if linux_env.filesystem.exists(rpathname):
+        info = linux_env.stat(rpathname)
+        data = _dump_struct_stat_x86_64(info)
+        jitter.vm.set_mem(statbuf, data)
+        jitter.syscall_ret_systemv(0)
+    else:
+        # ENOENT (No such file or directory)
+        jitter.syscall_ret_systemv(-1)
+
+
+def sys_arml_stat64(jitter, linux_env):
+    # Parse arguments
+    filename, statbuf = jitter.syscall_args_systemv(2)
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_newstat(%r, %x)", rpathname, statbuf)
+
+    # Stub
+    if linux_env.filesystem.exists(rpathname):
+        info = linux_env.stat(rpathname)
+        data = _dump_struct_stat_arml(info)
+        jitter.vm.set_mem(statbuf, data)
+        jitter.syscall_ret_systemv(0)
+    else:
+        # ENOENT (No such file or directory)
+        jitter.syscall_ret_systemv(-1)
+
+
+def sys_x86_64_writev(jitter, linux_env):
+    # Parse arguments
+    fd, vec, vlen = jitter.syscall_args_systemv(3)
+    log.debug("sys_writev(%d, %d, %x)", fd, vec, vlen)
+
+    # Stub
+    fdesc = linux_env.file_descriptors[fd]
+    for iovec_num in range(vlen):
+        # struct iovec {
+        #    void  *iov_base;    /* Starting address */
+        #    size_t iov_len;     /* Number of bytes to transfer */
+        # };
+        iovec = jitter.vm.get_mem(vec + iovec_num * 8 * 2, 8*2)
+        iov_base, iov_len = struct.unpack("QQ", iovec)
+        fdesc.write(jitter.get_c_str(iov_base)[:iov_len])
+
+    jitter.syscall_ret_systemv(vlen)
+
+
+def sys_arml_writev(jitter, linux_env):
+    # Parse arguments
+    fd, vec, vlen = jitter.syscall_args_systemv(3)
+    log.debug("sys_writev(%d, %d, %x)", fd, vec, vlen)
+
+    # Stub
+    fdesc = linux_env.file_descriptors[fd]
+    for iovec_num in range(vlen):
+        # struct iovec {
+        #    void  *iov_base;    /* Starting address */
+        #    size_t iov_len;     /* Number of bytes to transfer */
+        # };
+        iovec = jitter.vm.get_mem(vec + iovec_num * 4 * 2, 4*2)
+        iov_base, iov_len = struct.unpack("II", iovec)
+        fdesc.write(jitter.get_c_str(iov_base)[:iov_len])
+
+    jitter.syscall_ret_systemv(vlen)
+
+
+def sys_generic_exit_group(jitter, linux_env):
+    # Parse arguments
+    status, = jitter.syscall_args_systemv(1)
+    log.debug("sys_exit_group(%d)", status)
+
+    # Stub
+    log.debug("Exit with status code %d", status)
+    jitter.running = False
+
+
+def sys_generic_read(jitter, linux_env):
+    # Parse arguments
+    fd, buf, count = jitter.syscall_args_systemv(3)
+    log.debug("sys_read(%d, %x, %x)", fd, buf, count)
+
+    # Stub
+    data = linux_env.read(fd, count)
+    jitter.vm.set_mem(buf, data)
+    jitter.syscall_ret_systemv(len(data))
+
+
+def sys_x86_64_fstat(jitter, linux_env):
+    # Parse arguments
+    fd, statbuf = jitter.syscall_args_systemv(2)
+    log.debug("sys_fstat(%d, %x)", fd, statbuf)
+
+    # Stub
+    info = linux_env.fstat(fd)
+    data = _dump_struct_stat_x86_64(info)
+    jitter.vm.set_mem(statbuf, data)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_arml_fstat64(jitter, linux_env):
+    # Parse arguments
+    fd, statbuf = jitter.syscall_args_systemv(2)
+    log.debug("sys_fstat(%d, %x)", fd, statbuf)
+
+    # Stub
+    info = linux_env.fstat(fd)
+    data = _dump_struct_stat_arml(info)
+    jitter.vm.set_mem(statbuf, data)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_generic_mmap(jitter, linux_env):
+    # Parse arguments
+    addr, len_, prot, flags, fd, off = jitter.syscall_args_systemv(6)
+    log.debug("sys_mmap(%x, %x, %x, %x, %x, %x)", addr, len_, prot, flags, fd, off)
+
+    # Stub
+    addr = linux_env.mmap(addr, len_, prot & 0xFFFFFFFF, flags & 0xFFFFFFFF,
+                          fd & 0xFFFFFFFF, off, jitter.vm)
+    jitter.syscall_ret_systemv(addr)
+
+
+def sys_generic_mmap2(jitter, linux_env):
+    # Parse arguments
+    addr, len_, prot, flags, fd, off = jitter.syscall_args_systemv(6)
+    log.debug("sys_mmap2(%x, %x, %x, %x, %x, %x)", addr, len_, prot, flags, fd, off)
+    off = off * 4096
+
+    # Stub
+    addr = linux_env.mmap(addr, len_, prot & 0xFFFFFFFF, flags & 0xFFFFFFFF,
+                          fd & 0xFFFFFFFF, off, jitter.vm)
+    jitter.syscall_ret_systemv(addr)
+
+
+def sys_generic_mprotect(jitter, linux_env):
+    # Parse arguments
+    start, len_, prot = jitter.syscall_args_systemv(3)
+    assert jitter.vm.is_mapped(start, len_)
+    log.debug("sys_mprotect(%x, %x, %x)", start, len_, prot)
+
+    # Do nothing
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_generic_close(jitter, linux_env):
+    # Parse arguments
+    fd, = jitter.syscall_args_systemv(1)
+    log.debug("sys_close(%x)", fd)
+
+    # Stub
+    linux_env.close(fd)
+    jitter.syscall_ret_systemv(0)
+
+
+def sys_x86_64_arch_prctl(jitter, linux_env):
+    # Parse arguments
+    code_name = {
+        0x1001: "ARCH_SET_GS",
+        0x1002: "ARCH_SET_FS",
+        0x1003: "ARCH_GET_FS",
+        0x1004: "ARCH_GET_GS",
+        0x1011: "ARCH_GET_CPUID",
+        0x1012: "ARCH_SET_CPUID",
+        0x2001: "ARCH_MAP_VDSO_X32",
+        0x2002: "ARCH_MAP_VDSO_32",
+        0x2003: "ARCH_MAP_VDSO_64",
+        0x3001: "ARCH_CET_STATUS",
+        0x3002: "ARCH_CET_DISABLE",
+        0x3003: "ARCH_CET_LOCK",
+        0x3004: "ARCH_CET_EXEC",
+        0x3005: "ARCH_CET_ALLOC_SHSTK",
+        0x3006: "ARCH_CET_PUSH_SHSTK",
+        0x3007: "ARCH_CET_LEGACY_BITMAP",
+    }
+    code = jitter.cpu.RDI
+    rcode = code_name[code]
+    addr = jitter.cpu.RSI
+    log.debug("sys_arch_prctl(%s, %x)", rcode, addr)
+
+    if code == 0x1002:
+        jitter.cpu.set_segm_base(jitter.cpu.FS, addr)
+    elif code == 0x3001:
+        # CET status (disabled)
+        jitter.vm.set_mem(addr, pck64(0))
+    else:
+        raise RuntimeError("Not implemented")
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_set_tid_address(jitter, linux_env):
+    # Parse arguments
+    tidptr = jitter.cpu.RDI
+    # clear_child_tid = tidptr
+    log.debug("sys_set_tid_address(%x)", tidptr)
+
+    jitter.cpu.RAX = linux_env.process_tid
+
+
+def sys_x86_64_set_robust_list(jitter, linux_env):
+    # Parse arguments
+    head = jitter.cpu.RDI
+    len_ = jitter.cpu.RSI
+    # robust_list = head
+    log.debug("sys_set_robust_list(%x, %x)", head, len_)
+    jitter.cpu.RAX = 0
+
+def sys_x86_64_rt_sigprocmask(jitter, linux_env):
+    # Parse arguments
+    how = jitter.cpu.RDI
+    nset = jitter.cpu.RSI
+    oset = jitter.cpu.RDX
+    sigsetsize = jitter.cpu.R10
+    log.debug("sys_rt_sigprocmask(%x, %x, %x, %x)", how, nset, oset, sigsetsize)
+    if oset != 0:
+        raise RuntimeError("Not implemented")
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_prlimit64(jitter, linux_env):
+    # Parse arguments
+    pid = jitter.cpu.RDI
+    resource = jitter.cpu.RSI
+    new_rlim = jitter.cpu.RDX
+    if new_rlim != 0:
+        raise RuntimeError("Not implemented")
+    old_rlim = jitter.cpu.R10
+    log.debug("sys_prlimit64(%x, %x, %x, %x)", pid, resource, new_rlim,
+              old_rlim)
+
+    # Stub
+    if resource == 3:
+        # RLIMIT_STACK
+        jitter.vm.set_mem(old_rlim,
+                          struct.pack("QQ",
+                                      0x100000,
+                                      0x7fffffffffffffff, # RLIM64_INFINITY
+                          ))
+    else:
+        raise RuntimeError("Not implemented")
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_statfs(jitter, linux_env):
+    # Parse arguments
+    pathname = jitter.cpu.RDI
+    buf = jitter.cpu.RSI
+    rpathname = jitter.get_c_str(pathname)
+    log.debug("sys_statfs(%r, %x)", rpathname, buf)
+
+    # Stub
+    if not linux_env.filesystem.exists(rpathname):
+        jitter.cpu.RAX = -1
+    else:
+        info = linux_env.filesystem.statfs()
+        raise RuntimeError("Not implemented")
+
+
+def sys_x86_64_ioctl(jitter, linux_env):
+    # Parse arguments
+    fd, cmd, arg = jitter.syscall_args_systemv(3)
+    log.debug("sys_ioctl(%x, %x, %x)", fd, cmd, arg)
+
+    info = linux_env.ioctl(fd, cmd, arg)
+    if info is False:
+        jitter.syscall_ret_systemv(-1)
+    else:
+        if cmd == termios.TCGETS:
+            data = struct.pack("BBBB", *info)
+            jitter.vm.set_mem(arg, data)
+        elif cmd == termios.TIOCGWINSZ:
+            data = struct.pack("HHHH", *info)
+            jitter.vm.set_mem(arg, data)
+        else:
+            assert data is None
+        jitter.syscall_ret_systemv(0)
+
+
+def sys_arml_ioctl(jitter, linux_env):
+    # Parse arguments
+    fd, cmd, arg = jitter.syscall_args_systemv(3)
+    log.debug("sys_ioctl(%x, %x, %x)", fd, cmd, arg)
+
+    info = linux_env.ioctl(fd, cmd, arg)
+    if info is False:
+        jitter.syscall_ret_systemv(-1)
+    else:
+        if cmd == termios.TCGETS:
+            data = struct.pack("BBBB", *info)
+            jitter.vm.set_mem(arg, data)
+        elif cmd == termios.TIOCGWINSZ:
+            data = struct.pack("HHHH", *info)
+            jitter.vm.set_mem(arg, data)
+        else:
+            assert data is None
+        jitter.syscall_ret_systemv(0)
+
+def sys_generic_open(jitter, linux_env):
+    # Parse arguments
+    filename, flags, mode = jitter.syscall_args_systemv(3)
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_open(%r, %x, %x)", rpathname, flags, mode)
+    # Stub
+    # 'mode' is ignored
+    jitter.syscall_ret_systemv(linux_env.open_(rpathname, flags))
+
+
+def sys_generic_write(jitter, linux_env):
+    # Parse arguments
+    fd, buf, count = jitter.syscall_args_systemv(3)
+    log.debug("sys_write(%d, %x, %x)", fd, buf, count)
+
+    # Stub
+    data = jitter.vm.get_mem(buf, count)
+    jitter.syscall_ret_systemv(linux_env.write(fd, data))
+
+
+def sys_x86_64_getdents(jitter, linux_env):
+    # Parse arguments
+    fd = jitter.cpu.RDI
+    dirent = jitter.cpu.RSI
+    count = jitter.cpu.RDX
+    log.debug("sys_getdents(%x, %x, %x)", fd, dirent, count)
+
+    # Stub
+    def packing_callback(cur_len, d_ino, d_type, name):
+        # struct linux_dirent {
+        #        unsigned long  d_ino;     /* Inode number */
+        #        unsigned long  d_off;     /* Offset to next linux_dirent */
+        #        unsigned short d_reclen;  /* Length of this linux_dirent */
+        #        char           d_name[];  /* Filename (null-terminated) */
+        #                          /* length is actually (d_reclen - 2 -
+        #                             offsetof(struct linux_dirent, d_name)) */
+        #        /*
+        #        char           pad;       // Zero padding byte
+        #        char           d_type;    // File type (only since Linux
+        #                                  // 2.6.4); offset is (d_reclen - 1)
+        #        */
+        #    }
+        d_reclen = 8 * 2 + 2 + 1 + len(name) + 1
+        d_off = cur_len + d_reclen
+        entry = struct.pack("QqH", d_ino, d_off, d_reclen) + \
+                name.encode("utf8") + b"\x00" + struct.pack("B", d_type)
+        assert len(entry) == d_reclen
+        return entry
+
+    out = linux_env.getdents(fd, count, packing_callback)
+    jitter.vm.set_mem(dirent, out)
+    jitter.cpu.RAX = len(out)
+
+
+def sys_arml_getdents64(jitter, linux_env):
+    # Parse arguments
+    fd = jitter.cpu.R0
+    dirent = jitter.cpu.R1
+    count = jitter.cpu.R2
+    log.debug("sys_getdents64(%x, %x, %x)", fd, dirent, count)
+
+    # Stub
+    def packing_callback(cur_len, d_ino, d_type, name):
+        # struct linux_dirent64 {
+        #        ino64_t        d_ino;    /* 64-bit inode number */
+        #        off64_t        d_off;    /* 64-bit offset to next structure */
+        #        unsigned short d_reclen; /* Size of this dirent */
+        #        unsigned char  d_type;   /* File type */
+        #        char           d_name[]; /* Filename (null-terminated) */
+        #    };
+        d_reclen = 8 * 2 + 2 + 1 + len(name) + 1
+        d_off = cur_len + d_reclen
+        entry = struct.pack("QqHB", d_ino, d_off, d_reclen, d_type) + \
+                name + b"\x00"
+        assert len(entry) == d_reclen
+        return entry
+
+    out = linux_env.getdents(fd, count, packing_callback)
+    jitter.vm.set_mem(dirent, out)
+    jitter.cpu.R0 = len(out)
+
+
+def sys_x86_64_newlstat(jitter, linux_env):
+    # Parse arguments
+    filename = jitter.cpu.RDI
+    statbuf = jitter.cpu.RSI
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_newlstat(%s, %x)", rpathname, statbuf)
+
+    # Stub
+    if not linux_env.filesystem.exists(rpathname):
+        # ENOENT (No such file or directory)
+        jitter.cpu.RAX = -1
+    else:
+        info = linux_env.lstat(rpathname)
+        data = _dump_struct_stat_x86_64(info)
+        jitter.vm.set_mem(statbuf, data)
+        jitter.cpu.RAX = 0
+
+
+def sys_arml_lstat64(jitter, linux_env):
+    # Parse arguments
+    filename = jitter.cpu.R0
+    statbuf = jitter.cpu.R1
+    rpathname = jitter.get_c_str(filename)
+    log.debug("sys_newlstat(%s, %x)", rpathname, statbuf)
+
+    # Stub
+    if not linux_env.filesystem.exists(rpathname):
+        # ENOENT (No such file or directory)
+        jitter.cpu.R0 = -1
+    else:
+        info = linux_env.lstat(rpathname)
+        data = _dump_struct_stat_arml(info)
+        jitter.vm.set_mem(statbuf, data)
+        jitter.cpu.R0 = 0
+
+
+def sys_x86_64_lgetxattr(jitter, linux_env):
+    # Parse arguments
+    pathname = jitter.cpu.RDI
+    name = jitter.cpu.RSI
+    value = jitter.cpu.RDX
+    size = jitter.cpu.R10
+    rpathname = jitter.get_c_str(pathname)
+    rname = jitter.get_c_str(name)
+    log.debug("sys_lgetxattr(%r, %r, %x, %x)", rpathname, rname, value, size)
+
+    # Stub
+    jitter.vm.set_mem(value, b"\x00" * size)
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_getxattr(jitter, linux_env):
+    # Parse arguments
+    pathname = jitter.cpu.RDI
+    name = jitter.cpu.RSI
+    value = jitter.cpu.RDX
+    size = jitter.cpu.R10
+    rpathname = jitter.get_c_str(pathname)
+    rname = jitter.get_c_str(name)
+    log.debug("sys_getxattr(%r, %r, %x, %x)", rpathname, rname, value, size)
+
+    # Stub
+    jitter.vm.set_mem(value, b"\x00" * size)
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_socket(jitter, linux_env):
+    # Parse arguments
+    family = jitter.cpu.RDI
+    type_ = jitter.cpu.RSI
+    protocol = jitter.cpu.RDX
+    log.debug("sys_socket(%x, %x, %x)", family, type_, protocol)
+
+    jitter.cpu.RAX = linux_env.socket(family, type_, protocol)
+
+
+def sys_x86_64_connect(jitter, linux_env):
+    # Parse arguments
+    fd = jitter.cpu.RDI
+    uservaddr = jitter.cpu.RSI
+    addrlen = jitter.cpu.RDX
+    raddr = jitter.get_c_str(uservaddr + 2)
+    log.debug("sys_connect(%x, %r, %x)", fd, raddr, addrlen)
+
+    # Stub
+    # Always refuse the connection
+    jitter.cpu.RAX = -1
+
+
+def sys_x86_64_clock_gettime(jitter, linux_env):
+    # Parse arguments
+    which_clock = jitter.cpu.RDI
+    tp = jitter.cpu.RSI
+    log.debug("sys_clock_gettime(%x, %x)", which_clock, tp)
+
+    # Stub
+    value = linux_env.clock_gettime()
+    jitter.vm.set_mem(tp, struct.pack("Q", value))
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_lseek(jitter, linux_env):
+    # Parse arguments
+    fd = jitter.cpu.RDI
+    offset = jitter.cpu.RSI
+    whence = jitter.cpu.RDX
+    log.debug("sys_lseek(%d, %x, %x)", fd, offset, whence)
+
+    # Stub
+    fdesc = linux_env.file_descriptors[fd]
+    mask = (1 << 64) - 1
+    if offset > (1 << 63):
+        offset = - ((offset ^ mask) + 1)
+
+    new_offset = fdesc.lseek(offset, whence)
+    jitter.cpu.RAX = new_offset
+
+
+def sys_x86_64_munmap(jitter, linux_env):
+    # Parse arguments
+    addr = jitter.cpu.RDI
+    len_ = jitter.cpu.RSI
+    log.debug("sys_munmap(%x, %x)", addr, len_)
+
+    # Do nothing
+    jitter.cpu.RAX = 0
+
+
+def sys_x86_64_readlink(jitter, linux_env):
+    # Parse arguments
+    path = jitter.cpu.RDI
+    buf = jitter.cpu.RSI
+    bufsize = jitter.cpu.RDX
+    rpath = jitter.get_c_str(path)
+    log.debug("sys_readlink(%r, %x, %x)", rpath, buf, bufsize)
+
+    # Stub
+    link = linux_env.filesystem.readlink(rpath)
+    if link is None:
+        # Not a link
+        jitter.cpu.RAX = -1
+    else:
+        data = link[:bufsize - 1] + b"\x00"
+        jitter.vm.set_mem(buf, data)
+        jitter.cpu.RAX = len(data) - 1
+
+def sys_x86_64_getpid(jitter, linux_env):
+    # Parse arguments
+    log.debug("sys_getpid()")
+
+    # Stub
+    jitter.cpu.RAX = linux_env.process_pid
+
+
+def sys_x86_64_sysinfo(jitter, linux_env):
+    # Parse arguments
+    info = jitter.cpu.RDI
+    log.debug("sys_sysinfo(%x)", info)
+
+    # Stub
+    data = struct.pack("QQQQQQQQQQHQQI",
+                       0x1234, # uptime
+                       0x2000, # loads (1 min)
+                       0x2000, # loads (5 min)
+                       0x2000, # loads (15 min)
+                       0x10000000, # total ram
+                       0x10000000, # free ram
+                       0x10000000, # shared memory
+                       0x0, # memory used by buffers
+                       0x0, # total swap
+                       0x0, # free swap
+                       0x1, # nb current processes
+                       0x0, # total high mem
+                       0x0, # available high mem
+                       0x1, # memory unit size
+    )
+    jitter.vm.set_mem(info, data)
+    jitter.cpu.RAX = 0
+
+
+def sys_generic_geteuid(jitter, linux_env):
+    # Parse arguments
+    log.debug("sys_geteuid()")
+
+    # Stub
+    jitter.syscall_ret_systemv(linux_env.user_euid)
+
+
+def sys_generic_getegid(jitter, linux_env):
+    # Parse arguments
+    log.debug("sys_getegid()")
+
+    # Stub
+    jitter.syscall_ret_systemv(linux_env.user_egid)
+
+
+def sys_generic_getuid(jitter, linux_env):
+    # Parse arguments
+    log.debug("sys_getuid()")
+
+    # Stub
+    jitter.syscall_ret_systemv(linux_env.user_uid)
+
+
+def sys_generic_getgid(jitter, linux_env):
+    # Parse arguments
+    log.debug("sys_getgid()")
+
+    # Stub
+    jitter.syscall_ret_systemv(linux_env.user_gid)
+
+
+def sys_generic_setgid(jitter, linux_env):
+    # Parse arguments
+    gid, = jitter.syscall_args_systemv(1)
+    log.debug("sys_setgid(%x)", gid)
+
+    # Stub
+    # Denied if different
+    if gid != linux_env.user_gid:
+        jitter.syscall_ret_systemv(-1)
+    else:
+        jitter.syscall_ret_systemv(0)
+
+
+def sys_generic_setuid(jitter, linux_env):
+    # Parse arguments
+    uid, = jitter.syscall_args_systemv(1)
+    log.debug("sys_setuid(%x)", uid)
+
+    # Stub
+    # Denied if different
+    if uid != linux_env.user_uid:
+        jitter.syscall_ret_systemv(-1)
+    else:
+        jitter.syscall_ret_systemv(0)
+
+
+def sys_arml_set_tls(jitter, linux_env):
+    # Parse arguments
+    ptr = jitter.cpu.R0
+    log.debug("sys_set_tls(%x)", ptr)
+
+    # Stub
+    linux_env.tls = ptr
+    jitter.cpu.R0 = 0
+
+
+def sys_generic_fcntl64(jitter, linux_env):
+    # Parse arguments
+    fd, cmd, arg = jitter.syscall_args_systemv(3)
+    log.debug("sys_fcntl(%x, %x, %x)", fd, cmd, arg)
+
+    # Stub
+    fdesc = linux_env.file_descriptors[fd]
+    if cmd == fcntl.F_GETFL:
+        jitter.syscall_ret_systemv(fdesc.flags)
+    elif cmd == fcntl.F_SETFL:
+        # Ignore flag change
+        jitter.syscall_ret_systemv(0)
+    elif cmd == fcntl.F_GETFD:
+        jitter.syscall_ret_systemv(fdesc.flags)
+    elif cmd == fcntl.F_SETFD:
+        # Ignore flag change
+        jitter.syscall_ret_systemv(0)
+    else:
+        raise RuntimeError("Not implemented")
+
+
+def sys_x86_64_pread64(jitter, linux_env):
+    # Parse arguments
+    fd = jitter.cpu.RDI
+    buf = jitter.cpu.RSI
+    count = jitter.cpu.RDX
+    pos = jitter.cpu.R10
+    log.debug("sys_pread64(%x, %x, %x, %x)", fd, buf, count, pos)
+
+    # Stub
+    fdesc = linux_env.file_descriptors[fd]
+    cur_pos = fdesc.tell()
+    fdesc.seek(pos)
+    data = fdesc.read(count)
+    jitter.vm.set_mem(buf, data)
+    fdesc.seek(cur_pos)
+    jitter.cpu.RAX = len(data)
+
+
+def sys_arml_gettimeofday(jitter, linux_env):
+    # Parse arguments
+    tv = jitter.cpu.R0
+    tz = jitter.cpu.R1
+    log.debug("sys_gettimeofday(%x, %x)", tv, tz)
+
+    # Stub
+    value = linux_env.clock_gettime()
+    if tv:
+        jitter.vm.set_mem(tv, struct.pack("II", value, 0))
+    if tz:
+        jitter.vm.set_mem(tz, struct.pack("II", 0, 0))
+    jitter.cpu.R0 = 0
+
+
+def sys_mips32b_socket(jitter, linux_env):
+    # Parse arguments
+    family, type_, protocol = jitter.syscall_args_systemv(3)
+    log.debug("sys_socket(%x, %x, %x)", family, type_, protocol)
+
+    ret1 = linux_env.socket(family, type_, protocol)
+    jitter.syscall_ret_systemv(ret1, 0, 0)
+
+
+syscall_callbacks_x86_32 = {
+    0x7A: sys_x86_32_newuname,
+}
+
+
+syscall_callbacks_x86_64 = {
+    0x0: sys_generic_read,
+    0x1: sys_generic_write,
+    0x2: sys_generic_open,
+    0x3: sys_generic_close,
+    0x4: sys_x86_64_newstat,
+    0x5: sys_x86_64_fstat,
+    0x6: sys_x86_64_newlstat,
+    0x8: sys_x86_64_lseek,
+    0x9: sys_generic_mmap,
+    0x10: sys_x86_64_ioctl,
+    0xA: sys_generic_mprotect,
+    0xB: sys_x86_64_munmap,
+    0xC: sys_generic_brk,
+    0xD: sys_x86_64_rt_sigaction,
+    0xE: sys_x86_64_rt_sigprocmask,
+    0x11: sys_x86_64_pread64,
+    0x14: sys_x86_64_writev,
+    0x15: sys_generic_access,
+    0x27: sys_x86_64_getpid,
+    0x29: sys_x86_64_socket,
+    0x2A: sys_x86_64_connect,
+    0x3F: sys_x86_64_newuname,
+    0x48: sys_generic_fcntl64,
+    0x4E: sys_x86_64_getdents,
+    0x59: sys_x86_64_readlink,
+    0x63: sys_x86_64_sysinfo,
+    0x66: sys_generic_getuid,
+    0x68: sys_generic_getgid,
+    0x6B: sys_generic_geteuid,
+    0x6C: sys_generic_getegid,
+    0xE4: sys_x86_64_clock_gettime,
+    0x89: sys_x86_64_statfs,
+    0x9E: sys_x86_64_arch_prctl,
+    0xBF: sys_x86_64_getxattr,
+    0xC0: sys_x86_64_lgetxattr,
+    0xDA: sys_x86_64_set_tid_address,
+    0xE7: sys_generic_exit_group,
+    0x101: sys_x86_64_openat,
+    0x111: sys_x86_64_set_robust_list,
+    0x12E: sys_x86_64_prlimit64,
+}
+
+
+syscall_callbacks_arml = {
+
+    0x3: sys_generic_read,
+    0x4: sys_generic_write,
+    0x5: sys_generic_open,
+    0x6: sys_generic_close,
+    0x2d: sys_generic_brk,
+    0x21: sys_generic_access,
+    0x36: sys_arml_ioctl,
+    0x7a: sys_arml_newuname,
+    0x7d: sys_generic_mprotect,
+    0x92: sys_arml_writev,
+    0xc0: sys_generic_mmap2,
+    0xc3: sys_arml_stat64,
+    0xc4: sys_arml_lstat64,
+    0xc5: sys_arml_fstat64,
+    0xc7: sys_generic_getuid,
+    0xc8: sys_generic_getgid,
+    0xc9: sys_generic_geteuid,
+    0xcA: sys_generic_getegid,
+    0x4e: sys_arml_gettimeofday,
+    0xd5: sys_generic_setuid,
+    0xd6: sys_generic_setgid,
+    0xd9: sys_arml_getdents64,
+    0xdd: sys_generic_fcntl64,
+    0xf8: sys_generic_exit_group,
+
+    # ARM-specific ARM_NR_BASE == 0x0f0000
+    0xf0005: sys_arml_set_tls,
+}
+
+
+syscall_callbacks_mips32b = {
+    0x1057: sys_mips32b_socket,
+}
+
+def syscall_x86_64_exception_handler(linux_env, syscall_callbacks, jitter):
+    """Call to actually handle an EXCEPT_SYSCALL exception
+    In the case of an error raised by a SYSCALL, call the corresponding
+    syscall_callbacks
+    @linux_env: LinuxEnvironment_x86_64 instance
+    @syscall_callbacks: syscall number -> func(jitter, linux_env)
+    """
+
+    # Dispatch to SYSCALL stub
+    syscall_number = jitter.cpu.RAX
+    callback = syscall_callbacks.get(syscall_number)
+    if callback is None:
+        raise KeyError(
+            "No callback found for syscall number 0x%x" % syscall_number
+        )
+    callback(jitter, linux_env)
+    log.debug("-> %x", jitter.cpu.RAX)
+
+    # Clean exception and move pc to the next instruction, to let the jitter
+    # continue
+    jitter.cpu.set_exception(jitter.cpu.get_exception() ^ EXCEPT_SYSCALL)
+    return True
+
+
+
+def syscall_x86_32_exception_handler(linux_env, syscall_callbacks, jitter):
+    """Call to actually handle an EXCEPT_INT_XX exception
+    In the case of an error raised by a SYSCALL, call the corresponding
+    syscall_callbacks
+    @linux_env: LinuxEnvironment_x86_32 instance
+    @syscall_callbacks: syscall number -> func(jitter, linux_env)
+    """
+    # Ensure the jitter has break on a SYSCALL
+    if jitter.cpu.interrupt_num != 0x80:
+        return True
+
+    # Dispatch to SYSCALL stub
+    syscall_number = jitter.cpu.EAX
+    callback = syscall_callbacks.get(syscall_number)
+    if callback is None:
+        raise KeyError(
+            "No callback found for syscall number 0x%x" % syscall_number
+        )
+    callback(jitter, linux_env)
+    log.debug("-> %x", jitter.cpu.EAX)
+
+    # Clean exception and move pc to the next instruction, to let the jitter
+    # continue
+    jitter.cpu.set_exception(jitter.cpu.get_exception() ^ EXCEPT_INT_XX)
+    return True
+
+
+
+def syscall_arml_exception_handler(linux_env, syscall_callbacks, jitter):
+    """Call to actually handle an EXCEPT_PRIV_INSN exception
+    In the case of an error raised by a SYSCALL, call the corresponding
+    syscall_callbacks
+    @linux_env: LinuxEnvironment_arml instance
+    @syscall_callbacks: syscall number -> func(jitter, linux_env)
+    """
+    # Ensure the jitter has break on a SYSCALL
+    if jitter.cpu.interrupt_num != 0x0:
+        return True
+
+    # Dispatch to SYSCALL stub
+    syscall_number = jitter.cpu.R7
+    callback = syscall_callbacks.get(syscall_number)
+    if callback is None:
+        raise KeyError(
+            "No callback found for syscall number 0x%x" % syscall_number
+        )
+    callback(jitter, linux_env)
+    log.debug("-> %x", jitter.cpu.R0)
+
+    # Clean exception and move pc to the next instruction, to let the jitter
+    # continue
+    jitter.cpu.set_exception(jitter.cpu.get_exception() ^ EXCEPT_INT_XX)
+    return True
+
+
+
+def syscall_mips32b_exception_handler(linux_env, syscall_callbacks, jitter):
+    """Call to actually handle an EXCEPT_SYSCALL exception
+    In the case of an error raised by a SYSCALL, call the corresponding
+    syscall_callbacks
+    @linux_env: LinuxEnvironment_mips32b instance
+    @syscall_callbacks: syscall number -> func(jitter, linux_env)
+    """
+
+    # Dispatch to SYSCALL stub
+    syscall_number = jitter.cpu.V0
+    callback = syscall_callbacks.get(syscall_number)
+    if callback is None:
+        raise KeyError(
+            "No callback found for syscall number 0x%x" % syscall_number
+        )
+    callback(jitter, linux_env)
+    log.debug("-> %x", jitter.cpu.V0)
+
+    # Clean exception and move pc to the next instruction, to let the jitter
+    # continue
+    jitter.cpu.set_exception(jitter.cpu.get_exception() ^ EXCEPT_SYSCALL)
+    return True
+
+
+
+def enable_syscall_handling(jitter, linux_env, syscall_callbacks):
+    """Activate handling of syscall for the current jitter instance.
+    Syscall handlers are provided by @syscall_callbacks
+    @linux_env: LinuxEnvironment instance
+    @syscall_callbacks: syscall number -> func(jitter, linux_env)
+
+    Example of use:
+    >>> linux_env = LinuxEnvironment_x86_64()
+    >>> enable_syscall_handling(jitter, linux_env, syscall_callbacks_x86_64)
+    """
+    arch_name = jitter.jit.arch_name
+    if arch_name == "x8664":
+        handler = syscall_x86_64_exception_handler
+        handler = functools.partial(handler, linux_env, syscall_callbacks)
+        jitter.add_exception_handler(EXCEPT_SYSCALL, handler)
+    elif arch_name == "x8632":
+        handler = syscall_x86_32_exception_handler
+        handler = functools.partial(handler, linux_env, syscall_callbacks)
+        jitter.add_exception_handler(EXCEPT_INT_XX, handler)
+    elif arch_name == "arml":
+        handler = syscall_arml_exception_handler
+        handler = functools.partial(handler, linux_env, syscall_callbacks)
+        jitter.add_exception_handler(EXCEPT_INT_XX, handler)
+    elif arch_name == "mips32b":
+        handler = syscall_mips32b_exception_handler
+        handler = functools.partial(handler, linux_env, syscall_callbacks)
+        jitter.add_exception_handler(EXCEPT_SYSCALL, handler)
+    else:
+        raise ValueError("No syscall handler implemented for %s" % arch_name)
diff --git a/src/miasm/os_dep/linux_stdlib.py b/src/miasm/os_dep/linux_stdlib.py
new file mode 100644
index 00000000..f0c708ba
--- /dev/null
+++ b/src/miasm/os_dep/linux_stdlib.py
@@ -0,0 +1,213 @@
+#-*- coding:utf-8 -*-
+
+from __future__ import print_function
+import struct
+from sys import stdout
+
+try:
+    # Python3 binary stdout
+    stdout = stdout.buffer
+except AttributeError:
+    pass
+
+from miasm.core.utils import int_to_byte, cmp_elts
+from miasm.os_dep.common import heap
+from miasm.os_dep.common import get_fmt_args as _get_fmt_args
+
+
+class c_linobjs(object):
+
+    base_addr = 0x20000000
+    align_addr = 0x1000
+    def __init__(self):
+        self.alloc_ad = self.base_addr
+        self.alloc_align = self.align_addr
+        self.heap = heap()
+
+linobjs = c_linobjs()
+
+ABORT_ADDR = 0x1337beef
+
+def xxx___libc_start_main(jitter):
+    """Basic implementation of __libc_start_main
+
+    int __libc_start_main(int *(main) (int, char * *, char * *), int argc,
+                          char * * ubp_av, void (*init) (void),
+                          void (*fini) (void), void (*rtld_fini) (void),
+                          void (* stack_end));
+
+    Note:
+     - init, fini, rtld_fini are ignored
+     - return address is forced to ABORT_ADDR, to avoid calling abort/hlt/...
+     - in powerpc, signature is:
+
+    int __libc_start_main (int argc, char **argv, char **ev, ElfW (auxv_t) *
+                       auxvec, void (*rtld_fini) (void), struct startup_info
+                       *stinfo, char **stack_on_entry)
+
+    """
+    global ABORT_ADDR
+    if jitter.arch.name == "ppc32":
+        ret_ad, args = jitter.func_args_systemv(
+            ["argc", "argv", "ev", "aux_vec", "rtld_fini", "st_info",
+             "stack_on_entry"]
+        )
+
+        # Mimic glibc implementation
+        if args.stack_on_entry != 0:
+            argc = struct.unpack(">I",
+                                 jitter.vm.get_mem(args.stack_on_entry, 4))[0]
+            argv = args.stack_on_entry + 4
+            envp = argv + ((argc + 1) * 4)
+        else:
+            argc = args.argc
+            argv = args.argv
+            envp = args.ev
+        # sda_base, main, init, fini
+        _, main, _, _ = struct.unpack(">IIII",
+                                      jitter.vm.get_mem(args.st_info, 4 * 4))
+
+    else:
+        ret_ad, args = jitter.func_args_systemv(
+            ["main", "argc", "ubp_av", "init", "fini", "rtld_fini", "stack_end"]
+        )
+
+        main = args.main
+        # done by __libc_init_first
+        size = jitter.lifter.pc.size // 8
+        argc = args.argc
+        argv = args.ubp_av
+        envp = argv + (args.argc + 1) * size
+
+
+    # Call int main(int argc, char** argv, char** envp)
+    jitter.func_ret_systemv(main)
+    ret_ad = ABORT_ADDR
+    jitter.func_prepare_systemv(ret_ad, argc, argv, envp)
+    return True
+
+
+def xxx_isprint(jitter):
+    '''
+    #include <ctype.h>
+    int isprint(int c);
+
+    checks for any printable character including space.
+    '''
+    ret_addr, args = jitter.func_args_systemv(['c'])
+    ret = 1 if 0x20 <= args.c & 0xFF < 0x7f else 0
+    return jitter.func_ret_systemv(ret_addr, ret)
+
+
+def xxx_memcpy(jitter):
+    '''
+    #include <string.h>
+    void *memcpy(void *dest, const void *src, size_t n);
+
+    copies n bytes from memory area src to memory area dest.
+    '''
+    ret_addr, args = jitter.func_args_systemv(['dest', 'src', 'n'])
+    jitter.vm.set_mem(args.dest, jitter.vm.get_mem(args.src, args.n))
+    return jitter.func_ret_systemv(ret_addr, args.dest)
+
+
+def xxx_memset(jitter):
+    '''
+    #include <string.h>
+    void *memset(void *s, int c, size_t n);
+
+    fills the first n bytes of the memory area pointed to by s with the constant
+    byte c.'''
+
+    ret_addr, args = jitter.func_args_systemv(['dest', 'c', 'n'])
+    jitter.vm.set_mem(args.dest, int_to_byte(args.c & 0xFF) * args.n)
+    return jitter.func_ret_systemv(ret_addr, args.dest)
+
+
+def xxx_puts(jitter):
+    '''
+    #include <stdio.h>
+    int puts(const char *s);
+
+    writes the string s and a trailing newline to stdout.
+    '''
+    ret_addr, args = jitter.func_args_systemv(['s'])
+    index = args.s
+    char = jitter.vm.get_mem(index, 1)
+    while char != b'\x00':
+        stdout.write(char)
+        index += 1
+        char = jitter.vm.get_mem(index, 1)
+    stdout.write(b'\n')
+    return jitter.func_ret_systemv(ret_addr, 1)
+
+
+def get_fmt_args(jitter, fmt, cur_arg):
+    return _get_fmt_args(fmt, cur_arg, jitter.get_c_str, jitter.get_arg_n_systemv)
+
+
+def xxx_snprintf(jitter):
+    ret_addr, args = jitter.func_args_systemv(['string', 'size', 'fmt'])
+    cur_arg, fmt = 3, args.fmt
+    size = args.size if args.size else 1
+    output = get_fmt_args(jitter, fmt, cur_arg)
+    output = output[:size - 1]
+    ret = len(output)
+    jitter.set_c_str(args.string, output)
+    return jitter.func_ret_systemv(ret_addr, ret)
+
+
+def xxx_sprintf(jitter):
+    ret_addr, args = jitter.func_args_systemv(['string', 'fmt'])
+    cur_arg, fmt = 2, args.fmt
+    output = get_fmt_args(jitter, fmt, cur_arg)
+    ret = len(output)
+    jitter.set_c_str(args.string, output)
+    return jitter.func_ret_systemv(ret_addr, ret)
+
+
+def xxx_printf(jitter):
+    ret_addr, args = jitter.func_args_systemv(['fmt'])
+    cur_arg, fmt = 1, args.fmt
+    output = get_fmt_args(jitter, fmt, cur_arg)
+    ret = len(output)
+    stdout.write(output.encode('utf8'))
+    return jitter.func_ret_systemv(ret_addr, ret)
+
+
+def xxx_strcpy(jitter):
+    ret_ad, args = jitter.func_args_systemv(["dst", "src"])
+    str_src = jitter.get_c_str(args.src)
+    jitter.set_c_str(args.dst, str_src)
+    jitter.func_ret_systemv(ret_ad, args.dst)
+
+
+def xxx_strlen(jitter):
+    ret_ad, args = jitter.func_args_systemv(["src"])
+    str_src = jitter.get_c_str(args.src)
+    jitter.func_ret_systemv(ret_ad, len(str_src))
+
+
+def xxx_malloc(jitter):
+    ret_ad, args = jitter.func_args_systemv(["msize"])
+    addr = linobjs.heap.alloc(jitter, args.msize)
+    jitter.func_ret_systemv(ret_ad, addr)
+
+
+def xxx_free(jitter):
+    ret_ad, args = jitter.func_args_systemv(["ptr"])
+    jitter.func_ret_systemv(ret_ad, 0)
+
+
+def xxx_strcmp(jitter):
+    ret_ad, args = jitter.func_args_systemv(["ptr_str1", "ptr_str2"])
+    s1 = jitter.get_c_str(args.ptr_str1)
+    s2 = jitter.get_c_str(args.ptr_str2)
+    jitter.func_ret_systemv(ret_ad, cmp_elts(s1, s2))
+
+
+def xxx_strncmp(jitter):
+    ret_ad, args = jitter.func_args_systemv(["ptr_str1", "ptr_str2", "size"])
+    s1 = jitter.get_c_str(args.ptr_str1, args.size)
+    s2 = jitter.get_c_str(args.ptr_str2, args.size)
+    jitter.func_ret_systemv(ret_ad, cmp_elts(s1, s2))
diff --git a/src/miasm/os_dep/win_32_structs.py b/src/miasm/os_dep/win_32_structs.py
new file mode 100644
index 00000000..fc9c62ea
--- /dev/null
+++ b/src/miasm/os_dep/win_32_structs.py
@@ -0,0 +1,231 @@
+from miasm.core.types import MemStruct, Num, Ptr, Str, \
+    Array, RawStruct, Union, \
+    BitField, Self, Void, Bits, \
+    set_allocator, MemUnion, Struct
+
+
+class UnicodeString(MemStruct):
+    fields = [
+        ("length", Num("H")),
+        ("maxlength", Num("H")),
+        ("data", Ptr("<I", Str("utf16"))),
+    ]
+
+
+class ListEntry(MemStruct):
+    fields = [
+        ("flink", Ptr("<I", Void())),
+        ("blink", Ptr("<I", Void())),
+    ]
+
+
+class LdrDataEntry(MemStruct):
+
+    """
+    +0x000 InLoadOrderLinks : _LIST_ENTRY
+    +0x008 InMemoryOrderLinks : _LIST_ENTRY
+    +0x010 InInitializationOrderLinks : _LIST_ENTRY
+    +0x018 DllBase : Ptr32 Void
+    +0x01c EntryPoint : Ptr32 Void
+    +0x020 SizeOfImage : Uint4B
+    +0x024 FullDllName : _UNICODE_STRING
+    +0x02c BaseDllName : _UNICODE_STRING
+    +0x034 Flags : Uint4B
+    +0x038 LoadCount : Uint2B
+    +0x03a TlsIndex : Uint2B
+    +0x03c HashLinks : _LIST_ENTRY
+    +0x03c SectionPointer : Ptr32 Void
+    +0x040 CheckSum : Uint4B
+    +0x044 TimeDateStamp : Uint4B
+    +0x044 LoadedImports : Ptr32 Void
+    +0x048 EntryPointActivationContext : Ptr32 Void
+    +0x04c PatchInformation : Ptr32 Void
+    """
+
+    fields = [
+        ("InLoadOrderLinks", ListEntry),
+        ("InMemoryOrderLinks", ListEntry),
+        ("InInitializationOrderLinks", ListEntry),
+        ("DllBase", Ptr("<I", Void())),
+        ("EntryPoint", Ptr("<I", Void())),
+        ("SizeOfImage", Num("<I")),
+        ("FullDllName", UnicodeString),
+        ("BaseDllName", UnicodeString),
+        ("Flags", Array(Num("B"), 4)),
+        ("LoadCount", Num("H")),
+        ("TlsIndex", Num("H")),
+        ("union1", Union([
+            ("HashLinks", Ptr("<I", Void())),
+            ("SectionPointer", Ptr("<I", Void())),
+        ])),
+        ("CheckSum", Num("<I")),
+        ("union2", Union([
+            ("TimeDateStamp", Num("<I")),
+            ("LoadedImports", Ptr("<I", Void())),
+        ])),
+        ("EntryPointActivationContext", Ptr("<I", Void())),
+        ("PatchInformation", Ptr("<I", Void())),
+
+    ]
+
+
+class PEB_LDR_DATA(MemStruct):
+
+    """
+    +0x000 Length                          : Uint4B
+    +0x004 Initialized                     : UChar
+    +0x008 SsHandle                        : Ptr32 Void
+    +0x00c InLoadOrderModuleList           : _LIST_ENTRY
+    +0x014 InMemoryOrderModuleList         : _LIST_ENTRY
+    +0x01C InInitializationOrderModuleList         : _LIST_ENTRY
+    """
+
+    fields = [
+        ("Length", Num("<I")),
+        ("Initialized", Num("<I")),
+        ("SsHandle", Ptr("<I", Void())),
+        ("InLoadOrderModuleList", ListEntry),
+        ("InMemoryOrderModuleList", ListEntry),
+        ("InInitializationOrderModuleList", ListEntry)
+    ]
+
+
+class PEB(MemStruct):
+
+    """
+    +0x000 InheritedAddressSpace    : UChar
+    +0x001 ReadImageFileExecOptions : UChar
+    +0x002 BeingDebugged            : UChar
+    +0x003 SpareBool                : UChar
+    +0x004 Mutant                   : Ptr32 Void
+    +0x008 ImageBaseAddress         : Ptr32 Void
+    +0x00c Ldr                      : Ptr32 _PEB_LDR_DATA
+    +0x010 processparameter
+    """
+
+    fields = [
+        ("InheritedAddressSpace", Num("B")),
+        ("ReadImageFileExecOptions", Num("B")),
+        ("BeingDebugged", Num("B")),
+        ("SpareBool", Num("B")),
+        ("Mutant", Ptr("<I", Void())),
+        ("ImageBaseAddress", Num("<I")),
+        ("Ldr", Ptr("<I", PEB_LDR_DATA)),
+    ]
+
+
+class EXCEPTION_REGISTRATION_RECORD(MemStruct):
+    """
+    +0x00 Next    : struct _EXCEPTION_REGISTRATION_RECORD *
+    +0x04 Handler : Ptr32 Void
+    """
+
+    fields = [
+        ("Next", Ptr("<I", Self())),
+        ("Handler", Ptr("<I", Void())),
+    ]
+
+
+class EXCEPTION_RECORD(MemStruct):
+    """
+    DWORD                    ExceptionCode;
+    DWORD                    ExceptionFlags;
+    struct _EXCEPTION_RECORD *ExceptionRecord;
+    PVOID                    ExceptionAddress;
+    DWORD                    NumberParameters;
+    ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+    """
+    EXCEPTION_MAXIMUM_PARAMETERS = 15
+
+    fields = [
+        ("ExceptionCode", Num("<I")),
+        ("ExceptionFlags", Num("<I")),
+        ("ExceptionRecord", Ptr("<I", Self())),
+        ("ExceptionAddress", Ptr("<I", Void())),
+        ("NumberParameters", Num("<I")),
+        ("ExceptionInformation", Ptr("<I", Void())),
+    ]
+
+
+class NT_TIB(MemStruct):
+
+    """
+    +00 struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList
+    +04 void *StackBase
+    +08 void *StackLimit
+    +0c void *SubSystemTib
+    +10 void *FiberData
+    +10 uint32 Version
+    +14 void *ArbitraryUserPointer
+    +18 struct _NT_TIB *Self
+    """
+
+    fields = [
+        ("ExceptionList", Ptr("<I", EXCEPTION_REGISTRATION_RECORD)),
+        ("StackBase", Ptr("<I", Void())),
+        ("StackLimit", Ptr("<I", Void())),
+        ("SubSystemTib", Ptr("<I", Void())),
+        (None, Union([
+            ("FiberData", Ptr("<I", Void())),
+            ("Version", Num("<I"))
+        ])),
+        ("ArbitraryUserPointer", Ptr("<I", Void())),
+        ("Self", Ptr("<I", Self())),
+    ]
+
+
+class TEB(MemStruct):
+
+    """
+    +0x000 NtTib                     : _NT_TIB
+    +0x01c EnvironmentPointer        : Ptr32 Void
+    +0x020 ClientId                  : _CLIENT_ID
+    +0x028 ActiveRpcHandle           : Ptr32 Void
+    +0x02c ThreadLocalStoragePointer : Ptr32 Void
+    +0x030 ProcessEnvironmentBlock   : Ptr32 _PEB
+    +0x034 LastErrorValue            : Uint4B
+    ...
+    """
+
+    fields = [
+        ("NtTib", NT_TIB),
+        ("EnvironmentPointer", Ptr("<I", Void())),
+        ("ClientId", Array(Num("B"), 0x8)),
+        ("ActiveRpcHandle", Ptr("<I", Void())),
+        ("ThreadLocalStoragePointer", Ptr("<I", Void())),
+        ("ProcessEnvironmentBlock", Ptr("<I", PEB)),
+        ("LastErrorValue", Num("<I")),
+    ]
+
+
+class ContextException(MemStruct):
+    fields = [
+        ("ContextFlags", Num("<I")),
+        ("dr0", Num("<I")),
+        ("dr1", Num("<I")),
+        ("dr2", Num("<I")),
+        ("dr3", Num("<I")),
+        ("dr4", Num("<I")),
+        ("dr5", Num("<I")),
+
+        ("Float", Array(Num("B"), 112)),
+
+        ("gs", Num("<I")),
+        ("fs", Num("<I")),
+        ("es", Num("<I")),
+        ("ds", Num("<I")),
+
+        ("edi", Num("<I")),
+        ("esi", Num("<I")),
+        ("ebx", Num("<I")),
+        ("edx", Num("<I")),
+        ("ecx", Num("<I")),
+        ("eax", Num("<I")),
+        ("ebp", Num("<I")),
+        ("eip", Num("<I")),
+
+        ("cs", Num("<I")),
+        ("eflags", Num("<I")),
+        ("esp", Num("<I")),
+        ("ss", Num("<I")),
+    ]
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
diff --git a/src/miasm/os_dep/win_api_x86_32_seh.py b/src/miasm/os_dep/win_api_x86_32_seh.py
new file mode 100644
index 00000000..57416477
--- /dev/null
+++ b/src/miasm/os_dep/win_api_x86_32_seh.py
@@ -0,0 +1,705 @@
+#-*- coding:utf-8 -*-
+
+#
+# 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.
+#
+import logging
+import os
+import struct
+
+from future.utils import viewitems
+
+from miasm.loader import pe_init
+
+from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
+from miasm.core.utils import pck32
+import miasm.arch.x86.regs as x86_regs
+
+from miasm.os_dep.win_32_structs import LdrDataEntry, ListEntry, \
+    TEB, NT_TIB, PEB, PEB_LDR_DATA, ContextException, \
+    EXCEPTION_REGISTRATION_RECORD, EXCEPTION_RECORD
+
+# Constants Windows
+EXCEPTION_BREAKPOINT = 0x80000003
+EXCEPTION_SINGLE_STEP = 0x80000004
+EXCEPTION_ACCESS_VIOLATION = 0xc0000005
+EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
+EXCEPTION_PRIV_INSTRUCTION = 0xc0000096
+EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d
+
+
+log = logging.getLogger("seh_helper")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.INFO)
+
+# fs:[0] Page (TIB)
+tib_address = 0x7ff70000
+PEB_AD = 0x7ffdf000
+LDR_AD = 0x340000
+DEFAULT_SEH = 0x7ffff000
+
+MAX_MODULES = 0x40
+
+peb_address = PEB_AD
+peb_ldr_data_offset = 0x1ea0
+peb_ldr_data_address = LDR_AD + peb_ldr_data_offset
+
+
+modules_list_offset = 0x1f00
+
+InInitializationOrderModuleList_offset = 0x1ee0
+InInitializationOrderModuleList_address = LDR_AD + \
+    InInitializationOrderModuleList_offset
+
+InLoadOrderModuleList_offset = 0x1ee0 + \
+    MAX_MODULES * 0x1000
+InLoadOrderModuleList_address = LDR_AD + \
+    InLoadOrderModuleList_offset
+
+
+process_environment_address = 0x10000
+process_parameters_address = 0x200000
+
+return_from_exception = 0x6eadbeef
+
+
+name2module = []
+main_pe = None
+main_pe_name = "c:\\xxx\\toto.exe"
+
+MAX_SEH = 5
+
+
+def build_teb(jitter, teb_address):
+    """
+    Build TEB information using following structure:
+
+    @jitter: jitter instance
+    @teb_address: the TEB address
+    """
+
+    # Only allocate space for ExceptionList/ProcessEnvironmentBlock/Self
+    jitter.vm.add_memory_page(
+        teb_address,
+        PAGE_READ | PAGE_WRITE,
+        b"\x00" * NT_TIB.get_offset("StackBase"),
+        "TEB.NtTib.ExceptionList"
+    )
+    jitter.vm.add_memory_page(
+        teb_address + NT_TIB.get_offset("Self"),
+        PAGE_READ | PAGE_WRITE,
+        b"\x00" * (NT_TIB.sizeof() - NT_TIB.get_offset("Self")),
+        "TEB.NtTib.Self"
+    )
+    jitter.vm.add_memory_page(
+        teb_address + TEB.get_offset("ProcessEnvironmentBlock"),
+        PAGE_READ | PAGE_WRITE,
+        b"\x00" * (
+            TEB.get_offset("LastErrorValue") -
+            TEB.get_offset("ProcessEnvironmentBlock")
+        ),
+        "TEB.ProcessEnvironmentBlock"
+    )
+    Teb = TEB(jitter.vm, teb_address)
+    Teb.NtTib.ExceptionList = DEFAULT_SEH
+    Teb.NtTib.Self = teb_address
+    Teb.ProcessEnvironmentBlock = peb_address
+
+def build_peb(jitter, peb_address):
+    """
+    Build PEB information using following structure:
+
+    @jitter: jitter instance
+    @peb_address: the PEB address
+    """
+
+    if main_pe:
+        offset, length = 8, 4
+    else:
+        offset, length = 0xC, 0
+    length += 4
+
+    jitter.vm.add_memory_page(
+        peb_address + offset,
+        PAGE_READ | PAGE_WRITE,
+        b"\x00" * length,
+        "PEB + 0x%x" % offset
+    )
+
+    Peb = PEB(jitter.vm, peb_address)
+    if main_pe:
+        Peb.ImageBaseAddress = main_pe.NThdr.ImageBase
+    Peb.Ldr = peb_ldr_data_address
+
+
+def build_ldr_data(jitter, modules_info):
+    """
+    Build Loader information using following structure:
+
+    +0x000 Length                          : Uint4B
+    +0x004 Initialized                     : UChar
+    +0x008 SsHandle                        : Ptr32 Void
+    +0x00c InLoadOrderModuleList           : _LIST_ENTRY
+    +0x014 InMemoryOrderModuleList         : _LIST_ENTRY
+    +0x01C InInitializationOrderModuleList         : _LIST_ENTRY
+    # dummy dll base
+    +0x024 DllBase : Ptr32 Void
+
+    @jitter: jitter instance
+    @modules_info: LoadedModules instance
+
+    """
+    # ldr offset pad
+    offset = 0xC
+    addr = LDR_AD + peb_ldr_data_offset
+    ldrdata = PEB_LDR_DATA(jitter.vm, addr)
+
+    main_pe = modules_info.name2module.get(main_pe_name, None)
+    ntdll_pe = modules_info.name2module.get("ntdll.dll", None)
+
+
+    size = 0
+    if main_pe:
+        size += ListEntry.sizeof() * 2
+        main_addr_entry = modules_info.module2entry[main_pe]
+    if ntdll_pe:
+        size += ListEntry.sizeof()
+        ntdll_addr_entry = modules_info.module2entry[ntdll_pe]
+
+    jitter.vm.add_memory_page(
+        addr + offset,
+        PAGE_READ | PAGE_WRITE,
+        b"\x00" * size,
+        "Loader struct"
+    )  # (ldrdata.get_size() - offset))
+
+    last_module = modules_info.module2entry[
+        modules_info.modules[-1]]
+
+    if main_pe:
+        ldrdata.InLoadOrderModuleList.flink = main_addr_entry
+        ldrdata.InLoadOrderModuleList.blink = last_module
+
+
+        ldrdata.InMemoryOrderModuleList.flink = main_addr_entry + \
+            LdrDataEntry.get_type().get_offset("InMemoryOrderLinks")
+        ldrdata.InMemoryOrderModuleList.blink = last_module + \
+            LdrDataEntry.get_type().get_offset("InMemoryOrderLinks")
+    if ntdll_pe:
+        ldrdata.InInitializationOrderModuleList.flink = ntdll_addr_entry + \
+            LdrDataEntry.get_type().get_offset("InInitializationOrderLinks")
+        ldrdata.InInitializationOrderModuleList.blink = last_module + \
+                LdrDataEntry.get_type().get_offset("InInitializationOrderLinks")
+
+    # Add dummy dll base
+    jitter.vm.add_memory_page(peb_ldr_data_address + 0x24,
+                              PAGE_READ | PAGE_WRITE, pck32(0),
+                              "Loader struct dummy dllbase")
+
+
+class LoadedModules(object):
+
+    """Class representing modules in memory"""
+
+    def __init__(self):
+        self.modules = []
+        self.name2module = {}
+        self.module2entry = {}
+        self.module2name = {}
+
+    def add(self, name, module, module_entry):
+        """Track a new module
+        @name: module name (with extension)
+        @module: module object
+        @module_entry: address of the module entry
+        """
+
+        self.modules.append(module)
+        self.name2module[name] = module
+        self.module2entry[module] = module_entry
+        self.module2name[module] = name
+
+    def __repr__(self):
+        return "\n".join(str(x) for x in viewitems(self.name2module))
+
+
+def create_modules_chain(jitter, name2module):
+    """
+    Create the modules entries. Those modules are not linked in this function.
+
+    @jitter: jitter instance
+    @name2module: dict containing association between name and its pe instance
+    """
+
+    modules_info = LoadedModules()
+    base_addr = LDR_AD + modules_list_offset  # XXXX
+    offset_name = 0x500
+    offset_path = 0x600
+
+    out = ""
+    for i, (fname, pe_obj) in enumerate(viewitems(name2module), 1):
+        if pe_obj is None:
+            log.warning("Unknown module: omitted from link list (%r)",
+                        fname)
+            continue
+        addr = base_addr + i * 0x1000
+        bpath = fname.replace('/', '\\')
+        bname_str = os.path.split(fname)[1].lower()
+        bname_unicode = bname_str.encode("utf-16le")
+        log.info("Add module %x %r", pe_obj.NThdr.ImageBase, bname_str)
+
+        modules_info.add(bname_str, pe_obj, addr)
+
+        # Allocate a partial LdrDataEntry (0-Flags)
+        jitter.vm.add_memory_page(
+            addr,
+            PAGE_READ | PAGE_WRITE,
+            b"\x00" * LdrDataEntry.get_offset("Flags"),
+            "Module info %r" % bname_str
+        )
+
+        LdrEntry = LdrDataEntry(jitter.vm, addr)
+
+        LdrEntry.DllBase = pe_obj.NThdr.ImageBase
+        LdrEntry.EntryPoint = pe_obj.Opthdr.AddressOfEntryPoint
+        LdrEntry.SizeOfImage = pe_obj.NThdr.sizeofimage
+        LdrEntry.FullDllName.length = len(bname_unicode)
+        LdrEntry.FullDllName.maxlength = len(bname_unicode) + 2
+        LdrEntry.FullDllName.data = addr + offset_path
+        LdrEntry.BaseDllName.length = len(bname_unicode)
+        LdrEntry.BaseDllName.maxlength = len(bname_unicode) + 2
+        LdrEntry.BaseDllName.data = addr + offset_name
+
+        jitter.vm.add_memory_page(
+            addr + offset_name,
+            PAGE_READ | PAGE_WRITE,
+            bname_unicode + b"\x00" * 2,
+            "Module name %r" % bname_str
+        )
+
+        if isinstance(bpath, bytes):
+            bpath = bpath.decode('utf8')
+        bpath_unicode = bpath.encode('utf-16le')
+        jitter.vm.add_memory_page(
+            addr + offset_path,
+            PAGE_READ | PAGE_WRITE,
+            bpath_unicode + b"\x00" * 2,
+            "Module path %r" % bname_str
+        )
+
+    return modules_info
+
+
+def set_link_list_entry(jitter, loaded_modules, modules_info, offset):
+    for i, module in enumerate(loaded_modules):
+        cur_module_entry = modules_info.module2entry[module]
+        prev_module = loaded_modules[(i - 1) % len(loaded_modules)]
+        next_module = loaded_modules[(i + 1) % len(loaded_modules)]
+        prev_module_entry = modules_info.module2entry[prev_module]
+        next_module_entry = modules_info.module2entry[next_module]
+        if i == 0:
+            prev_module_entry = peb_ldr_data_address + 0xC
+        if i == len(loaded_modules) - 1:
+            next_module_entry = peb_ldr_data_address + 0xC
+
+        list_entry = ListEntry(jitter.vm, cur_module_entry + offset)
+        list_entry.flink = next_module_entry + offset
+        list_entry.blink = prev_module_entry + offset
+
+
+
+def fix_InLoadOrderModuleList(jitter, modules_info):
+    """Fix InLoadOrderModuleList double link list. First module is the main pe,
+    then ntdll, kernel32.
+
+    @jitter: the jitter instance
+    @modules_info: the LoadedModules instance
+    """
+
+    log.debug("Fix InLoadOrderModuleList")
+    main_pe = modules_info.name2module.get(main_pe_name, None)
+    kernel32_pe = modules_info.name2module.get("kernel32.dll", None)
+    ntdll_pe = modules_info.name2module.get("ntdll.dll", None)
+    special_modules = [main_pe, kernel32_pe, ntdll_pe]
+    if not all(special_modules):
+        log.warn(
+            'No main pe, ldr data will be unconsistant %r', special_modules)
+        loaded_modules = modules_info.modules
+    else:
+        loaded_modules = [module for module in modules_info.modules
+                          if module not in special_modules]
+        loaded_modules[0:0] = [main_pe]
+        loaded_modules[1:1] = [ntdll_pe]
+        loaded_modules[2:2] = [kernel32_pe]
+
+    set_link_list_entry(jitter, loaded_modules, modules_info, 0x0)
+
+
+def fix_InMemoryOrderModuleList(jitter, modules_info):
+    """Fix InMemoryOrderLinks double link list. First module is the main pe,
+    then ntdll, kernel32.
+
+    @jitter: the jitter instance
+    @modules_info: the LoadedModules instance
+    """
+
+    log.debug("Fix InMemoryOrderModuleList")
+    main_pe = modules_info.name2module.get(main_pe_name, None)
+    kernel32_pe = modules_info.name2module.get("kernel32.dll", None)
+    ntdll_pe = modules_info.name2module.get("ntdll.dll", None)
+    special_modules = [main_pe, kernel32_pe, ntdll_pe]
+    if not all(special_modules):
+        log.warn('No main pe, ldr data will be unconsistant')
+        loaded_modules = modules_info.modules
+    else:
+        loaded_modules = [module for module in modules_info.modules
+                          if module not in special_modules]
+        loaded_modules[0:0] = [main_pe]
+        loaded_modules[1:1] = [ntdll_pe]
+        loaded_modules[2:2] = [kernel32_pe]
+
+    set_link_list_entry(jitter, loaded_modules, modules_info, 0x8)
+
+
+def fix_InInitializationOrderModuleList(jitter, modules_info):
+    """Fix InInitializationOrderModuleList double link list. First module is the
+    ntdll, then kernel32.
+
+    @jitter: the jitter instance
+    @modules_info: the LoadedModules instance
+
+    """
+
+    log.debug("Fix InInitializationOrderModuleList")
+    main_pe = modules_info.name2module.get(main_pe_name, None)
+    kernel32_pe = modules_info.name2module.get("kernel32.dll", None)
+    ntdll_pe = modules_info.name2module.get("ntdll.dll", None)
+    special_modules = [main_pe, kernel32_pe, ntdll_pe]
+    if not all(special_modules):
+        log.warn('No main pe, ldr data will be unconsistant')
+        loaded_modules = modules_info.modules
+    else:
+        loaded_modules = [module for module in modules_info.modules
+                          if module not in special_modules]
+        loaded_modules[0:0] = [ntdll_pe]
+        loaded_modules[1:1] = [kernel32_pe]
+
+    set_link_list_entry(jitter, loaded_modules, modules_info, 0x10)
+
+
+def add_process_env(jitter):
+    """
+    Build a process environment structure
+    @jitter: jitter instance
+    """
+
+    env_unicode = 'ALLUSEESPROFILE=C:\\Documents and Settings\\All Users\x00'.encode('utf-16le')
+    env_unicode += b"\x00" * 0x10
+    jitter.vm.add_memory_page(
+        process_environment_address,
+        PAGE_READ | PAGE_WRITE,
+        env_unicode,
+        "Process environment"
+    )
+    jitter.vm.set_mem(process_environment_address, env_unicode)
+
+
+def add_process_parameters(jitter):
+    """
+    Build a process parameters structure
+    @jitter: jitter instance
+    """
+
+    o = b""
+    o += pck32(0x1000)  # size
+    o += b"E" * (0x48 - len(o))
+    o += pck32(process_environment_address)
+    jitter.vm.add_memory_page(
+        process_parameters_address,
+        PAGE_READ | PAGE_WRITE,
+        o, "Process parameters"
+    )
+
+
+# http://blog.fireeye.com/research/2010/08/download_exec_notes.html
+seh_count = 0
+
+
+def init_seh(jitter):
+    """
+    Build the modules entries and create double links
+    @jitter: jitter instance
+    """
+
+    global seh_count
+    seh_count = 0
+    tib_ad = jitter.cpu.get_segm_base(jitter.cpu.FS)
+    build_teb(jitter, tib_ad)
+    build_peb(jitter, peb_address)
+
+    modules_info = create_modules_chain(jitter, name2module)
+    fix_InLoadOrderModuleList(jitter, modules_info)
+    fix_InMemoryOrderModuleList(jitter, modules_info)
+    fix_InInitializationOrderModuleList(jitter, modules_info)
+
+    build_ldr_data(jitter, modules_info)
+    add_process_env(jitter)
+    add_process_parameters(jitter)
+
+
+
+def regs2ctxt(jitter, context_address):
+    """
+    Build x86_32 cpu context for exception handling
+    @jitter: jitload instance
+    """
+
+    ctxt = ContextException(jitter.vm, context_address)
+    ctxt.memset(b"\x00")
+    # ContextFlags
+    # XXX
+
+    # DRX
+    ctxt.dr0 = 0
+    ctxt.dr1 = 0
+    ctxt.dr2 = 0
+    ctxt.dr3 = 0
+    ctxt.dr4 = 0
+    ctxt.dr5 = 0
+
+    # Float context
+    # XXX
+
+    # Segment selectors
+    ctxt.gs = jitter.cpu.GS
+    ctxt.fs = jitter.cpu.FS
+    ctxt.es = jitter.cpu.ES
+    ctxt.ds = jitter.cpu.DS
+
+    # Gpregs
+    ctxt.edi = jitter.cpu.EDI
+    ctxt.esi = jitter.cpu.ESI
+    ctxt.ebx = jitter.cpu.EBX
+    ctxt.edx = jitter.cpu.EDX
+    ctxt.ecx = jitter.cpu.ECX
+    ctxt.eax = jitter.cpu.EAX
+    ctxt.ebp = jitter.cpu.EBP
+    ctxt.eip = jitter.cpu.EIP
+
+    # CS
+    ctxt.cs = jitter.cpu.CS
+
+    # Eflags
+    # XXX TODO real eflag
+
+    # ESP
+    ctxt.esp = jitter.cpu.ESP
+
+    # SS
+    ctxt.ss = jitter.cpu.SS
+
+
+def ctxt2regs(jitter, ctxt_ptr):
+    """
+    Restore x86_32 registers from an exception context
+    @ctxt: the serialized context
+    @jitter: jitload instance
+    """
+
+    ctxt = ContextException(jitter.vm, ctxt_ptr)
+
+    # Selectors
+    jitter.cpu.GS = ctxt.gs
+    jitter.cpu.FS = ctxt.fs
+    jitter.cpu.ES = ctxt.es
+    jitter.cpu.DS = ctxt.ds
+
+    # Gpregs
+    jitter.cpu.EDI = ctxt.edi
+    jitter.cpu.ESI = ctxt.esi
+    jitter.cpu.EBX = ctxt.ebx
+    jitter.cpu.EDX = ctxt.edx
+    jitter.cpu.ECX = ctxt.ecx
+    jitter.cpu.EAX = ctxt.eax
+    jitter.cpu.EBP = ctxt.ebp
+    jitter.cpu.EIP = ctxt.eip
+
+    # CS
+    jitter.cpu.CS = ctxt.cs
+
+    # Eflag
+    # XXX TODO
+
+    # ESP
+    jitter.cpu.ESP = ctxt.esp
+    # SS
+    jitter.cpu.SS = ctxt.ss
+
+
+def fake_seh_handler(jitter, except_code, previous_seh=None):
+    """
+    Create an exception context
+    @jitter: jitter instance
+    @except_code: x86 exception code
+    @previous_seh: (optional) last SEH address when multiple SEH are used
+    """
+    global seh_count
+    log.info('Exception at %x %r', jitter.cpu.EIP, seh_count)
+    seh_count += 1
+
+    # Get space on stack for exception handling
+    new_ESP = jitter.cpu.ESP - 0x3c8
+    exception_base_address = new_ESP
+    exception_record_address = exception_base_address + 0xe8
+    context_address = exception_base_address + 0xfc
+    fake_seh_address = exception_base_address + 0x14
+
+    # Save a CONTEXT
+    regs2ctxt(jitter, context_address)
+    jitter.cpu.ESP = new_ESP
+
+    # Get current seh (fs:[0])
+    tib = NT_TIB(jitter.vm, tib_address)
+    seh = tib.ExceptionList.deref
+    if previous_seh:
+        # Recursive SEH
+        while seh.get_addr() != previous_seh:
+            seh = seh.Next.deref
+        seh = seh.Next.deref
+
+    log.debug(
+        'seh_ptr %x { old_seh %r eh %r} ctx_addr %x',
+        seh.get_addr(),
+        seh.Next,
+        seh.Handler,
+        context_address
+    )
+
+    # Write exception_record
+    except_record = EXCEPTION_RECORD(jitter.vm, exception_record_address)
+    except_record.memset(b"\x00")
+    except_record.ExceptionCode = except_code
+    except_record.ExceptionAddress = jitter.cpu.EIP
+
+    # Prepare the stack
+    jitter.push_uint32_t(context_address)               # Context
+    jitter.push_uint32_t(seh.get_addr())                # SEH
+    jitter.push_uint32_t(except_record.get_addr())      # ExceptRecords
+    jitter.push_uint32_t(return_from_exception)         # Ret address
+
+    # Set fake new current seh for exception
+    log.debug("Fake seh ad %x", fake_seh_address)
+    fake_seh = EXCEPTION_REGISTRATION_RECORD(jitter.vm, fake_seh_address)
+    fake_seh.Next.val = tib.ExceptionList.val
+    fake_seh.Handler = 0xaaaaaaaa
+    tib.ExceptionList.val = fake_seh.get_addr()
+    dump_seh(jitter)
+
+    # Remove exceptions
+    jitter.vm.set_exception(0)
+    jitter.cpu.set_exception(0)
+
+    # XXX set ebx to nul?
+    jitter.cpu.EBX = 0
+
+    log.debug('Jumping at %r', seh.Handler)
+    return seh.Handler.val
+
+
+def dump_seh(jitter):
+    """
+    Walk and dump the SEH entries
+    @jitter: jitter instance
+    """
+    log.debug('Dump_seh. Tib_address: %x', tib_address)
+    cur_seh_ptr = NT_TIB(jitter.vm, tib_address).ExceptionList
+    loop = 0
+    while cur_seh_ptr and jitter.vm.is_mapped(cur_seh_ptr.val,
+                                              len(cur_seh_ptr)):
+        if loop > MAX_SEH:
+            log.debug("Too many seh, quit")
+            return
+        err = cur_seh_ptr.deref
+        log.debug('\t' * (loop + 1) + 'seh_ptr: %x { prev_seh: %r eh %r }',
+                 err.get_addr(), err.Next, err.Handler)
+        cur_seh_ptr = err.Next
+        loop += 1
+
+
+def set_win_fs_0(jitter, fs=4):
+    """
+    Set FS segment selector and create its corresponding segment
+    @jitter: jitter instance
+    @fs: segment selector value
+    """
+    jitter.cpu.FS = fs
+    jitter.cpu.set_segm_base(fs, tib_address)
+    segm_to_do = set([x86_regs.FS])
+    return segm_to_do
+
+
+def return_from_seh(jitter):
+    """Handle the return from an exception handler
+    @jitter: jitter instance"""
+
+    # Get object addresses
+    seh_address = jitter.vm.get_u32(jitter.cpu.ESP + 0x4)
+    context_address = jitter.vm.get_u32(jitter.cpu.ESP + 0x8)
+
+    # Get registers changes
+    log.debug('Context address: %x', context_address)
+    status = jitter.cpu.EAX
+    ctxt2regs(jitter, context_address)
+
+    # Rebuild SEH (remove fake SEH)
+    tib = NT_TIB(jitter.vm, tib_address)
+    seh = tib.ExceptionList.deref
+    log.debug('Old seh: %x New seh: %x', seh.get_addr(), seh.Next.val)
+    tib.ExceptionList.val = seh.Next.val
+    dump_seh(jitter)
+
+    # Handle returned values
+    if status == 0x0:
+        # ExceptionContinueExecution
+        log.debug('SEH continue')
+        jitter.pc = jitter.cpu.EIP
+        log.debug('Context::Eip: %x', jitter.pc)
+
+    elif status == 1:
+        # ExceptionContinueSearch
+        log.debug("Delegate to the next SEH handler")
+        # exception_base_address: context_address - 0xfc
+        # -> exception_record_address: exception_base_address + 0xe8
+        exception_record = EXCEPTION_RECORD(jitter.vm,
+                                            context_address - 0xfc + 0xe8)
+
+        pc = fake_seh_handler(jitter, exception_record.ExceptionCode,
+                              seh_address)
+        jitter.pc = pc
+
+    else:
+        # https://msdn.microsoft.com/en-us/library/aa260344%28v=vs.60%29.aspx
+        # But the type _EXCEPTION_DISPOSITION may take 2 others values:
+        #  - ExceptionNestedException = 2
+        #  - ExceptionCollidedUnwind = 3
+        raise ValueError("Valid values are ExceptionContinueExecution and "
+                         "ExceptionContinueSearch")
+
+    # Jitter's breakpoint compliant
+    return True