about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xexample/jitter/arm.py3
-rw-r--r--example/jitter/sandbox_call.py23
-rw-r--r--miasm2/analysis/sandbox.py230
-rw-r--r--miasm2/arch/aarch64/jit.py14
-rw-r--r--miasm2/arch/arm/jit.py20
-rw-r--r--miasm2/arch/x86/jit.py72
-rw-r--r--miasm2/os_dep/linux_stdlib.py86
-rw-r--r--test/arch/x86/qemu/testqemu.py8
-rwxr-xr-xtest/os_dep/linux/test_env.aarch64lbin0 -> 6168 bytes
-rwxr-xr-xtest/os_dep/linux/test_env.armlbin0 -> 5608 bytes
-rw-r--r--test/os_dep/linux/test_env.c10
-rw-r--r--test/os_dep/linux/test_env.py36
-rwxr-xr-xtest/os_dep/linux/test_env.x86_32bin0 -> 5588 bytes
-rwxr-xr-xtest/os_dep/linux/test_env.x86_64bin0 -> 6312 bytes
-rwxr-xr-xtest/test_all.py9
15 files changed, 435 insertions, 76 deletions
diff --git a/example/jitter/arm.py b/example/jitter/arm.py
index eac6c0e6..e475abeb 100755
--- a/example/jitter/arm.py
+++ b/example/jitter/arm.py
@@ -24,8 +24,5 @@ else:
 if options.verbose is True:
     print sb.jitter.vm
 
-if options.address is None:
-    raise ValueError('Invalid address')
-
 # Run the code
 sb.run()
