about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/core/asmbloc.py412
-rw-r--r--miasm2/jitter/jitcore.py42
-rw-r--r--miasm2/os_dep/win_api_x86_32_seh.py80
3 files changed, 267 insertions, 267 deletions
diff --git a/miasm2/core/asmbloc.py b/miasm2/core/asmbloc.py
index 96c2f4ec..54cd51cf 100644
--- a/miasm2/core/asmbloc.py
+++ b/miasm2/core/asmbloc.py
@@ -410,183 +410,6 @@ class asm_symbol_pool:
         return label
 
 
-def dis_bloc(mnemo, pool_bin, label, offset, job_done, symbol_pool,
-             dont_dis=None, split_dis=None, follow_call=False,
-             dontdis_retcall=False, lines_wd=None, dis_bloc_callback=None,
-             dont_dis_nulstart_bloc=False, attrib=None):
-    # pool_bin.offset = offset
-    if dont_dis is None:
-        dont_dis = []
-    if split_dis is None:
-        split_dis = []
-    if attrib is None:
-        attrib = {}
-    lines_cpt = 0
-    in_delayslot = False
-    delayslot_count = mnemo.delayslot
-    offsets_to_dis = set()
-    add_next_offset = False
-    cur_block = asm_bloc(label)
-    log_asmbloc.debug("dis at %X", int(offset))
-    while not in_delayslot or delayslot_count > 0:
-        if in_delayslot:
-            delayslot_count -= 1
-
-        if offset in dont_dis:
-            if not cur_block.lines:
-                job_done.add(offset)
-                # Block is empty -> bad block
-                cur_block = asm_block_bad(label, errno=2)
-            else:
-                # Block is not empty, stop the desassembly pass and add a
-                # constraint to the next block
-                cur_block.add_cst(offset, asm_constraint.c_next, symbol_pool)
-            break
-
-        if lines_cpt > 0 and offset in split_dis:
-            cur_block.add_cst(offset, asm_constraint.c_next, symbol_pool)
-            offsets_to_dis.add(offset)
-            break
-
-        lines_cpt += 1
-        if lines_wd is not None and lines_cpt > lines_wd:
-            # log_asmbloc.warning( "lines watchdog reached at %X"%int(offset))
-            break
-
-        if offset in job_done:
-            cur_block.add_cst(offset, asm_constraint.c_next, symbol_pool)
-            break
-
-        off_i = offset
-        try:
-            instr = mnemo.dis(pool_bin, attrib, offset)
-        except (Disasm_Exception, IOError), e:
-            log_asmbloc.warning(e)
-            instr = None
-
-        if instr is None:
-            log_asmbloc.warning("cannot disasm at %X", int(off_i))
-            if not cur_block.lines:
-                job_done.add(offset)
-                # Block is empty -> bad block
-                cur_block = asm_block_bad(label, errno=0)
-            else:
-                # Block is not empty, stop the desassembly pass and add a
-                # constraint to the next block
-                cur_block.add_cst(off_i, asm_constraint.c_next, symbol_pool)
-            break
-
-        # XXX TODO nul start block option
-        if dont_dis_nulstart_bloc and instr.b.count('\x00') == instr.l:
-            log_asmbloc.warning("reach nul instr at %X", int(off_i))
-            if not cur_block.lines:
-                # Block is empty -> bad block
-                cur_block = asm_block_bad(label, errno=1)
-            else:
-                # Block is not empty, stop the desassembly pass and add a
-                # constraint to the next block
-                cur_block.add_cst(off_i, asm_constraint.c_next, symbol_pool)
-            break
-
-        # special case: flow graph modificator in delayslot
-        if in_delayslot and instr and (instr.splitflow() or instr.breakflow()):
-            add_next_offset = True
-            break
-
-        job_done.add(offset)
-        log_asmbloc.debug("dis at %X", int(offset))
-
-        offset += instr.l
-        log_asmbloc.debug(instr)
-        log_asmbloc.debug(instr.args)
-
-        cur_block.addline(instr)
-        if not instr.breakflow():
-            continue
-        # test split
-        if instr.splitflow() and not (instr.is_subcall() and dontdis_retcall):
-            add_next_offset = True
-            # cur_bloc.add_cst(n, asm_constraint.c_next, symbol_pool)
-            pass
-        if instr.dstflow():
-            instr.dstflow2label(symbol_pool)
-            dst = instr.getdstflow(symbol_pool)
-            dstn = []
-            for d in dst:
-                if isinstance(d, m2_expr.ExprId) and \
-                        isinstance(d.name, asm_label):
-                    dstn.append(d.name)
-            dst = dstn
-            if (not instr.is_subcall()) or follow_call:
-                cur_block.bto.update(
-                    [asm_constraint(x, asm_constraint.c_to) for x in dst])
-
-        # get in delayslot mode
-        in_delayslot = True
-        delayslot_count = instr.delayslot
-
-    for c in cur_block.bto:
-        offsets_to_dis.add(c.label.offset)
-
-    if add_next_offset:
-        cur_block.add_cst(offset, asm_constraint.c_next, symbol_pool)
-        offsets_to_dis.add(offset)
-
-    # Fix multiple constraints
-    cur_block.fix_constraints()
-
-    if dis_bloc_callback is not None:
-        dis_bloc_callback(mn=mnemo, attrib=attrib, pool_bin=pool_bin,
-                          cur_bloc=cur_block, offsets_to_dis=offsets_to_dis,
-                          symbol_pool=symbol_pool)
-    # print 'dst', [hex(x) for x in offsets_to_dis]
-    return cur_block, offsets_to_dis
-
-
-def dis_bloc_all(mnemo, pool_bin, offset, job_done, symbol_pool, dont_dis=None,
-                 split_dis=None, follow_call=False, dontdis_retcall=False,
-                 blocs_wd=None, lines_wd=None, blocs=None,
-                 dis_bloc_callback=None, dont_dis_nulstart_bloc=False,
-                 attrib=None):
-    log_asmbloc.info("dis bloc all")
-    if dont_dis is None:
-        dont_dis = []
-    if split_dis is None:
-        split_dis = []
-    if attrib is None:
-        attrib = {}
-    if blocs is None:
-        blocs = AsmCFG()
-    todo = [offset]
-
-    bloc_cpt = 0
-    while len(todo):
-        bloc_cpt += 1
-        if blocs_wd is not None and bloc_cpt > blocs_wd:
-            log_asmbloc.debug("blocs watchdog reached at %X", int(offset))
-            break
-
-        n = int(todo.pop(0))
-        if n is None:
-            continue
-        if n in job_done:
-            continue
-        label = symbol_pool.getby_offset_create(n)
-        cur_block, nexts = dis_bloc(mnemo, pool_bin, label, n, job_done,
-                                    symbol_pool, dont_dis, split_dis,
-                                    follow_call, dontdis_retcall,
-                                    dis_bloc_callback=dis_bloc_callback,
-                                    lines_wd=lines_wd,
-                                    dont_dis_nulstart_bloc=dont_dis_nulstart_bloc,
-                                    attrib=attrib)
-        todo += nexts
-        blocs.add_node(cur_block)
-
-    blocs.apply_splitting(symbol_pool, dis_block_callback=dis_bloc_callback,
-                          mn=mnemo, attrib=attrib, pool_bin=pool_bin)
-    return blocs
-
-
 class AsmCFG(DiGraph):
 
     """Directed graph standing for a ASM Control Flow Graph with:
@@ -1433,11 +1256,50 @@ def asm_resolve_final(mnemo, blocks, symbol_pool, dst_interval=None):
 
 class disasmEngine(object):
 
-    def __init__(self, arch, attrib, bs=None, **kwargs):
+    """Disassembly engine, taking care of disassembler options and mutli-block
+    strategy.
+
+    Engine options:
+
+    + Object supporting membership test (offset in ..)
+     - dont_dis: stop the current disassembly branch if reached
+     - split_dis: force a basic block end if reached,
+                  with a next constraint on its successor
+
+    + On/Off
+     - follow_call: recursively disassemble CALL destinations
+     - dontdis_retcall: stop on CALL return addresses
+     - dont_dis_nulstart_bloc: stop if a block begin with a few \x00
+
+    + Number
+     - lines_wd: maximum block's size (in number of instruction)
+     - blocs_wd: maximum number of distinct disassembled block
+
+    + callback(arch, attrib, pool_bin, cur_bloc, offsets_to_dis,
+               symbol_pool)
+     - dis_bloc_callback: callback after each new disassembled block
+
+    The engine also tracks already handled block, for performance and to avoid
+    infinite cycling.
+    Addresses of disassembled block is in the attribute `job_done`.
+    To force a new disassembly, the targeted offset must first be removed from
+    this structure.
+    """
+
+    def __init__(self, arch, attrib, bin_stream, **kwargs):
+        """Instanciate a new disassembly engine
+        @arch: targeted architecture
+        @attrib: architecture attribute
+        @bin_stream: bytes source
+        @kwargs: (optional) custom options
+        """
         self.arch = arch
         self.attrib = attrib
-        self.bs = bs
+        self.bin_stream = bin_stream
         self.symbol_pool = asm_symbol_pool()
+        self.job_done = set()
+
+        # Setup options
         self.dont_dis = []
         self.split_dis = []
         self.follow_call = False
@@ -1446,33 +1308,179 @@ class disasmEngine(object):
         self.blocs_wd = None
         self.dis_bloc_callback = None
         self.dont_dis_nulstart_bloc = False
-        self.job_done = set()
+
+        # Override options if needed
         self.__dict__.update(kwargs)
 
-    def dis_bloc(self, offset):
+    def _dis_bloc(self, offset):
+        """Disassemble the block at offset @offset
+        Return the created asm_bloc and future offsets to disassemble
+        """
+
+        lines_cpt = 0
+        in_delayslot = False
+        delayslot_count = self.arch.delayslot
+        offsets_to_dis = set()
+        add_next_offset = False
         label = self.symbol_pool.getby_offset_create(offset)
-        current_block, _ = dis_bloc(self.arch, self.bs, label, offset,
-                                    self.job_done, self.symbol_pool,
-                                    dont_dis=self.dont_dis,
-                                    split_dis=self.split_dis,
-                                    follow_call=self.follow_call,
-                                    dontdis_retcall=self.dontdis_retcall,
-                                    lines_wd=self.lines_wd,
-                                    dis_bloc_callback=self.dis_bloc_callback,
-                                    dont_dis_nulstart_bloc=self.dont_dis_nulstart_bloc,
-                                    attrib=self.attrib)
+        cur_block = asm_bloc(label)
+        log_asmbloc.debug("dis at %X", int(offset))
+        while not in_delayslot or delayslot_count > 0:
+            if in_delayslot:
+                delayslot_count -= 1
+
+            if offset in self.dont_dis:
+                if not cur_block.lines:
+                    self.job_done.add(offset)
+                    # Block is empty -> bad block
+                    cur_block = asm_block_bad(label, errno=2)
+                else:
+                    # Block is not empty, stop the desassembly pass and add a
+                    # constraint to the next block
+                    cur_block.add_cst(offset, asm_constraint.c_next,
+                                      self.symbol_pool)
+                break
+
+            if lines_cpt > 0 and offset in self.split_dis:
+                cur_block.add_cst(offset, asm_constraint.c_next,
+                                  self.symbol_pool)
+                offsets_to_dis.add(offset)
+                break
+
+            lines_cpt += 1
+            if self.lines_wd is not None and lines_cpt > self.lines_wd:
+                log_asmbloc.debug("lines watchdog reached at %X", int(offset))
+                break
+
+            if offset in self.job_done:
+                cur_block.add_cst(offset, asm_constraint.c_next,
+                                  self.symbol_pool)
+                break
+
+            off_i = offset
+            try:
+                instr = self.arch.dis(self.bin_stream, self.attrib, offset)
+            except (Disasm_Exception, IOError), e:
+                log_asmbloc.warning(e)
+                instr = None
+
+            if instr is None:
+                log_asmbloc.warning("cannot disasm at %X", int(off_i))
+                if not cur_block.lines:
+                    self.job_done.add(offset)
+                    # Block is empty -> bad block
+                    cur_block = asm_block_bad(label, errno=0)
+                else:
+                    # Block is not empty, stop the desassembly pass and add a
+                    # constraint to the next block
+                    cur_block.add_cst(off_i, asm_constraint.c_next,
+                                      self.symbol_pool)
+                break
+
+            # XXX TODO nul start block option
+            if self.dont_dis_nulstart_bloc and instr.b.count('\x00') == instr.l:
+                log_asmbloc.warning("reach nul instr at %X", int(off_i))
+                if not cur_block.lines:
+                    # Block is empty -> bad block
+                    cur_block = asm_block_bad(label, errno=1)
+                else:
+                    # Block is not empty, stop the desassembly pass and add a
+                    # constraint to the next block
+                    cur_block.add_cst(off_i, asm_constraint.c_next,
+                                      self.symbol_pool)
+                break
+
+            # special case: flow graph modificator in delayslot
+            if in_delayslot and instr and (instr.splitflow() or instr.breakflow()):
+                add_next_offset = True
+                break
+
+            self.job_done.add(offset)
+            log_asmbloc.debug("dis at %X", int(offset))
+
+            offset += instr.l
+            log_asmbloc.debug(instr)
+            log_asmbloc.debug(instr.args)
+
+            cur_block.addline(instr)
+            if not instr.breakflow():
+                continue
+            # test split
+            if instr.splitflow() and not (instr.is_subcall() and self.dontdis_retcall):
+                add_next_offset = True
+                pass
+            if instr.dstflow():
+                instr.dstflow2label(self.symbol_pool)
+                dst = instr.getdstflow(self.symbol_pool)
+                dstn = []
+                for d in dst:
+                    if isinstance(d, m2_expr.ExprId) and \
+                            isinstance(d.name, asm_label):
+                        dstn.append(d.name)
+                dst = dstn
+                if (not instr.is_subcall()) or self.follow_call:
+                    cur_block.bto.update(
+                        [asm_constraint(x, asm_constraint.c_to) for x in dst])
+
+            # get in delayslot mode
+            in_delayslot = True
+            delayslot_count = instr.delayslot
+
+        for c in cur_block.bto:
+            offsets_to_dis.add(c.label.offset)
+
+        if add_next_offset:
+            cur_block.add_cst(offset, asm_constraint.c_next, self.symbol_pool)
+            offsets_to_dis.add(offset)
+
+        # Fix multiple constraints
+        cur_block.fix_constraints()
+
+        if self.dis_bloc_callback is not None:
+            self.dis_bloc_callback(mn=self.arch, attrib=self.attrib,
+                                   pool_bin=self.bin_stream, cur_bloc=cur_block,
+                                   offsets_to_dis=offsets_to_dis,
+                                   symbol_pool=self.symbol_pool)
+        return cur_block, offsets_to_dis
+
+    def dis_bloc(self, offset):
+        """Disassemble the block at offset @offset and return the created
+        asm_bloc
+        @offset: targeted offset to disassemble
+        """
+        current_block, _ = self._dis_bloc(offset)
         return current_block
 
     def dis_multibloc(self, offset, blocs=None):
-        blocs = dis_bloc_all(self.arch, self.bs, offset, self.job_done,
-                             self.symbol_pool,
-                             dont_dis=self.dont_dis, split_dis=self.split_dis,
-                             follow_call=self.follow_call,
-                             dontdis_retcall=self.dontdis_retcall,
-                             blocs_wd=self.blocs_wd,
-                             lines_wd=self.lines_wd,
-                             blocs=blocs,
-                             dis_bloc_callback=self.dis_bloc_callback,
-                             dont_dis_nulstart_bloc=self.dont_dis_nulstart_bloc,
-                             attrib=self.attrib)
+        """Disassemble every block reachable from @offset regarding
+        specific disasmEngine conditions
+        Return an AsmCFG instance containing disassembled blocks
+        @offset: starting offset
+        @blocs: (optional) AsmCFG instance of already disassembled blocks to
+                merge with
+        """
+        log_asmbloc.info("dis bloc all")
+        if blocs is None:
+            blocs = AsmCFG()
+        todo = [offset]
+
+        bloc_cpt = 0
+        while len(todo):
+            bloc_cpt += 1
+            if self.blocs_wd is not None and bloc_cpt > self.blocs_wd:
+                log_asmbloc.debug("blocs watchdog reached at %X", int(offset))
+                break
+
+            target_offset = int(todo.pop(0))
+            if (target_offset is None or
+                    target_offset in self.job_done):
+                continue
+            cur_block, nexts = self._dis_bloc(target_offset)
+            todo += nexts
+            blocs.add_node(cur_block)
+
+        blocs.apply_splitting(self.symbol_pool,
+                              dis_block_callback=self.dis_bloc_callback,
+                              mn=self.arch, attrib=self.attrib,
+                              pool_bin=self.bin_stream)
         return blocs
diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py
index 59e7b752..74c438a7 100644
--- a/miasm2/jitter/jitcore.py
+++ b/miasm2/jitter/jitcore.py
@@ -56,6 +56,15 @@ class JitCore(object):
         self.options = {"jit_maxline": 50  # Maximum number of line jitted
                         }
 
+        self.mdis = asmbloc.disasmEngine(ir_arch.arch, ir_arch.attrib, bs,
+                                         lines_wd=self.options["jit_maxline"],
+                                         symbol_pool=ir_arch.symbol_pool,
+                                         follow_call=False,
+                                         dontdis_retcall=False,
+                                         split_dis=self.split_dis,
+                                         dis_bloc_callback=self.disasm_cb)
+
+
     def set_options(self, **kwargs):
         "Set options relative to the backend"
 
@@ -76,9 +85,8 @@ class JitCore(object):
         """The disassembly engine will no longer stop on address in args"""
         self.split_dis.difference_update(set(args))
 
-    def load(self, arch, attrib):
-        "Initialise the Jitter according to arch and attrib"
-
+    def load(self):
+        "Initialise the Jitter"
         raise NotImplementedError("Abstract class")
 
     def get_bloc_min_max(self, cur_bloc):
@@ -114,26 +122,24 @@ class JitCore(object):
         b.irblocs = irblocs
         self.jitirblocs(b.label, irblocs)
 
-    def disbloc(self, addr, cpu, vm):
-        "Disassemble a new bloc and JiT it"
+    def disbloc(self, addr, vm):
+        """Disassemble a new bloc and JiT it
+        @addr: address of the block to disassemble (asm_label or int)
+        @vm: VmMngr instance
+        """
 
         # Get the bloc
         if isinstance(addr, asmbloc.asm_label):
             addr = addr.offset
 
-        label = self.ir_arch.symbol_pool.getby_offset_create(addr)
+        # Prepare disassembler
+        self.mdis.job_done.clear()
+        self.mdis.lines_wd = self.options["jit_maxline"]
+        self.mdis.dis_bloc_callback = self.disasm_cb
 
         # Disassemble it
         try:
-            cur_bloc, _ = asmbloc.dis_bloc(self.ir_arch.arch, self.bs, label,
-                                           addr, set(),
-                                           self.ir_arch.symbol_pool, [],
-                                           follow_call=False,
-                                           dontdis_retcall=False,
-                                           lines_wd=self.options["jit_maxline"],
-                                           # max 10 asm lines
-                                           attrib=self.ir_arch.attrib,
-                                           split_dis=self.split_dis)
+            cur_bloc = self.mdis.dis_bloc(addr)
         except IOError:
             # vm_exception_flag is set
             cur_bloc = asmbloc.asm_bloc(label)
@@ -141,15 +147,13 @@ class JitCore(object):
         # Logging
         if self.log_newbloc:
             print cur_bloc
-        if self.disasm_cb is not None:
-            self.disasm_cb(cur_bloc)
 
         # Check for empty blocks
         if not cur_bloc.lines:
             raise ValueError("Cannot JIT a block without any assembly line")
 
         # Update label -> bloc
-        self.lbl2bloc[label] = cur_bloc
+        self.lbl2bloc[cur_bloc.label] = cur_bloc
 
         # Store min/max bloc address needed in jit automod code
         self.get_bloc_min_max(cur_bloc)
@@ -180,7 +184,7 @@ class JitCore(object):
 
         if not lbl in self.lbl2jitbloc:
             # Need to JiT the bloc
-            self.disbloc(lbl, cpu, vm)
+            self.disbloc(lbl, vm)
 
         # Run the bloc and update cpu/vmmngr state
         ret = self.jit_call(lbl, cpu, vm, breakpoints)
diff --git a/miasm2/os_dep/win_api_x86_32_seh.py b/miasm2/os_dep/win_api_x86_32_seh.py
index f90198f9..6bf491bf 100644
--- a/miasm2/os_dep/win_api_x86_32_seh.py
+++ b/miasm2/os_dep/win_api_x86_32_seh.py
@@ -148,13 +148,15 @@ def build_ldr_data(jitter, modules_info):
     +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 = LDR_AD + peb_ldr_data_offset + 0xC
+    offset = peb_ldr_data_address + 0xC
 
     # get main pe info
     main_pe = modules_info.name2module.get(main_pe_name, None)
@@ -178,6 +180,11 @@ def build_ldr_data(jitter, modules_info):
         jitter.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, data,
                                   "Loader struct")
 
+    # 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):
 
@@ -238,13 +245,8 @@ def create_modules_chain(jitter, name2module):
     offset_name = 0x500
     offset_path = 0x600
 
-    dummy_e = pe_init.PE()
-    dummy_e.NThdr.ImageBase = 0
-    dummy_e.Opthdr.AddressOfEntryPoint = 0
-    dummy_e.NThdr.sizeofimage = 0
-
     out = ""
-    for i, (fname, pe_obj) in enumerate([("", dummy_e)] + name2module.items()):
+    for i, (fname, pe_obj) in enumerate(name2module.items(), 1):
         if pe_obj is None:
             log.warning("Unknown module: ommited from link list (%r)",
                         fname)
@@ -291,9 +293,25 @@ def create_modules_chain(jitter, name2module):
     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
+        jitter.vm.set_mem(cur_module_entry + offset,
+                          (pck32(next_module_entry + offset) +
+                           pck32(prev_module_entry + offset)))
+
+
 def fix_InLoadOrderModuleList(jitter, modules_info):
     """Fix InLoadOrderModuleList double link list. First module is the main pe,
