diff --git a/ChangeLog b/ChangeLog index 98e44ae12..9b108a1f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ This file details the changelog of Qiling Framework. - Added more Posix syscall - Bugfix: GDB server on MIPS binary - Major refactor of Windows DLL +- Add Win32 16bit compatibility file api ------------------------------------ diff --git a/qiling/os/windows/api.py b/qiling/os/windows/api.py index e7ba30b89..14a168d30 100644 --- a/qiling/os/windows/api.py +++ b/qiling/os/windows/api.py @@ -18,6 +18,7 @@ ACCESS_MASK = INT BOOLEAN = INT GROUP = INT +HFILE = INT OBJECT_INFORMATION_CLASS = INT PROCESSINFOCLASS = INT SOCKET = INT @@ -155,4 +156,4 @@ REFIID = POINTER REGSAM = POINTER UINT_PTR = POINTER -ULONG_PTR = POINTER \ No newline at end of file +ULONG_PTR = POINTER diff --git a/qiling/os/windows/const.py b/qiling/os/windows/const.py index c0ab7f746..486edb63e 100644 --- a/qiling/os/windows/const.py +++ b/qiling/os/windows/const.py @@ -687,3 +687,22 @@ # https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-sethandleinformation HANDLE_FLAG_INHERIT = 0x1 HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x2 + +# https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfile +OF_READ = 0x00000000 +OF_WRITE = 0x00000001 +OF_READWRITE = 0x00000002 +OF_PARSE = 0x00000100 +OF_DELETE = 0x00000200 +OF_VERIFY = 0x00000400 +OF_CANCEL = 0x00000800 +OF_CREATE = 0x00001000 +OF_PROMPT = 0x00002000 +OF_EXIST = 0x00004000 +OF_REOPEN = 0x00008000 + +OF_SHARE_COMPAT = 0x00000000 +OF_SHARE_EXCLUSIVE = 0x00000010 +OF_SHARE_DENY_WRITE = 0x00000020 +OF_SHARE_DENY_READ = 0x00000030 +OF_SHARE_DENY_NONE = 0x00000040 diff --git a/qiling/os/windows/dlls/kernel32/winbase.py b/qiling/os/windows/dlls/kernel32/winbase.py index 53922c9cb..fd58eabaf 100644 --- a/qiling/os/windows/dlls/kernel32/winbase.py +++ b/qiling/os/windows/dlls/kernel32/winbase.py @@ -3,6 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +import os import configparser from qiling import Qiling @@ -13,6 +14,142 @@ from qiling.os.windows.structs import OsVersionInfoExA from qiling.os.windows.utils import cmp +# HFILE _lclose( +# HFILE hFile +# ); +@winsdkapi(cc=STDCALL, params={ + 'hFile' : HFILE +}) +def hook__lclose(ql: Qiling, address: int, params): + fileno = params["hFile"] + + if fileno < 0: + return HFILE_ERROR + + os.close(fileno) + + return fileno + +# HFILE _lcreat( +# LPCSTR lpPathName, +# int iAttribute +# ); +@winsdkapi(cc=STDCALL, params={ + 'lpPathName' : LPCSTR, + 'iAttribute' : INT +}) +def hook__lcreat(ql: Qiling, address: int, params): + s_lpPathName = params["lpPathName"] + iAttribute = params["iAttribute"] + + # There are 4 access bits, we don't care about hidden or system + mode = "w+b" + if iAttribute & 2: + mode += "r+b" + + try: + f = ql.os.fs_mapper.open(s_lpPathName, mode) + except FileNotFoundError: + ql.os.last_error = ERROR_FILE_NOT_FOUND + return -1 + + # The file obj will be closed, dup the file handle to keep open + return os.dup(f.fileno()) + +# HFILE _lopen( +# LPCSTR lpPathName, +# int iReadWrite +# ); +@winsdkapi(cc=STDCALL, params={ + 'lpPathName' : LPCSTR, + 'iReadWrite' : INT +}) +def hook__lopen(ql: Qiling, address: int, params): + s_lpPathName = params["lpPathName"] + iReadWrite = params["iReadWrite"] + + # access mask DesiredAccess + mode = "" + if iReadWrite & (OF_WRITE | OF_READWRITE): + mode += "wb" + else: + mode += "r" + + try: + f = ql.os.fs_mapper.open(s_lpPathName, mode) + except FileNotFoundError: + ql.os.last_error = ERROR_FILE_NOT_FOUND + return -1 + + # The file obj will be closed, dup the file handle to keep open + return os.dup(f.fileno()) + +# UINT _lread( +# HFILE hFile, +# LPVOID lpBuffer, +# UINT uBytes +# ); +@winsdkapi(cc=STDCALL, params={ + 'hFile' : HFILE, + 'lpBuffer' : LPVOID, + 'uBytes' : UINT +}) +def hook__lread(ql: Qiling, address: int, params): + fileno = params["hFile"] + lpBuffer = params["lpBuffer"] + uBytes = params["uBytes"] + + if fileno < 0: + return HFILE_ERROR + + data = os.read(fileno, uBytes) + ql.mem.write(lpBuffer, data) + + return len(data) + +# LONG _llseek( +# HFILE hFile, +# LONG lOffset, +# int iOrigin +# ); +@winsdkapi(cc=STDCALL, params={ + 'hFile' : HFILE, + 'lOffset' : LONG, + 'iOrigin' : INT +}) +def hook__llseek(ql: Qiling, address: int, params): + fileno = params["hFile"] + lOffset = params["lOffset"] + iOrigin = params["iOrigin"] + + if fileno < 0: + return HFILE_ERROR + + return os.lseek(fileno, lOffset, iOrigin) + +# UINT _lwrite( +# HFILE hFile, +# LPCCH lpBuffer, +# UINT uBytes +# ); +@winsdkapi(cc=STDCALL, params={ + 'hFile' : HFILE, + 'lpBuffer' : LPCCH, + 'uBytes' : UINT +}) +def hook__lwrite(ql: Qiling, address: int, params): + fileno = params["hFile"] + lpBuffer = params["lpBuffer"] + uBytes = params["uBytes"] + + if fileno < 0: + return HFILE_ERROR + + wbuf = ql.mem.read(lpBuffer, uBytes) + len = os.write(fileno, wbuf) + + return len + # __analysis_noreturn VOID FatalExit( # int ExitCode # );