Exemplo n.º 1
0
 def __init__(self):
     self.config = Config(cfg="analysis.conf")
     self.enabled = self.config.procmon
Exemplo n.º 2
0
 def get_task_id(self):
     conf = Config("c:\\cuckoo\\analysis.conf")
     return conf.task_id
Exemplo n.º 3
0
    def inject(self, dll=None, apc=False):
        """Cuckoo DLL injection.
        @param dll: Cuckoo DLL path.
        @param apc: APC use.
        """
        if not self.pid:
            log.warning("No valid pid specified, injection aborted")
            return False

        if not self.is_alive():
            log.warning(
                "The process with pid %s is not alive, "
                "injection aborted", self.pid)
            return False

        if not dll:
            dll = "cuckoomon.dll"

        dll = randomize_dll(os.path.join("dll", dll))

        if not dll or not os.path.exists(dll):
            log.warning(
                "No valid DLL specified to be injected in process "
                "with pid %d, injection aborted.", self.pid)
            return False

        arg = KERNEL32.VirtualAllocEx(self.h_process, None,
                                      len(dll) + 1, MEM_RESERVE | MEM_COMMIT,
                                      PAGE_READWRITE)

        if not arg:
            log.error(
                "VirtualAllocEx failed when injecting process with "
                "pid %d, injection aborted (Error: %s)", self.pid,
                get_error_string(KERNEL32.GetLastError()))
            return False

        bytes_written = c_int(0)
        if not KERNEL32.WriteProcessMemory(self.h_process, arg, dll + "\x00",
                                           len(dll) + 1, byref(bytes_written)):
            log.error(
                "WriteProcessMemory failed when injecting process with "
                "pid %d, injection aborted (Error: %s)", self.pid,
                get_error_string(KERNEL32.GetLastError()))
            return False

        kernel32_handle = KERNEL32.GetModuleHandleA("kernel32.dll")
        load_library = KERNEL32.GetProcAddress(kernel32_handle, "LoadLibraryA")

        config_path = os.path.join(os.getenv("TEMP"), "%s.ini" % self.pid)
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")
            cfgoptions = cfg.get_options()

            # The first time we come up with a random startup-time.
            if Process.first_process:
                # This adds 1 up to 30 times of 20 minutes to the startup
                # time of the process, therefore bypassing anti-vm checks
                # which check whether the VM has only been up for <10 minutes.
                Process.startup_time = random.randint(1, 30) * 20 * 60 * 1000

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))
            config.write("results={0}\n".format(PATHS["root"]))
            config.write("analyzer={0}\n".format(os.getcwd()))
            config.write("first-process={0}\n".format(
                "1" if Process.first_process else "0"))
            config.write("startup-time={0}\n".format(Process.startup_time))
            config.write("shutdown-mutex={0}\n".format(SHUTDOWN_MUTEX))
            config.write("force-sleepskip={0}\n".format(
                cfgoptions.get("force-sleepskip", "0")))

            Process.first_process = False

        event_name = "CuckooEvent%d" % self.pid
        self.event_handle = KERNEL32.CreateEventA(None, False, False,
                                                  event_name)
        if not self.event_handle:
            log.warning("Unable to create notify event..")
            return False

        if apc or self.suspended:
            log.debug("Using QueueUserAPC injection.")
            if not self.h_thread:
                log.info(
                    "No valid thread handle specified for injecting "
                    "process with pid %d, injection aborted.", self.pid)
                self.event_handle = None
                return False

            if not KERNEL32.QueueUserAPC(load_library, self.h_thread, arg):
                log.error(
                    "QueueUserAPC failed when injecting process with "
                    "pid %d (Error: %s)", self.pid,
                    get_error_string(KERNEL32.GetLastError()))
                self.event_handle = None
                return False
        else:
            log.debug("Using CreateRemoteThread injection.")
            new_thread_id = c_ulong(0)
            thread_handle = KERNEL32.CreateRemoteThread(
                self.h_process, None, 0, load_library, arg, 0,
                byref(new_thread_id))
            if not thread_handle:
                log.error(
                    "CreateRemoteThread failed when injecting process "
                    "with pid %d (Error: %s)", self.pid,
                    get_error_string(KERNEL32.GetLastError()))
                KERNEL32.CloseHandle(self.event_handle)
                self.event_handle = None
                return False
            else:
                KERNEL32.CloseHandle(thread_handle)

        log.info("Successfully injected process with pid %d." % self.pid)

        return True
