Skip to content

Commit 89721ef

Browse files
authored
Merge pull request #25 from mrexodia/new-memory-manager
New memory manager
2 parents f0fbbe9 + 2300dbe commit 89721ef

File tree

5 files changed

+527
-282
lines changed

5 files changed

+527
-282
lines changed

src/dumpulator/details.py

Lines changed: 14 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import struct
22
from collections import namedtuple
33

4-
from minidump.minidumpfile import AllocationProtect
54
from unicorn import *
65
from unicorn.x86_const import *
76

8-
def map_unicorn_perms(protect: AllocationProtect):
7+
from dumpulator.memory import MemoryProtect
8+
9+
def map_unicorn_perms(protect: MemoryProtect):
910
if isinstance(protect, int):
10-
protect = AllocationProtect(protect)
11+
protect = MemoryProtect(protect)
12+
assert isinstance(protect, MemoryProtect)
1113
mapping = {
12-
AllocationProtect.PAGE_EXECUTE: UC_PROT_EXEC | UC_PROT_READ,
13-
AllocationProtect.PAGE_EXECUTE_READ: UC_PROT_EXEC | UC_PROT_READ,
14-
AllocationProtect.PAGE_EXECUTE_READWRITE: UC_PROT_ALL,
15-
AllocationProtect.PAGE_EXECUTE_WRITECOPY: UC_PROT_ALL,
16-
AllocationProtect.PAGE_NOACCESS: UC_PROT_NONE,
17-
AllocationProtect.PAGE_READONLY: UC_PROT_READ,
18-
AllocationProtect.PAGE_READWRITE: UC_PROT_READ | UC_PROT_WRITE,
19-
AllocationProtect.PAGE_WRITECOPY: UC_PROT_READ | UC_PROT_WRITE,
14+
MemoryProtect.PAGE_EXECUTE: UC_PROT_EXEC | UC_PROT_READ,
15+
MemoryProtect.PAGE_EXECUTE_READ: UC_PROT_EXEC | UC_PROT_READ,
16+
MemoryProtect.PAGE_EXECUTE_READWRITE: UC_PROT_ALL,
17+
MemoryProtect.PAGE_EXECUTE_WRITECOPY: UC_PROT_ALL,
18+
MemoryProtect.PAGE_NOACCESS: UC_PROT_NONE,
19+
MemoryProtect.PAGE_READONLY: UC_PROT_READ,
20+
MemoryProtect.PAGE_READWRITE: UC_PROT_READ | UC_PROT_WRITE,
21+
MemoryProtect.PAGE_WRITECOPY: UC_PROT_READ | UC_PROT_WRITE,
2022
}
21-
return mapping.get(protect, UC_PROT_NONE)
23+
return mapping[protect]
2224

2325

