示例#1
0
 def start(self, path):
     try:
         servicename = self.options.get("servicename", "CAPEService")
         servicedesc = self.options.get("servicedesc", "CAPE Service")
         arguments = self.options.get("arguments")
         path = check_file_extension(path, ".exe")
         binPath = f'"{path}"'
         if arguments:
             binPath += f" {arguments}"
         scm_handle = ADVAPI32.OpenSCManagerA(None, None,
                                              SC_MANAGER_ALL_ACCESS)
         if scm_handle == 0:
             log.info("Failed to open SCManager")
             log.info(ctypes.FormatError())
             return
         service_handle = ADVAPI32.CreateServiceA(
             scm_handle,
             servicename,
             servicedesc,
             SERVICE_ALL_ACCESS,
             SERVICE_WIN32_OWN_PROCESS,
             SERVICE_DEMAND_START,
             SERVICE_ERROR_IGNORE,
             binPath,
             None,
             None,
             None,
             None,
             None,
         )
         if service_handle == 0:
             log.info("Failed to create service")
             log.info(ctypes.FormatError())
             return
         log.info("Created service (handle: 0x%x)", service_handle)
         servproc = Process(options=self.options,
                            config=self.config,
                            pid=self.config.services_pid,
                            suspended=False)
         filepath = servproc.get_filepath()
         servproc.inject(injectmode=INJECT_QUEUEUSERAPC,
                         interest=filepath,
                         nosleepskip=True)
         servproc.close()
         KERNEL32.Sleep(500)
         service_launched = ADVAPI32.StartServiceA(service_handle, 0, None)
         if service_launched:
             log.info("Successfully started service")
         else:
             log.info(ctypes.FormatError())
             log.info("Failed to start service")
         ADVAPI32.CloseServiceHandle(service_handle)
         ADVAPI32.CloseServiceHandle(scm_handle)
         return
     except Exception as e:
         log.info(sys.exc_info()[0])
         log.info(e)
         log.info(e.__dict__)
         log.info(e.__class__)
         log.exception(e)
示例#2
0
    def execute(self, path, args, interest):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @param interest: file of interest, passed to the cuckoomon config
        @return: process pid
        """
        free = self.options.get("free", False)
        suspended = not free

        kernel_analysis = bool(self.options.get("kernel_analysis", False))

        p = Process(options=self.options, config=self.config)
        if not p.execute(path=path,
                         args=args,
                         suspended=suspended,
                         kernel_analysis=kernel_analysis):
            raise CuckooPackageError(
                "Unable to execute the initial process, analysis aborted")

        if free:
            return None

        if not kernel_analysis:
            p.inject(INJECT_QUEUEUSERAPC, interest)

        p.resume()
        p.close()

        return p.pid
示例#3
0
    def start(self, path):
        free = self.options.get("free", False)
        args = self.options.get("arguments", None)
        dll = self.options.get("dll", None)
        gw = self.options.get("setgw",None)
                

        u = Utils()
        if gw:
           u.set_default_gw(gw)

        suspended = True

        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute initial process, "
                                     "analysis aborted")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            self.run_ie()
            p.close()
            return p.pid
        else:
            self.run_ie()
            return None
示例#4
0
    def execute(self, path, args, interest):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @param interest: file of interest, passed to the cuckoomon config
        @return: process pid
        """
        dll = self.options.get("dll")
        free = self.options.get("free")
        suspended = True
        if free:
            suspended = False
        kernel_analysis = self.options.get("kernel_analysis", False)
        
        if kernel_analysis != False:
            kernel_analysis = True

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended, kernel_analysis=kernel_analysis):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if free:
            return None

        if not kernel_analysis:
            p.inject(dll, interest)
        p.resume()
        p.close()
        
        return p.pid
示例#5
0
    def start(self, path):
        free = self.options.get("free", False)
        dll = self.options.get("dll", None)
        gw = self.options.get("setgw", None)

        u = Utils()
        if gw:
            u.set_default_gw(gw)

        suspended = True
        if free:
            suspended = False

        cmd_path = os.path.join(os.getenv("SystemRoot"), "system32", "cmd.exe")
        cmd_args = "/c start \"{0}\"".format(path)

        p = Process()
        if not p.execute(path=cmd_path, args=cmd_args, suspended=suspended):
            raise CuckooPackageError("Unable to execute initial process, "
                                     "analysis aborted")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
        else:
            return None
示例#6
0
    def start(self, path):
        free = self.options.get("free", False)
        args = self.options.get("arguments", None)
        dll = self.options.get("dll", None)
        gw = self.options.get("setgw",None)

        u = Utils()
        if gw:
           u.set_default_gw(gw)

        suspended = True

        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute initial process, "
                                     "analysis aborted")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
        else:
            return None
示例#7
0
    def debug(self, path, args, interest):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @param interest: file of interest, passed to the cuckoomon config
        @return: process pid
        """
        dll = self.options.get("dll")
        dll_64 = self.options.get("dll_64")
        gw = self.options.get("setgw", None)

        u = Utils()
        if gw:
            u.set_default_gw(gw)

        suspended = True

        p = Process(options=self.options, config=self.config)
        if not p.execute(
                path=path, args=args, suspended=suspended,
                kernel_analysis=False):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        is_64bit = p.is_64bit()

        if is_64bit:
            p.debug_inject(dll_64, interest, childprocess=False)
        else:
            p.debug_inject(dll, interest, childprocess=False)
        p.resume()
        p.close()

        return p.pid
示例#8
0
    def start(self, path):
        free = self.options.get("free", False)
        dll = self.options.get("dll", None)
        gw = self.options.get("setgw",None)

        u = Utils()
        if gw:
           u.set_default_gw(gw)

        suspended = True
        if free:
            suspended = False

        cmd_path = os.path.join(os.getenv("SystemRoot"), "system32", "cmd.exe")
        cmd_args = "/c start \"{0}\"".format(path)

        p = Process()
        if not p.execute(path=cmd_path, args=cmd_args, suspended=suspended):
            raise CuckooPackageError("Unable to execute initial process, "
                                     "analysis aborted")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
        else:
            return None
示例#9
0
文件: browser.py 项目: xme/CAPEv2
 def run(self):
     self.do_run = self.options.get("startbrowser", False)
     url = self.options.get("url")
     browserdelay = int(self.options.get("browserdelay", "30"))
     while self.do_run:
         time.sleep(1)
         self.seconds_elapsed = self.seconds_elapsed + 1
         if self.seconds_elapsed == browserdelay:
             iexplore = os.path.join(os.getenv("ProgramFiles"), "Internet Explorer", "iexplore.exe")
             ie = Process()
             if not url:
                 url = "https://www.yahoo.com/"
             ie.execute(path=iexplore, args="\"" + url + "\"", suspended=False)
             ie.close()
示例#10
0
    def run(self):
        startbrowser = self.options.get("startbrowser")
        url = self.options.get("url")
        if not startbrowser:
            return True

        while self.do_run:
            time.sleep(1000)
            self.seconds_elapsed = self.seconds_elapsed + 1
            if self.seconds_elapsed == 30:
                iexplore = os.path.join(os.getenv("ProgramFiles"), "Internet Explorer", "iexplore.exe")
                ie = Process()
                if not url:
                    url = "https://www.yahoo.com/"
                ie.execute(path=iexplore, args="\"" + url + "\"", suspended=False)
                ie.close()
示例#11
0
    def execute(self, path, args):
        dll = self.options.get("dll")
        free = self.options.get("free")
        suspended = True
        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
示例#12
0
    def execute(self, path, args, interest):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @param interest: file of interest, passed to the cuckoomon config
        @return: process pid
        """
        dll = self.options.get("dll")
        dll_64 = self.options.get("dll_64")
        free = self.options.get("free")
        gw = self.options.get("setgw", None)

        u = Utils()
        if gw:
            u.set_default_gw(gw)

        suspended = True
        if free:
            suspended = False
        kernel_analysis = self.options.get("kernel_analysis", False)

        if kernel_analysis != False:
            kernel_analysis = True

        p = Process(options=self.options, config=self.config)
        if not p.execute(path=path,
                         args=args,
                         suspended=suspended,
                         kernel_analysis=kernel_analysis):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if free:
            return None

        is_64bit = p.is_64bit()

        if not kernel_analysis:
            if is_64bit:
                p.inject(dll_64, INJECT_QUEUEUSERAPC, interest)
            else:
                p.inject(dll, INJECT_QUEUEUSERAPC, interest)
        p.resume()
        p.close()

        return p.pid