Exemplo n.º 4
0
    def inject(self, dll=None, interest=None, nosleepskip=False):
        """Cuckoo DLL injection.
        @param dll: Cuckoo DLL path.
        @param interest: path to file of interest, handed to cuckoomon config
        @param apc: APC use.
        """
        global LOGSERVER_POOL

        if not self.pid:
            return False

        thread_id = 0
        if self.thread_id:
            thread_id = self.thread_id

        if not self.is_alive():
            log.warning(
                "The process with pid %s is not alive, "
                "injection aborted", self.pid)
            return False

        is_64bit = self.is_64bit()
        if not dll:
            if is_64bit:
                dll = CUCKOOMON64_NAME
            else:
                dll = CUCKOOMON32_NAME
        else:
            os.path.join("dll", dll)

        dll = os.path.join(os.getcwd(), dll)

        if not dll or not os.path.exists(dll):
            log.warning(
                "No valid DLL specified to be injected in process "
                "with pid %d, injection aborted.", self.pid)
            return False

        if thread_id or self.suspended:
            log.debug("Using QueueUserAPC injection.")
        else:
            log.debug("Using CreateRemoteThread injection.")

        config_path = "C:\\%s.ini" % self.pid
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")
            cfgoptions = cfg.get_options()

            # start the logserver for this monitored process
            logserver_path = LOGSERVER_PREFIX + str(self.pid)
            if logserver_path not in LOGSERVER_POOL:
                LOGSERVER_POOL[logserver_path] = LogServer(
                    cfg.ip, cfg.port, logserver_path)

            firstproc = Process.first_process

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))
            config.write("logserver={0}\n".format(logserver_path))
            config.write("results={0}\n".format(PATHS["root"]))
            config.write("analyzer={0}\n".format(os.getcwd()))
            config.write(
                "first-process={0}\n".format("1" if firstproc else "0"))
            config.write("startup-time={0}\n".format(Process.startup_time))
            config.write("file-of-interest={0}\n".format(interest))
            config.write("shutdown-mutex={0}\n".format(SHUTDOWN_MUTEX))
            config.write("terminate-event={0}{1}\n".format(
                TERMINATE_EVENT, self.pid))

            if nosleepskip:
                config.write("force-sleepskip=0\n")
            if "norefer" not in cfgoptions:
                config.write("referrer={0}\n".format(
                    get_referrer_url(interest)))

            simple_optnames = [
                "force-sleepskip",
                "full-logs",
                "force-flush",
                "no-stealth",
                "buffer-max",
                "large-buffer-max",
                "serial",
                "sysvol_ctimelow",
                "sysvol_ctimehigh",
                "sys32_ctimelow",
                "sys32_ctimehigh",
                "debug",
                "disable_hook_content",
                "hook-type",
                "exclude-apis",
                "exclude-dlls",
            ]

            for optname in simple_optnames:
                if optname in cfgoptions:
                    config.write("{0}={1}\n".format(optname,
                                                    cfgoptions[optname]))

            if firstproc:
                Process.first_process = False

        orig_bin_name = ""
        bit_str = ""
        if is_64bit:
            orig_bin_name = LOADER64_NAME
            bit_str = "64-bit"
        else:
            orig_bin_name = LOADER32_NAME
            bit_str = "32-bit"

        bin_name = os.path.join(os.getcwd(), orig_bin_name)

        if os.path.exists(bin_name):
            ret = subprocess.call(
                [bin_name, "inject",
                 str(self.pid),
                 str(thread_id), dll])
            if ret != 0:
                if ret == 1:
                    log.info("Injected into suspended %s process with pid %d",
                             bit_str, self.pid)
                else:
                    log.error(
                        "Unable to inject into %s process with pid %d, error: %d",
                        bit_str, self.pid, ret)
                return False
            else:
                return True
        else:
            log.error(
                "Please place the %s binary from cuckoomon into analyzer/windows/bin in order to analyze %s binaries.",
                os.path.basename(bin_name), bit_str)
            return False
Exemplo n.º 5
0
    def run(self):
        """Run handler.
        @return: operation status.
        """
        global MONITORED_SERVICES
        global LASTINJECT_TIME
        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)

                # 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 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)

                # 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:
                            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()
                    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
        except Exception as e:
            error_exc = traceback.format_exc()
            log.exception(error_exc)
            return True