diff --git a/example/jitter/sandbox_call.py b/example/jitter/sandbox_call.py
new file mode 100644
index 00000000..49365004
--- /dev/null
+++ b/example/jitter/sandbox_call.py
@@ -0,0 +1,23 @@
+"""This example illustrate the Sandbox.call API, for direct call of a given
+function"""
+
+from miasm2.analysis.sandbox import Sandbox_Linux_arml
+from miasm2.analysis.binary import Container
+from miasm2.os_dep.linux_stdlib import linobjs
+from miasm2.core.utils import hexdump
+
+# Parse arguments
+parser = Sandbox_Linux_arml.parser(description="ELF sandboxer")
+parser.add_argument("filename", help="ELF Filename")
+options = parser.parse_args()
+
+sb = Sandbox_Linux_arml(options.filename, options, globals())
+
+with open(options.filename) as fdesc:
+    cont = Container.from_stream(fdesc)
+    addr_to_call = cont.symbol_pool.getby_name("md5_starts").offset
+
+# Calling md5_starts(malloc(0x64))
+addr = linobjs.heap.alloc(sb.jitter, 0x64)
+sb.call(addr_to_call, addr)
+hexdump(sb.jitter.vm.get_mem(addr, 0x64))
diff --git a/miasm2/analysis/sandbox.py b/miasm2/analysis/sandbox.py
index 87e84caf..3c29ace0 100644
--- a/miasm2/analysis/sandbox.py
+++ b/miasm2/analysis/sandbox.py
@@ -14,6 +14,8 @@ class Sandbox(object):
     Parent class for Sandbox abstraction
     """
 
+    CALL_FINNISH_ADDR = 0x1337babe
+
     @staticmethod
     def code_sentinelle(jitter):
         jitter.run = False
@@ -126,6 +128,20 @@ class Sandbox(object):
             self.jitter.init_run(addr)
             self.jitter.continue_run()
 
+    def call(self, prepare_cb, addr, *args):
+        """
+        Direct call of the function at @addr, with arguments @args prepare in
+        calling convention implemented by @prepare_cb
+        @prepare_cb: func(ret_addr, *args)
+        @addr: address of the target function
+        @args: arguments
+        """
+        self.jitter.init_run(addr)
+        self.jitter.add_breakpoint(self.CALL_FINNISH_ADDR, self.code_sentinelle)
+        prepare_cb(self.CALL_FINNISH_ADDR, *args)
+        self.jitter.continue_run()
+
+
 
 class OS(object):
 
@@ -248,6 +264,8 @@ class OS_Win(OS):
 
 class OS_Linux(OS):
 
+    PROGRAM_PATH = "./program"
+
     def __init__(self, custom_methods, *args, **kwargs):
         from miasm2.jitter.loader.elf import vm_load_elf, preload_elf, libimp_elf
         from miasm2.os_dep import linux_stdlib
@@ -269,9 +287,30 @@ class OS_Linux(OS):
         # Library calls handler
         self.jitter.add_lib_handler(self.libs, methods)
 
+        # Arguments
+        self.argv = [self.PROGRAM_PATH]
+        if self.options.command_line:
+             self.argv += self.options.command_line
+        self.envp = self.options.environment_vars
+
+    @classmethod
+    def update_parser(cls, parser):
+        parser.add_argument('-c', '--command-line',
+                            action="append",
+                            default=[],
+                            help="Command line arguments")
+        parser.add_argument('--environment-vars',
+                            action="append",
+                            default=[],
+                            help="Environment variables arguments")
+        parser.add_argument('--mimic-env',
+                            action="store_true",
+                            help="Mimic the environment of a starting executable")
 
 class OS_Linux_str(OS):
 
+    PROGRAM_PATH = "./program"
+
     def __init__(self, custom_methods, *args, **kwargs):
         from miasm2.jitter.loader.elf import libimp_elf
         from miasm2.os_dep import linux_stdlib
@@ -293,8 +332,25 @@ class OS_Linux_str(OS):
         # Library calls handler
         self.jitter.add_lib_handler(libs, methods)
 
+        # Arguments
+        self.argv = [self.PROGRAM_PATH]
+        if self.options.command_line:
+             self.argv += self.options.command_line
+        self.envp = self.options.environment_vars
+
     @classmethod
     def update_parser(cls, parser):
+        parser.add_argument('-c', '--command-line',
+                            action="append",
+                            default=[],
+                            help="Command line arguments")
+        parser.add_argument('--environment-vars',
+                            action="append",
+                            default=[],
+                            help="Environment variables arguments")
+        parser.add_argument('--mimic-env',
+                            action="store_true",
+                            help="Mimic the environment of a starting executable")
         parser.add_argument("load_base_addr", help="load base address")
 
 
@@ -409,6 +465,15 @@ class Sandbox_Win_x86_32(Sandbox, Arch_x86_32, OS_Win):
             addr = self.entry_point
         super(Sandbox_Win_x86_32, self).run(addr)
 
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_stdcall)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
+
 
 class Sandbox_Win_x86_64(Sandbox, Arch_x86_64, OS_Win):
 
@@ -433,6 +498,15 @@ class Sandbox_Win_x86_64(Sandbox, Arch_x86_64, OS_Win):
             addr = self.entry_point
         super(Sandbox_Win_x86_64, self).run(addr)
 
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_stdcall)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
+
 
 class Sandbox_Linux_x86_32(Sandbox, Arch_x86_32, OS_Linux):
 
@@ -440,10 +514,32 @@ class Sandbox_Linux_x86_32(Sandbox, Arch_x86_32, OS_Linux):
         Sandbox.__init__(self, *args, **kwargs)
 
         # Pre-stack some arguments
-        self.jitter.push_uint32_t(2)
-        self.jitter.push_uint32_t(1)
-        self.jitter.push_uint32_t(0)
-        self.jitter.push_uint32_t(0x1337beef)
+        if self.options.mimic_env:
+            env_ptrs = []
+            for env in self.envp:
+                env += "\x00"
+                self.jitter.cpu.ESP -= len(env)
+                ptr = self.jitter.cpu.ESP
+                self.jitter.vm.set_mem(ptr, env)
+                env_ptrs.append(ptr)
+            argv_ptrs = []
+            for arg in self.argv:
+                arg += "\x00"
+                self.jitter.cpu.ESP -= len(arg)
+                ptr = self.jitter.cpu.ESP
+                self.jitter.vm.set_mem(ptr, arg)
+                argv_ptrs.append(ptr)
+
+            self.jitter.push_uint32_t(0x1337beef)
+            self.jitter.push_uint32_t(0)
+            for ptr in reversed(env_ptrs):
+                self.jitter.push_uint32_t(ptr)
+            self.jitter.push_uint32_t(0)
+            for ptr in reversed(argv_ptrs):
+                self.jitter.push_uint32_t(ptr)
+            self.jitter.push_uint32_t(len(self.argv))
+        else:
+            self.jitter.push_uint32_t(0x1337beef)
 
         # Set the runtime guard
         self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
@@ -456,18 +552,49 @@ class Sandbox_Linux_x86_32(Sandbox, Arch_x86_32, OS_Linux):
             addr = self.entry_point
         super(Sandbox_Linux_x86_32, self).run(addr)
 
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_systemv)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
+
+
 
 class Sandbox_Linux_x86_64(Sandbox, Arch_x86_64, OS_Linux):
 
     def __init__(self, *args, **kwargs):
         Sandbox.__init__(self, *args, **kwargs)
 
-        # reserve stack for local reg
-        for _ in xrange(0x4):
+        # Pre-stack some arguments
+        if self.options.mimic_env:
+            env_ptrs = []
+            for env in self.envp:
+                env += "\x00"
+                self.jitter.cpu.RSP -= len(env)
+                ptr = self.jitter.cpu.RSP
+                self.jitter.vm.set_mem(ptr, env)
+                env_ptrs.append(ptr)
+            argv_ptrs = []
+            for arg in self.argv:
+                arg += "\x00"
+                self.jitter.cpu.RSP -= len(arg)
+                ptr = self.jitter.cpu.RSP
+                self.jitter.vm.set_mem(ptr, arg)
+                argv_ptrs.append(ptr)
+
+            self.jitter.push_uint64_t(0x1337beef)
             self.jitter.push_uint64_t(0)
-
-        # Pre-stack return address
-        self.jitter.push_uint64_t(0x1337beef)
+            for ptr in reversed(env_ptrs):
+                self.jitter.push_uint64_t(ptr)
+            self.jitter.push_uint64_t(0)
+            for ptr in reversed(argv_ptrs):
+                self.jitter.push_uint64_t(ptr)
+            self.jitter.push_uint64_t(len(self.argv))
+        else:
+            self.jitter.push_uint64_t(0x1337beef)
 
         # Set the runtime guard
         self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
@@ -480,22 +607,65 @@ class Sandbox_Linux_x86_64(Sandbox, Arch_x86_64, OS_Linux):
             addr = self.entry_point
         super(Sandbox_Linux_x86_64, self).run(addr)
 
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_systemv)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
+
 
 class Sandbox_Linux_arml(Sandbox, Arch_arml, OS_Linux):
 
     def __init__(self, *args, **kwargs):
         Sandbox.__init__(self, *args, **kwargs)
 
+        # Pre-stack some arguments
+        if self.options.mimic_env:
+            env_ptrs = []
+            for env in self.envp:
+                env += "\x00"
+                self.jitter.cpu.SP -= len(env)
+                ptr = self.jitter.cpu.SP
+                self.jitter.vm.set_mem(ptr, env)
+                env_ptrs.append(ptr)
+            argv_ptrs = []
+            for arg in self.argv:
+                arg += "\x00"
+                self.jitter.cpu.SP -= len(arg)
+                ptr = self.jitter.cpu.SP
+                self.jitter.vm.set_mem(ptr, arg)
+                argv_ptrs.append(ptr)
+
+            self.jitter.push_uint32_t(0)
+            for ptr in reversed(env_ptrs):
+                self.jitter.push_uint32_t(ptr)
+            self.jitter.push_uint32_t(0)
+            for ptr in reversed(argv_ptrs):
+                self.jitter.push_uint32_t(ptr)
+            self.jitter.push_uint32_t(len(self.argv))
+
         self.jitter.cpu.LR = 0x1337beef
 
         # Set the runtime guard
         self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
 
     def run(self, addr=None):
-        if addr is None and self.options.address is not None:
-            addr = int(self.options.address, 16)
+        if addr is None and self.options.address is None:
+            addr = self.entry_point
         super(Sandbox_Linux_arml, self).run(addr)
 
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_systemv)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
+
 
 class Sandbox_Linux_armb_str(Sandbox, Arch_armb, OS_Linux_str):
 
@@ -534,12 +704,46 @@ class Sandbox_Linux_aarch64l(Sandbox, Arch_aarch64l, OS_Linux):
     def __init__(self, *args, **kwargs):
         Sandbox.__init__(self, *args, **kwargs)
 
+        # Pre-stack some arguments
+        if self.options.mimic_env:
+            env_ptrs = []
+            for env in self.envp:
+                env += "\x00"
+                self.jitter.cpu.SP -= len(env)
+                ptr = self.jitter.cpu.SP
+                self.jitter.vm.set_mem(ptr, env)
+                env_ptrs.append(ptr)
+            argv_ptrs = []
+            for arg in self.argv:
+                arg += "\x00"
+                self.jitter.cpu.SP -= len(arg)
+                ptr = self.jitter.cpu.SP
+                self.jitter.vm.set_mem(ptr, arg)
+                argv_ptrs.append(ptr)
+
+            self.jitter.push_uint64_t(0)
+            for ptr in reversed(env_ptrs):
+                self.jitter.push_uint64_t(ptr)
+            self.jitter.push_uint64_t(0)
+            for ptr in reversed(argv_ptrs):
+                self.jitter.push_uint64_t(ptr)
+            self.jitter.push_uint64_t(len(self.argv))
+
         self.jitter.cpu.LR = 0x1337beef
 
         # Set the runtime guard
         self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)
 
     def run(self, addr=None):
-        if addr is None and self.options.address is not None:
-            addr = int(self.options.address, 0)
+        if addr is None and self.options.address is None:
+            addr = self.entry_point
         super(Sandbox_Linux_aarch64l, self).run(addr)
+
+    def call(self, addr, *args, **kwargs):
+        """
+        Direct call of the function at @addr, with arguments @args
+        @addr: address of the target function
+        @args: arguments
+        """
+        prepare_cb = kwargs.pop('prepare_cb', self.jitter.func_prepare_systemv)
+        super(self.__class__, self).call(prepare_cb, addr, *args)
diff --git a/miasm2/arch/aarch64/jit.py b/miasm2/arch/aarch64/jit.py
index 255bb91d..31570f52 100644
--- a/miasm2/arch/aarch64/jit.py
+++ b/miasm2/arch/aarch64/jit.py
@@ -37,7 +37,7 @@ class jitter_aarch64l(jitter):
     def func_args_stdcall(self, n_args):
         args = []
         for i in xrange(min(n_args, self.max_reg_arg)):
-            args.append(self.cpu.get_gpreg()['X%d' % i])
+            args.append(getattr(self.cpu, 'X%d' % i))
         for i in xrange(max(0, n_args - self.max_reg_arg)):
             args.append(self.get_stack_arg(i))
         ret_ad = self.cpu.LR
@@ -56,6 +56,18 @@ class jitter_aarch64l(jitter):
             arg = self.get_stack_arg(index - self.max_reg_arg)
         return arg
 
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for index in xrange(min(len(args), 4)):
+            setattr(self.cpu, 'X%d' % index, args[index])
+        for index in xrange(4, len(args)):
+            self.vm.set_mem(self.cpu.SP + 8 * (index - 4), pck64(args[index]))
+        self.cpu.LR = ret_addr
+
+    func_args_systemv = func_args_stdcall
+    func_ret_systemv = func_ret_stdcall
+    get_arg_n_systemv = get_arg_n_stdcall
+    func_prepare_systemv = func_prepare_stdcall
+
     def init_run(self, *args, **kwargs):
         jitter.init_run(self, *args, **kwargs)
         self.cpu.PC = self.pc
diff --git a/miasm2/arch/arm/jit.py b/miasm2/arch/arm/jit.py
index 70c708e1..545d60de 100644
--- a/miasm2/arch/arm/jit.py
+++ b/miasm2/arch/arm/jit.py
@@ -34,11 +34,7 @@ class jitter_arml(jitter):
 
     @named_arguments
     def func_args_stdcall(self, n_args):
-        args = []
-        for i in xrange(min(n_args, 4)):
-            args.append(self.cpu.get_gpreg()['R%d' % i])
-        for i in xrange(max(0, n_args - 4)):
-            args.append(self.get_stack_arg(i))
+        args = [self.get_arg_n_stdcall(i) for i in xrange(n_args)]
         ret_ad = self.cpu.LR
         return ret_ad, args
 
@@ -48,13 +44,25 @@ class jitter_arml(jitter):
             self.cpu.R0 = ret_value
         return True
 
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for index in xrange(min(len(args), 4)):
+            setattr(self.cpu, 'R%d' % index, args[index])
+        for index in xrange(4, len(args)):
+            self.vm.set_mem(self.cpu.SP + 4 * (index - 4), pck32(args[index]))
+        self.cpu.LR = ret_addr
+
     def get_arg_n_stdcall(self, index):
         if index < 4:
-            arg = self.cpu.get_gpreg()['R%d' % index]
+            arg = getattr(self.cpu, 'R%d' % index)
         else:
             arg = self.get_stack_arg(index-4)
         return arg
 
+    func_args_systemv = func_args_stdcall
+    func_ret_systemv = func_ret_stdcall
+    func_prepare_systemv = func_prepare_stdcall
+    get_arg_n_systemv = get_arg_n_stdcall
+
     def init_run(self, *args, **kwargs):
         jitter.init_run(self, *args, **kwargs)
         self.cpu.PC = self.pc
diff --git a/miasm2/arch/x86/jit.py b/miasm2/arch/x86/jit.py
index cfdabf8c..ef1f162b 100644
--- a/miasm2/arch/x86/jit.py
+++ b/miasm2/arch/x86/jit.py
@@ -92,6 +92,10 @@ class jitter_x86_32(jitter):
     def get_stack_arg(self, index):
         return upck32(self.vm.get_mem(self.cpu.ESP + 4 * index, 4))
 
+    def init_run(self, *args, **kwargs):
+        jitter.init_run(self, *args, **kwargs)
+        self.cpu.EIP = self.pc
+
     # calling conventions
 
     # stdcall
@@ -108,6 +112,13 @@ class jitter_x86_32(jitter):
         if ret_value2 is not None:
             self.cpu.EDX = ret_value2
 
+    def func_prepare_stdcall(self, ret_addr, *args):
+        for arg in reversed(args):
+            self.push_uint32_t(arg)
+        self.push_uint32_t(ret_addr)
+
+    get_arg_n_stdcall = get_stack_arg
+
     # cdecl
     @named_arguments
     def func_args_cdecl(self, n_args):
@@ -115,18 +126,24 @@ class jitter_x86_32(jitter):
         args = [self.get_stack_arg(i) for i in xrange(n_args)]
         return ret_ad, args
 
-    def func_ret_cdecl(self, ret_addr, ret_value):
+    def func_ret_cdecl(self, ret_addr, ret_value=None):
         self.cpu.EIP = ret_addr
-        self.cpu.EAX = ret_value
+        if ret_value is not None:
+            self.cpu.EAX = ret_value
 
-    def init_run(self, *args, **kwargs):
-        jitter.init_run(self, *args, **kwargs)
-        self.cpu.EIP = self.pc
+    get_arg_n_cdecl = get_stack_arg
+
+    # System V
+    func_args_systemv = func_args_cdecl
+    func_ret_systemv = func_ret_cdecl
+    func_prepare_systemv = func_prepare_stdcall
+    get_arg_n_systemv = get_stack_arg
 
 
 class jitter_x86_64(jitter):
 
     C_Gen = x86_64_CGen
+    args_regs_systemv = ['RDI', 'RSI', 'RDX', 'RCX', 'R8', 'R9']
 
     def __init__(self, *args, **kwargs):
         sp = asmblock.AsmSymbolPool()
@@ -152,6 +169,13 @@ class jitter_x86_64(jitter):
     def get_stack_arg(self, index):
         return upck64(self.vm.get_mem(self.cpu.RSP + 8 * index, 8))
 
+    def init_run(self, *args, **kwargs):
+        jitter.init_run(self, *args, **kwargs)
+        self.cpu.RIP = self.pc
+
+    # calling conventions
+
+    # stdcall
     @named_arguments
     def func_args_stdcall(self, n_args):
         args_regs = ['RCX', 'RDX', 'R8', 'R9']
@@ -169,23 +193,31 @@ class jitter_x86_64(jitter):
             self.cpu.RAX = ret_value
         return True
 
+    # cdecl
+    func_args_cdecl = func_args_stdcall
+    func_ret_cdecl = func_ret_stdcall
+
+    # System V
+
+    def get_arg_n_systemv(self, index):
+        args_regs = self.args_regs_systemv
+        if index < len(args_regs):
+            return getattr(self.cpu, args_regs[index])
+        return self.get_stack_arg(index - len(args_regs))
+
     @named_arguments
-    def func_args_cdecl(self, n_args):
-        args_regs = ['RCX', 'RDX', 'R8', 'R9']
+    def func_args_systemv(self, n_args):
         ret_ad = self.pop_uint64_t()
-        args = []
-        for i in xrange(min(n_args, 4)):
-            args.append(self.cpu.get_gpreg()[args_regs[i]])
-        for i in xrange(max(0, n_args - 4)):
-            args.append(self.get_stack_arg(i))
+        args = [self.get_arg_n_systemv(index) for index in xrange(n_args)]
         return ret_ad, args
 
-    def func_ret_cdecl(self, ret_addr, ret_value=None):
-        self.pc = self.cpu.RIP = ret_addr
-        if ret_value is not None:
-            self.cpu.RAX = ret_value
-        return True
+    func_ret_systemv = func_ret_cdecl
 
-    def init_run(self, *args, **kwargs):
-        jitter.init_run(self, *args, **kwargs)
-        self.cpu.RIP = self.pc
+    def func_prepare_systemv(self, ret_addr, *args):
+        args_regs = self.args_regs_systemv
+        self.push_uint64_t(ret_addr)
+        for i in xrange(min(len(args), len(args_regs))):
+            setattr(self.cpu, args_regs[i], args[i])
+        remaining_args = args[len(args_regs):]
+        for arg in reversed(remaining_args):
+            self.push_uint64_t(arg)
diff --git a/miasm2/os_dep/linux_stdlib.py b/miasm2/os_dep/linux_stdlib.py
index b05b2cd9..9e68454c 100644
--- a/miasm2/os_dep/linux_stdlib.py
+++ b/miasm2/os_dep/linux_stdlib.py
@@ -17,6 +17,36 @@ class c_linobjs(object):
 
 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/...
+
+    """
+    global ABORT_ADDR
+    ret_ad, args = jitter.func_args_systemv(["main", "argc", "ubp_av", "init",
+                                             "fini", "rtld_fini", "stack_end"])
+
+    # done by __libc_init_first
+    size = jitter.ir_arch.pc.size / 8
+    argv = args.ubp_av
+    envp = argv + (args.argc + 1) * size
+
+    # Call int main(int argc, char** argv, char** envp)
+    jitter.func_ret_systemv(args.main)
+    ret_ad = ABORT_ADDR
+    jitter.func_prepare_systemv(ret_ad, args.argc, argv, envp)
+    return True
+
 
 def xxx_isprint(jitter):
     '''
@@ -25,9 +55,9 @@ def xxx_isprint(jitter):
 
     checks for any printable character including space.
     '''