示例#13
0
    def execute(self, path, args):
        dll = self.options.get("dll")
        free = self.options.get("free")
        suspended = True
        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
示例#14
0
文件: exe.py 项目: xarly/cuckoo
    def start(self, path):
        free = self.options.get("free", False)
        args = self.options.get("arguments", None)
        suspended = True
        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute initial process, analysis aborted")

        if not free and suspended:
            p.inject()
            p.resume()
            p.close()
            return p.pid
        else:
            return None
示例#15
0
    def execute(self, path, args):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @return: process pid
        """
        dll = self.options.get("dll")
        free = self.options.get("free")
        suspended = True
        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
示例#16
0
    def debug(self, path, args, interest):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @param interest: file of interest, passed to the cuckoomon config
        @return: process pid
        """

        suspended = True

        p = Process(options=self.options, config=self.config)
        if not p.execute(
                path=path, args=args, suspended=suspended,
                kernel_analysis=False):
            raise CuckooPackageError(
                "Unable to execute the initial process, analysis aborted")

        p.debug_inject(interest, childprocess=False)
        p.resume()
        p.close()

        return p.pid
    def execute(self, path, args):
        """Starts an executable for analysis.
        @param path: executable path
        @param args: executable arguments
        @return: process pid
        """
        dll = self.options.get("dll")
        free = self.options.get("free")
        suspended = True
        if free:
            suspended = False

        p = Process()
        if not p.execute(path=path, args=args, suspended=suspended):
            raise CuckooPackageError("Unable to execute the initial process, "
                                     "analysis aborted.")

        if not free and suspended:
            p.inject(dll)
            p.resume()
            p.close()
            return p.pid
示例#18
0
    def start(self, path):
        pin = "C:\\pin\\pin.exe"
        pindll = os.path.join(os.getcwd(), "dll", "PinVMShield.dll")
        if not pindll:
            raise CuckooPackageError("Unable to find any DBA available")

        free = self.options.get("free", False)
        args = self.options.get("arguments", None)
        dbi = self.options.get("dbi", None)
        if dbi == "true":
            isdbi = True
        else:
            isdbi = False

        suspended = True
        if free:
            suspended = False

        p = Process()
        if not isdbi:
            if not p.execute(path=path, args=args, suspended=suspended):
                raise CuckooPackageError(
                    "Unable to execute initial process, analysis aborted")
        else:
            if not p.execute(path=pin,
                             args="-t \"%s\" -- \"%s\" %s" %
                             (pindll, path, args),
                             suspended=suspended):
                raise CuckooPackageError(
                    "Unable to execute initial process, analysis aborted")
        if not free and suspended:
            p.inject()
            p.resume()
            p.close()
            return p.pid
        else:
            return None
示例#19
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        data = ""
        wait = False
        proc = None

        # Read the data submitted to the Pipe Server.
        while True:
            while True:
                try:
                    PipeHandler.read_lock.acquire()
                    data = self.h_pipe.readline()
                    PipeHandler.read_lock.release()
                    break
                except IOError:
                    log.error(
                        "Unable to open process communication pipe, retrying.")

            if data == '':
                break

            if data:
                #one line = one logging command
                c = [data]
                for command in c:

                    if not command.endswith(
                            '\n'):  #if we have read a partial line
                        log.info("Saving a part of a log")
                        self.part = command  #save it for later
                        continue

                    if self.part != '':  # append any pieces to the end
                        log.info("Using a part of a log")
                        command = self.part + command
                        self.part = ''

                    if command.startswith("FILE_ACTIVITY:"):
                        self.writeToLogFile(
                            os.path.join(PATHS["logs"], self.F_LOGFILE),
                            command[14:len(command)])
                    elif command.startswith("FILE_CREATE:"):
                        self.writeToLogFile(
                            os.path.join(PATHS["logs"], self.C_LOGFILE),
                            command[12:len(command)])
                    elif command.startswith("FILE_DELETE:"):
                        self.writeToLogFile(
                            os.path.join(PATHS["logs"], self.D_LOGFILE),
                            command[12:len(command)])
                    elif command.startswith("FILE_WRITE:"):
                        self.writeToLogFile(
                            os.path.join(PATHS["logs"], self.W_LOGFILE),
                            command[11:len(command)])
                    elif command.startswith("PROCESS:"):
                        process_id = int(command[8:len(command)])
                        if process_id not in PROCESS_LIST:
                            if psutil.pid_exists(process_id):
                                h_p = psutil.Process(process_id)
                                proc = Process(pid=process_id,
                                               h_process=h_p,
                                               thread_id=None)
                                filename = proc.get_filepath()
                                log.info(
                                    "Announced new process name: %s with pid %d",
                                    filename, process_id)
                                if not filename in PROTECTED_LIST:
                                    proc.start_trace()
                                add_pids(process_id)
                    elif command.startswith("EXEC:"):
                        log.info(command)
                    else:
                        log.error("Invalid pipe command: %s", command)
                    continue

            #break

        # We wait until the injected library reports back.
        if wait:
            proc.wait()

        if proc:
            proc.close()

        self.done = True
        return True
示例#20
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        data = ""
        response = "OK"
        wait = False
        proc = None

        # Read the data submitted to the Pipe Server.
        while True:
            bytes_read = c_int(0)

            buf = create_string_buffer(BUFSIZE)
            success = KERNEL32.ReadFile(self.h_pipe, buf, sizeof(buf),
                                        byref(bytes_read), None)

            data += buf.value

            if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                continue
            #elif not success or bytes_read.value == 0:
            #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
            #        pass

            break

        if data:
            command = data.strip()

            # Parse the prefix for the received notification.
            # In case of GETPIDS we're gonna return the current process ID
            # and the process ID of our parent process (agent.py).
            if command == "GETPIDS":
                response = struct.pack("II", PID, PPID)

            # When analyzing we don't want to hook all functions, as we're
            # having some stability issues with regards to webbrowsers.
            elif command == "HOOKDLLS":
                is_url = Config(cfg="analysis.conf").category != "file"

                url_dlls = "ntdll", "kernel32"

                def hookdll_encode(names):
                    # We have to encode each dll name as unicode string
                    # with length 16.
                    names = [
                        name + "\x00" * (16 - len(name)) for name in names
                    ]
                    f = lambda s: "".join(ch + "\x00" for ch in s)
                    return "".join(f(name) for name in names)

                # If this sample is not a URL, then we don't want to limit
                # any API hooks (at least for now), so we write a null-byte
                # which indicates that all DLLs should be hooked.
                if not is_url:
                    response = "\x00"
                else:
                    response = hookdll_encode(url_dlls)

            # In case of PID, the client is trying to notify the creation of
            # a new process to be injected and monitored.
            elif command.startswith("PROCESS:"):
                # We acquire the process lock in order to prevent the analyzer
                # to terminate the analysis while we are operating on the new
                # process.
                PROCESS_LOCK.acquire()

                # Set the current DLL to the default one provided
                # at submission.
                dll = DEFAULT_DLL

                # We parse the process ID.
                data = command[8:]
                process_id = thread_id = None
                if not "," in data:
                    if data.isdigit():
                        process_id = int(data)
                elif len(data.split(",")) == 2:
                    process_id, param = data.split(",")
                    thread_id = None
                    if process_id.isdigit():
                        process_id = int(process_id)
                    else:
                        process_id = None

                    if param.isdigit():
                        thread_id = int(param)
                    else:
                        # XXX: Expect a new DLL as a message parameter?
                        if isinstance(param, str):
                            dll = param

                if process_id:
                    if process_id not in (PID, PPID):
                        # We inject the process only if it's not being
                        # monitored already, otherwise we would generated
                        # polluted logs.
                        if process_id not in PROCESS_LIST:
                            # Open the process and inject the DLL.
                            # Hope it enjoys it.
                            proc = Process(pid=process_id, thread_id=thread_id)

                            filepath = proc.get_filepath()
                            filename = os.path.basename(filepath)

                            log.info("Announced process name: %s", filename)

                            if not protected_filename(filename):
                                # Add the new process ID to the list of
                                # monitored processes.
                                add_pids(process_id)

                                # If we have both pid and tid, then we can use
                                # apc to inject
                                if process_id and thread_id:
                                    proc.inject(dll, apc=True)
                                else:
                                    # we inject using CreateRemoteThread, this
                                    # needs the waiting in order to make sure
                                    # no race conditions occur
                                    proc.inject(dll)
                                    wait = True

                                log.info(
                                    "Successfully injected process with "
                                    "pid %s", proc.pid)
                    else:
                        log.warning("Received request to inject Cuckoo "
                                    "processes, skip")

                # Once we're done operating on the processes list, we release
                # the lock.
                PROCESS_LOCK.release()
            # In case of FILE_NEW, the client is trying to notify the creation
            # of a new file.
            elif command.startswith("FILE_NEW:"):
                # We extract the file path.
                file_path = command[9:].decode("utf-8")
                # We add the file to the list.
                add_file(file_path)
            # In case of FILE_DEL, the client is trying to notify an ongoing
            # deletion of an existing file, therefore we need to dump it
            # straight away.
            elif command.startswith("FILE_DEL:"):
                # Extract the file path.
                file_path = command[9:].decode("utf-8")
                # Dump the file straight away.
                del_file(file_path)
            elif command.startswith("FILE_MOVE:"):
                # syntax = FILE_MOVE:old_file_path::new_file_path
                if "::" in command[10:]:
                    old_fname, new_fname = command[10:].split("::", 1)
                    move_file(old_fname.decode("utf-8"),
                              new_fname.decode("utf-8"))

        KERNEL32.WriteFile(self.h_pipe, create_string_buffer(response),
                           len(response), byref(bytes_read), None)

        KERNEL32.CloseHandle(self.h_pipe)

        # We wait until cuckoomon reports back.
        if wait:
            proc.wait()

        if proc:
            proc.close()

        return True
