about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm/jitter/vm_mngr.c27
-rw-r--r--miasm/jitter/vm_mngr.h1
-rw-r--r--miasm/jitter/vm_mngr_py.c19
-rw-r--r--miasm/os_dep/win_api_x86_32.py53
-rw-r--r--test/jitter/vm_mngr.py8
-rwxr-xr-xtest/os_dep/win_api_x86_32.py47
6 files changed, 147 insertions, 8 deletions
diff --git a/miasm/jitter/vm_mngr.c b/miasm/jitter/vm_mngr.c
index 53ec9065..0c8a0586 100644
--- a/miasm/jitter/vm_mngr.c
+++ b/miasm/jitter/vm_mngr.c
@@ -820,7 +820,32 @@ void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
 
 	vm_mngr->memory_pages_array[i] = *mpn_a;
 	vm_mngr->memory_pages_number ++;
+}
+
+void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad)
+{
+  struct memory_page_node * mpn;
+  int i;
 
+  i = find_page_node(vm_mngr->memory_pages_array,
+		     ad,
+		     0,
+		     vm_mngr->memory_pages_number - 1);
+  if (i < 0) {
+    return;
+  }
+
+  mpn = &vm_mngr->memory_pages_array[i];
+  free(mpn->name);
+  free(mpn->ad_hp);
+  memmove(&vm_mngr->memory_pages_array[i],
+  	      &vm_mngr->memory_pages_array[i+1],
+  	      sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i - 1)
+  	      );
+  vm_mngr->memory_pages_number --;
+  vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array,
+					sizeof(struct memory_page_node) *
+					(vm_mngr->memory_pages_number));
 }
 
 /* Return a char* representing the repr of vm_mngr_t object */
@@ -961,5 +986,3 @@ _MIASM_EXPORT uint64_t get_exception_flag(vm_mngr_t* vm_mngr)
 {
 	return vm_mngr->exception_flags;
 }
-
-
diff --git a/miasm/jitter/vm_mngr.h b/miasm/jitter/vm_mngr.h
index 7ae44d99..946d3b48 100644
--- a/miasm/jitter/vm_mngr.h
+++ b/miasm/jitter/vm_mngr.h
@@ -237,6 +237,7 @@ void reset_memory_page_pool(vm_mngr_t* vm_mngr);
 void reset_code_bloc_pool(vm_mngr_t* vm_mngr);
 void dump_code_bloc_pool(vm_mngr_t* vm_mngr);
 void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a);
+void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad);
 
 
 void init_memory_breakpoint(vm_mngr_t* vm_mngr);
diff --git a/miasm/jitter/vm_mngr_py.c b/miasm/jitter/vm_mngr_py.c
index 69e62fef..8bee0586 100644
--- a/miasm/jitter/vm_mngr_py.c
+++ b/miasm/jitter/vm_mngr_py.c
@@ -129,6 +129,23 @@ PyObject* vm_add_memory_page(VmMngr* self, PyObject* args)
 }
 
 
