def hook_CreateThread(ql: Qiling, address: int, params): CREATE_SUSPENDED = 0x00000004 lpThreadAttributes = params["lpThreadAttributes"] dwStackSize = params["dwStackSize"] lpStartAddress = params["lpStartAddress"] lpParameter = params["lpParameter"] dwCreationFlags = params["dwCreationFlags"] lpThreadId = params["lpThreadId"] # new thread obj new_thread = QlWindowsThread(ql) if dwCreationFlags & CREATE_SUSPENDED == CREATE_SUSPENDED: thread_status = QlWindowsThread.READY else: thread_status = QlWindowsThread.RUNNING # create new thread thread_id = new_thread.create(lpStartAddress, lpParameter, thread_status) # append the new thread to ThreadManager ql.os.thread_manager.append(new_thread) # create thread handle new_handle = Handle(obj=new_thread) ql.os.handle_manager.append(new_handle) # set lpThreadId # FIXME: Temporary fix for the crash # if lpThreadId != 0: # ql.mem.write_ptr(lpThreadId, thread_id) # set thread handle return new_handle.id
def setup(ql): ql.heap = Heap(ql, ql.commos.HEAP_BASE_ADDR, ql.commos.HEAP_BASE_ADDR + ql.commos.HEAP_SIZE) ql.hook_mem_unmapped(ql_x86_windows_hook_mem_error) # setup gdt if ql.arch == QL_X86: ql_x86_setup_gdt_segment_fs(ql, FS_SEGMENT_ADDR, FS_SEGMENT_SIZE) ql_x86_setup_gdt_segment_gs(ql, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE) ql_x86_setup_gdt_segment_ds(ql) ql_x86_setup_gdt_segment_cs(ql) ql_x86_setup_gdt_segment_ss(ql) elif ql.arch == QL_X8664: ql_x8664_set_gs(ql) # handle manager ql.handle_manager = HandleManager() # registry manger ql.registry_manager = RegistryManager(ql) # clipboard ql.clipboard = Clipboard(ql) # fibers ql.fiber_manager = FiberManager(ql) # Place to set errors for retrieval by GetLastError() # thread manager main_thread = Thread(ql) ql.thread_manager = ThreadManager(ql, main_thread) new_handle = Handle(thread=main_thread) ql.handle_manager.append(new_handle) # user configuration ql.config = ql_init_configuration(ql) # variables used inside hooks ql.hooks_variables = {}
def __CreateEvent(ql: Qiling, address: int, params): # Implementation seems similar enough to Mutex to just use it try: namespace, name = params["lpName"].split("\\") except ValueError: name = params["lpName"] namespace = "" handle = ql.os.handle_manager.search(name) if handle is not None: ql.os.last_error = ERROR_ALREADY_EXISTS # FIXME: fail with a nullptr? # return 0 else: mutex = Mutex(name, namespace) if params['bInitialState']: mutex.lock() handle = Handle(obj=mutex, name=name) ql.os.handle_manager.append(handle) # FIXME: shouldn't it be 'id' instead of 'ID'? return handle.ID
def _CreateFile(ql: Qiling, address: int, params): s_lpFileName = params["lpFileName"] dwDesiredAccess = params["dwDesiredAccess"] # dwShareMode = params["dwShareMode"] # lpSecurityAttributes = params["lpSecurityAttributes"] # dwCreationDisposition = params["dwCreationDisposition"] # dwFlagsAndAttributes = params["dwFlagsAndAttributes"] # hTemplateFile = params["hTemplateFile"] # access mask DesiredAccess mode = "" if dwDesiredAccess & GENERIC_WRITE: mode += "wb" else: mode += "rb" try: f = ql.os.fs_mapper.open(s_lpFileName, mode) except FileNotFoundError: ql.os.last_error = ERROR_FILE_NOT_FOUND return INVALID_HANDLE_VALUE new_handle = Handle(obj=f) ql.os.handle_manager.append(new_handle) return new_handle.id
def hook_MapViewOfFile(ql: Qiling, address: int, params): hFileMappingObject = params['hFileMappingObject'] dwFileOffsetLow = params['dwFileOffsetLow'] dwNumberOfBytesToMap = params['dwNumberOfBytesToMap'] map_file_handle = ql.os.handle_manager.search_by_obj(hFileMappingObject) if map_file_handle is None: ret = ql.os.heap.alloc(dwNumberOfBytesToMap) new_handle = Handle(obj=hFileMappingObject, name=ret) ql.os.handle_manager.append(new_handle) else: ret = map_file_handle.name hFile = ql.os.handle_manager.get(hFileMappingObject).obj if ql.os.handle_manager.get(hFile): f = ql.os.handle_manager.get(hFile).obj if type(f) is file: f.seek(dwFileOffsetLow, 0) data = f.read(dwNumberOfBytesToMap) ql.mem.write(ret, data) return ret
def hook_InitializeSListHead(ql: Qiling, address: int, params): ListHead = params["ListHead"] handle = Handle(obj=[], id=ListHead) ql.os.handle_manager.append(handle) return 0
def _CreateFileMapping(ql: Qiling, address: int, params): hFile = params['hFile'] lpName = params['lpName'] new_handle = Handle(obj=hFile, name=lpName) ql.os.handle_manager.append(new_handle) return new_handle.id
def hook_FindFirstFileA(ql: Qiling, address: int, params): filename = params['lpFileName'] pointer = params['lpFindFileData'] if filename == 0: return INVALID_HANDLE_VALUE elif len(filename) >= MAX_PATH: return ERROR_INVALID_PARAMETER target_dir = os.path.join(ql.rootfs, filename.replace("\\", os.sep)) ql.log.info('TARGET_DIR = %s' % target_dir) real_path = ql.os.path.transform_to_real_path(filename) # Verify the directory is in ql.rootfs to ensure no path traversal has taken place if not os.path.exists(real_path): ql.os.last_error = ERROR_FILE_NOT_FOUND return INVALID_HANDLE_VALUE # Check if path exists filesize = 0 try: f = ql.os.fs_mapper.open(real_path, "r") filesize = os.path.getsize(real_path) except FileNotFoundError: ql.os.last_error = ERROR_FILE_NOT_FOUND return INVALID_HANDLE_VALUE # Get size of the file file_size_low = filesize & 0xffffff file_size_high = filesize >> 32 # Create a handle for the path new_handle = Handle(obj=f) ql.os.handle_manager.append(new_handle) # Spoof filetime values filetime = ql.pack64(datetime.now().microsecond) find_data = Win32FindData( ql, FILE_ATTRIBUTE_NORMAL, filetime, filetime, filetime, file_size_high, file_size_low, 0, 0, filename, 0, 0, 0, 0, ) find_data.write(pointer) return new_handle.id
def hook__wfopen_s(ql: Qiling, address: int, params): dst = params["pFile"] filename = params["filename"] mode = params["mode"] f = ql.os.fs_mapper.open(filename, mode) new_handle = Handle(obj=f) ql.os.handle_manager.append(new_handle) ql.mem.write(dst, ql.pack(new_handle.id)) return 1
def hook_OpenThreadToken(ql: Qiling, address: int, params): token_pointer = params["TokenHandle"] token = Token(ql) new_handle = Handle(obj=token) ql.os.handle_manager.append(new_handle) ql.mem.write_ptr(token_pointer, new_handle.id) return 1
def hook_OpenProcessToken(ql: Qiling, address: int, params): token_pointer = params["TokenHandle"] token = Token(ql) new_handle = Handle(obj=token) ql.os.handle_manager.append(new_handle) ql.mem.write(token_pointer, ql.pack(new_handle.id)) return 1
def _ShellExecute(ql: Qiling, obj: ShellExecuteInfoA): def __wstr(shellex: Sequence): return ql.os.utils.read_wstring(shellex[0]) if shellex[0] else '' ql.log.debug(f'Target executed a shell command!') ql.log.debug(f' | Operation : "{__wstr(obj.verb)}"') ql.log.debug(f' | Parameters : "{__wstr(obj.params)}"') ql.log.debug(f' | File : "{__wstr(obj.file)}"') ql.log.debug(f' | Directory : "{__wstr(obj.dir)}"') if obj.show[0] == SW_HIDE: ql.log.debug(" | With an hidden window") process = QlWindowsThread(ql, status=0, isFake=True) handle = Handle(obj=process) ql.os.handle_manager.append(handle) return handle
def __CreateMutex(ql: Qiling, address: int, params): try: _type, name = params["lpName"].split("\\") except ValueError: name = params["lpName"] _type = "" handle = ql.os.handle_manager.search(name) if handle is not None: # ql.os.last_error = ERROR_ALREADY_EXISTS return 0 owning = params["bInitialOwner"] mutex = Mutex(name, _type) if owning: mutex.lock() handle = Handle(obj=mutex, name=name) ql.os.handle_manager.append(handle) return handle.id
def hook_GetConsoleWindow(ql: Qiling, address: int, params): handle = Handle(name="console_window") ql.os.handle_manager.append(handle) return handle.id