示例#21
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        data = ""
        response = "OK"
        wait = False
        proc = None

        # Read the data submitted to the Pipe Server.
        while True:
            bytes_read = c_int(0)

            buf = create_string_buffer(BUFSIZE)
            success = KERNEL32.ReadFile(self.h_pipe, buf, sizeof(buf), byref(bytes_read), None)

            data += buf.value

            if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                continue
            # elif not success or bytes_read.value == 0:
            #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
            #        pass

            break

        if data:
            command = data.strip()

            # Parse the prefix for the received notification.
            # In case of GETPIDS we're gonna return the current process ID
            # and the process ID of our parent process (agent.py).
            if command == "GETPIDS":
                response = struct.pack("II", PID, PPID)

            # When analyzing we don't want to hook all functions, as we're
            # having some stability issues with regards to webbrowsers.
            elif command == "HOOKDLLS":
                is_url = Config(cfg="analysis.conf").category != "file"

                url_dlls = "ntdll", "kernel32"

                def hookdll_encode(names):
                    # We have to encode each dll name as unicode string
                    # with length 16.
                    names = [name + "\x00" * (16 - len(name)) for name in names]
                    f = lambda s: "".join(ch + "\x00" for ch in s)
                    return "".join(f(name) for name in names)

                # If this sample is not a URL, then we don't want to limit
                # any API hooks (at least for now), so we write a null-byte
                # which indicates that all DLLs should be hooked.
                if not is_url:
                    response = "\x00"
                else:
                    response = hookdll_encode(url_dlls)

            # In case of PID, the client is trying to notify the creation of
            # a new process to be injected and monitored.
            elif command.startswith("PROCESS:"):
                # We acquire the process lock in order to prevent the analyzer
                # to terminate the analysis while we are operating on the new
                # process.
                PROCESS_LOCK.acquire()

                # Set the current DLL to the default one provided
                # at submission.
                dll = DEFAULT_DLL

                # We parse the process ID.
                data = command[8:]
                process_id = thread_id = None
                if not "," in data:
                    if data.isdigit():
                        process_id = int(data)
                elif len(data.split(",")) == 2:
                    process_id, param = data.split(",")
                    thread_id = None
                    if process_id.isdigit():
                        process_id = int(process_id)
                    else:
                        process_id = None

                    if param.isdigit():
                        thread_id = int(param)
                    else:
                        # XXX: Expect a new DLL as a message parameter?
                        if isinstance(param, str):
                            dll = param

                if process_id:
                    if process_id not in (PID, PPID):
                        # We inject the process only if it's not being
                        # monitored already, otherwise we would generated
                        # polluted logs.
                        if process_id not in PROCESS_LIST:
                            # Open the process and inject the DLL.
                            # Hope it enjoys it.
                            proc = Process(pid=process_id, thread_id=thread_id)

                            filepath = proc.get_filepath()
                            filename = os.path.basename(filepath)

                            log.info("Announced process name: %s", filename)

                            if not protected_filename(filename):
                                # Add the new process ID to the list of
                                # monitored processes.
                                add_pids(process_id)

                                # If we have both pid and tid, then we can use
                                # apc to inject
                                if process_id and thread_id:
                                    proc.inject(dll, apc=True)
                                else:
                                    # we inject using CreateRemoteThread, this
                                    # needs the waiting in order to make sure
                                    # no race conditions occur
                                    proc.inject(dll)
                                    wait = True

                                log.info("Successfully injected process with " "pid %s", proc.pid)
                    else:
                        log.warning("Received request to inject Cuckoo " "processes, skip")

                # Once we're done operating on the processes list, we release
                # the lock.
                PROCESS_LOCK.release()
            # In case of FILE_NEW, the client is trying to notify the creation
            # of a new file.
            elif command.startswith("FILE_NEW:"):
                # We extract the file path.
                file_path = command[9:].decode("utf-8")
                # We add the file to the list.
                add_file(file_path)
            # In case of FILE_DEL, the client is trying to notify an ongoing
            # deletion of an existing file, therefore we need to dump it
            # straight away.
            elif command.startswith("FILE_DEL:"):
                # Extract the file path.
                file_path = command[9:].decode("utf-8")
                # Dump the file straight away.
                del_file(file_path)
            elif command.startswith("FILE_MOVE:"):
                # syntax = FILE_MOVE:old_file_path::new_file_path
                if "::" in command[10:]:
                    old_fname, new_fname = command[10:].split("::", 1)
                    move_file(old_fname.decode("utf-8"), new_fname.decode("utf-8"))

        KERNEL32.WriteFile(self.h_pipe, create_string_buffer(response), len(response), byref(bytes_read), None)

        KERNEL32.CloseHandle(self.h_pipe)

        # We wait until cuckoomon reports back.
        if wait:
            proc.wait()

        if proc:
            proc.close()

        return True