Exemplo n.º 6
0
    def prepare(self):
        """Prepare env for analysis."""
        # Get SeDebugPrivilege for the Python process. It will be needed in
        # order to perform the injections.
        grant_privilege("SeDebugPrivilege")
        grant_privilege("SeLoadDriverPrivilege")

        # Initialize logging.
        init_logging()

        # Parse the analysis configuration file generated by the agent.
        self.config = Config(cfg="analysis.conf")

        # Pass the configuration through to the Process class.
        Process.set_config(self.config)

        # Set virtual machine clock.
        set_clock(
            datetime.datetime.strptime(self.config.clock, "%Y%m%dT%H:%M:%S"))

        # Set the default DLL to be used for this analysis.
        self.default_dll = self.config.options.get("dll")

        # If a pipe name has not set, then generate a random one.
        self.config.pipe = self.get_pipe_path(
            self.config.options.get("pipe", random_string(16, 32)))

        # Generate a random name for the logging pipe server.
        self.config.logpipe = self.get_pipe_path(random_string(16, 32))

        # Initialize and start the Command Handler pipe server. This is going
        # to be used for communicating with the monitored processes.
        self.command_pipe = PipeServer(PipeDispatcher,
                                       self.config.pipe,
                                       message=True,
                                       dispatcher=CommandPipeHandler(self))
        self.command_pipe.daemon = True
        self.command_pipe.start()

        # Initialize and start the Log Pipe Server - the log pipe server will
        # open up a pipe that monitored processes will use to send logs to
        # before they head off to the host machine.
        destination = self.config.ip, self.config.port
        self.log_pipe_server = PipeServer(PipeForwarder,
                                          self.config.logpipe,
                                          destination=destination)
        self.log_pipe_server.daemon = True
        self.log_pipe_server.start()

        # We update the target according to its category. If it's a file, then
        # we store the target path.
        if self.config.category == "file":
            self.target = os.path.join(os.environ["TEMP"],
                                       self.config.file_name)
        elif self.config.category == "archive":
            zip_path = os.path.join(os.environ["TEMP"], self.config.file_name)
            zipfile.ZipFile(zip_path).extractall(os.environ["TEMP"])
            self.target = os.path.join(os.environ["TEMP"],
                                       self.config.options["filename"])
        # If it's a URL, well.. we store the URL.
        else:
            self.target = self.config.target
Exemplo n.º 7
0
 def __init__(self):
     self.config = Config(cfg="analysis.conf")
     self.pids_reported = set()
