about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.codespell_ignore2
-rw-r--r--example/elfesteem/test_pe.py31
-rw-r--r--example/jitter/run_with_linuxenv.py2
-rw-r--r--example/loader/build_pe.py33
-rw-r--r--example/loader/minidump_to_pe.py (renamed from example/elfesteem/minidump_to_pe.py)0
-rw-r--r--miasm/analysis/data_flow.py2
-rw-r--r--miasm/analysis/depgraph.py2
-rw-r--r--miasm/arch/mep/arch.py2
-rw-r--r--miasm/arch/x86/arch.py19
-rw-r--r--miasm/arch/x86/sem.py42
-rw-r--r--miasm/core/graph.py2
-rw-r--r--miasm/expression/expression.py5
-rw-r--r--miasm/expression/simplifications.py2
-rw-r--r--miasm/expression/simplifications_common.py32
-rw-r--r--miasm/ir/ir.py4
-rw-r--r--miasm/jitter/codegen.py2
-rw-r--r--miasm/jitter/emulatedsymbexec.py30
-rw-r--r--miasm/jitter/llvmconvert.py2
-rw-r--r--miasm/jitter/op_semantics.c35
-rw-r--r--miasm/jitter/vm_mngr.h4
-rw-r--r--miasm/loader/elf_init.py2
-rw-r--r--miasm/os_dep/linux/environment.py76
-rw-r--r--miasm/os_dep/linux/syscall.py16
-rw-r--r--optional_requirements.txt1
-rw-r--r--requirements.txt1
-rw-r--r--[-rwxr-xr-x]setup.py13
-rw-r--r--test/arch/mep/asm/test_asm.py4
-rw-r--r--test/arch/mep/asm/test_major_opcode_4.py2
-rw-r--r--test/arch/x86/arch.py20
-rw-r--r--test/expression/simplifications.py5
-rwxr-xr-xtest/test_all.py12
31 files changed, 348 insertions, 57 deletions
diff --git a/.codespell_ignore b/.codespell_ignore
index 8eab9f6f..06b8df87 100644
--- a/.codespell_ignore
+++ b/.codespell_ignore
@@ -5,3 +5,5 @@ mye
 iff
 nto
 rela