示例#22
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        global MONITORED_SERVICES
        global LASTINJECT_TIME
        data = ""
        response = "OK"

        # Read the data submitted to the Pipe Server.
        while True:
            bytes_read = c_int(0)

            buf = create_string_buffer(BUFSIZE)
            success = KERNEL32.ReadFile(self.h_pipe,
                                        buf,
                                        sizeof(buf),
                                        byref(bytes_read),
                                        None)

            data += buf.value

            if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                continue
            # elif not success or bytes_read.value == 0:
            #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
            #        pass

            break

        if data:
            command = data.strip()

            # Debug, Regular, Warning, or Critical information from CuckooMon.
            if command.startswith("DEBUG:"):
                log.debug(command[6:])
            elif command.startswith("INFO:"):
                log.info(command[5:])
            elif command.startswith("WARNING:"):
                log.warning(command[8:])
            elif command.startswith("CRITICAL:"):
                log.critical(command[9:])

            # Parse the prefix for the received notification.
            # In case of GETPIDS we're gonna return the current process ID
            # and the process ID of our parent process (agent.py).
            elif command == "GETPIDS":
                response = struct.pack("II", PID, PPID)

            # When analyzing we don't want to hook all functions, as we're
            # having some stability issues with regards to webbrowsers.
            elif command == "HOOKDLLS":
                is_url = Config(cfg="analysis.conf").category != "file"

                url_dlls = "ntdll", "kernel32"

                def hookdll_encode(names):
                    # We have to encode each dll name as unicode string
                    # with length 16.
                    names = [name + "\x00" * (16-len(name)) for name in names]
                    f = lambda s: "".join(ch + "\x00" for ch in s)
                    return "".join(f(name) for name in names)

                # If this sample is not a URL, then we don't want to limit
                # any API hooks (at least for now), so we write a null-byte
                # which indicates that all DLLs should be hooked.
                if not is_url:
                    response = "\x00"
                else:
                    response = hookdll_encode(url_dlls)

            # remove pid from process list because we received a notification
            # from kernel land
            elif command.startswith("KTERMINATE:"):
                data = command[11:]
                process_id = int(data)
                if process_id:
                    if process_id in PROCESS_LIST:
                        remove_pid(process_id) 

            # same than below but we don't want to inject any DLLs because
            # it's a kernel analysis
            elif command.startswith("KPROCESS:"):
                PROCESS_LOCK.acquire()
                data = command[9:]
                process_id = int(data)
                thread_id = None
                if process_id:
                    if process_id not in (PID, PPID):
                        if process_id not in PROCESS_LIST:
                            proc = Process(pid=process_id,thread_id=thread_id)
                            filepath = proc.get_filepath()
                            filename = os.path.basename(filepath)

                            if not protected_filename(filename):
                                add_pid(process_id)
                                log.info("Announce process name : %s", filename)
                PROCESS_LOCK.release()                
            
            elif command.startswith("KERROR:"):
                error_msg = command[7:]
                log.error("Error : %s", str(error_msg))
           
            # if a new driver has been loaded, we stop the analysis
            elif command == "KSUBVERT":
                for pid in PROCESS_LIST:
                    log.info("Process with pid %s has terminated", pid)
                    PROCESS_LIST.remove(pid)

            # Handle case of a service being started by a monitored process
            # Switch the service type to own process behind its back so we
            # can monitor the service more easily with less noise
            elif command.startswith("SERVICE:"):
                servname = command[8:]
                si = subprocess.STARTUPINFO()
                si.dwFlags = subprocess.STARTF_USESHOWWINDOW
                si.wShowWindow = subprocess.SW_HIDE
                subprocess.call("sc config " + servname + " type= own", startupinfo=si)
                log.info("Announced starting service \"%s\"", servname)

                if not MONITORED_SERVICES:
                    # Inject into services.exe so we can monitor service creation
                    # if tasklist previously failed to get the services.exe PID we'll be
                    # unable to inject
                    if SERVICES_PID:
                        servproc = Process(pid=SERVICES_PID,suspended=False)
                        filepath = servproc.get_filepath()
                        servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                        LASTINJECT_TIME = datetime.now()
                        servproc.close()
                        KERNEL32.Sleep(1000)
                        MONITORED_SERVICES = True
                    else:
                        log.error('Unable to monitor service %s' % (servname))

            # For now all we care about is bumping up our LASTINJECT_TIME to account for long delays between
            # injection and actual resume time where the DLL would have a chance to load in the new process
            # and report back to have its pid added to the list of monitored processes
            elif command.startswith("RESUME:"):
                LASTINJECT_TIME = datetime.now()

            # Handle case of malware terminating a process -- notify the target
            # ahead of time so that it can flush its log buffer
            elif command.startswith("KILL:"):
                PROCESS_LOCK.acquire()

                process_id = int(command[5:])
                if process_id not in (PID, PPID) and process_id in PROCESS_LIST:
                    # only notify processes we've hooked
                    event_name = TERMINATE_EVENT + str(process_id)
                    event_handle = KERNEL32.OpenEventA(EVENT_MODIFY_STATE, False, event_name)
                    if not event_handle:
                        log.warning("Unable to open termination event for pid %u.", process_id)
                    else:
                        # make sure process is aware of the termination
                        KERNEL32.SetEvent(event_handle)
                        KERNEL32.CloseHandle(event_handle)

                PROCESS_LOCK.release()
            # Handle notification of cuckoomon loading in a process
            elif command.startswith("LOADED:"):
                PROCESS_LOCK.acquire()
                process_id = int(command[7:])
                if process_id not in PROCESS_LIST:
                    add_pids(process_id)
                PROCESS_LOCK.release()
                log.info("Cuckoomon successfully loaded in process with pid %u.", process_id)

            # In case of PID, the client is trying to notify the creation of
            # a new process to be injected and monitored.
            elif command.startswith("PROCESS:"):
                # We acquire the process lock in order to prevent the analyzer
                # to terminate the analysis while we are operating on the new
                # process.
                PROCESS_LOCK.acquire()

                # Set the current DLL to the default one provided
                # at submission.
                dll = DEFAULT_DLL
                suspended = False
                # We parse the process ID.
                data = command[8:]
                if len(data) > 2 and data[1] == ':':
                    if data[0] == '1':
                        suspended = True
                    data = command[10:]

                process_id = thread_id = None
                if "," not in data:
                    if data.isdigit():
                        process_id = int(data)
                elif data.count(",") == 1:
                    process_id, param = data.split(",")
                    thread_id = None
                    if process_id.isdigit():
                        process_id = int(process_id)
                    else:
                        process_id = None

                    if param.isdigit():
                        thread_id = int(param)

                if process_id:
                    if process_id not in (PID, PPID):
                        # We inject the process only if it's not being
                        # monitored already, otherwise we would generate
                        # polluted logs.
                        if process_id not in PROCESS_LIST:
                            # Open the process and inject the DLL.
                            # Hope it enjoys it.
                            proc = Process(pid=process_id,
                                           thread_id=thread_id,
                                           suspended=suspended)

                            filepath = proc.get_filepath()
                            is_64bit = proc.is_64bit()
                            filename = os.path.basename(filepath)

                            log.info("Announced %s process name: %s pid: %d", "64-bit" if is_64bit else "32-bit", filename, process_id)

                            if not in_protected_path(filename):
                                res = proc.inject(dll, filepath)
                                LASTINJECT_TIME = datetime.now()
                            proc.close()
                    else:
                        log.warning("Received request to inject Cuckoo "
                                    "process with pid %d, skip", process_id)

                # Once we're done operating on the processes list, we release
                # the lock.
                PROCESS_LOCK.release()
            # In case of FILE_NEW, the client is trying to notify the creation
            # of a new file.
            elif command.startswith("FILE_NEW:"):
                # We extract the file path.
                file_path = unicode(command[9:].decode("utf-8"))
                # We add the file to the list.
                add_file(file_path)
            # In case of FILE_DEL, the client is trying to notify an ongoing
            # deletion of an existing file, therefore we need to dump it
            # straight away.
            elif command.startswith("FILE_DEL:"):
                # Extract the file path.
                file_path = unicode(command[9:].decode("utf-8"))
                # Dump the file straight away.
                del_file(file_path)
            elif command.startswith("FILE_MOVE:"):
                # Syntax = "FILE_MOVE:old_file_path::new_file_path".
                if "::" in command[10:]:
                    old_fname, new_fname = command[10:].split("::", 1)
                    move_file(unicode(old_fname.decode("utf-8")),
                              unicode(new_fname.decode("utf-8")))
            else:
                log.warning("Received unknown command from cuckoomon: %s", command)

        KERNEL32.WriteFile(self.h_pipe,
                           create_string_buffer(response),
                           len(response),
                           byref(bytes_read),
                           None)

        KERNEL32.CloseHandle(self.h_pipe)

        return True