Exemplo n.º 8
0
    def kernel_analyze(self):
        """zer0m0n kernel analysis
        """
        log.info("Starting kernel analysis")
        log.info("Installing driver")
        if is_os_64bit():
            sys_file = os.path.join(os.getcwd(), "dll", "zer0m0n_x64.sys")
        else:
            sys_file = os.path.join(os.getcwd(), "dll", "zer0m0n.sys")
        exe_file = os.path.join(os.getcwd(), "dll", "logs_dispatcher.exe")
        if not sys_file or not exe_file or not os.path.exists(
                sys_file) or not os.path.exists(exe_file):
            log.warning(
                "No valid zer0m0n files to be used for process with pid %d, injection aborted",
                self.pid)
            return False

        exe_name = random_string(6)
        service_name = random_string(6)
        driver_name = random_string(6)
        inf_data = '[Version]\r\nSignature = "$Windows NT$"\r\nClass = "ActivityMonitor"\r\nClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}\r\nProvider= %Prov%\r\nDriverVer = 22/01/2014,1.0.0.0\r\nCatalogFile = %DriverName%.cat\r\n[DestinationDirs]\r\nDefaultDestDir = 12\r\nMiniFilter.DriverFiles = 12\r\n[DefaultInstall]\r\nOptionDesc = %ServiceDescription%\r\nCopyFiles = MiniFilter.DriverFiles\r\n[DefaultInstall.Services]\r\nAddService = %ServiceName%,,MiniFilter.Service\r\n[DefaultUninstall]\r\nDelFiles = MiniFilter.DriverFiles\r\n[DefaultUninstall.Services]\r\nDelService = %ServiceName%,0x200\r\n[MiniFilter.Service]\r\nDisplayName= %ServiceName%\r\nDescription= %ServiceDescription%\r\nServiceBinary= %12%\\%DriverName%.sys\r\nDependencies = "FltMgr"\r\nServiceType = 2\r\nStartType = 3\r\nErrorControl = 1\r\nLoadOrderGroup = "FSFilter Activity Monitor"\r\nAddReg = MiniFilter.AddRegistry\r\n[MiniFilter.AddRegistry]\r\nHKR,,"DebugFlags",0x00010001 ,0x0\r\nHKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%\r\nHKR,"Instances\\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%\r\nHKR,"Instances\\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%\r\n[MiniFilter.DriverFiles]\r\n%DriverName%.sys\r\n[SourceDisksFiles]\r\n' + driver_name + '.sys = 1,,\r\n[SourceDisksNames]\r\n1 = %DiskId1%,,,\r\n[Strings]\r\n' + 'Prov = "' + random_string(
            8
        ) + '"\r\nServiceDescription = "' + random_string(
            12
        ) + '"\r\nServiceName = "' + service_name + '"\r\nDriverName = "' + driver_name + '"\r\nDiskId1 = "' + service_name + ' Device Installation Disk"\r\nDefaultInstance = "' + service_name + ' Instance"\r\nInstance1.Name = "' + service_name + ' Instance"\r\nInstance1.Altitude = "370050"\r\nInstance1.Flags = 0x0'

        new_inf = os.path.join(os.getcwd(), "dll",
                               "{0}.inf".format(service_name))
        new_sys = os.path.join(os.getcwd(), "dll",
                               "{0}.sys".format(driver_name))
        copy(sys_file, new_sys)
        new_exe = os.path.join(os.getcwd(), "dll", "{0}.exe".format(exe_name))
        copy(exe_file, new_exe)
        log.info("[-] Driver name : " + new_sys)
        log.info("[-] Inf name : " + new_inf)
        log.info("[-] Application name : " + new_exe)
        log.info("[-] Service : " + service_name)

        fh = open(new_inf, "w")
        fh.write(inf_data)
        fh.close()

        os_is_64bit = is_os_64bit()
        if os_is_64bit:
            wow64 = c_ulong(0)
            KERNEL32.Wow64DisableWow64FsRedirection(byref(wow64))

        os.system(
            'cmd /c "rundll32 setupapi.dll, InstallHinfSection DefaultInstall 132 '
            + new_inf + '"')
        os.system("net start " + service_name)

        si = STARTUPINFO()
        si.cb = sizeof(si)
        pi = PROCESS_INFORMATION()
        cr = CREATE_NEW_CONSOLE

        ldp = KERNEL32.CreateProcessW(new_exe, None, None, None, None, cr,
                                      None, os.getenv("TEMP"), byref(si),
                                      byref(pi))
        if not ldp:
            if os_is_64bit:
                KERNEL32.Wow64RevertWow64FsRedirection(wow64)
            log.error("Failed starting " + exe_name + ".exe.")
            return False

        config_path = os.path.join(os.getenv("TEMP"), "%s.ini" % self.pid)
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))

        log.info("Sending startup information")
        hFile = KERNEL32.CreateFileW(PATH_KERNEL_DRIVER,
                                     GENERIC_READ | GENERIC_WRITE, 0, None,
                                     OPEN_EXISTING, 0, None)
        if os_is_64bit:
            KERNEL32.Wow64RevertWow64FsRedirection(wow64)
        if hFile:
            p = Process(pid=os.getpid())
            ppid = p.get_parent_pid()
            pid_vboxservice = 0
            pid_vboxtray = 0

            # get pid of VBoxService.exe and VBoxTray.exe
            proc_info = PROCESSENTRY32()
            proc_info.dwSize = sizeof(PROCESSENTRY32)

            snapshot = KERNEL32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
            flag = KERNEL32.Process32First(snapshot, byref(proc_info))
            while flag:
                if proc_info.sz_exeFile == "VBoxService.exe":
                    log.info("VBoxService.exe found !")
                    pid_vboxservice = proc_info.th32ProcessID
                    flag = 0
                elif proc_info.sz_exeFile == "VBoxTray.exe":
                    pid_vboxtray = proc_info.th32ProcessID
                    log.info("VBoxTray.exe found !")
                    flag = 0
                flag = KERNEL32.Process32Next(snapshot, byref(proc_info))
            bytes_returned = c_ulong(0)
            msg = str(self.pid) + "_" + str(ppid) + "_" + str(
                os.getpid()) + "_" + str(pi.dwProcessId) + "_" + str(
                    pid_vboxservice) + "_" + str(pid_vboxtray) + '\0'
            KERNEL32.DeviceIoControl(hFile, IOCTL_PID, msg, len(msg), None, 0,
                                     byref(bytes_returned), None)
            msg = os.getcwd() + '\0'
            KERNEL32.DeviceIoControl(hFile,
                                     IOCTL_CUCKOO_PATH, str(msg, 'utf-8'),
                                     len(str(msg, 'utf-8')), None, 0,
                                     byref(bytes_returned), None)
        else:
            log.warning("Failed to access kernel driver")

        return True
