def write_bytes(self, address, data): address = int(address) if not self.isProcessOpen: raise ProcessException( "Can't write_bytes(%s, %s), process %s is not open" % (address, data, self.pid)) buffer = create_string_buffer(data) sizeWriten = c_size_t(0) bufferSize = sizeof(buffer) - 1 _address = address _length = bufferSize + 1 try: old_protect = self.VirtualProtectEx(_address, _length, PAGE_EXECUTE_READWRITE) except: pass res = kernel32.WriteProcessMemory(self.h_process, address, buffer, bufferSize, byref(sizeWriten)) try: self.VirtualProtectEx(_address, _length, old_protect) except: pass return res
def _open(self): self.isProcessOpen = True self.task = ctypes.c_uint32() self.mytask=libc.mach_task_self() ret=libc.task_for_pid(self.mytask, ctypes.c_int(self.pid), ctypes.pointer(self.task)) if ret!=0: raise ProcessException("task_for_pid failed with error code : %s"%ret)
def VirtualProtectEx(self, base_address, size, protection): old_protect = c_ulong(0) if not kernel32.VirtualProtectEx(self.h_process, base_address, size, protection, byref(old_protect)): raise ProcessException('Error: VirtualProtectEx(%08X, %d, %08X)' % (base_address, size, protection)) return old_protect.value
def read_bytes(self, address, bytes = 4): pdata = ctypes.c_void_p(0) data_cnt = ctypes.c_uint32(0) ret = libc.mach_vm_read(self.task, ctypes.c_ulonglong(address), ctypes.c_longlong(bytes), ctypes.pointer(pdata), ctypes.pointer(data_cnt)); #if ret==1: # return "" if ret!=0: raise ProcessException("mach_vm_read returned : %s"%ret) buf=ctypes.string_at(pdata.value, data_cnt.value) libc.vm_deallocate(self.mytask, pdata, data_cnt) return buf
def _open_from_name(self, processName, debug=False): processes = self.processes_from_name(processName) if not processes: raise ProcessException("can't get pid from name %s" % processName) elif len(processes) > 1: raise ValueError( "There is multiple processes with name %s. Please select a process from its pid instead" % processName) if debug: self._open(processes[0]["pid"], debug=True) else: self._open(processes[0]["pid"], debug=False)
def pid_from_name(name): #quick and dirty, works with all linux not depending on ps output for pid in os.listdir("/proc"): try: int(pid) except: continue pname="" with open("/proc/%s/cmdline"%pid,'r') as f: pname=f.read() if name in pname: return int(pid) raise ProcessException("No process with such name: %s"%name)
def pid_from_name(name): processes = [] for pid in os.listdir('/proc'): try: pid = int(pid) pname, cmdline = SunProcess._name_args(pid) if name in pname: return pid if name in cmdline.split(' ', 1)[0]: return pid except: pass raise ProcessException('No process with such name: %s' % name)
def iter_region(self, start_offset=None, end_offset=None, protec=None, optimizations=None): """ optimizations : i for inode==0 (no file mapping) s to avoid scanning shared regions x to avoid scanning x regions r don't scan ronly regions """ maps = [] address = ctypes.c_ulong(0) mapsize = ctypes.c_ulong(0) name = ctypes.c_uint32(0) count = ctypes.c_uint32(VM_REGION_BASIC_INFO_COUNT_64) info = vm_region_basic_info_64() while True: r = libc.mach_vm_region(self.task, ctypes.pointer(address), ctypes.pointer(mapsize), VM_REGION_BASIC_INFO_64, ctypes.pointer(info), ctypes.pointer(count), ctypes.pointer(name)) # If we get told "invalid address", we have crossed into kernel land... if r == 1: break if r != 0: raise ProcessException('mach_vm_region failed with error code %s' % r) if start_offset is not None: if address.value < start_offset: address.value += mapsize.value continue if end_offset is not None: if address.value > end_offset: break p = info.protection if p & VM_PROT_EXECUTE: if optimizations and 'x' in optimizations: address.value += mapsize.value continue if info.shared: if optimizations and 's' in optimizations: address.value += mapsize.value continue if p & VM_PROT_READ: if not (p & VM_PROT_WRITE): if optimizations and 'r' in optimizations: address.value += mapsize.value continue yield address.value, mapsize.value address.value += mapsize.value
def read_bytes(self, address, bytes=4, use_NtWow64ReadVirtualMemory64=False): #print "reading %s bytes from addr %s"%(bytes, address) if use_NtWow64ReadVirtualMemory64: if NtWow64ReadVirtualMemory64 is None: raise WindowsError( "NtWow64ReadVirtualMemory64 is not available from a 64bit process" ) RpM = NtWow64ReadVirtualMemory64 else: RpM = ReadProcessMemory address = int(address) buffer = create_string_buffer(bytes) bytesread = c_size_t(0) data = '' length = bytes while length: if RpM(self.h_process, address, buffer, bytes, byref(bytesread)) or (use_NtWow64ReadVirtualMemory64 and GetLastError() == 0): if bytesread.value: data += buffer.raw[:bytesread.value] length -= bytesread.value address += bytesread.value if not len(data): raise ProcessException( 'Error %s in ReadProcessMemory(%08x, %d, read=%d)' % (GetLastError(), address, length, bytesread.value)) return data else: if GetLastError( ) == 299: #only part of ReadProcessMemory has been done, let's return it data += buffer.raw[:bytesread.value] return data raise WinError() # data += buffer.raw[:bytesread.value] # length -= bytesread.value # address += bytesread.value return data
def mem_search(self, value, ftype='match', protec=PAGE_READWRITE | PAGE_READONLY, optimizations=None, start_offset=None, end_offset=None): """ iterator returning all indexes where the pattern has been found """ # pre-compile regex to run faster if ftype == 're' or ftype == 'groups' or ftype == 'ngroups': # value should be an array of regex if type(value) is not list: value = [value] tmp = [] for reg in value: if type(reg) is tuple: name = reg[0] if type(reg[1]) != REGEX_TYPE: regex = re.compile(reg[1], re.IGNORECASE) else: regex = reg[1] elif type(reg) == REGEX_TYPE: name = '' regex = reg else: name = '' regex = re.compile(reg, re.IGNORECASE) tmp.append((name, regex)) value = tmp elif ftype != 'match' and ftype != 'group' and ftype != 're' and ftype != 'groups' and ftype != 'ngroups' and ftype != 'lambda': structtype, structlen = utils.type_unpack(ftype) value = struct.pack(structtype, value) # different functions avoid if statement before parsing the buffer if ftype == 're': func = self.parse_re_function elif ftype == 'groups': func = self.parse_groups_function elif ftype == 'ngroups': func = self.parse_named_groups_function elif ftype == 'float': func = self.parse_float_function elif ftype == 'lambda': # use a custm function func = value else: func = self.parse_any_function if not self.process.isProcessOpen: raise ProcessException("Can't read_bytes, process %s is not open" % (self.process.pid)) for offset, chunk_size in self.process.iter_region( start_offset=start_offset, end_offset=end_offset, protec=protec, optimizations=optimizations): b = '' current_offset = offset chunk_read = 0 chunk_exc = False while chunk_read < chunk_size: try: b += self.process.read_bytes(current_offset, chunk_size) except IOError as e: print traceback.format_exc() if e.errno == 13: raise else: logger.warning(e) chunk_exc = True break except Exception as e: logger.warning(e) chunk_exc = True break finally: current_offset += chunk_size chunk_read += chunk_size if chunk_exc: continue if b: if ftype == "lambda": for res in func(b, offset): yield res else: for res in func(b, value, offset): yield res
def VirtualQueryEx64(self, lpAddress): mbi = MEMORY_BASIC_INFORMATION64() if not VirtualQueryEx64(self.h_process, lpAddress, byref(mbi), sizeof(mbi)): raise ProcessException('Error VirtualQueryEx: 0x%08X' % lpAddress) return mbi