示例#23
0
文件: analyzer.py 项目: xarly/cuckoo
    def run(self):
        """Run handler.
        @return: operation status.
        """
        data = ""
        response = "OK"
        wait = False
        proc = None

        # Read the data submitted to the Pipe Server.
        while True:
            bytes_read = c_int(0)

            buf = create_string_buffer(BUFSIZE)
            success = KERNEL32.ReadFile(self.h_pipe,
                                        buf,
                                        sizeof(buf),
                                        byref(bytes_read),
                                        None)

            data += buf.value

            if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                continue
            #elif not success or bytes_read.value == 0:
            #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
            #        pass
            
            break

        if data:
            command = data.strip()

            # Parse the prefix for the received notification.
            # In case of GETPIDS we're gonna return the current process ID
            # and the process ID of our parent process (agent.py).
            if command == "GETPIDS":
                response = struct.pack("II", PID, PPID)
            # In case of PID, the client is trying to notify the creation of
            # a new process to be injected and monitored.
            elif command.startswith("PROCESS:"):
                # We acquire the process lock in order to prevent the analyzer
                # to terminate the analysis while we are operating on the new
                # process.
                PROCESS_LOCK.acquire()

                # We parse the process ID.
                data = command[8:]

                process_id = thread_id = None
                if not "," in data:
                    if data.isdigit():
                        process_id = int(data)
                elif len(data.split(",")) == 2:
                    process_id, thread_id = data.split(",")
                    if process_id.isdigit():
                        process_id = int(process_id)
                    else:
                        process_id = None

                    if thread_id.isdigit():
                        thread_id = int(thread_id)
                    else:
                        thread_id = None

                if process_id:
                    if process_id not in (PID, PPID):
                        # We inject the process only if it's not being monitored
                        # already, otherwise we would generated polluted logs.
                        if process_id not in PROCESS_LIST:
                            # Open the process and inject the DLL.
                            # Hope it enjoys it.
                            proc = Process(pid=process_id,
                                           thread_id=thread_id)

                            filepath = proc.get_filepath()
                            filename = os.path.basename(filepath)

                            log.info("Announced process name: %s", filename)

                            if not protected_filename(filename):
                                # Add the new process ID to the list of monitored
                                # processes.
                                add_pids(process_id)

                                # If we have both pid and tid, then we can use
                                # apc to inject
                                if process_id and thread_id:
                                    proc.inject(apc=True)
                                else:
                                    # we inject using CreateRemoteThread, this
                                    # needs the waiting in order to make sure no
                                    # race conditions occur
                                    proc.inject()
                                    wait = True

                                log.info("Successfully injected process with pid %s", proc.pid)
                    else:
                        log.warning("Received request to inject Cuckoo processes, skip")

                # Once we're done operating on the processes list, we release
                # the lock.
                PROCESS_LOCK.release()
            # In case of FILE_NEW, the client is trying to notify the creation
            # of a new file.
            elif command.startswith("FILE_NEW:"):
                # We extract the file path.
                file_path = command[9:].decode("utf-8")
                # We add the file to the list.
                add_file(file_path)
            # In case of FILE_DEL, the client is trying to notify an ongoing
            # deletion of an existing file, therefore we need to dump it
            # straight away.
            elif command.startswith("FILE_DEL:"):
                # Extract the file path.
                file_path = command[9:].decode("utf-8")
                # Dump the file straight away.
                del_file(file_path)
            elif command.startswith("FILE_MOVE:"):
                # syntax = FILE_MOVE:old_file_path::new_file_path
                if "::" in command[10:]:
                    old_fname, new_fname = command[10:].split("::", 1)
                    move_file(old_fname.decode("utf-8"),
                              new_fname.decode("utf-8"))

        KERNEL32.WriteFile(self.h_pipe,
                           create_string_buffer(response),
                           len(response),
                           byref(bytes_read),
                           None)

        KERNEL32.CloseHandle(self.h_pipe)

        # We wait until cuckoomon reports back.
        if wait:
            proc.wait()

        if proc:
            proc.close()

        return True
示例#24
0
    def start(self, path):

        try:
            sc = self.get_path("sc.exe")
            servicename = self.options.get("servicename", "CAPEService")
            servicedesc = self.options.get("servicedesc", "CAPE Service")
            arguments = self.options.get("arguments")

            if "." not in os.path.basename(path):
                new_path = path + ".exe"
                os.rename(path, new_path)
                path = new_path

            binPath = "\"{0}\"".format(path)
            if arguments:
                binPath += " {0}".format(arguments)

            scm_handle = ADVAPI32.OpenSCManagerA(None, None,
                                                 SC_MANAGER_ALL_ACCESS)
            if scm_handle == 0:
                log.info("Failed to open SCManager")
                log.info(ctypes.FormatError())
                return

            service_handle = ADVAPI32.CreateServiceA(
                scm_handle, servicename, servicedesc, SERVICE_ALL_ACCESS,
                SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
                SERVICE_ERROR_IGNORE, binPath, None, None, None, None, None)
            if service_handle == 0:
                log.info("Failed to create service")
                log.info(ctypes.FormatError())
                return

            log.info("Created service (handle: 0x%x)", service_handle)

            servproc = Process(options=self.options,
                               config=self.config,
                               pid=self.config.services_pid,
                               suspended=False)
            servproc.set_critical()
            filepath = servproc.get_filepath()
            is_64bit = servproc.is_64bit()
            if is_64bit:
                servproc.inject(injectmode=INJECT_QUEUEUSERAPC,
                                interest=filepath,
                                nosleepskip=True)
            else:
                servproc.inject(injectmode=INJECT_QUEUEUSERAPC,
                                interest=filepath,
                                nosleepskip=True)
            servproc.close()
            KERNEL32.Sleep(500)

            service_launched = ADVAPI32.StartServiceA(service_handle, 0, None)
            if service_launched == True:
                log.info("Successfully started service")
            else:
                log.info(ctypes.FormatError())
                log.info("Failed to start service")

            ADVAPI32.CloseServiceHandle(service_handle)
            ADVAPI32.CloseServiceHandle(scm_handle)

            return

        except Exception as e:
            log.info(sys.exc_info()[0])
            log.info(e)
            log.info(e.__dict__)
            log.info(e.__class__)
            log.exception(e)