Exemplo n.º 9
0
    def prepare(self):
        """Prepare env for analysis."""
        # Get SeDebugPrivilege for the Python process. It will be needed in
        # order to perform the injections.
        grant_debug_privilege()

        # Initialize logging.
        init_logging()

        # Parse the analysis configuration file generated by the agent.
        self.config = Config(cfg="analysis.conf")

        # Pass the configuration through to the Process class.
        Process.set_config(self.config)

        # Set virtual machine clock.
        clock = datetime.strptime(self.config.clock, "%Y%m%dT%H:%M:%S")

        # Setting date and time.
        # NOTE: Windows system has only localized commands with date format
        # following localization settings, so these commands for english date
        # format cannot work in other localizations.
        # In addition DATE and TIME commands are blocking if an incorrect
        # syntax is provided, so an echo trick is used to bypass the input
        # request and not block analysis.
        os.system("echo:|date {0}".format(clock.strftime("%m-%d-%y")))
        os.system("echo:|time {0}".format(clock.strftime("%H:%M:%S")))

        # Set the default DLL to be used for this analysis.
        self.default_dll = self.config.options.get("dll")

        # If a pipe name has not set, then generate a random one.
        if "pipe" in self.config.options:
            self.config.pipe = "\\\\.\\PIPE\\%s" % self.config.options["pipe"]
        else:
            self.config.pipe = "\\\\.\\PIPE\\%s" % random_string(16, 32)

        # Generate a random name for the logging pipe server.
        self.config.logpipe = "\\\\.\\PIPE\\%s" % random_string(16, 32)

        # Initialize and start the Command Handler pipe server. This is going
        # to be used for communicating with the monitored processes.
        self.command_pipe = PipeServer(PipeDispatcher,
                                       self.config.pipe,
                                       message=True,
                                       dispatcher=CommandPipeHandler(self))
        self.command_pipe.daemon = True
        self.command_pipe.start()

        # Initialize and start the Log Pipe Server - the log pipe server will
        # open up a pipe that monitored processes will use to send logs to
        # before they head off to the host machine.
        destination = self.config.ip, self.config.port
        self.log_pipe_server = PipeServer(PipeForwarder,
                                          self.config.logpipe,
                                          destination=destination)
        self.log_pipe_server.daemon = True
        self.log_pipe_server.start()

        # We update the target according to its category. If it's a file, then
        # we store the target path.
        if self.config.category == "file":
            self.target = os.path.join(os.environ["TEMP"] + os.sep,
                                       self.config.file_name)
        # If it's a URL, well.. we store the URL.
        else:
            self.target = self.config.target
Exemplo n.º 10
0
    def inject(self, dll=None, interest=None, nosleepskip=False):
        """Cuckoo DLL injection.
        @param dll: Cuckoo DLL path.
        @param interest: path to file of interest, handed to cuckoomon config
        @param apc: APC use.
        """
        if not self.pid:
            log.warning("No valid pid specified, injection aborted")
            return False

        thread_id = 0
        if self.thread_id:
            thread_id = self.thread_id

        if not self.is_alive():
            log.warning(
                "The process with pid %s is not alive, "
                "injection aborted", self.pid)
            return False

        is_64bit = self.is_64bit()
        if not dll:
            if is_64bit:
                dll = "cuckoomon_x64.dll"
            else:
                dll = "cuckoomon.dll"

        dll = randomize_bin(os.path.join("dll", dll), "dll")

        if not dll or not os.path.exists(dll):
            log.warning(
                "No valid DLL specified to be injected in process "
                "with pid %d, injection aborted.", self.pid)
            return False

        config_path = "C:\\%s.ini" % self.pid
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")
            cfgoptions = cfg.get_options()

            # start the logserver for this monitored process
            self.logserver = LogServer(cfg.ip, cfg.port, self.logserver_path)

            firstproc = Process.first_process

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))
            config.write("logserver={0}\n".format(self.logserver_path))
            config.write("results={0}\n".format(PATHS["root"]))
            config.write("analyzer={0}\n".format(os.getcwd()))
            config.write(
                "first-process={0}\n".format("1" if firstproc else "0"))
            config.write("startup-time={0}\n".format(Process.startup_time))
            config.write("file-of-interest={0}\n".format(interest))
            config.write("shutdown-mutex={0}\n".format(SHUTDOWN_MUTEX))
            config.write("terminate-event={0}{1}\n".format(
                TERMINATE_EVENT, self.pid))
            if nosleepskip:
                config.write("force-sleepskip=0\n")
            elif "force-sleepskip" in cfgoptions:
                config.write("force-sleepskip={0}\n".format(
                    cfgoptions["force-sleepskip"]))
            if "full-logs" in cfgoptions:
                config.write("full-logs={0}\n".format(cfgoptions["full-logs"]))
            if "no-stealth" in cfgoptions:
                config.write("no-stealth={0}\n".format(
                    cfgoptions["no-stealth"]))
            if "norefer" not in cfgoptions:
                config.write("referrer={0}\n".format(
                    get_referrer_url(interest)))
            if firstproc:
                Process.first_process = False

        if thread_id or self.suspended:
            log.debug("Using QueueUserAPC injection.")
        else:
            log.debug("Using CreateRemoteThread injection.")

        orig_bin_name = ""
        bit_str = ""
        if is_64bit:
            orig_bin_name = "loader_x64.exe"
            bit_str = "64-bit"
        else:
            orig_bin_name = "loader.exe"
            bit_str = "32-bit"

        bin_name = randomize_bin(os.path.join("bin", orig_bin_name), "exe")

        if os.path.exists(bin_name):
            ret = subprocess.call(
                [bin_name, "inject",
                 str(self.pid),
                 str(thread_id), dll])
            if ret != 0:
                if ret == 1:
                    log.info("Injected into suspended %s process with pid %d",
                             bit_str, self.pid)
                else:
                    log.error(
                        "Unable to inject into %s process with pid %d, error: %d",
                        bit_str, self.pid, ret)
                return False
            else:
                return True
        else:
            log.error(
                "Please place the %s binary from cuckoomon into analyzer/windows/bin in order to analyze %s binaries.",
                os.path.basename(bin_name), bit_str)
            return False
