Example #1
0
  def Open(self):
    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:
      if ret == 5:
        # Most likely this means access denied. This is not perfect
        # but there is no way to find out.
        raise process_error.ProcessError(
            "Access denied (task_for_pid returned 5).")

      raise process_error.ProcessError(
          "task_for_pid failed with error code : %s" % ret)
Example #2
0
 def VirtualQueryEx(self, address):
   mbi = MEMORY_BASIC_INFORMATION()
   res = VirtualQueryEx(self.h_process, address, ctypes.byref(mbi),
                        ctypes.sizeof(mbi))
   if not res:
     raise process_error.ProcessError("Error VirtualQueryEx: 0x%08X" % address)
   return mbi
Example #3
0
  def __init__(self, pid=None):
    """Creates a process for reading memory."""
    super(Process, self).__init__()
    if pid is None:
      raise process_error.ProcessError("No pid given.")
    self.pid = pid

    self.task = None
    self.mytask = None
    self.Open()
Example #4
0
 def Is64bit(self):
   """Returns true if this is a 64 bit process."""
   if "64" not in platform.machine():
     return False
   iswow64 = ctypes.c_bool(False)
   if IsWow64Process is None:
     return False
   if not IsWow64Process(self.h_process, ctypes.byref(iswow64)):
     raise process_error.ProcessError("Error while calling IsWow64Process.")
   return not iswow64.value
Example #5
0
  def ReadBytes(self, address, num_bytes):
    """Reads at most num_bytes starting from offset <address>."""
    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(num_bytes), ctypes.pointer(pdata),
                            ctypes.pointer(data_cnt))
    if ret:
      raise process_error.ProcessError("Error in mach_vm_read, ret=%s" % ret)
    buf = ctypes.string_at(pdata.value, data_cnt.value)
    libc.vm_deallocate(self.mytask, pdata, data_cnt)
    return buf
Example #6
0
  def ReadBytes(self, address, num_bytes):
    """Reads at most num_bytes starting from offset <address>."""
    address = int(address)
    buf = ctypes.create_string_buffer(num_bytes)
    bytesread = ctypes.c_size_t(0)
    res = ReadProcessMemory(self.h_process, address, buf, num_bytes,
                            ctypes.byref(bytesread))
    if res == 0:
      err = wintypes.GetLastError()
      if err == 299:
        # Only part of ReadProcessMemory has been done, let's return it.
        return buf.raw[:bytesread.value]
      raise process_error.ProcessError("Error in ReadProcessMemory: %d" % err)

    return buf.raw[:bytesread.value]
Example #7
0
  def Open(self):
    """Opens the process for reading."""

    self.h_process = kernel32.OpenProcess(
        PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, self.pid)
    if not self.h_process:
      raise process_error.ProcessError(
          "Failed to open process (pid %d)." % self.pid)

    if self.Is64bit():
      si = self.GetNativeSystemInfo()
      self.max_addr = si.lpMaximumApplicationAddress
    else:
      si = self.GetSystemInfo()
      self.max_addr = 2147418111

    self.min_addr = si.lpMinimumApplicationAddress
Example #8
0
  def Regions(self,
              skip_executable_regions=False,
              skip_shared_regions=False,
              skip_readonly_regions=False):
    """Iterates over the readable regions for this process.

    We use mach_vm_region_recurse here to get a fine grained view of
    the process' memory space. The algorithm is that for some regions,
    the function returns is_submap=True which means that there are
    actually subregions that we need to examine by increasing the
    depth and calling the function again. For example, there are two
    regions, addresses 1000-2000 and 2000-3000 where 1000-2000 has two
    subregions, 1100-1200 and 1300-1400. In that case we would call:

    mvrr(address=0, depth=0)       -> (1000-2000, is_submap=True)
    mvrr(address=0, depth=1)       -> (1100-1200, is_submap=False)
    mvrr(address=1200, depth=1)    -> (1300-1400, is_submap=False)
    mvrr(address=1400, depth=1)    -> (2000-3000, is_submap=False)

    At this point, we know we went out of the original submap which
    ends at 2000. We need to recheck the region at 2000, it could be
    submap = True at depth 0 so we call

    mvrr(address=1400, depth=0)    -> (2000-3000, is_submap=False)

    Args:
      skip_executable_regions: Skips executable sections.
      skip_shared_regions: Skips shared sections. Includes mapped files.
      skip_readonly_regions: Skips readonly sections.

    Yields:
      Pairs (address, length) for each identified region.
    """

    address = ctypes.c_ulong(0)
    mapsize = ctypes.c_ulong(0)
    count = ctypes.c_uint32(submap_info_size)
    sub_info = vm_region_submap_short_info_data_64()
    depth = 0
    depth_end_addresses = {}

    while True:
      c_depth = ctypes.c_uint32(depth)

      r = libc.mach_vm_region_recurse(self.task, ctypes.pointer(address),
                                      ctypes.pointer(mapsize),
                                      ctypes.pointer(c_depth),
                                      ctypes.pointer(sub_info),
                                      ctypes.pointer(count))

      # If we get told "invalid address", we have crossed into kernel land...
      if r == 1:
        break

      if r != 0:
        raise process_error.ProcessError("Error in mach_vm_region, ret=%s" % r)

      if depth > 0 and address.value >= depth_end_addresses[depth]:
        del depth_end_addresses[depth]
        depth -= 1
        continue

      p = sub_info.protection
      if skip_executable_regions and p & VM_PROT_EXECUTE:
        address.value += mapsize.value
        continue

      if skip_shared_regions and sub_info.share_mode in [
          SM_COW, SM_SHARED, SM_TRUESHARED
      ]:
        address.value += mapsize.value
        continue

      if not p & VM_PROT_READ:
        address.value += mapsize.value
        continue

      writable = p & VM_PROT_WRITE
      if skip_readonly_regions and not writable:
        address.value += mapsize.value
        continue

      if sub_info.is_submap:
        depth += 1
        depth_end_addresses[depth] = address.value + mapsize.value
      else:
        yield address.value, mapsize.value
        address.value += mapsize.value
Example #9
0
 def __enter__(self):
     if self.pid in [101, 106]:
         raise process_error.ProcessError("Access Denied.")
     return self