-    ret_addr, args = jitter.func_args_stdcall(['c'])
+    ret_addr, args = jitter.func_args_systemv(['c'])
     ret = 1 if chr(args.c & 0xFF) in printable else 0
-    return jitter.func_ret_stdcall(ret_addr, ret)
+    return jitter.func_ret_systemv(ret_addr, ret)
 
 
 def xxx_memcpy(jitter):
@@ -37,9 +67,9 @@ def xxx_memcpy(jitter):
 
     copies n bytes from memory area src to memory area dest.
     '''
-    ret_addr, args = jitter.func_args_stdcall(['dest', 'src', 'n'])
+    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_stdcall(ret_addr, args.dest)
+    return jitter.func_ret_systemv(ret_addr, args.dest)
 
 
 def xxx_memset(jitter):
@@ -50,9 +80,9 @@ def xxx_memset(jitter):
     fills the first n bytes of the memory area pointed to by s with the constant
     byte c.'''
 
-    ret_addr, args = jitter.func_args_stdcall(['dest', 'c', 'n'])
+    ret_addr, args = jitter.func_args_systemv(['dest', 'c', 'n'])
     jitter.vm.set_mem(args.dest, chr(args.c & 0xFF) * args.n)
-    return jitter.func_ret_stdcall(ret_addr, args.dest)
+    return jitter.func_ret_systemv(ret_addr, args.dest)
 
 
 def xxx_puts(jitter):
