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 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
def run(self, waiting_time): # Open driver device self.hdevice = KERNEL32.CreateFileA(self.device_name, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None) if self.hdevice == INVALID_HANDLE_VALUE: self.log.error("CreateFileA failed with error : 0x%x" % KERNEL32.GetLastError()) quit() self.log.info("Driver device file opened, handle = %x" % self.hdevice) #todo : build command line self.process = Process(self.command_line, self.log) self.process.create_suspended() self.pre_run() self.log.info("Target process handle value is 0x%x" % self.process.process_handle) self.thread_running = True thread = Thread(target=self.pipe_reader_thread, args=()) #Create an unpack event which will be signaled when the self.hUnpackEvent = KERNEL32.CreateEventA(NULL, 0, 0, "DaEvent") self.UserlandNotidyEvent = KERNEL32.CreateEventA( NULL, 0, 0, "UserlandNotidyEvent") #Struct sent to the driver MyPidStruct = PID_STRUCT() MyPidStruct.do_log = self.kernel_log MyPidStruct.RWEPolicy = self.rwe_policy MyPidStruct.InitialNXState = self.initial_nx_state MyPidStruct.UserlandNotidyEvent = self.UserlandNotidyEvent MyPidStruct.TargetProcessHandle = self.process.process_handle #Initiate driver's state and communication mecanisms BytesReturned = DWORD(0) success = KERNEL32.DeviceIoControl(self.hdevice, IOCTL_SETUP_STUFF, ctypes.byref(MyPidStruct), ctypes.sizeof(MyPidStruct), NULL, 0, ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed") thread.start() #Resume main process thtread self.process.resume() self.log.info("Main thread resumed") #Wait for unpacking to terminate r = KERNEL32.WaitForSingleObject(self.hUnpackEvent, self.max_unpack_time) if (r == WAIT_ABANDONED): self.log.error("Wait abandoned, something went wrong") raise UnpackerException("Wait abandoned, something went wrong") if (r == WAIT_TIMEOUT): self.log.info("Wait timed out") self.log.info("Thread suspended") if (r == WAIT_OBJECT_0): self.log.info("Event signaled") BytesReturned = DWORD(0) success = KERNEL32.DeviceIoControl(self.hdevice, IOCTL_SUSPEND_TRACKED, NULL, 0, NULL, 0, ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed") self.thread_running = False result = self.post_treatment() BytesReturned = DWORD(0) success = KERNEL32.DeviceIoControl(self.hdevice, IOCTL_UNTRACK_AND_RESUME_PROCESSES, NULL, 0, NULL, 0, ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed") BytesReturned = DWORD(0) success = KERNEL32.DeviceIoControl(self.hdevice, IOCTL_CLEANUP, NULL, 0, NULL, 0, ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed") KERNEL32.CloseHandle(self.hdevice) KERNEL32.CloseHandle(self.UserlandNotidyEvent) self.process.terminate() KERNEL32.ExitProcess(0)