Exemplo n.º 11
0
 def __init__(self, options={}, analyzer=None):
     self.config = Config(cfg="analysis.conf")
     self.proc = None
Exemplo n.º 12
0
 def __init__(self):
     self.config = Config(cfg="analysis.conf")
     self.proc = None
Exemplo n.º 13
0
 def __init__(self):
     self.config = Config(cfg="analysis.conf")
     self.fallback_strace = False
Exemplo n.º 14
0
# Copyright (C) 2014-2016 Cuckoo Foundation.
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.

import logging
import os
import socket
import time
from pathlib import Path

from lib.core.config import Config

config = Config(cfg="analysis.conf")
log = logging.getLogger(__name__)

BUFSIZE = 1024 * 1024


def upload_to_host(file_path,
                   dump_path,
                   pids="",
                   ppids="",
                   metadata="",
                   category="",
                   duplicated=False):
    nc = None
    if not os.path.exists(file_path):
        log.warning("File %s doesn't exist anymore", file_path)
        return
    file_size = Path(file_path).stat().st_size
    log.info("File %s size is %d, Max size: %s", file_path, file_size,
Exemplo n.º 15
0
    def inject(self, dll=os.path.join("dll", "cuckoomon.dll"), apc=False):
        """Cuckoo DLL injection.
        @param dll: Cuckoo DLL path.
        @param apc: APC use.
        """
        if self.pid == 0:
            log.warning("No valid pid specified, injection aborted")
            return False

        if not self.is_alive():
            log.warning("The process with pid %d is not alive, injection "
                        "aborted" % self.pid)
            return False

        dll = randomize_dll(dll)

        if not dll or not os.path.exists(dll):
            log.warning("No valid DLL specified to be injected in process "
                        "with pid %d, injection aborted" % self.pid)
            return False

        arg = KERNEL32.VirtualAllocEx(self.h_process,
                                      None,
                                      len(dll) + 1,
                                      MEM_RESERVE | MEM_COMMIT,
                                      PAGE_READWRITE)

        if not arg:
            log.error("VirtualAllocEx failed when injecting process with "
                      "pid %d, injection aborted (Error: %s)"
                      % (self.pid, get_error_string(KERNEL32.GetLastError())))
            return False

        bytes_written = c_int(0)
        if not KERNEL32.WriteProcessMemory(self.h_process,
                                           arg,
                                           dll + "\x00",
                                           len(dll) + 1,
                                           byref(bytes_written)):
            log.error("WriteProcessMemory failed when injecting process "
                      "with pid %d, injection aborted (Error: %s)"
                      % (self.pid, get_error_string(KERNEL32.GetLastError())))
            return False

        kernel32_handle = KERNEL32.GetModuleHandleA("kernel32.dll")
        load_library = KERNEL32.GetProcAddress(kernel32_handle,
                                               "LoadLibraryA")

        config_path = os.path.join(os.getenv("TEMP"), "%s.ini" % self.pid)
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))
            config.write("results={0}\n".format(PATHS["root"]))
            config.write("analyzer={0}\n".format(os.getcwd()))
            config.write("first-process={0}\n".format(Process.first_process))

            Process.first_process = False

        if apc or self.suspended:
            log.info("Using QueueUserAPC injection")
            if not self.h_thread:
                log.info("No valid thread handle specified for injecting "
                         "process with pid %d, injection aborted" % self.pid)
                return False

            if not KERNEL32.QueueUserAPC(load_library, self.h_thread, arg):
                log.error("QueueUserAPC failed when injecting process "
                          "with pid %d (Error: %s)"
                          % (self.pid,
                             get_error_string(KERNEL32.GetLastError())))
                return False
            log.info("Successfully injected process with pid %d" % self.pid)
        else:
            event_name = "CuckooEvent%d" % self.pid
            self.event_handle = KERNEL32.CreateEventA(None,
                                                      False,
                                                      False,
                                                      event_name)
            if not self.event_handle:
                log.warning("Unable to create notify event..")
                return False

            log.info("Using CreateRemoteThread injection")
            new_thread_id = c_ulong(0)
            thread_handle = KERNEL32.CreateRemoteThread(self.h_process,
                                                        None,
                                                        0,
                                                        load_library,
                                                        arg,
                                                        0,
                                                        byref(new_thread_id))
            if not thread_handle:
                log.error("CreateRemoteThread failed when injecting " +
                    "process with pid %d (Error: %s)" % (self.pid,
                    get_error_string(KERNEL32.GetLastError())))
                KERNEL32.CloseHandle(self.event_handle)
                self.event_handle = None
                return False
            else:
                KERNEL32.CloseHandle(thread_handle)

        return True
