예제 #1
0
    def run(self):
        """Run analysis.
        @return: operation status.
        """
        start = KERNEL32.GetTickCount()

        self.prepare()
        self.path = os.getcwd()

        log.debug("Starting analyzer from: %s", self.path)
        log.debug("Pipe server name: %s", self.config.pipe)
        log.debug("Log pipe server name: %s", self.config.logpipe)

        # If no analysis package was specified at submission, we try to select
        # one automatically.
        if not self.config.package:
            log.debug("No analysis package specified, trying to detect "
                      "it automagically.")

            # If the analysis target is a file, we choose the package according
            # to the file format.
            if self.config.category == "file":
                package = choose_package(self.config.file_type,
                                         self.config.file_name,
                                         self.config.pe_exports.split(","))
            # If it's an URL, we'll just use the default Internet Explorer
            # package.
            else:
                package = "ie"

            # If we weren't able to automatically determine the proper package,
            # we need to abort the analysis.
            if not package:
                raise CuckooError("No valid package available for file "
                                  "type: {0}".format(self.config.file_type))

            log.info("Automatically selected analysis package \"%s\"", package)
        # Otherwise just select the specified package.
        else:
            package = self.config.package

        # Generate the package path.
        package_name = "modules.packages.%s" % package

        # Try to import the analysis package.
        try:
            package_module = __import__(package_name, globals(), locals(),
                                        ["dummy"], -1)
        # If it fails, we need to abort the analysis.
        except ImportError:
            raise CuckooError("Unable to import package \"{0}\", does "
                              "not exist.".format(package_name))

        # Initialize the package parent abstract.
        Package()

        # Find the package class, the file name does not always equal the class name (eg doc.py -> Class _DOC_)
        class_name = next((attr for attr in dir(package_module)
                           if attr.lower() == package.lower()), None)
        if not class_name:
            raise CuckooError("Unable to select package class "
                              "(package={0})".format(package_name))

        package_class = getattr(package_module, class_name)

        # Initialize the analysis package.
        log.debug("arguments options: [%s]", str(self.config.options))
        self.package = package_class(self.config.options, analyzer=self)

        # Move the sample to the current working directory as provided by the
        # task - one is able to override the starting path of the sample.
        # E.g., for some samples it might be useful to run from %APPDATA%
        # instead of %TEMP%.
        if self.config.category == "file":
            self.target = self.package.move_curdir(self.target)

        # Initialize Auxiliary modules
        aux_start = KERNEL32.GetTickCount()

        Auxiliary()
        prefix = auxiliary.__name__ + "."
        for loader, name, ispkg in pkgutil.iter_modules(
                auxiliary.__path__, prefix):
            if ispkg:
                continue

            # Import the auxiliary module.
            try:
                __import__(name, globals(), locals(), ["dummy"], -1)
            except ImportError as e:
                log.warning(
                    "Unable to import the auxiliary module "
                    "\"%s\": %s", name, e)

        # Walk through the available auxiliary modules.
        aux_enabled, aux_avail = [], []
        for module in Auxiliary.__subclasses__():
            # Try to start the auxiliary module.
            try:
                self.config.options[
                    'timeout'] = self.config.timeout  # pass timeout to aux modules
                aux = module(options=self.config.options, analyzer=self)
                aux_avail.append(aux)
                aux.init()
                aux.start()
            except (NotImplementedError, AttributeError):
                log.exception("Auxiliary module %s was not implemented",
                              module.__name__)
            except CuckooDisableModule:
                continue
            except Exception as e:
                log.exception("Cannot execute auxiliary module %s: %s",
                              module.__name__, e)
            else:
                log.debug("Started auxiliary module %s", module.__name__)
                aux_enabled.append(aux)

        aux_end = KERNEL32.GetTickCount()
        log.debug("Loaded auxiliary modules in {}s".format(
            str((aux_end - aux_start) / 1000)))

        # Forward the command pipe and logpipe names on to zer0m0n.
        zer0m0n.cmdpipe(self.config.pipe)
        zer0m0n.channel(self.config.logpipe)

        # Initialize zer0m0n with our compiled Yara rules.
        zer0m0n.yarald("bin/rules.yarac")

        # Start analysis package. If for any reason, the execution of the
        # analysis package fails, we have to abort the analysis.
        process_monitoring_start = KERNEL32.GetTickCount()

        pids = self.package.start(self.target)

        process_monitoring_end = KERNEL32.GetTickCount()
        log.debug("Monitored first process in {}s".format(
            str((process_monitoring_end - process_monitoring_start) / 1000)))

        # If the analysis package returned a list of process identifiers, we
        # add them to the list of monitored processes and enable the process monitor.
        if pids:
            self.process_list.add_pids(pids)
            pid_check = True

        # If the package didn't return any process ID (for example in the case
        # where the package isn't enabling any behavioral analysis), we don't
        # enable the process monitor.
        else:
            log.info("No process IDs returned by the package, running "
                     "for the full timeout.")
            pid_check = False

        # Check in the options if the user toggled the timeout enforce. If so,
        # we need to override pid_check and disable process monitor.
        if self.config.enforce_timeout:
            log.info("Enabled timeout enforce, running for the full timeout.")
            pid_check = False

        end = KERNEL32.GetTickCount()
        log.info("Initialized VM in {}s".format(str((end - start) / 1000)))

        end = KERNEL32.GetTickCount() + int(self.config.timeout) * 1000

        while self.do_run:
            now = KERNEL32.GetTickCount()

            # log.debug("Time passed: {}, terminating at {}".format((end-now)/1000, str(self.config.timeout)))

            if now >= end:
                log.info("Analysis timeout hit, terminating analysis.")
                break

            # If the process lock is locked, it means that something is
            # operating on the list of monitored processes. Therefore we
            # cannot proceed with the checks until the lock is released.
            if self.process_lock.locked():
                KERNEL32.Sleep(1000)
                continue

            try:
                # If the process monitor is enabled we start checking whether
                # the monitored processes are still alive.
                if pid_check:
                    for pid in self.process_list.pids:
                        if not Process(pid=pid).is_alive():
                            log.info("Process with pid %s has terminated", pid)
                            self.process_list.remove_pid(pid)

                    # If none of the monitored processes are still alive, we
                    # can terminate the analysis.
                    if not self.process_list.pids:
                        log.info("Process list is empty, "
                                 "terminating analysis.")
                        break

                    # Update the list of monitored processes available to the
                    # analysis package. It could be used for internal
                    # operations within the module.
                    self.package.set_pids(self.process_list.pids)

                try:
                    # The analysis packages are provided with a function that
                    # is executed at every loop's iteration. If such function
                    # returns False, it means that it requested the analysis
                    # to be terminate.
                    if not self.package.check():
                        log.info("The analysis package requested the "
                                 "termination of the analysis.")
                        break

                # If the check() function of the package raised some exception
                # we don't care, we can still proceed with the analysis but we
                # throw a warning.
                except Exception as e:
                    log.warning(
                        "The package \"%s\" check function raised "
                        "an exception: %s", package_name, e)
            finally:
                # Zzz.
                KERNEL32.Sleep(1000)

        if not self.do_run:
            log.debug("The analyzer has been stopped on request by an "
                      "auxiliary module.")

        # Create the shutdown mutex.
        KERNEL32.CreateMutexA(None, False, SHUTDOWN_MUTEX)

        try:
            # Before shutting down the analysis, the package can perform some
            # final operations through the finish() function.
            self.package.finish()
        except Exception as e:
            log.warning(
                "The package \"%s\" finish function raised an "
                "exception: %s", package_name, e)

        try:
            # Upload files the package created to package_files in the
            # results folder.
            for path, name in self.package.package_files() or []:
                upload_to_host(path, os.path.join("package_files", name))
        except Exception as e:
            log.warning(
                "The package \"%s\" package_files function raised an "
                "exception: %s", package_name, e)

        # Terminate the Auxiliary modules.
        for aux in aux_enabled:
            try:
                aux.stop()
            except (NotImplementedError, AttributeError):
                continue
            except Exception as e:
                log.warning("Cannot terminate auxiliary module %s: %s",
                            aux.__class__.__name__, e)

        if self.config.terminate_processes:
            # Try to terminate remaining active processes.
            log.info("Terminating remaining processes before shutdown.")

            for pid in self.process_list.pids:
                proc = Process(pid=pid)
                if proc.is_alive():
                    try:
                        proc.terminate()
                    except:
                        continue

        # Run the finish callback of every available Auxiliary module.
        for aux in aux_avail:
            try:
                aux.finish()
            except (NotImplementedError, AttributeError):
                continue
            except Exception as e:
                log.warning(
                    "Exception running finish callback of auxiliary "
                    "module %s: %s", aux.__class__.__name__, e)

        # Let's invoke the completion procedure.
        self.complete()
        return True
