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 Open(self):
     path = "/proc/{}/mem".format(self.pid)
     cpath = ctypes.create_string_buffer(path.encode("utf-8"))
     try:
         self.mem_file = open64(ctypes.byref(cpath), os.O_RDONLY)
     except OSError as e:
         raise process_error.ProcessError(e)
Example #3
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 #4
0
 def Match(self, process, chunks: Iterable[streaming.Chunk],
           deadline: rdfvalue.RDFDatetime,
           progress: Callable[[], None]) -> Iterator[rdf_memory.YaraMatch]:
     timeout_secs = (deadline - rdfvalue.RDFDatetime.Now()).ToInt(
         rdfvalue.SECONDS)
     if not self._rules_uploaded:
         self._client.UploadSignature(self._rules_str)
         self._rules_uploaded = True
     if process.pid not in self._pid_to_serializable_file_descriptor:
         raise (process_error.ProcessError(
             f"Failed to open process {process.pid}.")
                ) from self._pid_to_exception.get(process.pid)
     chunks_pb = [
         memory_pb2.Chunk(offset=chunk.offset, size=chunk.amount)
         for chunk in chunks
     ]
     overlap_end_map = {
         chunk.offset: chunk.offset + chunk.overlap
         for chunk in chunks
     }
     response = self._client.ProcessScan(
         self._pid_to_serializable_file_descriptor[process.pid], chunks_pb,
         timeout_secs)
     if response.status == memory_pb2.ProcessScanResponse.Status.NO_ERROR:
         return self._ScanResultToYaraMatches(response.scan_result,
                                              overlap_end_map)
     elif (response.status ==
           memory_pb2.ProcessScanResponse.Status.TOO_MANY_MATCHES):
         raise TooManyMatchesError()
     elif (response.status ==
           memory_pb2.ProcessScanResponse.Status.TIMEOUT_ERROR):
         raise YaraTimeoutError()
     else:
         raise YaraWrapperError()
Example #5
0
    def Regions(self,
                skip_mapped_files=False,
                skip_shared_regions=False,
                skip_executable_regions=False,
                skip_readonly_regions=False):
        """Returns an iterator over the readable regions for this process."""
        try:
            maps_file = open("/proc/" + str(self.pid) + "/maps", "r")
        except OSError as e:
            raise process_error.ProcessError(e)

        with maps_file:
            for line in maps_file:
                m = self.maps_re.match(line)
                if not m:
                    continue
                start = int(m.group(1), 16)
                end = int(m.group(2), 16)
                region_protec = m.group(3)
                inode = int(m.group(6))

                if "r" in region_protec:
                    if skip_mapped_files and inode != 0:
                        continue
                    if skip_shared_regions and "s" in region_protec:
                        continue
                    if skip_executable_regions and "x" in region_protec:
                        continue
                    if skip_readonly_regions and "w" not in region_protec:
                        continue
                    yield start, end - start
Example #6
0
    def __init__(self, pid=None):
        """Creates a process for reading memory."""
        super().__init__()
        if pid is None:
            raise process_error.ProcessError("No pid given.")
        self.pid = pid

        self.mem_file = None
Example #7
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 #8
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 #9
0
 def __init__(self, pid=None, handle=None):
     """Creates a process for reading memory."""
     super().__init__()
     if pid is None and handle is None:
         raise process_error.ProcessError("No pid or handle given.")
     if pid is not None:
         self.pid = int(pid)
     else:
         self.pid = None
     self._existing_handle = handle
Example #10
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 #11
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 #12
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 #13
0
 def Match(self, process, chunk: streaming.Chunk,
           timeout_secs: int) -> Iterator[rdf_memory.YaraMatch]:
     if not self._rules_uploaded:
         self._client.UploadSignature(self._rules_str)
         self._rules_uploaded = True
     if process.pid not in self._pid_to_serializable_file_descriptor:
         raise (process_error.ProcessError(
             f"Failed to open process {process.pid}.")
                ) from self._pid_to_exception.get(process.pid)
     response = self._client.ProcessScan(
         self._pid_to_serializable_file_descriptor[process.pid],
         chunk.offset, chunk.amount, timeout_secs)
     if response.status == memory_pb2.ProcessScanResponse.Status.NO_ERROR:
         return self._ScanResultToYaraMatches(response.scan_result,
                                              chunk.offset + chunk.overlap)
     elif (response.status ==
           memory_pb2.ProcessScanResponse.Status.TOO_MANY_MATCHES):
         raise TooManyMatchesError()
     elif (response.status ==
           memory_pb2.ProcessScanResponse.Status.TIMEOUT_ERROR):
         raise YaraTimeoutError()
     else:
         raise YaraWrapperError()
Example #14
0
 def __enter__(self):
     if self.pid in [101, 106]:
         raise process_error.ProcessError("Access Denied.")
     return self
Example #15
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 #16
0
 def Open(self):
     path = ctypes.create_string_buffer("/proc/" + str(self.pid) + "/mem")
     try:
         self.mem_file = open64(ctypes.byref(path), os.O_RDONLY)
     except OSError as e:
         raise process_error.ProcessError(e)