Exemplo n.º 16
0
    def prepare(self):
        """Prepare env for analysis."""
        global DEFAULT_DLL
        global SERVICES_PID
        global HIDE_PIDS

        # Get SeDebugPrivilege for the Python process. It will be needed in
        # order to perform the injections.
        grant_debug_privilege()

        # randomize cuckoomon DLL and loader executable names
        copy("dll\\cuckoomon.dll", CUCKOOMON32_NAME)
        copy("dll\\cuckoomon_x64.dll", CUCKOOMON64_NAME)
        copy("bin\\loader.exe", LOADER32_NAME)
        copy("bin\\loader_x64.exe", LOADER64_NAME)

        # Create the folders used for storing the results.
        create_folders()

        add_protected_path(os.getcwd())
        add_protected_path(PATHS["root"])

        # Initialize logging.
        init_logging()

        # Parse the analysis configuration file generated by the agent.
        self.config = Config(cfg="analysis.conf")

        # Set virtual machine clock.
        clock = datetime.strptime(self.config.clock, "%Y%m%dT%H:%M:%S")
        # Setting date and time.
        # NOTE: Windows system has only localized commands with date format
        # following localization settings, so these commands for english date
        # format cannot work in other localizations.
        # In addition DATE and TIME commands are blocking if an incorrect
        # syntax is provided, so an echo trick is used to bypass the input
        # request and not block analysis.
        thedate = clock.strftime("%m-%d-%y")
        thetime = clock.strftime("%H:%M:%S")
        os.system("echo:|date {0}".format(thedate))
        os.system("echo:|time {0}".format(thetime))
        log.info("Date set to: {0}, time set to: {1}".format(thedate, thetime))

        # Set the default DLL to be used by the PipeHandler.
        DEFAULT_DLL = self.config.get_options().get("dll")

        # get PID for services.exe for monitoring services
        svcpid = self.pids_from_process_name_list(["services.exe"])
        if svcpid:
            SERVICES_PID = svcpid[0]

        protected_procname_list = [
            "vmwareuser.exe",
            "vmwareservice.exe",
            "vboxservice.exe",
            "vboxtray.exe",
            "sandboxiedcomlaunch.exe",
            "sandboxierpcss.exe",
            "procmon.exe",
            "regmon.exe",
            "filemon.exe",
            "wireshark.exe",
            "netmon.exe",
            "prl_tools_service.exe",
            "prl_tools.exe",
            "prl_cc.exe",
            "sharedintapp.exe",
            "vmtoolsd.exe",
            "vmsrvc.exe",
            "python.exe",
            "perl.exe",
        ]

        HIDE_PIDS = set(
            self.pids_from_process_name_list(protected_procname_list))

        # Initialize and start the Pipe Servers. This is going to be used for
        # communicating with the injected and monitored processes.
        for x in xrange(self.PIPE_SERVER_COUNT):
            self.pipes[x] = PipeServer(self.config)
            self.pipes[x].daemon = True
            self.pipes[x].start()

        # We update the target according to its category. If it's a file, then
        # we store the path.
        if self.config.category == "file":
            self.target = os.path.join(os.environ["TEMP"] + os.sep,
                                       str(self.config.file_name))
        # If it's a URL, well.. we store the URL.
        else:
            self.target = self.config.target
Exemplo n.º 17
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()

            # Debug, Regular, or Critical information from CuckooMon.
            if command.startswith("DEBUG:"):
                log.debug(command[6:])
            elif command.startswith("INFO:"):
                log.info(command[5:])
            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)

            # 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 data.count(",") == 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
Exemplo n.º 18
0
 def __init__(self, proto=""):
     config = Config(cfg="analysis.conf")
     self.hostip, self.hostport = config.ip, config.port
     self.sock = None
     self.proto = proto
     self.connected = False