@@ -62,7 +92,7 @@ def xxx_puts(jitter):
 
     writes the string s and a trailing newline to stdout.
     '''
-    ret_addr, args = jitter.func_args_stdcall(['s'])
+    ret_addr, args = jitter.func_args_systemv(['s'])
     index = args.s
     char = jitter.vm.get_mem(index, 1)
     while char != '\x00':
@@ -70,7 +100,7 @@ def xxx_puts(jitter):
         index += 1
         char = jitter.vm.get_mem(index, 1)
     stdout.write('\n')
-    return jitter.func_ret_stdcall(ret_addr, 1)
+    return jitter.func_ret_systemv(ret_addr, 1)
 
 
 def get_fmt_args(jitter, fmt, cur_arg):
@@ -89,9 +119,9 @@ def get_fmt_args(jitter, fmt, cur_arg):
                 if char.lower() in '%cdfsux':
                     break
             if token.endswith('s'):
-                arg = jitter.get_str_ansi(jitter.get_arg_n_stdcall(cur_arg))
+                arg = jitter.get_str_ansi(jitter.get_arg_n_systemv(cur_arg))
             else:
-                arg = jitter.get_arg_n_stdcall(cur_arg)
+                arg = jitter.get_arg_n_systemv(cur_arg)
             char = token % arg
             cur_arg += 1
         output += char
@@ -99,67 +129,67 @@ def get_fmt_args(jitter, fmt, cur_arg):
 
 
 def xxx_snprintf(jitter):
-    ret_addr, args = jitter.func_args_stdcall(['string', 'size', 'fmt'])
+    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.vm.set_mem(args.string, output + '\x00')
-    return jitter.func_ret_stdcall(ret_addr, ret)
+    return jitter.func_ret_systemv(ret_addr, ret)
 
 
 def xxx_sprintf(jitter):
-    ret_addr, args = jitter.func_args_stdcall(['string', 'fmt'])
+    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.vm.set_mem(args.string, output + '\x00')
-    return jitter.func_ret_stdcall(ret_addr, ret)
+    return jitter.func_ret_systemv(ret_addr, ret)
 
 
 def xxx_printf(jitter):
-    ret_addr, args = jitter.func_args_stdcall(['fmt'])
+    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)
     print output,
-    return jitter.func_ret_stdcall(ret_addr, ret)
+    return jitter.func_ret_systemv(ret_addr, ret)
 
 
 def xxx_strcpy(jitter):
-    ret_ad, args = jitter.func_args_stdcall(["dst", "src"])
+    ret_ad, args = jitter.func_args_systemv(["dst", "src"])
     str_src = jitter.get_str_ansi(args.src) + '\x00'
     jitter.vm.set_mem(args.dst, str_src)
-    jitter.func_ret_stdcall(ret_ad, args.dst)
+    jitter.func_ret_systemv(ret_ad, args.dst)
 
 
 def xxx_strlen(jitter):
-    ret_ad, args = jitter.func_args_stdcall(["src"])
+    ret_ad, args = jitter.func_args_systemv(["src"])
     str_src = jitter.get_str_ansi(args.src)
-    jitter.func_ret_stdcall(ret_ad, len(str_src))
+    jitter.func_ret_systemv(ret_ad, len(str_src))
 
 
 def xxx_malloc(jitter):
-    ret_ad, args = jitter.func_args_stdcall(["msize"])
+    ret_ad, args = jitter.func_args_systemv(["msize"])
     addr = linobjs.heap.alloc(jitter, args.msize)
-    jitter.func_ret_stdcall(ret_ad, addr)
+    jitter.func_ret_systemv(ret_ad, addr)
 
 
 def xxx_free(jitter):
-    ret_ad, args = jitter.func_args_stdcall(["ptr"])
-    jitter.func_ret_stdcall(ret_ad, 0)
+    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_stdcall(["ptr_str1", "ptr_str2"])
+    ret_ad, args = jitter.func_args_systemv(["ptr_str1", "ptr_str2"])
     s1 = jitter.get_str_ansi(args.ptr_str1)
     s2 = jitter.get_str_ansi(args.ptr_str2)
-    jitter.func_ret_stdcall(ret_ad, cmp(s1, s2))
+    jitter.func_ret_systemv(ret_ad, cmp(s1, s2))
 
 
 def xxx_strncmp(jitter):
-    ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2", "size"])
+    ret_ad, args = jitter.func_args_systemv(["ptr_str1", "ptr_str2", "size"])
     s1 = jitter.get_str_ansi(args.ptr_str1, args.size)
     s2 = jitter.get_str_ansi(args.ptr_str2, args.size)
-    jitter.func_ret_stdcall(ret_ad, cmp(s1, s2))
+    jitter.func_ret_systemv(ret_ad, cmp(s1, s2))
diff --git a/test/arch/x86/qemu/testqemu.py b/test/arch/x86/qemu/testqemu.py
index 5f26d6f3..e6c487f2 100644
--- a/test/arch/x86/qemu/testqemu.py
+++ b/test/arch/x86/qemu/testqemu.py
@@ -40,7 +40,7 @@ nb_tests = 1
 def xxx___printf_chk(jitter):
     """Tiny implementation of printf_chk"""
     global nb_tests
-    ret_ad, args = jitter.func_args_cdecl(["out", "format"])
+    ret_ad, args = jitter.func_args_systemv(["out", "format"])
     if args.out != 1:
         raise RuntimeError("Not implemented")
     fmt = jitter.get_str_ansi(args.format)
@@ -89,7 +89,7 @@ def xxx___printf_chk(jitter):
 
     sys.stdout.write("[%d] %s" % (nb_tests, output))
     nb_tests += 1
-    jitter.func_ret_cdecl(ret_ad, 0)
+    jitter.func_ret_systemv(ret_ad, 0)
 
 def xxx_puts(jitter):
     '''