-    then ntdll, kernel32. dummy is last pe.
+    then ntdll, kernel32.
 
     @jitter: the jitter instance
     @modules_info: the LoadedModules instance
@@ -303,8 +321,7 @@ def fix_InLoadOrderModuleList(jitter, modules_info):
     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)
-    dummy_pe = modules_info.name2module.get("", None)
-    special_modules = [main_pe, kernel32_pe, ntdll_pe, dummy_pe]
+    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)
@@ -315,22 +332,13 @@ def fix_InLoadOrderModuleList(jitter, modules_info):
         loaded_modules[0:0] = [main_pe]
         loaded_modules[1:1] = [ntdll_pe]
         loaded_modules[2:2] = [kernel32_pe]
-        loaded_modules.append(dummy_pe)
 
-    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]
-        jitter.vm.set_mem(cur_module_entry,
-                          (pck32(next_module_entry) +
-                           pck32(prev_module_entry)))
+    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. dummy is last pe.
+    then ntdll, kernel32.
 
     @jitter: the jitter instance
     @modules_info: the LoadedModules instance
@@ -340,8 +348,7 @@ def fix_InMemoryOrderModuleList(jitter, modules_info):
     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)
-    dummy_pe = modules_info.name2module.get("", None)
-    special_modules = [main_pe, kernel32_pe, ntdll_pe, dummy_pe]
+    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
@@ -351,22 +358,13 @@ def fix_InMemoryOrderModuleList(jitter, modules_info):
         loaded_modules[0:0] = [main_pe]
         loaded_modules[1:1] = [ntdll_pe]
         loaded_modules[2:2] = [kernel32_pe]