Exemplo n.º 19
0
    def debug_inject(self,
                     dll=None,
                     interest=None,
                     childprocess=False,
                     nosleepskip=False):
        """CAPE DLL debugger injection.
        @param dll: CAPE DLL debugger path.
        @param interest: path to file of interest, handed to cuckoomon config
        """
        global LOGSERVER_POOL

        if not self.pid:
            log.warning("No valid pid specified, injection aborted")
            return False

        thread_id = 0
        if self.thread_id:
            thread_id = self.thread_id

        if not self.is_alive():
            log.warning(
                "The process with pid %s is not alive, "
                "injection aborted", self.pid)
            return False

        is_64bit = self.is_64bit()
        if not dll:
            log.debug("No debugger DLL has been specified for injection")
            if is_64bit:
                dll = CUCKOOMON64_NAME
            else:
                dll = CUCKOOMON32_NAME
        else:
            dll = os.path.join("dll", dll)

        log.info("DLL to inject is %s", dll)

        dll = os.path.join(os.getcwd(), dll)

        if not dll or not os.path.exists(dll):
            log.warning(
                "No valid DLL specified to be injected in process "
                "with pid %d, injection aborted.", self.pid)
            return False

        config_path = "C:\\%s.ini" % self.pid
        with open(config_path, "w") as config:
            cfg = Config("analysis.conf")
            cfgoptions = cfg.get_options()

            # start the logserver for this monitored process
            logserver_path = LOGSERVER_PREFIX + str(self.pid)
            if logserver_path not in LOGSERVER_POOL:
                LOGSERVER_POOL[logserver_path] = LogServer(
                    cfg.ip, cfg.port, logserver_path)

            Process.process_num += 1
            firstproc = Process.process_num == 1

            config.write("host-ip={0}\n".format(cfg.ip))
            config.write("host-port={0}\n".format(cfg.port))
            config.write("pipe={0}\n".format(PIPE))
            config.write("logserver={0}\n".format(logserver_path))
            config.write("results={0}\n".format(PATHS["root"]))
            config.write("analyzer={0}\n".format(os.getcwd()))
            config.write(
                "first-process={0}\n".format("1" if firstproc else "0"))
            config.write("startup-time={0}\n".format(Process.startup_time))
            config.write("file-of-interest={0}\n".format(interest))
            config.write("shutdown-mutex={0}\n".format(SHUTDOWN_MUTEX))
            config.write("terminate-event={0}{1}\n".format(
                TERMINATE_EVENT, self.pid))

            if nosleepskip or ("force-sleepskip" not in cfgoptions
                               and len(interest) > 2 and interest[1] != ':'
                               and interest[0] != '\\'
                               and Process.process_num <= 2):
                config.write("force-sleepskip=0\n")

            if "norefer" not in cfgoptions and "referrer" not in cfgoptions:
                config.write("referrer={0}\n".format(
                    get_referrer_url(interest)))

            simple_optnames = [
                "force-sleepskip",
                "full-logs",
                "force-flush",
                "no-stealth",
                "buffer-max",
                "large-buffer-max",
                "serial",
                "sysvol_ctimelow",
                "sysvol_ctimehigh",
                "sys32_ctimelow",
                "sys32_ctimehigh",
                "debug",
                "disable_hook_content",
                "hook-type",
                "exclude-apis",
                "exclude-dlls",
                "referrer",
            ]

            for optname in simple_optnames:
                if optname in cfgoptions:
                    config.write("{0}={1}\n".format(optname,
                                                    cfgoptions[optname]))
                    log.info("Option '%s' with value '%s' sent to monitor",
                             optname, cfgoptions[optname])

            if "procdump" in cfgoptions:
                config.write("procdump={0}\n".format(cfgoptions["procdump"]))
            if "import_reconstruction" in cfgoptions:
                config.write("import_reconstruction={0}\n".format(
                    cfgoptions["import_reconstruction"]))
            if "CAPE_var1" in cfgoptions:
                config.write("CAPE_var1={0}\n".format(cfgoptions["CAPE_var1"]))
            if "CAPE_var2" in cfgoptions:
                config.write("CAPE_var2={0}\n".format(cfgoptions["CAPE_var2"]))
            if "CAPE_var3" in cfgoptions:
                config.write("CAPE_var3={0}\n".format(cfgoptions["CAPE_var3"]))
            if "CAPE_var4" in cfgoptions:
                config.write("CAPE_var4={0}\n".format(cfgoptions["CAPE_var4"]))

        orig_bin_name = ""
        bit_str = ""
        if is_64bit:
            orig_bin_name = LOADER64_NAME
            bit_str = "64-bit"
        else:
            orig_bin_name = LOADER32_NAME
            bit_str = "32-bit"

        bin_name = os.path.join(os.getcwd(), orig_bin_name)

        if os.path.exists(bin_name) == False:
            log.error(
                "Please place the %s binary from cuckoomon into analyzer/windows/bin in order to debug %s binaries.",
                os.path.basename(bin_name), bit_str)
            return False
        else:
            if childprocess == False:
                ret = subprocess.call([
                    bin_name, "debug_load",
                    str(self.pid),
                    str(thread_id),
                    str(self.h_process),
                    str(self.h_thread), dll
                ])
            else:
                ret = subprocess.call([
                    bin_name, "debug",
                    str(self.pid),
                    str(thread_id),
                    str(self.h_process),
                    str(self.h_thread), dll
                ])
            if ret != 0:
                if ret == 1:
                    log.info(
                        "Injected debugger DLL into suspended %s process with pid %d",
                        bit_str, self.pid)
                else:
                    log.error(
                        "Unable to inject debugger DLL into %s process with pid %d, error: %d",
                        bit_str, self.pid, ret)
                return False
            else:
                return True