@@ -98,7 +98,7 @@ def xxx_puts(jitter):
 
     writes the string s and a trailing newline to stdout.
     '''
-    ret_addr, args = jitter.func_args_cdecl(['target'])
+    ret_addr, args = jitter.func_args_systemv(['target'])
     output = jitter.get_str_ansi(args.target)
     # Check with expected result
     line = expected.next()
@@ -106,7 +106,7 @@ def xxx_puts(jitter):
         print "Expected:", line
         print "Obtained:", output
         raise RuntimeError("Bad semantic")
-    return jitter.func_ret_cdecl(ret_addr, 1)
+    return jitter.func_ret_systemv(ret_addr, 1)
 
 # Parse arguments
 parser = Sandbox_Linux_x86_32.parser(description="ELF sandboxer")
diff --git a/test/os_dep/linux/test_env.aarch64l b/test/os_dep/linux/test_env.aarch64l
new file mode 100755
index 00000000..19e97780
--- /dev/null
+++ b/test/os_dep/linux/test_env.aarch64l
Binary files differdiff --git a/test/os_dep/linux/test_env.arml b/test/os_dep/linux/test_env.arml
new file mode 100755
index 00000000..c24d061e
--- /dev/null
+++ b/test/os_dep/linux/test_env.arml
Binary files differdiff --git a/test/os_dep/linux/test_env.c b/test/os_dep/linux/test_env.c
new file mode 100644
index 00000000..7b265561
--- /dev/null
+++ b/test/os_dep/linux/test_env.c
@@ -0,0 +1,10 @@
+#include<stdlib.h>
+#include<stdio.h>
+
+int main(int argc, char** argv, char** envp)
+{
+	printf("argc %d\n", argc);
+	printf("argv[0] %s\n", argv[0]);
+	printf("argv[1] %s\n", argv[1]);
+	printf("envp[0] %s\n", envp[0]);
+}
diff --git a/test/os_dep/linux/test_env.py b/test/os_dep/linux/test_env.py
new file mode 100644
index 00000000..a44d62c4
--- /dev/null
+++ b/test/os_dep/linux/test_env.py
@@ -0,0 +1,36 @@
+import os
+import sys
+from pdb import pm
+from miasm2.analysis.binary import Container
+from miasm2.analysis.sandbox import Sandbox_Linux_x86_32, Sandbox_Linux_x86_64,\
+    Sandbox_Linux_arml, Sandbox_Linux_aarch64l
+
+if len(sys.argv) < 2:
+    print "Usage: %s <arch> ..." % sys.argv[0]
+    exit(0)
+
+arch = sys.argv[1]
+
+if arch == "x86_32":
+    sandbox = Sandbox_Linux_x86_32
+elif arch == "x86_64":
+    sandbox = Sandbox_Linux_x86_64
+elif arch == "arml":
+    sandbox = Sandbox_Linux_arml
+elif arch == "aarch64l":
+    sandbox = Sandbox_Linux_aarch64l
+else:
+    raise ValueError("Unsuported arch: %s" % arch)
+
+# Parse arguments
+parser = sandbox.parser(description="ELF sandboxer")
+parser.add_argument("filename", help="ELF Filename")
+options = parser.parse_args(sys.argv[2:])
+
+# Create sandbox
+sb = sandbox(options.filename, options, globals())
+
+# Run
+sb.run()
+
+assert(sb.jitter.run is False)
diff --git a/test/os_dep/linux/test_env.x86_32 b/test/os_dep/linux/test_env.x86_32
new file mode 100755
index 00000000..9f0f96bc
--- /dev/null
+++ b/test/os_dep/linux/test_env.x86_32
Binary files differdiff --git a/test/os_dep/linux/test_env.x86_64 b/test/os_dep/linux/test_env.x86_64
new file mode 100755
index 00000000..f9d78a1d
--- /dev/null
+++ b/test/os_dep/linux/test_env.x86_64
Binary files differdiff --git a/test/test_all.py b/test/test_all.py
index 0a29d4d3..f76019c4 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -257,6 +257,12 @@ for script in ["win_api_x86_32.py",
                ]:
     testset += RegressionTest([script], base_dir="os_dep", tags=[TAGS['tcc']])
 
+for arch in ["x86_32", "x86_64", "arml", "aarch64l"]:
+    testset += RegressionTest(["test_env.py", arch, "test_env.%s" % arch, "-c",
+                               "arg1", "-c", "arg2", "--environment-vars",
+                               "TEST=TOTO", "--mimic-env"],
+                              base_dir="os_dep/linux", tags=[TAGS['tcc']])
+
 ## Analysis
 testset += RegressionTest(["depgraph.py"], base_dir="analysis",
                           products=[fname for fnames in (
@@ -608,7 +614,7 @@ for jitter in ExampleJitter.jitter_engines:
                              tags=tags.get(jitter, []))
 
 for script, dep in [(["x86_32.py", Example.get_sample("x86_32_sc.bin")], []),
-                    (["arm.py", Example.get_sample("md5_arm"), "-a", "A684"],
+                    (["arm.py", Example.get_sample("md5_arm"), "--mimic-env"],
                      []),
                     (["sandbox_elf_aarch64l.py", Example.get_sample("md5_aarch64l"), "-a", "0x400A00"],
                      []),
@@ -620,6 +626,7 @@ for script, dep in [(["x86_32.py", Example.get_sample("x86_32_sc.bin")], []),
                       "b", "-a", "0"], [test_armb]),
                     (["arm_sc.py", "0", Example.get_sample("demo_arm_l.bin"),
                       "l", "-a", "0"], [test_arml]),
+                    (["sandbox_call.py", Example.get_sample("md5_arm")], []),
                     ] + [(["sandbox_pe_x86_32.py",
                            Example.get_sample("x86_32_" + name + ".bin")],
                           [test_box[name]])