2426
class Registers:
@@ -561,197 +563,3 @@ def __setitem__(self, index, value):
561563
"Reserved"
562564
]
563565
assert len(interrupt_names) == 32
564-
565-
566-
567-
class MemoryManager():
568-
def __init__(self, uc: Uc):
569-
self._memory_map = []
570-
self._uc = uc
571-
572-
def mem_protect(self, addr, size, perms):
573-
for memory_region in self._memory_map: # Query parents
574-
if addr in memory_region and addr+size in memory_region: # Verify that the memory you are altering is inside a parent memory chunk
575-
perms = map_unicorn_perms(perms)
576-
memory_region.children.confliction_check(addr,size) # Identify if there are any conflictions
577-
new_addr, new_size = memory_region.children.mem_protect_correct(addr, size, perms) # Using the conflictions, correct the memory layout
578-
memory_region.children.add_child(ChildMemoryRegion(new_addr,new_size,perms, None, memory_region.start))
579-
self._uc.mem_protect(addr, size, perms)
580-
else:
581-
print("MEMORY_MANAGER | Attempted to change write permissions to memory that isn't mapped...")
582-
return
583-
584-
def mem_free(self, addr): # MAJOR : NEED TO MANAGE FREE'ING PARENT MEMORY AND SHRINKING EFFECTED CHILD MEMORY OR DELETING CHILDREN ENTIRELY
585-
for memory_region in self._memory_map:
586-
if memory_region.start == addr:
587-
self._memory_map.remove(memory_region) # NEED TO ADD SELF._UC.MEM_UNMAP(ADDRESS,SIZE) ASSERT SIZE >= 0x1000
588-
return
589-
return
590-
591-
def mem_allocate(self, addr:int, size:int, perms:int=UC_PROT_ALL, comment=None): # WORKS
592-
assert size >= 0x1000
593-
if self.check_memory_avail(addr, size) == True:
594-
self._memory_map.append(ParentMemoryRegion(addr,size,perms,comment))
595-
self._uc.mem_map(addr, size, perms)
596-
return
597-
else:
598-
print("MEMORY_MANAGER | There was an attempt to illegally overmap memory from", addr, "to", addr+size)
599-
return
600-
601-
def mem_find(self, addr): # WORKS
602-
for memory_region in self._memory_map:
603-
if addr in memory_region:
604-
return memory_region
605-
self.mem_error("MEMORY_MANAGER | Unable to find parent memory for given address...")
606-
return 0
607-
608-
def check_memory_avail(self, addr, size):
609-
for memory_region in self._memory_map:
610-
if memory_region.query_parent(addr, size) == False:
611-
return True
612-
else:
613-
return False
614-
return True
615-
616-
def write(self, addr, data):
617-
self._uc.mem_write(addr, data)
618-
619-
def read(self, addr, size):
620-
return self._uc.mem_read(addr, size)
621-
622-
def readable_contents(self):
623-
if len(self._memory_map):
624-
for mem_region in self._memory_map:
625-
print("MEMORY_MANAGER | There is a parent block which starts at", mem_region.start, "and ends at", mem_region.end)
626-
else:
627-
print("MEMORY_MANAGER | There is no memory allocated...")
628-
629-
class MemoryRegionChildL:
630-
def __init__(self):
631-
self._child_mem_list = []
632-
self._conflicting_regions = []
633-
634-
def sort(self):
635-
length = len(self._child_mem_list)
636-
for i in range(length-1):
637-
for j in range(0, length-i-1):
638-
if self._child_mem_list[j] > self._child_mem_list[j+1]:
639-
swapped = True
640-
self._child_mem_list[j], self._child_mem_list[j+1] = self._child_mem_list[j+1], self._child_mem_list[j]
641-
if not swapped:
642-
return
643-
644-
def confliction_check(self, addr, size): # Updates the conflicting memory regions list
645-
self._conflicting_regions = []
646-
assert len(self._conflicting_regions) == 0 # Make sure that confliction regions is cleared
647-
for gen_address in range(addr, addr+size, 0x100):
648-
for child_mem in self._child_mem_list:
649-
if gen_address in child_mem:
650-
self._conflicting_regions.append(child_mem)
651-
return
652-
653-
def mem_protect_correct(self, addr, size, perms):
654-
new_addr = addr
655-
new_size = size
656-
for mem_region in self._conflicting_regions: #Clear the area for the new write permissions
657-
if new_addr not in mem_region and new_addr+new_size not in mem_region: # No need to correct to split this area, it will be overwritten anyway.
658-
self.remove_child(mem_region)
659-
elif new_addr in mem_region and new_addr+new_size not in mem_region and mem_region.perms != perms: # The start of the region is in the mem_region, but not the end.
660-
mod_region = self.find_child(mem_region)
661-
mod_region.end = new_addr
662-
mod_region.size = mem_region.end - mem_region.start
663-
elif new_addr not in mem_region and new_addr+new_size in mem_region and mem_region.perms != perms:
664-
mod_region = self.find_child(mem_region)
665-
mod_region.start = new_addr+new_size
666-
mod_region.size = mem_region.end - mem_region.start
667-
elif new_addr in mem_region and new_addr+new_size in mem_region and mem_region.perms != perms:
668-
new_region = ChildMemoryRegion(addr+size, mem_region.end-addr+size, mem_region.perms, mem_region.comment, mem_region.start)
669-
mod_region = self.find_child(mem_region)
670-
mod_region.end = new_addr
671-
mod_region.size = mem_region.end - mem_region.start
672-
self._child_mem_list.append(new_region)
673-
elif new_addr in mem_region and new_addr+new_size in mem_region and mem_region.perms == perms:
674-
return False # The attempted write permissions is within a single child memory block, with the same permissions, its safe to fail the change protection.
675-
elif new_addr in mem_region and new_addr+new_size not in mem_region and mem_region.perms == perms:
676-
new_addr = mem_region.start
677-
new_size += addr - mem_region.start
678-
self.remove_child(mem_region)
679-
elif new_addr not in mem_region and new_addr+new_size in mem_region and mem_region.perms == perms:
680-
new_size += mem_region.end - new_addr+new_size
681-
self.remove_child(mem_region)
682-
else:
683-
print("MEMORY_REGION_CHILD | Unhandled logic in mem_protect_correct")
684-
return False
685-
return new_addr, new_size
686-
687-
def add_child(self, memory_region):
688-
self._child_mem_list.append(memory_region)
689-
return
690-
691-
def find_child(self, mem_region):
692-
for i, mem in enumerate(self._child_mem_list):
693-
if mem_region.start == mem.start:
694-
return self._child_mem_list[i]
695-
696-
def remove_child(self, mem_region):
697-
for i, mem in enumerate(self._child_mem_list):
698-
if mem_region.start == mem.start:
699-
del self._child_mem_list[i]
700-
break
701-
702-
def print_contents(self):
703-
for i in self._child_mem_list:
704-
print("A child memory block starts at", i.start, "ends at", i.start+i.size, "with permissions of", i.perms, "and a comment of", i.comment)
705-
706-
class ChildMemoryRegion:
707-
def __init__(self, start_addr, size, perms, comment=None, alloc_base=None):
708-
self.region = comment
709-
self.start = start_addr
710-
self.end = self.start+size
711-
self.alloc_base = alloc_base
712-
self.size = size
713-
self.perms = perms
714-
self.comment = comment
715-
716-
def __gt__(self, other):
717-
if self.start > other.start:
718-
return True
719-
return False
720-
721-
def __contains__(self, addr):
722-
if self.start <= addr and addr <= self.end:
723-
# print(self.start, "<=",addr, " & ",addr, "<=", self.end)
724-
return True
725-
else:
726-
return False
727-
728-
class ParentMemoryRegion:
729-
def __init__(self, start_addr, size, perms, comment=None, alloc_base=None):
730-
self.region = comment
731-
self.start = start_addr
732-
self.end = self.start+size
733-
self.alloc_base = alloc_base
734-
self.size = size
735-
self.perms = perms
736-
self.comment = comment
737-
self.children = MemoryRegionChildL()
738-
739-
@property
740-
def is_parent(self):
741-
return self.alloc_base is None
742-
743-
def __contains__(self, addr):
744-
if self.start <= addr and addr <= self.end:
745-
return True
746-
else:
747-
return False
748-
749-
def query_parent(self, addr, size):
750-
for gen_address in range(addr, addr+size, 0x100): # Could change the range step
751-
if gen_address in self:
752-
return True
753-
return False
754-
755-
def print_contents(self):
756-
print("MEMORY_REGION | This block starts at", self.start, "ends at", self.end, "with permissions of", self.perms,)
757-
return

0 commit comments

Comments
 (0)