예제 #2
0
    def run(self):
        # human starts before the sample invocation, wait for 3s to start
        minimal_timeout = KERNEL32.GetTickCount() + 3000
        # set office close timeout after 2/3 of analysis (in milliseconds)
        office_close_sec = int(self.options.get("timeout") * (3. / 4) * 1000)
        office_close_timeout = KERNEL32.GetTickCount() + office_close_sec
        is_office_close = False
        is_full_screen = False
        pdf_clicks_ctr = 10

        # adaptive sleep timer
        sleep = 50 if self.is_ultrafast else 750

        while self.do_run:

            KERNEL32.Sleep(
                sleep)  # we wait for minimal timeout anyway so no loss here

            if KERNEL32.GetTickCount() < minimal_timeout:
                continue

            if not is_office_close and KERNEL32.GetTickCount(
            ) > office_close_timeout:
                USER32.EnumWindows(EnumWindowsProc(get_office_window), 0)
                is_office_close = True

            if self.do_click_mouse and self.do_move_mouse:
                # extract foregroud window name
                fg_window_name = ""
                hwnd = USER32.GetForegroundWindow()
                try:
                    fg_window_name = get_window_text(hwnd).lower()
                except:
                    log.exception("failed to extract window name")
                    pass

                # make the office window on front
                if fg_window_name in ["", "program manager"]:
                    x, y = self.coordinates.center()
                    move_mouse(x, y)
                    click_mouse(x, y)
                    continue
                else:
                    log.info("fg_window_name: %s", fg_window_name)

                if "word" in fg_window_name or "excel" in fg_window_name:
                    if not is_full_screen:
                        set_full_screen(hwnd)
                        is_full_screen = True
                    x, y = self.coordinates.next()
                    move_mouse(x, y)
                    double_click(x, y)

                elif "powerpoint" in fg_window_name:
                    if not is_full_screen:
                        set_full_screen(hwnd)
                        is_full_screen = True
                    x, y = self.coordinates.center()
                    move_mouse(x, y)
                    click_mouse(x, y)

                elif "acrobat reader" in fg_window_name:
                    if not is_full_screen:
                        set_full_screen(hwnd)
                        is_full_screen = True
                        # place cursor on top left
                        x, y = 120, 200
                        move_mouse(x, y)
                        click_mouse(x, y)

                    if pdf_clicks_ctr > 0:
                        # press tab
                        click_button(win32con.VK_TAB)
                        # press enter
                        click_button(win32con.VK_RETURN)
                        pdf_clicks_ctr = pdf_clicks_ctr - 1
                        # wait for result
                        KERNEL32.Sleep(1000)

                else:
                    # make random move
                    x, y = self.coordinates.random()
                    move_mouse(x, y)

            if self.do_click_buttons:
                USER32.EnumWindows(EnumWindowsProc(foreach_window), 0)