示例#25
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        global MONITORED_SERVICES
        global MONITORED_WMI
        global MONITORED_DCOM
        global MONITORED_TASKSCHED
        global LASTINJECT_TIME
        global NUM_INJECTED
        try:
            data = ""
            response = "OK"

            # Read the data submitted to the Pipe Server.
            while True:
                bytes_read = c_int(0)

                buf = create_string_buffer(BUFSIZE)
                success = KERNEL32.ReadFile(self.h_pipe,
                                            buf,
                                            sizeof(buf),
                                            byref(bytes_read),
                                            None)

                data += buf.value

                if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                    continue
                # elif not success or bytes_read.value == 0:
                #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
                #        pass

                break

            if data:
                command = data.strip()

                # Debug, Regular, Warning, or Critical information from CuckooMon.
                if command.startswith("DEBUG:"):
                    log.debug(command[6:])
                elif command.startswith("INFO:"):
                    log.info(command[5:])
                elif command.startswith("WARNING:"):
                    log.warning(command[8:])
                elif command.startswith("CRITICAL:"):
                    log.critical(command[9:])

                # Parse the prefix for the received notification.
                # In case of GETPIDS we're gonna return the current process ID
                # and the process ID of our parent process (agent.py).
                elif command == "GETPIDS":
                    hidepids = set()
                    hidepids.update(HIDE_PIDS)
                    hidepids.update([PID, PPID])
                    response = struct.pack("%dI" % len(hidepids), *hidepids)

                # remove pid from process list because we received a notification
                # from kernel land
                elif command.startswith("KTERMINATE:"):
                    data = command[11:]
                    process_id = int(data)
                    if process_id:
                        if process_id in PROCESS_LIST:
                            remove_pid(process_id) 

                # same than below but we don't want to inject any DLLs because
                # it's a kernel analysis
                elif command.startswith("KPROCESS:"):
                    PROCESS_LOCK.acquire()
                    data = command[9:]
                    process_id = int(data)
                    thread_id = None
                    if process_id:
                        if process_id not in (PID, PPID):
                            if process_id not in PROCESS_LIST:
                                proc = Process(pid=process_id,thread_id=thread_id)
                                filepath = proc.get_filepath()
                                filename = os.path.basename(filepath)

                                if not in_protected_path(filename):
                                    add_pid(process_id)
                                    log.info("Announce process name : %s", filename)
                    PROCESS_LOCK.release()                
            
                elif command.startswith("KERROR:"):
                    error_msg = command[7:]
                    log.error("Error : %s", str(error_msg))
           
                # if a new driver has been loaded, we stop the analysis
                elif command == "KSUBVERT":
                    for pid in PROCESS_LIST:
                        log.info("Process with pid %s has terminated", pid)
                        PROCESS_LIST.remove(pid)

                elif command.startswith("INTEROP:"):
                    if not MONITORED_DCOM:
                        MONITORED_DCOM = True
                        dcom_pid = pid_from_service_name("DcomLaunch")
                        if dcom_pid:
                            servproc = Process(pid=dcom_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                elif command.startswith("WMI:"):
                    if not MONITORED_WMI:
                        MONITORED_WMI = True
                        si = subprocess.STARTUPINFO()
                        # STARTF_USESHOWWINDOW
                        si.dwFlags = 1
                        # SW_HIDE
                        si.wShowWindow = 0
                        log.info("Stopping WMI Service")
                        p = subprocess.Popen(['net', 'stop', 'winmgmt'], startupinfo=si, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
                        dummyvar = p.communicate(input='Y\n')
                        log.info("Stopped WMI Service")
                        subprocess.call("sc config winmgmt type= own", startupinfo=si)

                        if not MONITORED_DCOM:
                            dcom_pid = pid_from_service_name("DcomLaunch")
                            if dcom_pid:
                                servproc = Process(pid=dcom_pid,suspended=False)
                                servproc.set_critical()
                                filepath = servproc.get_filepath()
                                servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                                LASTINJECT_TIME = datetime.now()
                                servproc.close()
                                KERNEL32.Sleep(2000)

                        log.info("Starting WMI Service")
                        subprocess.call("net start winmgmt", startupinfo=si)
                        log.info("Started WMI Service")

                        wmi_pid = pid_from_service_name("winmgmt")
                        if wmi_pid:
                            servproc = Process(pid=wmi_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                elif command.startswith("TASKSCHED:"):
                    if not MONITORED_TASKSCHED:
                        MONITORED_TASKSCHED = True
                        si = subprocess.STARTUPINFO()
                        # STARTF_USESHOWWINDOW
                        si.dwFlags = 1
                        # SW_HIDE
                        si.wShowWindow = 0
                        log.info("Stopping Task Scheduler Service")
                        p = subprocess.Popen(['net', 'stop', 'schedule'], startupinfo=si, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
                        dummyvar = p.communicate(input='Y\n')
                        log.info("Stopped Task Scheduler Service")
                        subprocess.call("sc config schedule type= own", startupinfo=si)

                        log.info("Starting Task Scheduler Service")
                        subprocess.call("net start schedule", startupinfo=si)
                        log.info("Started Task Scheduler Service")

                        sched_pid = pid_from_service_name("schedule")
                        if sched_pid:
                            servproc = Process(pid=sched_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                # Handle case of a service being started by a monitored process
                # Switch the service type to own process behind its back so we
                # can monitor the service more easily with less noise
                elif command.startswith("SERVICE:"):
                    servname = command[8:]
                    si = subprocess.STARTUPINFO()
                    # STARTF_USESHOWWINDOW
                    si.dwFlags = 1
                    # SW_HIDE
                    si.wShowWindow = 0
                    subprocess.call("sc config " + servname + " type= own", startupinfo=si)
                    log.info("Announced starting service \"%s\"", servname)

                    if not MONITORED_SERVICES:
                        # Inject into services.exe so we can monitor service creation
                        # if tasklist previously failed to get the services.exe PID we'll be
                        # unable to inject
                        if SERVICES_PID:
                            servproc = Process(pid=SERVICES_PID,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(1000)
                            MONITORED_SERVICES = True
                        else:
                            log.error('Unable to monitor service %s' % (servname))

                # For now all we care about is bumping up our LASTINJECT_TIME to account for long delays between
                # injection and actual resume time where the DLL would have a chance to load in the new process
                # and report back to have its pid added to the list of monitored processes
                elif command.startswith("RESUME:"):
                    LASTINJECT_TIME = datetime.now()

                # Handle attempted shutdowns/restarts -- flush logs for all monitored processes
                # additional handling can be added later
                elif command.startswith("SHUTDOWN:"):
                    log.info("Received shutdown request")
                    PROCESS_LOCK.acquire()
                    for process_id in PROCESS_LIST:
                        event_name = TERMINATE_EVENT + str(process_id)
                        event_handle = KERNEL32.OpenEventA(EVENT_MODIFY_STATE, False, event_name)
                        if event_handle:
                            KERNEL32.SetEvent(event_handle)
                            KERNEL32.CloseHandle(event_handle)
                            if self.options.get("procmemdump"):
                                p = Process(pid=process_id)
                                p.dump_memory()
                            dump_files()
                    PROCESS_LOCK.release()
                # Handle case of malware terminating a process -- notify the target
                # ahead of time so that it can flush its log buffer
                elif command.startswith("KILL:"):
                    PROCESS_LOCK.acquire()

                    process_id = int(command[5:])
                    if process_id not in (PID, PPID) and process_id in PROCESS_LIST:
                        # only notify processes we've hooked
                        event_name = TERMINATE_EVENT + str(process_id)
                        event_handle = KERNEL32.OpenEventA(EVENT_MODIFY_STATE, False, event_name)
                        if not event_handle:
                            log.warning("Unable to open termination event for pid %u.", process_id)
                        else:
                            log.info("Notified of termination of process with pid %u.", process_id)
                            # dump the memory of exiting processes
                            if self.options.get("procmemdump"):
                                p = Process(pid=process_id)
                                p.dump_memory()
                            # make sure process is aware of the termination
                            KERNEL32.SetEvent(event_handle)
                            KERNEL32.CloseHandle(event_handle)

                    PROCESS_LOCK.release()
                # Handle notification of cuckoomon loading in a process
                elif command.startswith("LOADED:"):
                    PROCESS_LOCK.acquire()
                    process_id = int(command[7:])
                    if process_id not in PROCESS_LIST:
                        add_pids(process_id)
                    PROCESS_LOCK.release()
                    NUM_INJECTED += 1
                    log.info("Cuckoomon successfully loaded in process with pid %u.", process_id)

                # In case of PID, the client is trying to notify the creation of
                # a new process to be injected and monitored.
                elif command.startswith("PROCESS:"):
                    # We acquire the process lock in order to prevent the analyzer
                    # to terminate the analysis while we are operating on the new
                    # process.
                    PROCESS_LOCK.acquire()

                    # Set the current DLL to the default one provided
                    # at submission.
                    dll = DEFAULT_DLL
                    suspended = False
                    # We parse the process ID.
                    data = command[8:]
                    if len(data) > 2 and data[1] == ':':
                        if data[0] == '1':
                            suspended = True
                        data = command[10:]

                    process_id = thread_id = None
                    if "," not in data:
                        if data.isdigit():
                            process_id = int(data)
                    elif data.count(",") == 1:
                        process_id, param = data.split(",")
                        thread_id = None
                        if process_id.isdigit():
                            process_id = int(process_id)
                        else:
                            process_id = None

                        if param.isdigit():
                            thread_id = int(param)

                    if process_id:
                        if process_id not in (PID, PPID):
                            # We inject the process only if it's not being
                            # monitored already, otherwise we would generate
                            # polluted logs.
                            if process_id not in PROCESS_LIST:
                                # Open the process and inject the DLL.
                                # Hope it enjoys it.
                                proc = Process(pid=process_id,
                                               thread_id=thread_id,
                                               suspended=suspended)

                                filepath = proc.get_filepath()
                                # if it's a URL analysis, provide the URL to all processes as
                                # the "interest" -- this will allow cuckoomon to see in the
                                # child browser process that a URL analysis is occurring
                                if self.config.category == "file" or NUM_INJECTED > 1:
                                    interest = filepath
                                else:
                                    interest = self.config.target

                                is_64bit = proc.is_64bit()
                                filename = os.path.basename(filepath)

                                if not in_protected_path(filename) and proc.check_inject():
                                    log.info("Announced %s process name: %s pid: %d", "64-bit" if is_64bit else "32-bit", filename, process_id)
                                    proc.inject(dll, interest)
                                    LASTINJECT_TIME = datetime.now()
                                proc.close()
                        else:
                            log.warning("Received request to inject Cuckoo "
                                        "process with pid %d, skip", process_id)

                    # Once we're done operating on the processes list, we release
                    # the lock.
                    PROCESS_LOCK.release()
                # In case of FILE_NEW, the client is trying to notify the creation
                # of a new file.
                elif command.startswith("FILE_NEW:"):
                    FILES_LIST_LOCK.acquire()
                    # We extract the file path.
                    file_path = unicode(command[9:].decode("utf-8"))
                    # We add the file to the list.
                    add_file(file_path)
                    FILES_LIST_LOCK.release()
                # In case of FILE_DEL, the client is trying to notify an ongoing
                # deletion of an existing file, therefore we need to dump it
                # straight away.
                elif command.startswith("FILE_DEL:"):
                    FILES_LIST_LOCK.acquire()
                    # Extract the file path.
                    file_path = unicode(command[9:].decode("utf-8"))
                    # Dump the file straight away.
                    del_file(file_path)
                    FILES_LIST_LOCK.release()
                elif command.startswith("FILE_MOVE:"):
                    FILES_LIST_LOCK.acquire()
                    # Syntax = "FILE_MOVE:old_file_path::new_file_path".
                    if "::" in command[10:]:
                        old_fname, new_fname = command[10:].split("::", 1)
                        move_file(unicode(old_fname.decode("utf-8")),
                                  unicode(new_fname.decode("utf-8")))
                    FILES_LIST_LOCK.release()
                else:
                    log.warning("Received unknown command from cuckoomon: %s", command)

            KERNEL32.WriteFile(self.h_pipe,
                               create_string_buffer(response),
                               len(response),
                               byref(bytes_read),
                               None)

            KERNEL32.CloseHandle(self.h_pipe)

            return True
        except Exception as e:
            error_exc = traceback.format_exc()
            log.exception(error_exc)
            return True
示例#26
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        global MONITORED_SERVICES
        global MONITORED_WMI
        global MONITORED_DCOM
        global MONITORED_TASKSCHED
        global MONITORED_BITS
        global LASTINJECT_TIME
        global NUM_INJECTED
        try:
            data = ""
            response = "OK"

            # Read the data submitted to the Pipe Server.
            while True:
                bytes_read = c_int(0)

                buf = create_string_buffer(BUFSIZE)
                success = KERNEL32.ReadFile(self.h_pipe,
                                            buf,
                                            sizeof(buf),
                                            byref(bytes_read),
                                            None)

                data += buf.value

                if not success and KERNEL32.GetLastError() == ERROR_MORE_DATA:
                    continue
                # elif not success or bytes_read.value == 0:
                #    if KERNEL32.GetLastError() == ERROR_BROKEN_PIPE:
                #        pass

                break

            if data:
                command = data.strip()

                # Debug, Regular, Warning, or Critical information from CuckooMon.
                if command.startswith("DEBUG:"):
                    log.debug(command[6:])
                elif command.startswith("INFO:"):
                    log.info(command[5:])
                elif command.startswith("WARNING:"):
                    log.warning(command[8:])
                elif command.startswith("CRITICAL:"):
                    log.critical(command[9:])

                # Parse the prefix for the received notification.
                # In case of GETPIDS we're gonna return the current process ID
                # and the process ID of our parent process (agent.py).
                elif command == "GETPIDS":
                    hidepids = set()
                    hidepids.update(HIDE_PIDS)
                    hidepids.update([PID, PPID])
                    response = struct.pack("%dI" % len(hidepids), *hidepids)

                # remove pid from process list because we received a notification
                # from kernel land
                elif command.startswith("KTERMINATE:"):
                    data = command[11:]
                    process_id = int(data)
                    if process_id:
                        if process_id in PROCESS_LIST:
                            remove_pid(process_id) 

                # same than below but we don't want to inject any DLLs because
                # it's a kernel analysis
                elif command.startswith("KPROCESS:"):
                    PROCESS_LOCK.acquire()
                    data = command[9:]
                    process_id = int(data)
                    thread_id = None
                    if process_id:
                        if process_id not in (PID, PPID):
                            if process_id not in PROCESS_LIST:
                                proc = Process(pid=process_id,thread_id=thread_id)
                                filepath = proc.get_filepath()
                                filename = os.path.basename(filepath)

                                if not in_protected_path(filename):
                                    add_pid(process_id)
                                    log.info("Announce process name : %s", filename)
                    PROCESS_LOCK.release()                
            
                elif command.startswith("KERROR:"):
                    error_msg = command[7:]
                    log.error("Error : %s", str(error_msg))
           
                # if a new driver has been loaded, we stop the analysis
                elif command == "KSUBVERT":
                    for pid in PROCESS_LIST:
                        log.info("Process with pid %s has terminated", pid)
                        PROCESS_LIST.remove(pid)

                elif command.startswith("INTEROP:"):
                    if not MONITORED_DCOM:
                        MONITORED_DCOM = True
                        dcom_pid = pid_from_service_name("DcomLaunch")
                        if dcom_pid:
                            servproc = Process(pid=dcom_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                elif command.startswith("WMI:"):
                    if not MONITORED_WMI:
                        MONITORED_WMI = True
                        si = subprocess.STARTUPINFO()
                        # STARTF_USESHOWWINDOW
                        si.dwFlags = 1
                        # SW_HIDE
                        si.wShowWindow = 0
                        log.info("Stopping WMI Service")
                        subprocess.call(['net', 'stop', 'winmgmt', '/y'], startupinfo=si)
                        log.info("Stopped WMI Service")
                        subprocess.call("sc config winmgmt type= own", startupinfo=si)

                        if not MONITORED_DCOM:
                            MONITORED_DCOM = True
                            dcom_pid = pid_from_service_name("DcomLaunch")
                            if dcom_pid:
                                servproc = Process(pid=dcom_pid,suspended=False)
                                servproc.set_critical()
                                filepath = servproc.get_filepath()
                                servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                                LASTINJECT_TIME = datetime.now()
                                servproc.close()
                                KERNEL32.Sleep(2000)

                        log.info("Starting WMI Service")
                        subprocess.call("net start winmgmt", startupinfo=si)
                        log.info("Started WMI Service")

                        wmi_pid = pid_from_service_name("winmgmt")
                        if wmi_pid:
                            servproc = Process(pid=wmi_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                elif command.startswith("TASKSCHED:"):
                    if not MONITORED_TASKSCHED:
                        MONITORED_TASKSCHED = True
                        si = subprocess.STARTUPINFO()
                        # STARTF_USESHOWWINDOW
                        si.dwFlags = 1
                        # SW_HIDE
                        si.wShowWindow = 0
                        log.info("Stopping Task Scheduler Service")
                        subprocess.call(['net', 'stop', 'schedule', '/y'], startupinfo=si)
                        log.info("Stopped Task Scheduler Service")
                        subprocess.call("sc config schedule type= own", startupinfo=si)

                        log.info("Starting Task Scheduler Service")
                        subprocess.call("net start schedule", startupinfo=si)
                        log.info("Started Task Scheduler Service")

                        sched_pid = pid_from_service_name("schedule")
                        if sched_pid:
                            servproc = Process(pid=sched_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                elif command.startswith("BITS:"):
                    if not MONITORED_BITS:
                        MONITORED_BITS = True
                        si = subprocess.STARTUPINFO()
                        # STARTF_USESHOWWINDOW
                        si.dwFlags = 1
                        # SW_HIDE
                        si.wShowWindow = 0
                        log.info("Stopping BITS Service")
                        subprocess.call(['net', 'stop', 'BITS', '/y'], startupinfo=si)
                        log.info("Stopped BITS Service")
                        subprocess.call("sc config BITS type= own", startupinfo=si)

                        if not MONITORED_DCOM:
                            MONITORED_DCOM = True
                            dcom_pid = pid_from_service_name("DcomLaunch")
                            if dcom_pid:
                                servproc = Process(pid=dcom_pid,suspended=False)
                                servproc.set_critical()
                                filepath = servproc.get_filepath()
                                servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                                LASTINJECT_TIME = datetime.now()
                                servproc.close()
                                KERNEL32.Sleep(2000)

                        log.info("Starting BITS Service")
                        subprocess.call("net start BITS", startupinfo=si)
                        log.info("Started BITS Service")

                        bits_pid = pid_from_service_name("BITS")
                        if bits_pid:
                            servproc = Process(pid=bits_pid,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(2000)

                # Handle case of a service being started by a monitored process
                # Switch the service type to own process behind its back so we
                # can monitor the service more easily with less noise
                elif command.startswith("SERVICE:"):
                    servname = command[8:]
                    si = subprocess.STARTUPINFO()
                    # STARTF_USESHOWWINDOW
                    si.dwFlags = 1
                    # SW_HIDE
                    si.wShowWindow = 0
                    subprocess.call("sc config " + servname + " type= own", startupinfo=si)
                    log.info("Announced starting service \"%s\"", servname)

                    if not MONITORED_SERVICES:
                        # Inject into services.exe so we can monitor service creation
                        # if tasklist previously failed to get the services.exe PID we'll be
                        # unable to inject
                        if SERVICES_PID:
                            servproc = Process(pid=SERVICES_PID,suspended=False)
                            servproc.set_critical()
                            filepath = servproc.get_filepath()
                            servproc.inject(dll=DEFAULT_DLL, interest=filepath, nosleepskip=True)
                            LASTINJECT_TIME = datetime.now()
                            servproc.close()
                            KERNEL32.Sleep(1000)
                            MONITORED_SERVICES = True
                        else:
                            log.error('Unable to monitor service %s' % (servname))

                # For now all we care about is bumping up our LASTINJECT_TIME to account for long delays between
                # injection and actual resume time where the DLL would have a chance to load in the new process
                # and report back to have its pid added to the list of monitored processes
                elif command.startswith("RESUME:"):
                    LASTINJECT_TIME = datetime.now()

                # Handle attempted shutdowns/restarts -- flush logs for all monitored processes
                # additional handling can be added later
                elif command.startswith("SHUTDOWN:"):
                    log.info("Received shutdown request")
                    PROCESS_LOCK.acquire()
                    for process_id in PROCESS_LIST:
                        event_name = TERMINATE_EVENT + str(process_id)
                        event_handle = KERNEL32.OpenEventA(EVENT_MODIFY_STATE, False, event_name)
                        if event_handle:
                            KERNEL32.SetEvent(event_handle)
                            KERNEL32.CloseHandle(event_handle)
                            if self.options.get("procmemdump"):
                                p = Process(pid=process_id)
                                p.dump_memory()
                            dump_files()
                    PROCESS_LOCK.release()
                # Handle case of malware terminating a process -- notify the target
                # ahead of time so that it can flush its log buffer
                elif command.startswith("KILL:"):
                    PROCESS_LOCK.acquire()

                    process_id = int(command[5:])
                    if process_id not in (PID, PPID) and process_id in PROCESS_LIST:
                        # only notify processes we've hooked
                        event_name = TERMINATE_EVENT + str(process_id)
                        event_handle = KERNEL32.OpenEventA(EVENT_MODIFY_STATE, False, event_name)
                        if not event_handle:
                            log.warning("Unable to open termination event for pid %u.", process_id)
                        else:
                            log.info("Notified of termination of process with pid %u.", process_id)
                            # dump the memory of exiting processes
                            if self.options.get("procmemdump"):
                                p = Process(pid=process_id)
                                p.dump_memory()
                            # make sure process is aware of the termination
                            KERNEL32.SetEvent(event_handle)
                            KERNEL32.CloseHandle(event_handle)

                    PROCESS_LOCK.release()
                # Handle notification of cuckoomon loading in a process
                elif command.startswith("LOADED:"):
                    PROCESS_LOCK.acquire()
                    process_id = int(command[7:])
                    if process_id not in PROCESS_LIST:
                        add_pids(process_id)
                    PROCESS_LOCK.release()
                    NUM_INJECTED += 1
                    log.info("Cuckoomon successfully loaded in process with pid %u.", process_id)

                # In case of PID, the client is trying to notify the creation of
                # a new process to be injected and monitored.
                elif command.startswith("PROCESS:"):
                    # We acquire the process lock in order to prevent the analyzer
                    # to terminate the analysis while we are operating on the new
                    # process.
                    PROCESS_LOCK.acquire()

                    # Set the current DLL to the default one provided
                    # at submission.
                    dll = DEFAULT_DLL
                    suspended = False
                    # We parse the process ID.
                    data = command[8:]
                    if len(data) > 2 and data[1] == ':':
                        if data[0] == '1':
                            suspended = True
                        data = command[10:]

                    process_id = thread_id = None
                    if "," not in data:
                        if data.isdigit():
                            process_id = int(data)
                    elif data.count(",") == 1:
                        process_id, param = data.split(",")
                        thread_id = None
                        if process_id.isdigit():
                            process_id = int(process_id)
                        else:
                            process_id = None

                        if param.isdigit():
                            thread_id = int(param)

                    if process_id:
                        if process_id not in (PID, PPID):
                            # We inject the process only if it's not being
                            # monitored already, otherwise we would generate
                            # polluted logs.
                            if process_id not in PROCESS_LIST:
                                # Open the process and inject the DLL.
                                # Hope it enjoys it.
                                proc = Process(pid=process_id,
                                               thread_id=thread_id,
                                               suspended=suspended)

                                filepath = proc.get_filepath()
                                # if it's a URL analysis, provide the URL to all processes as
                                # the "interest" -- this will allow cuckoomon to see in the
                                # child browser process that a URL analysis is occurring
                                if self.config.category == "file" or NUM_INJECTED > 1:
                                    interest = filepath
                                else:
                                    interest = self.config.target

                                is_64bit = proc.is_64bit()
                                filename = os.path.basename(filepath)

                                if not in_protected_path(filename) and proc.check_inject():
                                    log.info("Announced %s process name: %s pid: %d", "64-bit" if is_64bit else "32-bit", filename, process_id)
                                    proc.inject(dll, interest)
                                    LASTINJECT_TIME = datetime.now()
                                proc.close()
                        else:
                            log.warning("Received request to inject Cuckoo "
                                        "process with pid %d, skip", process_id)

                    # Once we're done operating on the processes list, we release
                    # the lock.
                    PROCESS_LOCK.release()
                # In case of FILE_NEW, the client is trying to notify the creation
                # of a new file.
                elif command.startswith("FILE_NEW:"):
                    FILES_LIST_LOCK.acquire()
                    # We extract the file path.
                    file_path = unicode(command[9:].decode("utf-8"))
                    # We add the file to the list.
                    add_file(file_path)
                    FILES_LIST_LOCK.release()
                # In case of FILE_DEL, the client is trying to notify an ongoing
                # deletion of an existing file, therefore we need to dump it
                # straight away.
                elif command.startswith("FILE_DEL:"):
                    FILES_LIST_LOCK.acquire()
                    # Extract the file path.
                    file_path = unicode(command[9:].decode("utf-8"))
                    # Dump the file straight away.
                    del_file(file_path)
                    FILES_LIST_LOCK.release()
                elif command.startswith("FILE_MOVE:"):
                    FILES_LIST_LOCK.acquire()
                    # Syntax = "FILE_MOVE:old_file_path::new_file_path".
                    if "::" in command[10:]:
                        old_fname, new_fname = command[10:].split("::", 1)
                        move_file(unicode(old_fname.decode("utf-8")),
                                  unicode(new_fname.decode("utf-8")))
                    FILES_LIST_LOCK.release()
                else:
                    log.warning("Received unknown command from cuckoomon: %s", command)

            KERNEL32.WriteFile(self.h_pipe,
                               create_string_buffer(response),
                               len(response),
                               byref(bytes_read),
                               None)

            KERNEL32.CloseHandle(self.h_pipe)

            return True
        except Exception as e:
            error_exc = traceback.format_exc()
            log.exception(error_exc)
            return True