def invoke(self, ctlcode, value, outlength=0x1000): device_handle = KERNEL32.CreateFileA( "\\\\.\\%s" % self.pipepath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None) % 2**32 if device_handle == 0xffffffff: # Only report an error if the error is not "name not found", # indicating that no kernel analysis is currently taking place. if KERNEL32.GetLastError() != 2: log.warning("Error opening handle to driver (%s): %d!", driver_name, KERNEL32.GetLastError()) return False out = ctypes.create_string_buffer(outlength) length = ctypes.c_uint() ret = KERNEL32.DeviceIoControl(device_handle, ctlcode, value, len(value), out, ctypes.sizeof(out), ctypes.byref(length), None) KERNEL32.CloseHandle(device_handle) if not ret: log.warning("Error performing ioctl (0x%08x): %d!", ctlcode, KERNEL32.GetLastError()) return False return out.raw[:length.value]
def add_tracked_pid(self, pid): #Initiate driver's state and communication mecanisms BytesReturned = DWORD(0) pid = DWORD(pid) success = KERNEL32.DeviceIoControl(self.hdevice, IOCTL_ADD_TRACKED, ctypes.byref(pid), ctypes.sizeof(pid), NULL, 0, ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed")
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 = service_name = driver_name = random_string(6) inf_data = ('[Version]\r\n' 'Signature = "$Windows NT$"\r\n' 'Class = "ActivityMonitor"\r\n' 'ClassGuid = {{b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}}\r\n' 'Provider = %Prov%\r\n' 'DriverVer = 22/01/2014,1.0.0.0\r\n' 'CatalogFile = %DriverName%.cat\r\n' '[DestinationDirs]\r\n' 'DefaultDestDir = 12\r\n' 'MiniFilter.DriverFiles = 12\r\n' '[DefaultInstall]\r\n' 'OptionDesc = %ServiceDescription%\r\n' 'CopyFiles = MiniFilter.DriverFiles\r\n' '[DefaultInstall.Services]\r\n' \ 'AddService = %ServiceName%,,MiniFilter.Service\r\n' '[DefaultUninstall]\r\n' 'DelFiles = MiniFilter.DriverFiles\r\n' '[DefaultUninstall.Services]\r\n' 'DelService = %ServiceName%,0x200\r\n' '[MiniFilter.Service]\r\n' 'DisplayName = %ServiceName%\r\n' 'Description = %ServiceDescription%\r\n' 'ServiceBinary = %12%\\%DriverName%.sys\r\n' 'Dependencies = "FltMgr"\r\n' 'ServiceType = 2\r\n' 'StartType = 3\r\n' 'ErrorControl = 1\r\n' 'LoadOrderGroup = "FSFilter Activity Monitor"\r\n' 'AddReg = MiniFilter.AddRegistry\r\n' '[MiniFilter.AddRegistry]\r\n' 'HKR,,"DebugFlags",0x00010001 ,0x0\r\n' 'HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%\r\n' 'HKR,"Instances\\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%\r\n' 'HKR,"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\n' '1 = %DiskId1%,,,\r\n' '[Strings]\r\n' 'Prov = "{random_string8}"\r\n' 'ServiceDescription = "{random_string12}"\r\n' 'ServiceName = "{service_name}"\r\n' 'DriverName = "{driver_name}"\r\n' 'DiskId1 = "{service_name} Device Installation Disk"\r\n' 'DefaultInstance = "{service_name} Instance"\r\n' 'Instance1.Name = "{service_name} Instance"\r\n' 'Instance1.Altitude = "370050"\r\n' 'Instance1.Flags = 0x0' ).format( service_name=service_name, driver_name=driver_name, random_string8=random_string(8), random_string12=random_string(12) ) 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
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)
def pipe_reader_thread(self): evt_header = EVENT_HEADER() nbRead = DWORD(0) while (self.thread_running): valid_object = True #Wait for the driver to signal an event is ready for retrieval r = KERNEL32.WaitForSingleObject(self.UserlandNotidyEvent, INFINITE) if (r == WAIT_OBJECT_0): #An event has arrived, request it to the driver ReceiveBuffer = ctypes.create_string_buffer(1024) BytesReturned = DWORD(0) success = KERNEL32.DeviceIoControl( self.hdevice, IOCTL_RETRIEVE_EXCEPTION, NULL, 0, ctypes.byref(ReceiveBuffer), ctypes.sizeof(ReceiveBuffer), ctypes.byref(BytesReturned), 0) if not (success): self.log.error("DeviceIoControl failed") raise UnpackerException("DeviceIoControl failed") header_size = ctypes.sizeof(EVENT_HEADER) #Ensure there is a header if (BytesReturned.value < header_size): self.log.error( "Did not receive enough data from driver (%d bytes)" % BytesReturned.value) continue #Copy the data in a EVENT_HEADER object ctypes.memmove(ctypes.addressof(evt_header), ReceiveBuffer[0:header_size], header_size) #Ensure it is a known event if not (Events.has_key(evt_header.event_type)): self.log.error("Received unknown event with type : %d" % evt_header.event_type) continue #Ensure the object fits in the buffer n_remaining_bytes = BytesReturned.value - header_size event_class = Events[evt_header.event_type] if (n_remaining_bytes != ctypes.sizeof(event_class)): self.log.error( "Wrong event size. Received %d bytes, expected %d bytes" % (n_remaining_bytes, ctypes.sizeof(event_class))) continue event_obj = event_class() # "cast" the buffer in the appropriate event class ctypes.memmove(ctypes.addressof(event_obj), ReceiveBuffer[header_size:], ctypes.sizeof(event_class)) #call the user defined event handler result = self.event_handler(evt_header.event_type, event_obj) if (result == 0): self.stop() return