-        loaded_modules.append(dummy_pe)
 
-    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]
-        jitter.vm.set_mem(cur_module_entry + 0x8,
-                          (pck32(next_module_entry + 0x8) +
-                           pck32(prev_module_entry + 0x8)))
+    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. dummy is last pe.
+    ntdll, then kernel32.
 
     @jitter: the jitter instance
     @modules_info: the LoadedModules instance
@@ -377,8 +375,7 @@ def fix_InInitializationOrderModuleList(jitter, modules_info):
     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)
-    dummy_pe = modules_info.name2module.get("", None)
-    special_modules = [main_pe, kernel32_pe, ntdll_pe, dummy_pe]
+    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
@@ -387,17 +384,8 @@ def fix_InInitializationOrderModuleList(jitter, modules_info):
                           if module not in special_modules]
         loaded_modules[0:0] = [ntdll_pe]
         loaded_modules[1:1] = [kernel32_pe]
-        loaded_modules.append(dummy_pe)
 
-    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]
-        jitter.vm.set_mem(cur_module_entry + 0x10,
-                          (pck32(next_module_entry + 0x10) +
-                           pck32(prev_module_entry + 0x10)))
+    set_link_list_entry(jitter, loaded_modules, modules_info, 0x10)
 
 
 def add_process_env(jitter):