+PyObject* vm_remove_memory_page(VmMngr* self, PyObject* args)
+{
+  PyObject *addr;
+  uint64_t page_addr;
+
+  if (!PyArg_ParseTuple(args, "O", &addr))
+    RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+  PyGetInt_uint64_t(addr, page_addr);
+
+  remove_memory_page(&self->vm_mngr, page_addr);
+
+  Py_INCREF(Py_None);
+  return Py_None;
+
+
+}
 
 PyObject* vm_set_mem_access(VmMngr* self, PyObject* args)
 {
@@ -877,6 +894,8 @@ static PyMethodDef VmMngr_methods[] = {
 	{"add_memory_page",(PyCFunction)vm_add_memory_page, METH_VARARGS,
 	 "add_memory_page(address, access, content [, cmt]) -> Maps a memory page at @address of len(@content) bytes containing @content with protection @access\n"
 	"@cmt is a comment linked to the memory page"},
+	{"remove_memory_page",(PyCFunction)vm_remove_memory_page, METH_VARARGS,
+	 "remove_memory_page(address) -> removes a previously allocated memory page at @address"},
 	{"add_memory_breakpoint",(PyCFunction)vm_add_memory_breakpoint, METH_VARARGS,
 	 "add_memory_breakpoint(address, size, access) -> Add a memory breakpoint at @address of @size bytes with @access type"},
 	{"remove_memory_breakpoint",(PyCFunction)vm_remove_memory_breakpoint, METH_VARARGS,
diff --git a/miasm/os_dep/win_api_x86_32.py b/miasm/os_dep/win_api_x86_32.py
index 606c8792..7780a9e4 100644
--- a/miasm/os_dep/win_api_x86_32.py
+++ b/miasm/os_dep/win_api_x86_32.py
@@ -185,6 +185,7 @@ class c_winobjs(object):
         self.events_pool = {}
         self.find_data = None
 
+        self.allocated_pages = {}
         self.current_datetime = datetime.datetime(
             year=2017, month=8, day=21,
             hour=13, minute=37,
@@ -757,14 +758,54 @@ def kernel32_VirtualProtect(jitter):
         old = jitter.vm.get_mem_access(args.lpvoid)
         jitter.vm.set_u32(args.lpfloldprotect, ACCESS_DICT_INV[old])
 
-    log.warn("set page %x %x", args.lpvoid, args.dwsize)
-    for addr, data in jitter.vm.get_all_memory().items():
-        size = data["size"]
-        # Multi-page
-        if addr <= args.lpvoid < addr + size:
+    paddr = args.lpvoid - (args.lpvoid % winobjs.alloc_align)
+    psize = args.dwsize
+    for addr, items in list(winobjs.allocated_pages.items()):
+        alloc_addr, alloc_size = items
+        if not (alloc_addr <= paddr and
+                paddr + psize <= alloc_addr + alloc_size):
+            continue
+        size = jitter.vm.get_all_memory()[addr]["size"]
+        # Page is included in Protect area
+        if (paddr <= addr < addr + size <= paddr + psize):
             log.warn("set page %x %x", addr, ACCESS_DICT[flnewprotect])
             jitter.vm.set_mem_access(addr, ACCESS_DICT[flnewprotect])
+            continue
+
+        # Page is partly in Protect area: splitting is needed
+        if (addr <= paddr < addr + size or
+            addr <= paddr + psize < addr + size):
+
+            old_access = jitter.vm.get_mem_access(addr)
+
+            # splits = [
+            #     addr -> max(paddr, addr)
+            #     max(paddr, addr) -> min(addr + size, paddr + psize)
+            #     min(addr + size, paddr + psize) -> addr + size
+            # ]
+            splits = [
+                (addr, old_access,
+                 jitter.vm.get_mem(addr, max(paddr, addr) - addr)),
+                (max(paddr, addr), ACCESS_DICT[flnewprotect],
+                 jitter.vm.get_mem(
+                     max(paddr, addr),
+                     min(addr + size, paddr + psize) - max(paddr, addr))),
+                (min(addr + size, paddr + psize), old_access,
+                 jitter.vm.get_mem(
+                     min(addr + size, paddr + psize),
+                     addr + size - min(addr + size, paddr + psize)))
+            ]
 
+            jitter.vm.remove_memory_page(addr)
+            for split_addr, split_access, split_data in splits:
+                if not split_data:
+                    continue
+                log.warn("create page %x %x", split_addr,
+                         ACCESS_DICT[flnewprotect])
+                jitter.vm.add_memory_page(
+                    split_addr, split_access, split_data,
+                    "VirtualProtect split ret 0x%X" % ret_ad)
+                winobjs.allocated_pages[split_addr] = (alloc_addr, alloc_size)
     jitter.func_ret_stdcall(ret_ad, 1)
 
 
@@ -778,6 +819,7 @@ def kernel32_VirtualAlloc(jitter):
 
     if args.lpvoid == 0:
         alloc_addr = winobjs.heap.next_addr(args.dwsize)
+        winobjs.allocated_pages[alloc_addr] = (alloc_addr, args.dwsize)
         jitter.vm.add_memory_page(
             alloc_addr, ACCESS_DICT[args.flprotect], b"\x00" * args.dwsize,
             "Alloc in %s ret 0x%X" % (whoami(), ret_ad))
@@ -788,6 +830,7 @@ def kernel32_VirtualAlloc(jitter):
             jitter.vm.set_mem_access(args.lpvoid, ACCESS_DICT[args.flprotect])
         else:
             alloc_addr = winobjs.heap.next_addr(args.dwsize)
+            winobjs.allocated_pages[alloc_addr] = (alloc_addr, args.dwsize)
             # alloc_addr = args.lpvoid
             jitter.vm.add_memory_page(
                 alloc_addr, ACCESS_DICT[args.flprotect], b"\x00" * args.dwsize,
diff --git a/test/jitter/vm_mngr.py b/test/jitter/vm_mngr.py
index 468fb347..0fec1734 100644
--- a/test/jitter/vm_mngr.py
+++ b/test/jitter/vm_mngr.py
@@ -25,3 +25,11 @@ for i, access_right in enumerate(shuffled_rights):
 # Check for modification
 for i, access_right in enumerate(shuffled_rights):
     assert myjit.vm.get_mem_access(base_addr + i * page_size) == access_right
+
+# Remove pages
+for i in range(len(rights)):
+    myjit.vm.remove_memory_page(base_addr + i * page_size)
+
+# Add pages again
+for i, access_right in enumerate(rights):
+    myjit.vm.add_memory_page(base_addr + i * page_size, access_right, data)
diff --git a/test/os_dep/win_api_x86_32.py b/test/os_dep/win_api_x86_32.py
index 66a4e628..6d1c9835 100755
--- a/test/os_dep/win_api_x86_32.py
+++ b/test/os_dep/win_api_x86_32.py
@@ -226,9 +226,54 @@ class TestWinAPI(unittest.TestCase):
             if  i: self.assertTrue(vBool)
             else:  self.assertFalse(vBool)
 
+    def test_VirtualXXFunctions(self):
+        def call_vprotect(jitter, addr, size, protect):
+            jitter.push_uint32_t(0x0)
+            jitter.push_uint32_t(protect)
+            jitter.push_uint32_t(size)
+            jitter.push_uint32_t(addr)
+            jitter.push_uint32_t(0)
+            winapi.kernel32_VirtualProtect(jitter)
+
+        jit.push_uint32_t(0x2)
+        jit.push_uint32_t(0x2)
+        jit.push_uint32_t(0x4000)
+        jit.push_uint32_t(0x1000)
+        jit.push_uint32_t(0)
+        winapi.kernel32_VirtualAlloc(jit)
+        alloc_addr = jit.cpu.EAX
+
+        self.assertEqual(jit.vm.get_all_memory()[alloc_addr]["size"], 0x4000)
+        self.assertEqual(jit.vm.get_all_memory()[alloc_addr]["access"],
+                         winapi.ACCESS_DICT[0x2])
+
+        # Full area
+        call_vprotect(jit, alloc_addr, 0x4000, 0x1)
+        self.assertEqual(jit.vm.get_all_memory()[alloc_addr]["access"],
+                         winapi.ACCESS_DICT[0x1])
+        # Splits area [0--1000] [1000 -- 3000] [3000 -- 4000]
+        call_vprotect(jit, alloc_addr+0x1000, 0x2000, 0x40)
+        print(jit.vm)
+        for (addr, size, access) in [
+                (alloc_addr, 0x1000, 0x1),
+                (alloc_addr + 0x1000, 0x2000, 0x40),
+                (alloc_addr + 0x3000, 0x1000, 0x1)
+        ]:
+            self.assertEqual(jit.vm.get_all_memory()[addr]["size"], size)
+            self.assertEqual(jit.vm.get_all_memory()[addr]["access"],
+                             winapi.ACCESS_DICT[access])
+        # Protect over split areas
+        call_vprotect(jit, alloc_addr, 0x4000, 0x4)
+        for (addr, size) in [
+                (alloc_addr, 0x1000),
+                (alloc_addr + 0x1000, 0x2000),
+                (alloc_addr + 0x3000, 0x1000)
+        ]:
+            self.assertEqual(jit.vm.get_all_memory()[addr]["size"], size)
+            self.assertEqual(jit.vm.get_all_memory()[addr]["access"],
+                             winapi.ACCESS_DICT[0x4])
 
 if __name__ == '__main__':
     testsuite = unittest.TestLoader().loadTestsFromTestCase(TestWinAPI)
     report = unittest.TextTestRunner(verbosity=2).run(testsuite)
     exit(len(report.errors + report.failures))
-