+daa
+od
diff --git a/example/elfesteem/test_pe.py b/example/elfesteem/test_pe.py
deleted file mode 100644
index 543cbea5..00000000
--- a/example/elfesteem/test_pe.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /usr/bin/env python
-
-import miasm.loader.pe as pe
-from miasm.loader.pe_init import PE
-import rlcompleter
-import readline
-import pdb
-import sys
-from pprint import pprint as pp
-readline.parse_and_bind("tab: complete")
-
-
-e_ = PE()
-mysh = b"\xc3"
-s_text = e_.SHList.add_section(
-    name="text", addr=0x1000, rawsize=0x1000, data=mysh)
-e_.Opthdr.AddressOfEntryPoint = s_text.addr
-new_dll = [({"name": "kernel32.dll",
-             "firstthunk": s_text.addr + 0x100},
-            ["CreateFileA", "SetFilePointer", "WriteFile", "CloseHandle"]
-            ),
-           ({"name": "USER32.dll",
-             "firstthunk": None},
-            ["SetDlgItemInt", "GetMenu", "HideCaret"]
-            )
-           ]
-e_.DirImport.add_dlldesc(new_dll)
-
-s_myimp = e_.SHList.add_section(name="myimp", rawsize=0x1000)
-e_.DirImport.set_rva(s_myimp.addr)
-open('uu.bin', 'wb').write(bytes(e_))
diff --git a/example/jitter/run_with_linuxenv.py b/example/jitter/run_with_linuxenv.py
index f981d2dd..9b17b172 100644
--- a/example/jitter/run_with_linuxenv.py
+++ b/example/jitter/run_with_linuxenv.py
@@ -78,7 +78,7 @@ elf_phdr_header = next(
 # Prepare the desired environment
 argv = [args.target.encode()] + [arg.encode() for arg in args.extra_args]
 if args.flags:
-    argv += ["-%s" % args.flags]
+    argv += [("-%s" % args.flags).encode()]
 envp = {b"PATH": b"/usr/local/bin", b"USER": linux_env.user_name}
 auxv = environment.AuxVec(
     elf_base_addr + elf_phdr_header.vaddr,
diff --git a/example/loader/build_pe.py b/example/loader/build_pe.py
new file mode 100644
index 00000000..6baeb645
--- /dev/null
+++ b/example/loader/build_pe.py
@@ -0,0 +1,33 @@
+#! /usr/bin/env python
+
+from miasm.loader.pe_init import PE
+
+# Build an empty PE object
+pe_object = PE()
+
+# Add a section with a just a "RET"
+payload = b"\xc3"
+s_text = pe_object.SHList.add_section(
+    name="text", addr=0x1000, rawsize=0x1000, data=payload
+)
+
+# Set the entry point on this instruction
+pe_object.Opthdr.AddressOfEntryPoint = s_text.addr
+
+# Add some imports
+new_dll = [
+    ({"name": "kernel32.dll",
+      "firstthunk": s_text.addr + 0x100},
+     ["CreateFileA", "SetFilePointer", "WriteFile", "CloseHandle"]
+    ),
+    ({"name": "USER32.dll",
+      "firstthunk": None},
+     ["SetDlgItemInt", "GetMenu", "HideCaret"]
+    )
+]
+pe_object.DirImport.add_dlldesc(new_dll)
+s_myimp = pe_object.SHList.add_section(name="myimp", rawsize=0x1000)
+pe_object.DirImport.set_rva(s_myimp.addr)
+
+# Rebuild the PE and dump it to a file
+open('fresh_pe.exe', 'wb').write(bytes(pe_object))
diff --git a/example/elfesteem/minidump_to_pe.py b/example/loader/minidump_to_pe.py
index 30a95325..30a95325 100644
--- a/example/elfesteem/minidump_to_pe.py
+++ b/example/loader/minidump_to_pe.py
diff --git a/miasm/analysis/data_flow.py b/miasm/analysis/data_flow.py
index c86bece5..be0e4528 100644
--- a/miasm/analysis/data_flow.py
+++ b/miasm/analysis/data_flow.py
@@ -185,7 +185,7 @@ class DiGraphDefUse(DiGraph):
         self._edge_attr[(src, dst)] = edge_label
 
     def add_data_edge(self, src, dst):
-        """Adds an edge representing a data dependencie
+        """Adds an edge representing a data dependency
         and sets the label accordingly"""
         self.add_uniq_labeled_edge(src, dst, ATTR_DEP)
 
diff --git a/miasm/analysis/depgraph.py b/miasm/analysis/depgraph.py
index 219a32ee..80e94c7f 100644
--- a/miasm/analysis/depgraph.py
+++ b/miasm/analysis/depgraph.py
@@ -357,7 +357,7 @@ class DependencyResultImplicit(DependencyResult):
             conds = z3.Or(*out)
         else:
             # Ex: expr: lblgen1, expected: 0x1234
-            # -> Avoid unconsistent solution lblgen1 = 0x1234
+            # -> Avoid inconsistent solution lblgen1 = 0x1234
             conds = translator.from_expr(self.unsat_expr)
         return conds
 
diff --git a/miasm/arch/mep/arch.py b/miasm/arch/mep/arch.py
index 171f5fab..8a9f60fd 100644
--- a/miasm/arch/mep/arch.py
+++ b/miasm/arch/mep/arch.py
@@ -293,7 +293,7 @@ class mn_mep(cls_mn):
     """
 
     # Define variables that stores information used to disassemble & assemble
-    # Notes: - theses variables are mandatory
+    # Notes: - these variables are mandatory
     #        - they could be moved to the cls_mn class
 
     num = 0  # holds the number of mnemonics
diff --git a/miasm/arch/x86/arch.py b/miasm/arch/x86/arch.py
index a82fac02..3053301a 100644
--- a/miasm/arch/x86/arch.py
+++ b/miasm/arch/x86/arch.py
@@ -3212,6 +3212,14 @@ class bs_mem(object):
         self.value = v
         return v != 0b11
 
+class bs_reg(object):
+    def encode(self):
+        return self.value == 0b11
+
+    def decode(self, v):
+        self.value = v
+        return v == 0b11
+
 d_imm64 = bs(l=0, fname="imm64")
 
 d_eax = bs(l=0, cls=(bs_eax, ), fname='eax')
@@ -3239,6 +3247,7 @@ msegoff = bs(l=16, cls=(bs_msegoff,), fname="mseg")
 movoff = bs(l=0, cls=(bs_movoff,), fname="off")
 mod = bs(l=2, fname="mod")
 mod_mem = bs(l=2, cls=(bs_mem,), fname="mod")
+mod_reg = bs(l=2, cls=(bs_reg,), fname="mod")
 
 rmreg = bs(l=3, cls=(x86_rm_reg, ), order =1, fname = "reg")
 reg = bs(l=3, cls=(x86_reg, ), order =1, fname = "reg")
@@ -3721,7 +3730,7 @@ addop("lgs", [bs8(0x0f), bs8(0xb5)] + rmmod(rmreg, rm_arg_x=rm_mem, modrm=mod_me
 addop("lgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d2, modrm=mod_mem))
 addop("lidt", [bs8(0x0f), bs8(0x01)] + rmmod(d3, modrm=mod_mem))
 
-addop("lfence", [bs8(0x0f), bs8(0xae), bs8(0xe8)])
+addop("lfence", [bs8(0x0f), bs8(0xae), bs8(0xe8), no_xmm_pref])
 addop("mfence", [bs8(0x0f), bs8(0xae), bs8(0xf0)])
 addop("sfence", [bs8(0x0f), bs8(0xae), bs8(0xf8)])
 
@@ -4620,6 +4629,14 @@ addop("maskmovdqu", [bs8(0x0f), bs8(0xf7), pref_66] +
 
 addop("emms", [bs8(0x0f), bs8(0x77)])
 
+addop("incssp", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d5))
+addop("rdssp", [pref_f3, bs8(0x0f), bs8(0x1e)] + rmmod(d1, modrm=mod_reg))
+addop("saveprevssp", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xea)])
+addop("rstorssp", [pref_f3, bs8(0x0f), bs8(0x01)] + rmmod(d5, rm_arg_xmm, modrm=mod_mem))
+addop("wrss", [bs8(0x0f), bs8(0x38), bs8(0xf6)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg])
+addop("wruss", [pref_66, bs8(0x0f), bs8(0x38), bs8(0xf5)] + rmmod(rmreg, rm_arg), [rm_arg, rmreg])
+addop("setssbsy", [pref_f3, bs8(0x0f), bs8(0x01), bs8(0xe8)])
+addop("clrssbsy", [pref_f3, bs8(0x0f), bs8(0xae)] + rmmod(d6, rm_arg_xmm))
 addop("endbr64", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfa)])
 addop("endbr32", [pref_f3, bs8(0x0f), bs8(0x1e), bs8(0xfb)])
 
diff --git a/miasm/arch/x86/sem.py b/miasm/arch/x86/sem.py
index b924c44f..1af9359e 100644
--- a/miasm/arch/x86/sem.py
+++ b/miasm/arch/x86/sem.py
@@ -4981,6 +4981,38 @@ def emms(ir, instr):
     # Implemented as a NOP
     return [], []
 
+def incssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def rdssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def saveprevssp(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def rstorssp(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
+def wrss(ir, instr, src, dst):
+    # Implemented as a NOP
+    return [], []
+
+def wruss(ir, instr, src, dst):
+    # Implemented as a NOP
+    return [], []
+
+def setssbsy(ir, instr):
+    # Implemented as a NOP
+    return [], []
+
+def clrssbsy(ir, instr, dst):
+    # Implemented as a NOP
+    return [], []
+
 def endbr64(ir, instr):
     # Implemented as a NOP
     return [], []
@@ -5635,6 +5667,16 @@ mnemo_func = {'mov': mov,
               "movmskpd": movmskpd,
               "stmxcsr": stmxcsr,
               "ldmxcsr": ldmxcsr,
+
+              # CET (Control-flow Enforcement Technology)
+              "incssp": incssp,
+              "rdssp": rdssp,
+              "saveprevssp": saveprevssp,
+              "rstorssp": rstorssp,
+              "wrss": wrss,
+              "wruss": wruss,
+              "setssbsy": setssbsy,
+              "clrssbsy": clrssbsy,
               "endbr64": endbr64,
               "endbr32": endbr32,
               }
diff --git a/miasm/core/graph.py b/miasm/core/graph.py
index f585379b..01f580a3 100644
--- a/miasm/core/graph.py
+++ b/miasm/core/graph.py
@@ -978,7 +978,7 @@ class MatchGraph(DiGraph):
         """
         # Partial solution: nodes corrects, edges between these nodes corrects
         # A partial solution is a dictionary MatchGraphJoker -> @graph's node
-        todo = list()  # Dictionnaries containing partial solution
+        todo = list()  # Dictionaries containing partial solution
         done = list()  # Already computed partial solutions
 
         # Elect first candidates
diff --git a/miasm/expression/expression.py b/miasm/expression/expression.py
index 6c54b9a2..6f171d93 100644
--- a/miasm/expression/expression.py
+++ b/miasm/expression/expression.py
@@ -279,6 +279,11 @@ class Expr(object):
     def __ne__(self, other):
         return not self.__eq__(other)
 
+    def __lt__(self, other):
+        weight1 = EXPR_ORDER_DICT[self.__class__]
+        weight2 = EXPR_ORDER_DICT[other.__class__]
+        return weight1 < weight2
+
     def __add__(self, other):
         return ExprOp('+', self, other)
 
diff --git a/miasm/expression/simplifications.py b/miasm/expression/simplifications.py
index 585a9c6b..8f63ab91 100644
--- a/miasm/expression/simplifications.py
+++ b/miasm/expression/simplifications.py
@@ -58,7 +58,7 @@ class ExpressionSimplifier(object):
             simplifications_common.simp_test_signext_inf,
             simplifications_common.simp_test_zeroext_inf,
             simplifications_common.simp_cond_inf_eq_unsigned_zero,
-
+            simplifications_common.simp_compose_and_mask,
         ],
 
         m2_expr.ExprSlice: [
diff --git a/miasm/expression/simplifications_common.py b/miasm/expression/simplifications_common.py
index cda9c5e2..69d56997 100644
--- a/miasm/expression/simplifications_common.py
+++ b/miasm/expression/simplifications_common.py
@@ -607,7 +607,6 @@ def simp_compose(e_s, expr):
         return ExprCond(cond, arg1, arg2)
     return ExprCompose(*args)
 
-
 def simp_cond(_, expr):
     """
     Common simplifications on ExprCond.
@@ -1554,3 +1553,34 @@ def simp_add_multiple(_, expr):
     if len(out) == 1:
         return out[0]
     return ExprOp('+', *out)
+
+def simp_compose_and_mask(_, expr):
+    """
+    {X 0 8, Y 8 32} & 0xFF => zeroExt(X)
+    {X 0 8, Y 8 16, Z 16 32} & 0xFFFF => {X 0 8, Y 8 16, 0x0 16 32}
+    {X 0 8, 0x123456 8 32} & 0xFFFFFF => {X 0 8, 0x1234 8 24, 0x0 24 32}
+    """
+    if not expr.is_op('&'):
+        return expr
+    # handle the case where arg2 = arg1.mask
+    if len(expr.args) != 2:
+        return expr
+    arg1, arg2 = expr.args
+    if not arg1.is_compose():
+        return expr
+    if not arg2.is_int():
+        return expr
+    int2 = int(arg2)
+    if (int2 + 1) & int2 != 0:
+        return expr
+    mask_size = int2.bit_length() + 7 // 8
+    out = []
+    for offset, arg in arg1.iter_args():
+        if offset == mask_size:
+            return ExprCompose(*out).zeroExtend(expr.size)
+        elif mask_size > offset and mask_size < offset+arg.size and arg.is_int():
+            out.append(ExprSlice(arg, 0, mask_size-offset))
+            return ExprCompose(*out).zeroExtend(expr.size)
+        else:
+            out.append(arg)
+    return expr
diff --git a/miasm/ir/ir.py b/miasm/ir/ir.py
index eb9857b1..372b712a 100644
--- a/miasm/ir/ir.py
+++ b/miasm/ir/ir.py
@@ -831,7 +831,7 @@ class IntermediateRepresentation(object):
     def add_block(self, block, gen_pc_updt=False):
         """
         DEPRECATED function
-        Use add_block instead of add_block
+        Use add_asmblock_to_ircfg instead of add_block
         """
         warnings.warn("""DEPRECATION WARNING
         ircfg is now out of IntermediateRepresentation
@@ -844,7 +844,7 @@ class IntermediateRepresentation(object):
     def add_bloc(self, block, gen_pc_updt=False):
         """
         DEPRECATED function
-        Use add_block instead of add_block
+        Use add_asmblock_to_ircfg instead of add_bloc
         """
         self.add_block(block, gen_pc_updt)
 
diff --git a/miasm/jitter/codegen.py b/miasm/jitter/codegen.py
index 792feae0..abbf65d2 100644
--- a/miasm/jitter/codegen.py
+++ b/miasm/jitter/codegen.py
@@ -187,7 +187,7 @@ class CGen(object):
 
     def add_local_var(self, dst_var, dst_index, expr):
         """
-        Add local variable used to store temporay result
+        Add local variable used to store temporary result
         @dst_var: dictionary of Expr -> local_var_expr
         @dst_index : dictionary of size -> local var count
         @expr: Expression source
diff --git a/miasm/jitter/emulatedsymbexec.py b/miasm/jitter/emulatedsymbexec.py
index cf5e3036..aacfba9f 100644
--- a/miasm/jitter/emulatedsymbexec.py
+++ b/miasm/jitter/emulatedsymbexec.py
@@ -19,6 +19,36 @@ class EmulatedSymbExec(SymbolicExecutionEngine):
             2: 0x00000209,
             3: 0x078bf9ff
         },
+        2: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        4: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        7: {
+            0: 0,
+            1: (1 << 0) | (1 << 3),
+            2: 0,
+            3: 0
+        },
+        0x80000000: {
+            0: 0x80000008,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        0x80000001: {
+            0: 0,
+            1: 0,
+            2: (1 << 0) | (1 << 8),
+            3: (1 << 11) | (1 << 29),
+        },
     }
 
     def __init__(self, cpu, vm, *args, **kwargs):
diff --git a/miasm/jitter/llvmconvert.py b/miasm/jitter/llvmconvert.py
index d0e0407b..c4467411 100644
--- a/miasm/jitter/llvmconvert.py
+++ b/miasm/jitter/llvmconvert.py
@@ -1720,7 +1720,7 @@ class LLVMFunction(object):
             self.gen_bad_block(asmblock)
             return
 
-        # Create basic blocks (for label branchs)
+        # Create basic blocks (for label branches)
         entry_bbl, builder = self.entry_bbl, self.builder
         for instr in asmblock.lines:
             lbl = self.llvm_context.ir_arch.loc_db.get_or_create_offset_location(instr.offset)
diff --git a/miasm/jitter/op_semantics.c b/miasm/jitter/op_semantics.c
index 79dcdcf4..6725ae64 100644
--- a/miasm/jitter/op_semantics.c
+++ b/miasm/jitter/op_semantics.c
@@ -380,6 +380,41 @@ unsigned int x86_cpuid(unsigned int a, unsigned int reg_num)
 			return 0x00000000;
 		}
 	}
+	// Extended Function CPUID Information
+	else if (a == 0x80000000){
+		switch(reg_num){
+		case 0:
+			// Pentium 4 Processor supporting Hyper-Threading
+			// Technology to Intel Xeon Processor 5100 Series
+			return 0x80000008;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return 0x00000000;
+		case 3:
+			return 0x00000000;
+		}
+	}
+	else if (a == 0x80000001){
+		switch(reg_num){
+		case 0:
+			// Extended Processor Signature and Extended Feature
+			// Bits
+			return 0x00000000;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return (/* LAHF-SAHF */ 1 << 0)
+			| (/* LZCNT */ 0 << 5)
+			| (/* PREFETCHW */ 1 << 8);
+		case 3:
+			return (/* SYSCALL/SYSRET */ 1 << 11)
+			| (/* Execute Disable Bit available */ 0 << 20)
+			| (/* 1-GByte pages available */ 0 << 26)
+			| (/* RDTSCP and IA32_TSC_AUX available */ 0 << 27)
+			| (/* Intel ® 64 Architecture available */ 1 << 29);
+		}
+	}
 	else{
 		fprintf(stderr, "WARNING not implemented x86_cpuid index %X!\n", a);
 		exit(EXIT_FAILURE);
diff --git a/miasm/jitter/vm_mngr.h b/miasm/jitter/vm_mngr.h
index 913d06f8..35a648a5 100644
--- a/miasm/jitter/vm_mngr.h
+++ b/miasm/jitter/vm_mngr.h
@@ -35,14 +35,16 @@
 
 #ifdef __APPLE__
 #define __BYTE_ORDER __BYTE_ORDER__
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
 #elif defined(__NetBSD__) || defined(__OpenBSD__)
 #define __BYTE_ORDER _BYTE_ORDER
 #define __BIG_ENDIAN _BIG_ENDIAN
 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
 #elif defined(_WIN32) || defined(_WIN64)
+#define __BYTE_ORDER __LITTLE_ENDIAN
 #define __BIG_ENDIAN '>'
 #define __LITTLE_ENDIAN '<'
-#define __BYTE_ORDER __LITTLE_ENDIAN
 #endif
 
 
diff --git a/miasm/loader/elf_init.py b/miasm/loader/elf_init.py
index 36c4cfaf..786d030b 100644
--- a/miasm/loader/elf_init.py
+++ b/miasm/loader/elf_init.py
@@ -104,6 +104,8 @@ class WRel64(StructWrapper):
     wrapped._fields.append(("type", "u32"))
 
     def get_sym(self):
+        if not hasattr(self.parent.linksection, 'symtab'):
+            return None
         return self.parent.linksection.symtab[self.cstr.info >> 32].name
 
     def get_type(self):
diff --git a/miasm/os_dep/linux/environment.py b/miasm/os_dep/linux/environment.py
index 8826abb7..42e45dd3 100644
--- a/miasm/os_dep/linux/environment.py
+++ b/miasm/os_dep/linux/environment.py
@@ -1,7 +1,9 @@
 from __future__ import print_function
 from collections import namedtuple
 import functools
+import logging
 import os
+import re
 import struct
 import termios
 
@@ -11,6 +13,8 @@ from miasm.core.interval import interval
 from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
 
 
+REGEXP_T = type(re.compile(''))
+
 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",
@@ -21,6 +25,11 @@ StatFSInfo = namedtuple("StatFSInfo", [
     "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)-5s: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.WARNING)
 
 class FileDescriptor(object):
     """Stand for a file descriptor on a system
@@ -206,24 +215,73 @@ class FileSystem(object):
 
     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('$X')
+                return expr
+
         # Remove '../', etc.
         path = os.path.normpath(path)
 
         # Passthrough
         for passthrough in self.passthrough:
-            if hasattr(passthrough, "match"):
-                if passthrough.match(path):
+            if isinstance(passthrough, REGEXP_T):
+                if _convert_re(passthrough).match(path):
                     return path
-            elif passthrough == path:
+            elif _convert(passthrough) == path:
                 return path
 
-        # Remove leading '/' if any (multiple '//' are handled by 'abspath'
-        if path.startswith(os.path.sep):
-            path = path[1:]
+        # Remove leading '/' if any
+        path = path.lstrip(path_sep)
 
-        base_path = os.path.abspath(self.base_path)
+        base_path = os.path.abspath(_convert(self.base_path))
         out_path = os.path.join(base_path, path)
-        assert out_path.startswith(base_path + os.path.sep)
+        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
@@ -463,7 +521,7 @@ class LinuxEnvironment(object):
         if not isinstance(fdesc, FileDescriptorDirectory):
             raise RuntimeError("Not implemented")
 
-        out = ""
+        out = b""
         # fdesc.listdir continues from where it stopped
         for name in fdesc.listdir():
             d_ino = 1 # Not the real one
diff --git a/miasm/os_dep/linux/syscall.py b/miasm/os_dep/linux/syscall.py
index 1edf72c4..353d61cf 100644
--- a/miasm/os_dep/linux/syscall.py
+++ b/miasm/os_dep/linux/syscall.py
@@ -6,6 +6,7 @@ import struct
 import termios
 
 from miasm.jitter.csts import EXCEPT_PRIV_INSN, EXCEPT_INT_XX
+from miasm.core.utils import pck64
 
 log = logging.getLogger('syscalls')
 hnd = logging.StreamHandler()
@@ -347,6 +348,18 @@ def sys_x86_64_arch_prctl(jitter, linux_env):
         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]
@@ -355,6 +368,9 @@ def sys_x86_64_arch_prctl(jitter, linux_env):
 
     if code == 0x1002:
         jitter.cpu.set_segm_base(jitter.cpu.FS, addr)
+    elif code == 0x3001:
+        # CET status (disabled)
+        jitter.cpu.set_mem(addr, pck64(0))
     else:
         raise RuntimeError("Not implemented")
     jitter.cpu.RAX = 0
diff --git a/optional_requirements.txt b/optional_requirements.txt
index d6a28948..88d09170 100644
--- a/optional_requirements.txt
+++ b/optional_requirements.txt
@@ -1,2 +1,3 @@
 pycparser
 z3-solver==4.5.1.0
+llvmlite==0.26.0
diff --git a/requirements.txt b/requirements.txt
index 135ca071..eb542916 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,2 @@
 pyparsing
 future
-llvmlite==0.26.0
diff --git a/setup.py b/setup.py
index 2767c33d..e8ea7b3a 100755..100644
--- a/setup.py
+++ b/setup.py
@@ -3,6 +3,7 @@
 from __future__ import print_function
 from distutils.core import setup, Extension
 from distutils.util import get_platform
+from distutils.sysconfig import get_python_lib, get_config_vars
 import io
 import os
 import platform
@@ -10,6 +11,13 @@ from shutil import copy2
 import sys
 
 is_win = platform.system() == "Windows"
+is_mac = platform.system() == "Darwin"
+
+def set_extension_compile_args(extension):
+    rel_lib_path = extension.name.replace('.', '/')
+    abs_lib_path = os.path.join(get_python_lib(), rel_lib_path)
+    lib_name = abs_lib_path + '.so'
+    extension.extra_link_args = [ '-Wl,-install_name,' + lib_name]
 
 def buil_all():
     packages=[
@@ -139,6 +147,11 @@ def buil_all():
         # Force setuptools to use whatever msvc version installed
         os.environ['MSSdk'] = '1'
         os.environ['DISTUTILS_USE_SDK'] = '1'
+    elif is_mac:
+        for extension in ext_modules_all:
+            set_extension_compile_args(extension)
+        cfg_vars = get_config_vars()
+        cfg_vars['LDSHARED'] = cfg_vars['LDSHARED'].replace('-bundle', '-dynamiclib')
 
     print("building")
     build_ok = False
diff --git a/test/arch/mep/asm/test_asm.py b/test/arch/mep/asm/test_asm.py
index 7762669a..e8b8afb9 100644
--- a/test/arch/mep/asm/test_asm.py
+++ b/test/arch/mep/asm/test_asm.py
@@ -22,12 +22,12 @@ class TestMisc(object):
         for mn_str, mn_hex in unit_tests:
             print("-" * 49)  # Tests separation
 
-            # Dissassemble
+            # Disassemble
             mn_bin = decode_hex(mn_hex)
             mn = mn_mep.dis(mn_bin, "b")
 
             print("dis: %s -> %s" % (mn_hex.rjust(20), str(mn).rjust(20)))
-            assert(str(mn) == mn_str)  # dissassemble assertion
+            assert(str(mn) == mn_str)  # disassemble assertion
 
             # Assemble and return all possible candidates
             instr = mn_mep.fromstring(str(mn), "b")
diff --git a/test/arch/mep/asm/test_major_opcode_4.py b/test/arch/mep/asm/test_major_opcode_4.py
index a6f57ac2..fd466b62 100644
--- a/test/arch/mep/asm/test_major_opcode_4.py
+++ b/test/arch/mep/asm/test_major_opcode_4.py
@@ -107,7 +107,7 @@ class TestMajor4(object):
         check_instruction("LBU $4, 0x22($TP)", "4ca2", multi=2)
         # Note: the following instruction can not be easily manipulated due to
         # expressions simplifications performed by miasm at assembly and
-        # dissassembly, i.e. ExprMem($TP + 0) is simplified into ExprMem($TP)
+        # disassembly, i.e. ExprMem($TP + 0) is simplified into ExprMem($TP)
         #check_instruction("LBU $6, 0x0($TP)", "4e80", multi=2)
         check_instruction("LBU $7, 0x3C($TP)", "4fbc", multi=2)
         check_instruction("LBU $2, 0x4($TP)", "4a84", multi=2)
diff --git a/test/arch/x86/arch.py b/test/arch/x86/arch.py
index 202ecac5..68a14036 100644
--- a/test/arch/x86/arch.py
+++ b/test/arch/x86/arch.py
@@ -3097,6 +3097,26 @@ reg_tests = [
     (m32, "00000000    EMMS",
      "0f77"),
 
+    (m64, "00000000    INCSSP     RAX",
+     "f3480faee8"),
+    (m64, "00000000    INCSSP     EAX",
+     "f30faee8"),
+    (m64, "00000000    RDSSP      EAX",
+     "f30f1ec8"),
+    (m64, "00000000    RDSSP      RAX",
+     "f3480f1ec8"),
+    (m64, "00000000    SAVEPREVSSP",
+     "f30f01ea"),
+    (m64, "00000000    RSTORSSP   XMMWORD PTR [RAX]",
+     "f30f0128"),
+    (m64, "00000000    WRSS       QWORD PTR [0x1234], RDX",
+     "480f38f6142534120000"),
+    (m64, "00000000    WRUSS      DWORD PTR [EAX], EAX",
+     "67660f38f500"),
+    (m64, "00000000    SETSSBSY",
+     "f30f01e8"),
+    (m64, "00000000    CLRSSBSY   XMMWORD PTR [RAX]",
+     "f30fae30"),
     (m64, "00000000    ENDBR64",
      "f30f1efa"),
     (m32, "00000000    ENDBR32",
diff --git a/test/expression/simplifications.py b/test/expression/simplifications.py
index 1a22c43d..e0b666da 100644
--- a/test/expression/simplifications.py
+++ b/test/expression/simplifications.py
@@ -192,6 +192,11 @@ to_test = [(ExprInt(1, 32) - ExprInt(1, 32), ExprInt(0, 32)),
             ExprOp('&', a, ExprInt(0x0FFFFFFF, 32))),
            (ExprOp('<<', ExprOp('>>', a, ExprInt(0x4, 32)), ExprInt(0x4, 32)),
             ExprOp('&', a, ExprInt(0xFFFFFFF0, 32))),
+
+           (ExprCompose(ExprId("a", 8), ExprId("b", 24)) & ExprInt(0xFF, 32), ExprCompose(ExprId("a", 8), ExprInt(0x0, 24))),
+           (ExprCompose(ExprId("a", 8), ExprInt(0x12, 8), ExprId("b", 16)) & ExprInt(0xFFFF, 32), ExprCompose(ExprId("a", 8), ExprInt(0x12, 24))),
+           (ExprCompose(ExprId("a", 8), ExprInt(0x1234, 16), ExprId("b", 8)) & ExprInt(0xFFFF, 32), ExprCompose(ExprId("a", 8), ExprInt(0x34, 24))),
+
            (a[:32], a),
            (a[:8][:8], a[:8]),
            (a[:16][:8], a[:8]),
diff --git a/test/test_all.py b/test/test_all.py
index 6d4ee0a5..ce223211 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -697,6 +697,18 @@ for script in [["basic_op.py"],
                ]:
     testset += ExampleExpression(script)
 
+## Loader
+class ExampleLoader(Example):
+    """Loader examples specificities:
+    - script path begins with "loader/"
+    """
+    example_dir = "loader"
+
+
+testset += ExampleLoader(["build_pe.py"], products=["fresh_pe.exe"])
+# A sample is required, so "minidump_to_pe.py" is disabled for now
+
+
 ## Symbolic Execution
 class ExampleSymbolExec(Example):
     """Symbol Exec examples specificities: