儲存庫 vbox 的更動 52403
- 時間撮記:
- 2014-8-18 下午08:35:32 (10 年 以前)
- 位置:
- trunk
- 檔案:
-
- 修改 14 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/include/iprt/ldr.h
r52213 r52403 1002 1002 RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, 1003 1003 1004 /** Number of import or needed modules. */ 1005 RTLDRPROP_IMPORT_COUNT, 1006 /** Import module by index (32-bit) stored in the buffer. */ 1007 RTLDRPROP_IMPORT_MODULE, 1008 1004 1009 /** End of valid properties. */ 1005 1010 RTLDRPROP_END, … … 1024 1029 * @param hLdrMod The module handle. 1025 1030 * @param enmLdrProp The property to query. 1026 * @param pvBuf Pointer to the return buffer. 1027 * @param cbBuf The size of the return buffer. 1031 * @param pvBuf Pointer to the input / output buffer. In most cases 1032 * it's only used for returning data. 1033 * @param cbBuf The size of the buffer. 1028 1034 */ 1029 1035 RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf); … … 1046 1052 * @param hLdrMod The module handle. 1047 1053 * @param enmLdrProp The property to query. 1048 * @param pvBuf Pointer to the return buffer. 1049 * @param cbBuf The size of the return buffer. 1054 * @param pvBits Optional pointer to bits returned by 1055 * RTLdrGetBits(). This can be utilized by some module 1056 * interpreters to reduce memory consumption and file 1057 * access. 1058 * @param pvBuf Pointer to the input / output buffer. In most cases 1059 * it's only used for returning data. 1060 * @param cbBuf The size of the buffer. 1050 1061 * @param pcbRet Where to return the amount of data returned. On 1051 1062 * buffer size errors, this is set to the correct size. 1052 1063 * Optional. 1053 1064 */ 1054 RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvB uf, size_t cbBuf, size_t *pcbBuf);1065 RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBits, void *pvBuf, size_t cbBuf, size_t *pcbBuf); 1055 1066 1056 1067 -
trunk/src/VBox/HostDrivers/Support/Makefile.kmk
r52373 r52403 204 204 205 205 if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of this move up. 206 SUPR3HardenedStatic_DEFS += IN_RT IN_RT_R3 IN_RT_STATIC IPRT_NO_CRT RT_WITH_NOCRT_ALIASES LOG_DISABLED IPRT_NO_ERROR_DATA 206 SUPR3HardenedStatic_DEFS += \ 207 IN_RT \ 208 IN_RT_R3 \ 209 IN_RT_STATIC \ 210 IN_DIS \ 211 DIS_CORE_ONLY \ 212 IPRT_NO_CRT \ 213 RT_WITH_NOCRT_ALIASES \ 214 LOG_DISABLED \ 215 IPRT_NO_ERROR_DATA 207 216 SUPR3HardenedStatic_DEFS.win += LDR_ONLY_PE __STRALIGN_H_ 208 217 … … 331 340 $(VBOX_PATH_RUNTIME_SRC)/generic/memsafer-generic.cpp \ 332 341 $(VBOX_PATH_RUNTIME_SRC)/generic/uuid-generic.cpp \ 342 \ 343 ../../Disassembler/DisasmCore.cpp \ 344 ../../Disassembler/DisasmTables.cpp \ 345 ../../Disassembler/DisasmTablesX64.cpp \ 346 ../../Disassembler/DisasmReg.cpp 333 347 334 348 SUPR3HardenedStatic_SOURCES.amd64 += \ -
trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
r52366 r52403 975 975 NULL, 976 976 OPEN_ALWAYS, 977 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,977 FILE_ATTRIBUTE_NORMAL /*| FILE_FLAG_WRITE_THROUGH*/, 978 978 NULL); 979 979 RTUtf16Free(pwszPath); -
trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
r52375 r52403 43 43 DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo); 44 44 DECLHIDDEN(void) supHardenedWinTermImageVerifier(void); 45 DECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PCRTUTF16 pwszName); 45 46 DECLHIDDEN(void) supR3HardenedWinVerifyCachePreload(PCRTUTF16 pwszName); 47 46 48 47 49 typedef enum SUPHARDNTVPKIND … … 83 85 /** Pointer to an SUP image verifier loader reader instance. */ 84 86 typedef SUPHNTVIRDR *PSUPHNTVIRDR; 85 DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr); 86 DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool *pfCacheable, PRTERRINFO pErrInfo); 87 DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo); 88 DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr, 89 bool *pfCacheable, PRTERRINFO pErrInfo); 87 DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr); 88 DECLHIDDEN(bool) supHardenedWinIsWinVerifyTrustCallable(void); 89 DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, 90 bool *pfWinVerifyTrust, PRTERRINFO pErrInfo); 91 DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo); 92 DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr, 93 bool *pfWinVerifyTrust, PRTERRINFO pErrInfo); 90 94 /** @name SUPHNTVI_F_XXX - Flags for supHardenedWinVerifyImageByHandle. 91 95 * @{ */ -
trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
r52376 r52403 173 173 /** Pointer to CryptCATCatalogInfoFromContext. */ 174 174 PFNCRYPTCATCATALOGINFOFROMCONTEXT g_pfnCryptCATCatalogInfoFromContext; 175 176 /** Indicates active WinVerifyTrust thread. */ 177 static uint32_t volatile g_idActiveThread = UINT32_MAX; 178 175 179 #endif 176 180 … … 957 961 * 958 962 * @returns IPRT status code. 959 * @param hLdrMod File handle to the executable file.960 * @param pwszName Full NT path to the DLL in question, used for dealing961 * with unsigned system dlls as well as for error/logging.962 * @param pNtViRdr The reader instance /w flags.963 * @param p fCacheable Where to return whether the result can be cached. A964 * valid value is always returned. Optional.965 * @param pErrInfo Pointer to error info structure. Optional.963 * @param hLdrMod File handle to the executable file. 964 * @param pwszName Full NT path to the DLL in question, used for 965 * dealing with unsigned system dlls as well as for 966 * error/logging. 967 * @param pNtViRdr The reader instance /w flags. 968 * @param pfWinVerifyTrust Where to return whether WinVerifyTrust was used. 969 * @param pErrInfo Pointer to error info structure. Optional. 966 970 */ 967 971 DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr, 968 bool *pfCacheable, PRTERRINFO pErrInfo) 969 { 972 bool *pfWinVerifyTrust, PRTERRINFO pErrInfo) 973 { 974 if (pfWinVerifyTrust) 975 *pfWinVerifyTrust = false; 976 970 977 #ifdef IN_RING3 971 978 /* Check that the caller has performed the necessary library initialization. */ … … 1047 1054 * Call the windows verify trust API if we've resolved it and aren't in 1048 1055 * some obvious recursion. Assumes the loader semaphore will reduce the 1049 * risk of concurrency here, so no TLS, only a single staticvariable.1056 * risk of concurrency here, so no TLS, only a single global variable. 1050 1057 */ 1051 1058 if (g_pfnWinVerifyTrust) 1052 1059 { 1053 static uint32_t volatile s_idActiveThread = UINT32_MAX;1054 1060 uint32_t const idCurrentThread = GetCurrentThreadId(); 1055 if ( s_idActiveThread != idCurrentThread)1061 if (g_idActiveThread != idCurrentThread) 1056 1062 { 1057 ASMAtomicCmpXchgU32(&s_idActiveThread, idCurrentThread, UINT32_MAX); 1058 1059 if (pfCacheable) 1060 *pfCacheable = g_pfnWinVerifyTrust != NULL; 1063 ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX); 1064 1065 if (pfWinVerifyTrust) 1066 *pfWinVerifyTrust = true; 1067 1061 1068 if (rc != VERR_LDRVI_NOT_SIGNED) 1062 1069 { … … 1091 1098 } 1092 1099 1093 ASMAtomicCmpXchgU32(& s_idActiveThread, UINT32_MAX, idCurrentThread);1100 ASMAtomicCmpXchgU32(&g_idActiveThread, UINT32_MAX, idCurrentThread); 1094 1101 } 1095 1102 else 1096 1103 SUP_DPRINTF(("Detected WinVerifyTrust recursion: rc=%Rrc '%ls'.\n", rc, pwszName)); 1097 1104 } 1098 #else /* !IN_RING3 */ 1099 if (pfCacheable) 1100 *pfCacheable = true; 1101 #endif /* !IN_RING3 */ 1105 #endif /* IN_RING3 */ 1106 1107 #ifdef IN_SUP_HARDENED_R3 1108 /* 1109 * Hook for the LdrLoadDll code to schedule scanning of imports. 1110 */ 1111 if (RT_SUCCESS(rc)) 1112 supR3HardenedWinVerifyCacheScheduleImports(hLdrMod, pwszName); 1113 #endif 1102 1114 1103 1115 return rc; … … 1109 1121 * 1110 1122 * @returns IPRT status code. 1111 * @param hFile File handle to the executable file.1112 * @param pwszName Full NT path to the DLL in question, used for dealing1113 * with unsigned system dlls as well as for error/logging.1114 * @param fFlags Flags, SUPHNTVI_F_XXX.1115 * @param pfCacheable Where to return whether the result can be cached. A1116 * valid value is always returned. Optional.1117 * @param pErrInfo Pointer to error info structure. Optional.1123 * @param hFile File handle to the executable file. 1124 * @param pwszName Full NT path to the DLL in question, used for 1125 * dealing with unsigned system dlls as well as for 1126 * error/logging. 1127 * @param fFlags Flags, SUPHNTVI_F_XXX. 1128 * @param pfWinVerifyTrust Where to return whether WinVerifyTrust was used. 1129 * @param pErrInfo Pointer to error info structure. Optional. 1118 1130 */ 1119 1131 DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, 1120 bool *pfCacheable, PRTERRINFO pErrInfo) 1121 { 1122 /* Clear the cacheable indicator as it needs to be valid in all return paths. */ 1123 if (pfCacheable) 1124 *pfCacheable = false; 1125 1132 bool *pfWinVerifyTrust, PRTERRINFO pErrInfo) 1133 { 1126 1134 /* 1127 1135 * Create a reader instance. … … 1144 1152 * Verify it. 1145 1153 */ 1146 rc = supHardenedWinVerifyImageByLdrMod(hLdrMod, pwszName, pNtViRdr, pf Cacheable, pErrInfo);1154 rc = supHardenedWinVerifyImageByLdrMod(hLdrMod, pwszName, pNtViRdr, pfWinVerifyTrust, pErrInfo); 1147 1155 int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2); 1148 1156 } … … 1150 1158 supHardNtViRdrDestroy(&pNtViRdr->Core); 1151 1159 } 1152 SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d %s(%ls)\n", rc, pfCacheable && *pfCacheable ? "cacheable ": "", pwszName)); 1160 SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d (%ls)%s\n", 1161 rc, pwszName, pfWinVerifyTrust && *pfWinVerifyTrust ? "WinVerifyTrust" : "")); 1153 1162 return rc; 1154 1163 } … … 1188 1197 uBuf.UniStr.Buffer = (WCHAR *)L"TODO3"; 1189 1198 1190 return supHardenedWinVerifyImageByHandle(hFile, uBuf.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pErrInfo); 1199 return supHardenedWinVerifyImageByHandle(hFile, uBuf.UniStr.Buffer, fFlags, NULL /*pfWinVerifyTrust*/, pErrInfo); 1200 } 1201 #endif /* IN_RING3 */ 1202 1203 1204 #ifdef IN_RING3 1205 /** 1206 * Checks if WinVerifyTrust is callable on the current thread. 1207 * 1208 * Used by the main code to figure whether it makes sense to try revalidate an 1209 * image that hasn't passed thru WinVerifyTrust yet. 1210 * 1211 * @returns true if callable on current thread, false if not. 1212 */ 1213 DECLHIDDEN(bool) supHardenedWinIsWinVerifyTrustCallable(void) 1214 { 1215 return g_pfnWinVerifyTrust != NULL 1216 && g_idActiveThread != GetCurrentThreadId(); 1191 1217 } 1192 1218 #endif /* IN_RING3 */ … … 1755 1781 { 1756 1782 WCHAR wszName[200+60]; 1757 UINT cwcDir = GetSystem WindowsDirectoryW(wszName, RT_ELEMENTS(wszName) - 60);1758 memcpy(&wszName[cwcDir], RT_STR_TUPLE(L"\\System32\\"));1759 RTUtf16CopyAscii(&wszName[cwcDir + sizeof("\\System32\\") -1], RT_ELEMENTS(wszName) - cwcDir, pszName);1783 UINT cwcDir = GetSystemDirectoryW(wszName, RT_ELEMENTS(wszName) - 60); 1784 wszName[cwcDir] = '\\'; 1785 RTUtf16CopyAscii(&wszName[cwcDir + 1], RT_ELEMENTS(wszName) - cwcDir, pszName); 1760 1786 1761 1787 DWORD fFlags = 0; … … 1944 1970 */ 1945 1971 supR3HardenedWinRetrieveTrustedRootCAs(); 1946 1947 # ifdef IN_SUP_HARDENED_R31948 /*1949 * Do some verify cache preloading. The MS Visual C++ CRT DLLs works1950 * around recursion issues with WinVerifyTrust on 32-bit windows 7.1951 */1952 SUP_DPRINTF(("preloading part 2...\n"));1953 # if 0 /* Seeing if this helps with the later Win7/32 issue... apparently not :-/ */1954 supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\cfgmgr32.dll");1955 supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\devobj.dll");1956 supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\setupapi.dll");1957 supR3HardenedWinLoadSystem32Dll("setupapi.dll");1958 supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\rsaenh.dll");1959 supR3HardenedWinLoadSystem32Dll("rsaenh.dll");1960 # endif1961 1962 WCHAR wszPath[260+16];1963 supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\apphelp.dll");1964 memcpy(wszPath, g_SupLibHardenedExeNtPath.UniStr.Buffer, g_SupLibHardenedExeNtPath.UniStr.Length);1965 static char const *s_apszAppDlls[] =1966 {1967 NULL,1968 "VBoxRT.dll",1969 # if _MSC_VER < 16001970 "msvcr90.dll", "msvcp90.dll",1971 # elif _MSC_VER < 17001972 "msvcr100.dll", "msvcp100.dll",1973 # elif _MSC_VER < 18001974 "msvcr110.dll", "msvcp110.dll",1975 # elif _MSC_VER < 19001976 "msvcr120.dll", "msvcp120.dll",1977 # elif _MSC_VER < 19001978 "msvcr130.dll", "msvcp130.dll",1979 # else1980 # error "Unsupported compiler version."1981 # endif1982 };1983 s_apszAppDlls[0] = pszProgName;1984 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszAppDlls); i++)1985 {1986 RTUtf16CopyAscii(&wszPath[g_offSupLibHardenedExeNtName], 300 - g_offSupLibHardenedExeNtName, s_apszAppDlls[i]);1987 supR3HardenedWinVerifyCachePreload(wszPath);1988 }1989 SUP_DPRINTF(("preloading part 2 - done.\n"));1990 # endif1991 1972 } 1992 1973 … … 2208 2189 */ 2209 2190 fTryNextPolicy = false; 2191 bool fFreshContext = false; 2210 2192 BOOL fRc; 2211 2193 HCATADMIN hCatAdmin = ASMAtomicXchgPtr(&s_aHashes[i].hCachedCatAdmin, NULL); 2212 2194 if (hCatAdmin) 2195 { 2196 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Cached context %p\n", hCatAdmin)); 2197 fFreshContext = false; 2213 2198 fRc = TRUE; 2214 else if (g_pfnCryptCATAdminAcquireContext2) 2215 fRc = g_pfnCryptCATAdminAcquireContext2(&hCatAdmin, &s_aPolicies[iPolicy], s_aHashes[i].pszAlgorithm, 2216 NULL /*pStrongHashPolicy*/, 0 /*dwFlags*/); 2199 } 2217 2200 else 2218 fRc = g_pfnCryptCATAdminAcquireContext(&hCatAdmin, &s_aPolicies[iPolicy], 0 /*dwFlags*/); 2201 { 2202 l_fresh_context: 2203 fFreshContext = true; 2204 if (g_pfnCryptCATAdminAcquireContext2) 2205 fRc = g_pfnCryptCATAdminAcquireContext2(&hCatAdmin, &s_aPolicies[iPolicy], s_aHashes[i].pszAlgorithm, 2206 NULL /*pStrongHashPolicy*/, 0 /*dwFlags*/); 2207 else 2208 fRc = g_pfnCryptCATAdminAcquireContext(&hCatAdmin, &s_aPolicies[iPolicy], 0 /*dwFlags*/); 2209 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: New context %p\n", hCatAdmin)); 2210 } 2219 2211 if (fRc) 2220 2212 { … … 2250 2242 if (!hCatInfo) 2251 2243 { 2244 if (!fFreshContext) 2245 { 2246 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", GetLastError(), iCat)); 2247 if (hCatInfoPrev != NULL) 2248 g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/); 2249 g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/); 2250 goto l_fresh_context; 2251 } 2252 2252 if (iCat == 0) 2253 2253 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", GetLastError())); … … 2305 2305 "WinVerifyTrust failed with hrc=%#x on '%ls' and .cat-file='%ls'.", 2306 2306 hrc, pwszWinPath, CatInfo.wszCatalogFile); 2307 fTryNextPolicy = (hrc == CERT_E_UNTRUSTEDROOT);2307 fTryNextPolicy |= (hrc == CERT_E_UNTRUSTEDROOT); 2308 2308 } 2309 2309 -
trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
r52373 r52403 823 823 */ 824 824 uint32_t cSkipAreas = 0; 825 SUPHNTVPSKIPAREA aSkipAreas[ 3];825 SUPHNTVPSKIPAREA aSkipAreas[4]; 826 826 if (pImage->fNtCreateSectionPatch) 827 827 { … … 834 834 return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc); 835 835 aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue; 836 aSkipAreas[cSkipAreas++].cb = 16; 836 aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64); 837 838 /* Ignore our LdrLoadDll hack. */ 839 rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrLoadDll", &uValue); 840 if (RT_FAILURE(rc)) 841 return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrLoadDll': %Rrc", pImage->pszName, rc); 842 aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue; 843 aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64); 837 844 } 838 845 … … 844 851 aSkipAreas[cSkipAreas++].cb = RT_MAX(pbBits[(uint32_t)uValue], 0x50); 845 852 } 853 854 Assert(cSkipAreas <= RT_ELEMENTS(aSkipAreas)); 846 855 } 847 856 … … 907 916 fProt = PAGE_EXECUTE; 908 917 break; 918 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: 919 /* Only the executable is allowed to have this section, 920 and it's protected after we're done patching. */ 921 if (!pImage->fDll) 922 { 923 if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION) 924 fProt = PAGE_EXECUTE_READWRITE; 925 else 926 fProt = PAGE_EXECUTE_READ; 927 break; 928 } 909 929 default: 910 930 return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS, … … 915 935 /* The section bits, only child purification verifies all bits . */ 916 936 if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION 917 || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) 937 || ( (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) 938 && !(pThis->aSecHdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE)) 918 939 || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ) 919 940 { … … 1500 1521 if (!pEntry->fVerified) 1501 1522 { 1502 rc = supHardenedWinVerifyImageByLdrMod(pEntry->hLdrMod, pwszName, pEntry->pNtViRdr, NULL /*pf Cacheable*/, pErrInfo);1523 rc = supHardenedWinVerifyImageByLdrMod(pEntry->hLdrMod, pwszName, pEntry->pNtViRdr, NULL /*pfWinVerifyTrust*/, pErrInfo); 1503 1524 pEntry->fVerified = RT_SUCCESS(rc); 1504 1525 } -
trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
r52375 r52403 41 41 #include <VBox/sup.h> 42 42 #include <VBox/err.h> 43 #include <VBox/dis.h> 43 44 #include <iprt/ctype.h> 44 45 #include <iprt/string.h> … … 125 126 /** Pointer to the next entry with the same hash value. */ 126 127 struct VERIFIERCACHEENTRY * volatile pNext; 128 /** Next entry in the WinVerifyTrust todo list. */ 129 struct VERIFIERCACHEENTRY * volatile pNextTodoWvt; 130 127 131 /** The file handle. */ 128 132 HANDLE hFile; … … 135 139 /** Whether IndexNumber is valid */ 136 140 bool fIndexNumberValid; 141 /** Whether verified by WinVerifyTrust. */ 142 bool volatile fWinVerifyTrust; 137 143 /** cwcPath * sizeof(RTUTF16). */ 138 144 uint16_t cbPath; … … 142 148 /** Pointer to an image verifier path entry. */ 143 149 typedef VERIFIERCACHEENTRY *PVERIFIERCACHEENTRY; 150 151 152 /** 153 * Name of an import DLL that we need to check out. 154 */ 155 typedef struct VERIFIERCACHEIMPORT 156 { 157 /** Pointer to the next DLL in the list. */ 158 struct VERIFIERCACHEIMPORT * volatile pNext; 159 /** The length of pwszAltSearchDir if available. */ 160 uint32_t cwcAltSearchDir; 161 /** This points the directory containing the DLL needing it, this will be 162 * NULL for a System32 DLL. */ 163 PWCHAR pwszAltSearchDir; 164 /** The name of the import DLL (variable length). */ 165 char szName[1]; 166 } VERIFIERCACHEIMPORT; 167 /** Pointer to a import DLL that needs checking out. */ 168 typedef VERIFIERCACHEIMPORT *PVERIFIERCACHEIMPORT; 144 169 145 170 … … 171 196 static NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, 172 197 PLARGE_INTEGER, ULONG, ULONG, HANDLE); 198 #if 0 199 /** The jump back address of the patched LdrLoadDll. */ 200 extern "C" PFNRT g_pfnLdrLoadDllJmpBack = NULL; 201 #endif 202 /** Pointer to the bit of assembly code that will perform the original 203 * LdrLoadDll operation. */ 204 static NTSTATUS (NTAPI * g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE); 173 205 /** The hash table of verifier cache . */ 174 206 static VERIFIERCACHEENTRY * volatile g_apVerifierCache[128]; 207 /** Queue of cached images which needs WinVerifyTrust to check them. */ 208 static VERIFIERCACHEENTRY * volatile g_pVerifierCacheTodoWvt = NULL; 209 /** Queue of cached images which needs their imports checked. */ 210 static VERIFIERCACHEIMPORT * volatile g_pVerifierCacheTodoImports = NULL; 175 211 /** @ */ 176 212 177 213 /** Static error info structure used during init. */ 178 214 static RTERRINFOSTATIC g_ErrInfoStatic; 215 216 /** In the assembly file. */ 217 extern "C" uint8_t g_abSupHardReadWriteExecPage[PAGE_SIZE]; 179 218 180 219 … … 182 221 * Internal Functions * 183 222 *******************************************************************************/ 223 static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect, 224 bool *pfCallRealApi, const char *pszCaller); 225 184 226 #ifdef RT_ARCH_AMD64 185 227 # define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void) … … 351 393 352 394 /** 353 * Calculates the hash value for the given UTF-16 string.395 * Calculates the hash value for the given UTF-16 path string. 354 396 * 355 397 * @returns Hash value. … … 365 407 { 366 408 RTUTF16 wc = *pwc++; 409 if (wc < 0x80) 410 wc = wc != '/' ? RT_C_TO_LOWER(wc) : '\\'; 367 411 uHash = wc + (uHash << 6) + (uHash << 16) - uHash; 368 412 } 369 413 return uHash; 370 414 } 415 416 417 /** 418 * Calculates the hash value for a directory + filename combo as if they were 419 * one single string. 420 * 421 * @returns Hash value. 422 * @param pawcDir The directory name. 423 * @param cwcDir The length of the directory name. RTSTR_MAX if 424 * not available. 425 * @param pszName The import name (UTF-8). 426 */ 427 static uint32_t supR3HardenedWinVerifyCacheHashDirAndFile(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName) 428 { 429 uint32_t uHash = 0; 430 while (cwcDir-- > 0) 431 { 432 RTUTF16 wc = *pawcDir++; 433 if (wc < 0x80) 434 wc = wc != '/' ? RT_C_TO_LOWER(wc) : '\\'; 435 uHash = wc + (uHash << 6) + (uHash << 16) - uHash; 436 } 437 438 unsigned char ch = '\\'; 439 uHash = ch + (uHash << 6) + (uHash << 16) - uHash; 440 441 while ((ch = *pszName++) != '\0') 442 { 443 ch = RT_C_TO_LOWER(ch); 444 uHash = ch + (uHash << 6) + (uHash << 16) - uHash; 445 } 446 447 return uHash; 448 } 449 450 451 /** 452 * Verify string cache compare function. 453 * 454 * @returns true if the strings match, false if not. 455 * @param pawcLeft The left hand string. 456 * @param pawcRight The right hand string. 457 * @param cwcToCompare The number of chars to compare. 458 */ 459 static bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 pawcRight, uint32_t cwcToCompare) 460 { 461 /* Try a quick memory compare first. */ 462 if (memcmp(pawcLeft, pawcRight, cwcToCompare * sizeof(RTUTF16)) == 0) 463 return true; 464 465 /* Slow char by char compare. */ 466 while (cwcToCompare-- > 0) 467 { 468 RTUTF16 wcLeft = *pawcLeft++; 469 RTUTF16 wcRight = *pawcRight++; 470 if (wcLeft != wcRight) 471 { 472 wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\'; 473 wcLeft = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\'; 474 if (wcLeft != wcRight) 475 return false; 476 } 477 } 478 479 return true; 480 } 481 371 482 372 483 … … 378 489 * the cache or closed. 379 490 * @param rc The verifier result. 380 * @param fCacheable Whether this is a cacheable result. Passed in 381 * here instead of being handled by the caller to 382 * save code duplication. 383 * @param fForceCacheable Overrides the main state and @a fCacheable. 384 */ 385 static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc, bool fCacheable, 386 bool fForceCacheable) 387 { 388 /* 389 * Don't cache anything until we've got the WinVerifyTrust API up and running. 390 */ 391 if ( ( g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY 392 && fCacheable) 393 || fForceCacheable) 394 { 491 * @param fWinVerifyTrust Whether verified by WinVerifyTrust or not. 492 */ 493 static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc, bool fWinVerifyTrust) 494 { 495 /* 496 * Allocate and initalize a new entry. 497 */ 498 PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 499 sizeof(VERIFIERCACHEENTRY) + pUniStr->Length); 500 if (pEntry) 501 { 502 pEntry->pNext = NULL; 503 pEntry->pNextTodoWvt = NULL; 504 pEntry->hFile = hFile; 505 pEntry->rc = rc; 506 pEntry->uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr); 507 pEntry->fWinVerifyTrust = fWinVerifyTrust; 508 pEntry->cbPath = pUniStr->Length; 509 memcpy(pEntry->wszPath, pUniStr->Buffer, pUniStr->Length); 510 pEntry->wszPath[pUniStr->Length / sizeof(WCHAR)] = '\0'; 511 pEntry->fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &pEntry->IndexNumber); 512 395 513 /* 396 * Allocate and initalize a new entry.514 * Try insert it, careful with concurrent code as well as potential duplicates. 397 515 */ 398 PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 399 sizeof(VERIFIERCACHEENTRY) + pUniStr->Length); 400 if (pEntry) 401 { 402 pEntry->pNext = NULL; 403 pEntry->hFile = hFile; 404 pEntry->rc = rc; 405 pEntry->uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr); 406 pEntry->cbPath = pUniStr->Length; 407 memcpy(pEntry->wszPath, pUniStr->Buffer, pUniStr->Length); 408 pEntry->wszPath[pUniStr->Length / sizeof(WCHAR)] = '\0'; 409 pEntry->fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &pEntry->IndexNumber); 410 411 /* 412 * Try insert it, careful with concurrent code as well as potential duplicates. 413 */ 414 uint32_t iHashTab = pEntry->uHash % RT_ELEMENTS(g_apVerifierCache); 415 VERIFIERCACHEENTRY * volatile *ppEntry = &g_apVerifierCache[iHashTab]; 416 for (;;) 516 uint32_t iHashTab = pEntry->uHash % RT_ELEMENTS(g_apVerifierCache); 517 VERIFIERCACHEENTRY * volatile *ppEntry = &g_apVerifierCache[iHashTab]; 518 for (;;) 519 { 520 if (ASMAtomicCmpXchgPtr(ppEntry, pEntry, NULL)) 417 521 { 418 if (ASMAtomicCmpXchgPtr(ppEntry, pEntry, NULL)) 419 { 420 SUP_DPRINTF(("supR3HardenedWinVerifyCacheInsert: %ls\n", pUniStr->Buffer)); 421 return; 422 } 423 424 PVERIFIERCACHEENTRY pOther = *ppEntry; 425 if (!pOther) 426 continue; 427 if ( pOther->uHash == pEntry->uHash 428 && pOther->cbPath == pEntry->cbPath 429 && memcmp(pOther->wszPath, pEntry->wszPath, pEntry->cbPath) == 0) 430 break; 431 ppEntry = &pOther->pNext; 522 if (!fWinVerifyTrust) 523 do 524 pEntry->pNextTodoWvt = g_pVerifierCacheTodoWvt; 525 while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoWvt, pEntry, pEntry->pNextTodoWvt)); 526 527 SUP_DPRINTF(("supR3HardenedWinVerifyCacheInsert: %ls\n", pUniStr->Buffer)); 528 return; 432 529 } 433 530 434 /* Duplicate entry. */ 531 PVERIFIERCACHEENTRY pOther = *ppEntry; 532 if (!pOther) 533 continue; 534 if ( pOther->uHash == pEntry->uHash 535 && pOther->cbPath == pEntry->cbPath 536 && memcmp(pOther->wszPath, pEntry->wszPath, pEntry->cbPath) == 0) 537 break; 538 ppEntry = &pOther->pNext; 539 } 540 541 /* Duplicate entry. */ 435 542 #ifdef DEBUG_bird 436 543 __debugbreak(); 437 544 #endif 438 HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pEntry); 439 } 545 HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pEntry); 440 546 } 441 547 NtClose(hFile); … … 461 567 if ( pCur->uHash == uHash 462 568 && pCur->cbPath == cbPath 463 && memcmp(pCur->wszPath, pwszPath, cbPath) == 0)569 && supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pwszPath, cbPath / sizeof(RTUTF16))) 464 570 { 465 571 … … 478 584 } 479 585 return NULL; 586 } 587 588 589 /** 590 * Looks up an import DLL in the verifier hash table. 591 * 592 * @return Pointer to the entry on if found, NULL if not. 593 * @param pawcDir The directory name. 594 * @param cwcDir The length of the directory name. 595 * @param pszName The import name (UTF-8). 596 */ 597 static PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookupImport(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName) 598 { 599 uint32_t uHash = supR3HardenedWinVerifyCacheHashDirAndFile(pawcDir, cwcDir, pszName); 600 uint32_t iHashTab = uHash % RT_ELEMENTS(g_apVerifierCache); 601 uint32_t const cbPath = (uint32_t)((cwcDir + 1 + strlen(pszName)) * sizeof(RTUTF16)); 602 PVERIFIERCACHEENTRY pCur = g_apVerifierCache[iHashTab]; 603 while (pCur) 604 { 605 if ( pCur->uHash == uHash 606 && pCur->cbPath == cbPath) 607 { 608 if (supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pawcDir, cwcDir)) 609 { 610 if (pCur->wszPath[cwcDir] == '\\' || pCur->wszPath[cwcDir] == '/') 611 { 612 if (RTUtf16ICmpAscii(&pCur->wszPath[cwcDir + 1], pszName)) 613 { 614 return pCur; 615 } 616 } 617 } 618 } 619 620 pCur = pCur->pNext; 621 } 622 return NULL; 623 } 624 625 626 /** 627 * Schedules the import DLLs for verification and entry into the cache. 628 * 629 * @param hLdrMod The loader module which imports should be 630 * scheduled for verification. 631 * @param pwszName The full NT path of the module. 632 */ 633 DECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PCRTUTF16 pwszName) 634 { 635 /* 636 * Any imports? 637 */ 638 uint32_t cImports; 639 int rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_COUNT, NULL /*pvBits*/, &cImports, sizeof(cImports), NULL); 640 if (RT_SUCCESS(rc)) 641 { 642 if (cImports) 643 { 644 /* 645 * Figure out the DLL directory from pwszName. 646 */ 647 PCRTUTF16 pawcDir = pwszName; 648 uint32_t cwcDir = 0; 649 uint32_t i = 0; 650 RTUTF16 wc; 651 while ((wc = pawcDir[i++]) != '\0') 652 if ((wc == '\\' || wc == '/' || wc == ':') && cwcDir + 2 != i) 653 cwcDir = i - 1; 654 if ( g_System32NtPath.UniStr.Length / sizeof(WCHAR) == cwcDir 655 && supR3HardenedWinVerifyCacheIsMatch(pawcDir, g_System32NtPath.UniStr.Buffer, cwcDir)) 656 pawcDir = NULL; 657 658 /* 659 * Enumerate the imports. 660 */ 661 for (i = 0; i < cImports; i++) 662 { 663 union 664 { 665 char szName[256]; 666 uint32_t iImport; 667 } uBuf; 668 uBuf.iImport = i; 669 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_MODULE, NULL /*pvBits*/, &uBuf, sizeof(uBuf), NULL); 670 if (RT_SUCCESS(rc)) 671 { 672 /* 673 * Skip kernel32, ntdll and API set stuff. 674 */ 675 RTStrToLower(uBuf.szName); 676 if ( RTStrCmp(uBuf.szName, "kernel32.dll") == 0 677 || RTStrCmp(uBuf.szName, "kernelbase.dll") == 0 678 || RTStrCmp(uBuf.szName, "ntdll.dll") == 0 679 || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("api-ms-win-")) == 0 ) 680 { 681 continue; 682 } 683 684 /* 685 * Skip to the next one if it's already in the cache. 686 */ 687 if (supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer, 688 g_System32NtPath.UniStr.Length / sizeof(WCHAR), 689 uBuf.szName) != NULL) 690 { 691 SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for system32\n", uBuf.szName)); 692 continue; 693 } 694 if (supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer, 695 g_offSupLibHardenedExeNtName, 696 uBuf.szName) != NULL) 697 { 698 SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for appdir\n", uBuf.szName)); 699 continue; 700 } 701 if (pawcDir && supR3HardenedWinVerifyCacheLookupImport(pawcDir, cwcDir, uBuf.szName) != NULL) 702 { 703 SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for dll dir\n", uBuf.szName)); 704 continue; 705 } 706 707 /* We could skip already scheduled modules, but that'll require serialization and extra work... */ 708 709 /* 710 * Add it to the todo list. 711 */ 712 SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: Import todo: #%u '%s'.\n", i, uBuf.szName)); 713 uint32_t cbName = (uint32_t)strlen(uBuf.szName) + 1; 714 uint32_t cbNameAligned = RT_ALIGN_32(cbName, sizeof(RTUTF16)); 715 uint32_t cbNeeded = RT_OFFSETOF(VERIFIERCACHEIMPORT, szName[cbNameAligned]) 716 + (pawcDir ? (cwcDir + 1) * sizeof(RTUTF16) : 0); 717 PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeeded); 718 if (pImport) 719 { 720 /* Init it. */ 721 memcpy(pImport->szName, uBuf.szName, cbName); 722 if (!pawcDir) 723 { 724 pImport->cwcAltSearchDir = 0; 725 pImport->pwszAltSearchDir = NULL; 726 } 727 else 728 { 729 pImport->cwcAltSearchDir = cwcDir; 730 pImport->pwszAltSearchDir = (PRTUTF16)&pImport->szName[cbNameAligned]; 731 memcpy(pImport->pwszAltSearchDir, pawcDir, cwcDir * sizeof(RTUTF16)); 732 pImport->pwszAltSearchDir[cwcDir] = '\0'; 733 } 734 735 /* Insert it. */ 736 do 737 pImport->pNext = g_pVerifierCacheTodoImports; 738 while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoImports, pImport, pImport->pNext)); 739 } 740 } 741 else 742 SUP_DPRINTF(("RTLDRPROP_IMPORT_MODULE failed with rc=%Rrc i=%#x on '%ls'\n", rc, i, pwszName)); 743 } 744 } 745 else 746 SUP_DPRINTF(("'%ls' has no imports\n", pwszName)); 747 } 748 else 749 SUP_DPRINTF(("RTLDRPROP_IMPORT_COUNT failed with rc=%Rrc on '%ls'\n", rc, pwszName)); 750 } 751 752 753 /** 754 * Processes the list of import todos. 755 */ 756 static void supR3HardenedWinVerifyCacheProcessImportTodos(void) 757 { 758 /* 759 * Work until we've got nothing more todo. 760 */ 761 for (;;) 762 { 763 PVERIFIERCACHEIMPORT pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoImports, NULL, PVERIFIERCACHEIMPORT); 764 if (!pTodo) 765 break; 766 do 767 { 768 PVERIFIERCACHEIMPORT pCur = pTodo; 769 pTodo = pTodo->pNext; 770 771 /* 772 * Not in the cached already? 773 */ 774 if ( !supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer, 775 g_System32NtPath.UniStr.Length / sizeof(WCHAR), 776 pCur->szName) 777 && !supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer, 778 g_offSupLibHardenedExeNtName, 779 pCur->szName) 780 && ( pCur->cwcAltSearchDir == 0 781 || !supR3HardenedWinVerifyCacheLookupImport(pCur->pwszAltSearchDir, pCur->cwcAltSearchDir, pCur->szName)) ) 782 { 783 /* 784 * Try locate the imported DLL and open it. 785 */ 786 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Processing '%s'...\n", pCur->szName)); 787 788 NTSTATUS rcNt; 789 HANDLE hFile = INVALID_HANDLE_VALUE; 790 RTUTF16 wszPath[260 + 260]; /* Assumes we've limited the import name length to 256. */ 791 AssertCompile(sizeof(wszPath) > sizeof(g_System32NtPath)); 792 struct 793 { 794 PRTUTF16 pawcDir; 795 uint32_t cwcDir; 796 } Tmp, aDirs[] = 797 { 798 { g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR) }, 799 { g_SupLibHardenedExeNtPath.UniStr.Buffer, g_offSupLibHardenedExeNtName - 1 }, 800 { pCur->pwszAltSearchDir, pCur->cwcAltSearchDir }, 801 }; 802 803 /* Search System32 first, unless it's a 'V*' or 'm*' name, the latter for msvcrt. */ 804 if ( pCur->szName[0] == 'v' 805 || pCur->szName[0] == 'V' 806 || pCur->szName[0] == 'm' 807 || pCur->szName[0] == 'M') 808 { 809 Tmp = aDirs[0]; 810 aDirs[0] = aDirs[1]; 811 aDirs[1] = Tmp; 812 } 813 814 for (uint32_t i = 0; i < RT_ELEMENTS(aDirs); i++) 815 { 816 if (aDirs[i].pawcDir && aDirs[i].cwcDir && aDirs[i].cwcDir < RT_ELEMENTS(wszPath) / 3 * 2) 817 { 818 memcpy(wszPath, aDirs[i].pawcDir, aDirs[i].cwcDir * sizeof(RTUTF16)); 819 uint32_t cwc = aDirs[i].cwcDir; 820 wszPath[cwc++] = '\\'; 821 size_t cwcName = RT_ELEMENTS(wszPath) - cwc; 822 PRTUTF16 pwszName = &wszPath[cwc]; 823 int rc = RTStrToUtf16Ex(pCur->szName, RTSTR_MAX, &pwszName, cwcName, &cwcName); 824 if (RT_SUCCESS(rc)) 825 { 826 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; 827 UNICODE_STRING NtName; 828 NtName.Buffer = wszPath; 829 NtName.Length = (USHORT)((cwc + cwcName) * sizeof(WCHAR)); 830 NtName.MaximumLength = NtName.Length + sizeof(WCHAR); 831 OBJECT_ATTRIBUTES ObjAttr; 832 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/); 833 834 rcNt = NtCreateFile(&hFile, 835 FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE, 836 &ObjAttr, 837 &Ios, 838 NULL /* Allocation Size*/, 839 FILE_ATTRIBUTE_NORMAL, 840 FILE_SHARE_READ, 841 FILE_OPEN, 842 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 843 NULL /*EaBuffer*/, 844 0 /*EaLength*/); 845 if (NT_SUCCESS(rcNt)) 846 rcNt = Ios.Status; 847 if (NT_SUCCESS(rcNt)) 848 break; 849 hFile = INVALID_HANDLE_VALUE; 850 } 851 else 852 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex failed: %Rrc\n", rc)); 853 } 854 } 855 856 /* 857 * If we successfully opened it, verify it and cache the result. 858 */ 859 if (hFile != INVALID_HANDLE_VALUE) 860 { 861 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls'\n", pCur->szName, wszPath)); 862 863 ULONG fAccess = 0; 864 ULONG fProtect = 0; 865 bool fCallRealApi = false; 866 rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi, "Imports"); 867 NtClose(hFile); 868 } 869 else 870 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Failed to locate '%s'\n", pCur->szName)); 871 } 872 else 873 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName)); 874 875 HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pCur); 876 } while (pTodo); 877 } 480 878 } 481 879 … … 625 1023 626 1024 627 static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect, bool *pfCallRealApi,628 bool fForceCacheable)1025 static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect, 1026 bool *pfCallRealApi, const char *pszCaller) 629 1027 { 630 1028 *pfCallRealApi = false; … … 644 1042 if (!NT_SUCCESS(rcNt)) 645 1043 { 646 supR3HardenedError(VINF_SUCCESS, false, "NtCreateSection: NtQueryObject -> %#x (fImage=%d fProtect=%#x fAccess=%#x)\n", 647 fImage, *pfProtect, *pfAccess); 1044 supR3HardenedError(VINF_SUCCESS, false, 1045 "supR3HardenedScreenImage/%s: NtQueryObject -> %#x (fImage=%d fProtect=%#x fAccess=%#x)\n", 1046 pszCaller, fImage, *pfProtect, *pfAccess); 648 1047 return rcNt; 649 1048 } … … 659 1058 */ 660 1059 PVERIFIERCACHEENTRY pCacheHit = supR3HardenedWinVerifyCacheLookup(&uBuf.UniStr, hFile); 661 if (pCacheHit) 662 { 663 SUP_DPRINTF(("NtCreateSection: cache hit (%Rrc) on %ls\n", pCacheHit->rc, pCacheHit->wszPath)); 1060 if ( pCacheHit 1061 && ( pCacheHit->fWinVerifyTrust 1062 || RT_FAILURE(pCacheHit->rc) 1063 || g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY 1064 || !supHardenedWinIsWinVerifyTrustCallable() ) ) 1065 { 1066 SUP_DPRINTF(("supR3HardenedScreenImage/%s: cache hit (%Rrc) on %ls\n", pszCaller, pCacheHit->rc, pCacheHit->wszPath)); 664 1067 if (RT_SUCCESS(pCacheHit->rc)) 665 1068 { … … 667 1070 return STATUS_SUCCESS; 668 1071 } 669 supR3HardenedError(VINF_SUCCESS, false, "NtCreateSection: cached rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls\n", 670 pCacheHit->rc, fImage, *pfProtect, *pfAccess, uBuf.UniStr.Buffer); 1072 supR3HardenedError(VINF_SUCCESS, false, 1073 "supR3HardenedScreenImage/%s: cached rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls\n", 1074 pszCaller, pCacheHit->rc, fImage, *pfProtect, *pfAccess, uBuf.UniStr.Buffer); 671 1075 return STATUS_TRUST_FAILURE; 672 1076 } … … 708 1112 { 709 1113 supR3HardenedError(VINF_SUCCESS, false, 710 " NtCreateSection: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n",711 rcNt, hFile, uBuf.UniStr.Buffer);1114 "supR3HardenedScreenImage/%s: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n", 1115 pszCaller, rcNt, hFile, uBuf.UniStr.Buffer); 712 1116 return rcNt; 713 1117 } … … 722 1126 { 723 1127 supR3HardenedError(VINF_SUCCESS, false, 724 " NtCreateSection: Re-opened has different ID that input: %#llx vx %#llx (%ls)\n",725 rcNt, idMyFile.QuadPart, idInFile.QuadPart, uBuf.UniStr.Buffer);1128 "supR3HardenedScreenImage/%s: Re-opened has different ID that input: %#llx vx %#llx (%ls)\n", 1129 pszCaller, rcNt, idMyFile.QuadPart, idInFile.QuadPart, uBuf.UniStr.Buffer); 726 1130 NtClose(hMyFile); 727 1131 return STATUS_TRUST_FAILURE; … … 730 1134 else 731 1135 { 732 SUP_DPRINTF(("supR3Hardened Monitor_NtCreateSection: NtDuplicateObject -> %#x\n", rcNt));1136 SUP_DPRINTF(("supR3HardenedScreenImage/%s: NtDuplicateObject -> %#x\n", pszCaller, rcNt)); 733 1137 #ifdef DEBUG 734 1138 735 supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_NtCreateSection: NtDuplicateObject(,%#x,) failed: %#x\n", hFile, rcNt); 1139 supR3HardenedError(VINF_SUCCESS, false, 1140 "supR3HardenedScreenImage/%s: NtDuplicateObject(,%#x,) failed: %#x\n", pszCaller, hFile, rcNt); 736 1141 #endif 737 1142 hMyFile = hFile; … … 755 1160 * Drop all executable access to the mapping and let it continue. 756 1161 */ 757 SUP_DPRINTF(("supR3Hardened Monitor_NtCreateSection: Applying the drop-exec-kludge for '%ls'\n", uBuf.UniStr.Buffer));1162 SUP_DPRINTF(("supR3HardenedScreenImage/%s: Applying the drop-exec-kludge for '%ls'\n", pszCaller, uBuf.UniStr.Buffer)); 758 1163 if (*pfAccess & SECTION_MAP_EXECUTE) 759 1164 *pfAccess = (*pfAccess & ~SECTION_MAP_EXECUTE) | SECTION_MAP_READ; … … 821 1226 { 822 1227 supR3HardenedError(VINF_SUCCESS, false, 823 "supR3Hardened Monitor_NtCreateSection: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)",824 uBuf.UniStr.Buffer, fImage, *pfAccess, *pfProtect);1228 "supR3HardenedScreenImage/%s: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)", 1229 pszCaller, uBuf.UniStr.Buffer, fImage, *pfAccess, *pfProtect); 825 1230 if (hMyFile != hFile) 826 1231 NtClose(hMyFile); … … 835 1240 RTErrInfoInit(&ErrInfo, (char *)&uBuf.abBuffer[cbNameBuf], sizeof(uBuf) - cbNameBuf); 836 1241 837 bool f Cacheable = true;838 int rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, &f Cacheable, &ErrInfo);1242 bool fWinVerifyTrust = false; 1243 int rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, &fWinVerifyTrust, &ErrInfo); 839 1244 if (RT_FAILURE(rc)) 840 1245 { 841 1246 supR3HardenedError(VINF_SUCCESS, false, 842 "supR3Hardened Monitor_NtCreateSection: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n",843 rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg);1247 "supR3HardenedScreenImage/%s: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n", 1248 pszCaller, rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg); 844 1249 if (hMyFile != hFile) 845 1250 NtClose(hMyFile); 846 1251 return STATUS_TRUST_FAILURE; 847 1252 } 848 if (hMyFile != hFile) 849 supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fCacheable, fForceCacheable); 1253 1254 /* 1255 * Insert or update the cache. 1256 */ 1257 if (!pCacheHit) 1258 { 1259 if (hMyFile != hFile) 1260 supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fWinVerifyTrust); 1261 } 1262 else 1263 { 1264 if (fWinVerifyTrust) 1265 pCacheHit->fWinVerifyTrust = true; 1266 if (hMyFile != hFile) 1267 NtClose(hMyFile); 1268 } 850 1269 851 1270 *pfCallRealApi = true; … … 889 1308 if (!NT_SUCCESS(rcNt)) 890 1309 { 891 SUP_DPRINTF(("supR3HardenedWin PreScreenImage: Error %#x opening '%ls'.\n", rcNt, pwszName));1310 SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: Error %#x opening '%ls'.\n", rcNt, pwszName)); 892 1311 return; 893 1312 } … … 897 1316 bool fCallRealApi; 898 1317 //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: scanning %ls\n", pwszName)); 899 supR3HardenedScreenImage(hFile, false, &fAccess, &fProtect, &fCallRealApi, true /* fForceCacheable */);1318 supR3HardenedScreenImage(hFile, false, &fAccess, &fProtect, &fCallRealApi, "preload"); 900 1319 //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: done %ls\n", pwszName)); 901 1320 … … 930 1349 if (fImage || fExecMap || fExecProt) 931 1350 { 1351 DWORD dwSavedLastError = GetLastError(); 1352 932 1353 bool fCallRealApi; 933 1354 //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 1\n")); 934 NTSTATUS rcNt = supR3HardenedScreenImage(hFile, fImage, &fAccess, &fProtect, &fCallRealApi, false /*fForceCacheable*/);1355 NTSTATUS rcNt = supR3HardenedScreenImage(hFile, fImage, &fAccess, &fProtect, &fCallRealApi, "NtCreateSection"); 935 1356 //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi)); 1357 1358 SetLastError(dwSavedLastError); 1359 936 1360 if (!NT_SUCCESS(rcNt)) 937 1361 return rcNt; … … 939 1363 if (!fCallRealApi) 940 1364 return STATUS_TRUST_FAILURE; 1365 941 1366 } 942 1367 } … … 947 1372 return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile); 948 1373 } 1374 1375 1376 /** 1377 * Hooks that intercepts LdrLoadDll calls. 1378 * 1379 * Two purposes: 1380 * -# Enforce our own search path restrictions. 1381 * -# Prevalidate DLLs about to be loaded so we don't upset the loader data 1382 * by doing it from within the NtCreateSection hook (WinVerifyTrust 1383 * seems to be doing harm there on W7/32). 1384 * 1385 * @returns 1386 * @param pwszSearchPath The search path to use. 1387 * @param pfFlags Flags on input. DLL characteristics or something 1388 * on return? 1389 * @param pName The name of the module. 1390 * @param phMod Where the handle of the loaded DLL is to be 1391 * returned to the caller. 1392 */ 1393 static NTSTATUS NTAPI 1394 supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod) 1395 { 1396 DWORD dwSavedLastError = GetLastError(); 1397 1398 /* 1399 * Reject things we don't want to deal with. 1400 */ 1401 if (!pName || pName->Length == 0) 1402 { 1403 supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n"); 1404 return STATUS_INVALID_PARAMETER; 1405 } 1406 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%ls\n", 1407 (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath)); 1408 1409 /* 1410 * Reject long paths that's close to the 260 limit without looking. 1411 */ 1412 if (pName->Length > 256 * sizeof(WCHAR)) 1413 { 1414 supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length); 1415 return STATUS_NAME_TOO_LONG; 1416 } 1417 1418 /* 1419 * Absolute path? 1420 */ 1421 bool fSkipValidation = false; 1422 WCHAR wszPath[260]; 1423 UNICODE_STRING ResolvedName; 1424 if ( ( pName->Length >= 4 * sizeof(WCHAR) 1425 && RT_C_IS_ALPHA(pName->Buffer[0]) 1426 && pName->Buffer[1] == ':' 1427 && RTPATH_IS_SLASH(pName->Buffer[2]) ) 1428 || ( pName->Length >= 1 * sizeof(WCHAR) 1429 && RTPATH_IS_SLASH(pName->Buffer[1]) ) 1430 ) 1431 { 1432 memcpy(wszPath, pName->Buffer, pName->Length); 1433 wszPath[pName->Length / sizeof(WCHAR)] = '\0'; 1434 } 1435 /* 1436 * Not an absolute path. Check if it's one of those special API set DLLs. 1437 */ 1438 else if (supHardViUtf16PathStartsWithEx(pName->Buffer, pName->Length / sizeof(WCHAR), 1439 L"api-ms-win-", 11, false /*fCheckSlash*/)) 1440 { 1441 memcpy(wszPath, pName->Buffer, pName->Length); 1442 wszPath[pName->Length / sizeof(WCHAR)] = '\0'; 1443 fSkipValidation = true; 1444 } 1445 /* 1446 * Not an absolute path or special API set. There are two alternatives 1447 * now, either there is no path at all or there is a relative path. We 1448 * will resolve it to an absolute path in either case, failing the call 1449 * if we can't. If there isn't a path. 1450 */ 1451 else 1452 { 1453 PCWCHAR pawcName = pName->Buffer; 1454 uint32_t cwcName = pName->Length / sizeof(WCHAR); 1455 uint32_t offLastSlash = UINT32_MAX; 1456 uint32_t offLastDot = UINT32_MAX; 1457 for (uint32_t i = 0; i < cwcName; i++) 1458 switch (pawcName[i]) 1459 { 1460 case '\\': 1461 case '/': 1462 offLastSlash = i; 1463 offLastDot = UINT32_MAX; 1464 break; 1465 case '.': 1466 offLastDot = i; 1467 break; 1468 } 1469 1470 bool const fNeedDllSuffix = offLastDot == UINT32_MAX && offLastSlash == UINT32_MAX; 1471 1472 if (offLastDot != UINT32_MAX && offLastDot == cwcName - 1) 1473 cwcName--; 1474 1475 /* 1476 * Reject relative paths for now as they might be breakout attempts. 1477 */ 1478 if (offLastSlash != UINT32_MAX) 1479 { 1480 supR3HardenedError(VINF_SUCCESS, false, 1481 "supR3HardenedMonitor_LdrLoadDll: relative name not permitted: %.*ls\n", 1482 cwcName, pawcName); 1483 return STATUS_OBJECT_NAME_INVALID; 1484 } 1485 1486 /* 1487 * Search for the DLL. Only System32 is allowed as the target of 1488 * a search on the API level, all VBox calls will have full paths. 1489 */ 1490 UINT cwc = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath) - 32); 1491 if (!cwc) 1492 { 1493 supR3HardenedError(VINF_SUCCESS, false, 1494 "supR3HardenedMonitor_LdrLoadDll: GetSystemDirectoryW failed: %u\n", GetLastError()); 1495 return STATUS_UNEXPECTED_IO_ERROR; 1496 } 1497 if (cwc + 1 + cwcName + fNeedDllSuffix * 4 >= RT_ELEMENTS(wszPath)) 1498 { 1499 supR3HardenedError(VINF_SUCCESS, false, 1500 "supR3HardenedMonitor_LdrLoadDll: Name too long (system32): %.*ls\n", cwcName, pawcName); 1501 return STATUS_NAME_TOO_LONG; 1502 } 1503 wszPath[cwc++] = '\\'; 1504 memcpy(&wszPath[cwc], pawcName, cwcName * sizeof(WCHAR)); 1505 cwc += cwcName; 1506 if (!fNeedDllSuffix) 1507 wszPath[cwc] = '\0'; 1508 else 1509 { 1510 memcpy(&wszPath[cwc], L".dll", 5 * sizeof(WCHAR)); 1511 cwc += 4; 1512 } 1513 1514 ResolvedName.Buffer = wszPath; 1515 ResolvedName.Length = (USHORT)(cwc * sizeof(WCHAR)); 1516 ResolvedName.MaximumLength = ResolvedName.Length + sizeof(WCHAR); 1517 1518 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: '%.*ls' -> '%.*ls'\n", 1519 (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, 1520 ResolvedName.Length / sizeof(WCHAR), ResolvedName.Buffer)); 1521 pName = &ResolvedName; 1522 } 1523 1524 NTSTATUS rcNt; 1525 if (!fSkipValidation) 1526 { 1527 /* 1528 * Try open the file. If this fails, never mind, just pass it on to 1529 * the real API as we've replaced any searchable name with a full name 1530 * and the real API can come up with a fitting status code for it. 1531 */ 1532 HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/, 1533 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/); 1534 if (hFile != INVALID_HANDLE_VALUE) 1535 { 1536 ULONG fAccess = 0; 1537 ULONG fProtect = 0; 1538 bool fCallRealApi = false; 1539 rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi, "LdrLoadDll"); 1540 NtClose(hFile); 1541 if (!NT_SUCCESS(rcNt)) 1542 { 1543 supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: rejecting '%ls': rcNt=%#x", wszPath, rcNt); 1544 return rcNt; 1545 } 1546 1547 supR3HardenedWinVerifyCacheProcessImportTodos(); 1548 } 1549 else 1550 { 1551 DWORD dwErr = GetLastError(); 1552 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u\n", wszPath, dwErr)); 1553 } 1554 } 1555 1556 /* 1557 * Screened successfully enough. Call the real thing. 1558 */ 1559 SetLastError(dwSavedLastError); 1560 rcNt = g_pfnLdrLoadDllReal(pwszSearchPath, pfFlags, pName, phMod); 1561 1562 /* Log the result. */ 1563 dwSavedLastError = GetLastError(); 1564 if (NT_SUCCESS(rcNt) && phMod) 1565 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath)); 1566 else 1567 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath)); 1568 SetLastError(dwSavedLastError); 1569 1570 return rcNt; 1571 } 1572 949 1573 950 1574 … … 1059 1683 1060 1684 1685 static void supR3HardenedWinHookFailed(const char *pszWhich, uint8_t const *pbPrologue) 1686 { 1687 supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY, 1688 "Failed to install %s monitor: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n " 1689 #ifdef RT_ARCH_X86 1690 "(It is also possible you are running 32-bit VirtualBox under 64-bit windows.)\n" 1691 #endif 1692 , 1693 pszWhich, 1694 pbPrologue[0], pbPrologue[1], pbPrologue[2], pbPrologue[3], 1695 pbPrologue[4], pbPrologue[5], pbPrologue[6], pbPrologue[7], 1696 pbPrologue[8], pbPrologue[9], pbPrologue[10], pbPrologue[11], 1697 pbPrologue[12], pbPrologue[13], pbPrologue[14], pbPrologue[15]); 1698 } 1699 1700 1061 1701 /** 1062 1702 * Install hooks for intercepting calls dealing with mapping shared libraries … … 1067 1707 * @remarks We assume we're alone in this process, so no seralizing trickery is 1068 1708 * necessary when installing the patch. 1709 * 1710 * @remarks We would normally just copy the prologue sequence somewhere and add 1711 * a jump back at the end of it. But because we wish to avoid 1712 * allocating executable memory, we need to have preprepared assembly 1713 * "copies". This makes the non-system call patching a little tedious 1714 * and inflexible. 1069 1715 */ 1070 1716 DECLHIDDEN(void) supR3HardenedWinInstallHooks(void) … … 1102 1748 1103 1749 /* 1104 * Locate the routine .1750 * Locate the routines first so we can allocate memory that's near enough. 1105 1751 */ 1106 1752 HMODULE hmodNtDll = GetModuleHandleW(L"NTDLL"); … … 1109 1755 FARPROC pfnNtCreateSection = GetProcAddress(hmodNtDll, "NtCreateSection"); 1110 1756 SUPR3HARDENED_ASSERT(pfnNtCreateSection != NULL); 1111 SUPR3HARDENED_ASSERT(pfnNtCreateSection == (FARPROC)NtCreateSection); 1112 1113 uint8_t * const pbNtCreateSection = (uint8_t *)(uintptr_t)pfnNtCreateSection; 1757 //SUPR3HARDENED_ASSERT(pfnNtCreateSection == (FARPROC)NtCreateSection); 1758 1759 FARPROC pfnLdrLoadDll = GetProcAddress(hmodNtDll, "LdrLoadDll"); 1760 SUPR3HARDENED_ASSERT(pfnLdrLoadDll != NULL); 1761 //SUPR3HARDENED_ASSERT(pfnLdrLoadDll == (FARPROC)LdrLoadDll); 1762 1114 1763 1115 1764 #ifdef RT_ARCH_AMD64 … … 1118 1767 * actual function to be able to patch it. 1119 1768 */ 1120 size_t cbMem = _4K; 1121 void *pvMem = supR3HardenedWinAllocHookMemory((uintptr_t)pfnNtCreateSection, 1122 (uintptr_t)pfnNtCreateSection - _2G + PAGE_SIZE, 1123 -1, cbMem); 1769 uintptr_t uStart = RT_MAX((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll); 1770 size_t cbMem = _4K; 1771 void *pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart - _2G + PAGE_SIZE, -1, cbMem); 1124 1772 if (!pvMem) 1125 1773 { 1126 pvMem = supR3HardenedWinAllocHookMemory((uintptr_t)pfnNtCreateSection, 1127 (uintptr_t)pfnNtCreateSection + _2G - PAGE_SIZE, 1128 1, cbMem); 1774 uintptr_t uStart = RT_MIN((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll); 1775 pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart + _2G - PAGE_SIZE, 1, cbMem); 1129 1776 if (!pvMem) 1130 1777 supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY, … … 1132 1779 } 1133 1780 uintptr_t *puJmpTab = (uintptr_t *)pvMem; 1134 1781 #endif 1782 1783 /* 1784 * Hook #1 - NtCreateSection. 1785 * Purpose: Validate everything that can be mapped into the process before 1786 * it's mapped and we still have a file handle to work with. 1787 */ 1788 uint8_t * const pbNtCreateSection = (uint8_t *)(uintptr_t)pfnNtCreateSection; 1789 1790 #ifdef RT_ARCH_AMD64 1135 1791 /* 1136 1792 * Patch 64-bit hosts. … … 1170 1826 } 1171 1827 } 1172 1173 if (pfnCallReal) 1174 { 1175 g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack); 1176 *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal; 1177 *puJmpTab = (uintptr_t)supR3HardenedMonitor_NtCreateSection; 1178 1179 DWORD dwOldProt; 1180 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1181 PAGE_EXECUTE_READWRITE, &dwOldProt)); 1182 pbNtCreateSection[0] = 0xff; 1183 pbNtCreateSection[1] = 0x25; 1184 *(uint32_t *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]); 1185 1186 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1187 PAGE_EXECUTE_READ, &dwOldProt)); 1188 return; 1189 } 1828 if (!pfnCallReal) 1829 supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection); 1830 1831 g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack); 1832 *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal; 1833 *puJmpTab = (uintptr_t)supR3HardenedMonitor_NtCreateSection; 1834 1835 DWORD dwOldProt; 1836 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1837 PAGE_EXECUTE_READWRITE, &dwOldProt)); 1838 pbNtCreateSection[0] = 0xff; 1839 pbNtCreateSection[1] = 0x25; 1840 *(uint32_t *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]); 1841 1842 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1843 PAGE_EXECUTE_READ, &dwOldProt)); 1844 puJmpTab++; 1190 1845 1191 1846 #else … … 1249 1904 } 1250 1905 } 1251 1252 if (pfnCallReal) 1253 { 1254 g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack); 1255 *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal; 1256 1257 DWORD dwOldProt; 1258 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1259 PAGE_EXECUTE_READWRITE, &dwOldProt)); 1260 pbNtCreateSection[0] = 0xe9; 1261 *(uint32_t *)&pbNtCreateSection[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection 1262 - (uintptr_t)&pbNtCreateSection[1+4]; 1263 1264 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1265 PAGE_EXECUTE_READ, &dwOldProt)); 1266 return; 1267 } 1906 if (!pfnCallReal) 1907 supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection); 1908 1909 g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack); 1910 *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal; 1911 1912 DWORD dwOldProt; 1913 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1914 PAGE_EXECUTE_READWRITE, &dwOldProt)); 1915 pbNtCreateSection[0] = 0xe9; 1916 *(uint32_t *)&pbNtCreateSection[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection 1917 - (uintptr_t)&pbNtCreateSection[1+4]; 1918 1919 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16, 1920 PAGE_EXECUTE_READ, &dwOldProt)); 1268 1921 #endif 1269 1922 1270 supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY, 1271 "Failed to install NtCreateSection monitor: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n " 1272 #ifdef RT_ARCH_X86 1273 "(It is also possible you are running 32-bit VirtualBox under 64-bit windows.)\n" 1923 /* 1924 * Hook #2 - LdrLoadDll 1925 * Purpose: (a) Enforce LdrLoadDll search path constraints, and (b) pre-validate 1926 * DLLs so we can avoid calling WinVerifyTrust from the first hook, 1927 * and thus avoiding messing up the loader data on some installations. 1928 * 1929 * This differs from the above function in that is no a system call and 1930 * we're at the mercy of the compiler. 1931 */ 1932 uint8_t * const pbLdrLoadDll = (uint8_t *)(uintptr_t)pfnLdrLoadDll; 1933 uint32_t offExecPage = 0; 1934 memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE); 1935 1936 #ifdef RT_ARCH_AMD64 1937 /* 1938 * Patch 64-bit hosts. 1939 */ 1940 # if 0 1941 /* Pattern #1: 1942 Windows 8.1: 1943 0:000> u ntdll!LdrLoadDll 1944 ntdll!LdrLoadDll: 1945 00007ffa`814ccd44 488bc4 mov rax,rsp 1946 00007ffa`814ccd47 48895808 mov qword ptr [rax+8],rbx 1947 00007ffa`814ccd4b 48896810 mov qword ptr [rax+10h],rbp 1948 00007ffa`814ccd4f 48897018 mov qword ptr [rax+18h],rsi 1949 00007ffa`814ccd53 48897820 mov qword ptr [rax+20h],rdi 1950 00007ffa`814ccd57 4156 push r14 1951 00007ffa`814ccd59 4883ec70 sub rsp,70h 1952 00007ffa`814ccd5d f6059cd2100009 test byte ptr [ntdll!LdrpDebugFlags (00007ffa`815da000)],9 1953 */ 1954 if ( pbLdrLoadDll[0] == 0x48 /* mov rax,rsp */ 1955 && pbLdrLoadDll[1] == 0x8b 1956 && pbLdrLoadDll[2] == 0xc4 1957 && pbLdrLoadDll[3] == 0x48 /* mov qword ptr [rax+8],rbx */ 1958 && pbLdrLoadDll[4] == 0x89 1959 && pbLdrLoadDll[5] == 0x58 1960 && pbLdrLoadDll[6] == 0x08) 1961 { 1962 offJmpBack = 7; /* the 3rd instruction. */ 1963 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1; 1964 } 1965 /* 1966 Pattern #2: 1967 Windows 8.0: 1968 0:000> u ntdll_w8_64!LdrLoadDll 1969 ntdll_w8_64!LdrLoadDll: 1970 00007ffa`52ffa7c0 48895c2408 mov qword ptr [rsp+8],rbx 1971 00007ffa`52ffa7c5 4889742410 mov qword ptr [rsp+10h],rsi 1972 00007ffa`52ffa7ca 48897c2418 mov qword ptr [rsp+18h],rdi 1973 00007ffa`52ffa7cf 55 push rbp 1974 00007ffa`52ffa7d0 4156 push r14 1975 00007ffa`52ffa7d2 4157 push r15 1976 00007ffa`52ffa7d4 488bec mov rbp,rsp 1977 00007ffa`52ffa7d7 4883ec60 sub rsp,60h 1978 00007ffa`52ffa7db 8b05df321000 mov eax,dword ptr [ntdll_w8_64!LdrpDebugFlags (00007ffa`530fdac0)] 1979 00007ffa`52ffa7e1 4d8bf1 mov r14,r9 1980 1981 */ 1982 else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+8],rbx */ 1983 && pbLdrLoadDll[1] == 0x89 1984 && pbLdrLoadDll[2] == 0x5c 1985 && pbLdrLoadDll[3] == 0x24 1986 && pbLdrLoadDll[4] == 0x08 1987 && pbLdrLoadDll[5] == 0x48 /* mov qword ptr [rsp+10h],rsi */ 1988 && pbLdrLoadDll[6] == 0x89 1989 && pbLdrLoadDll[7] == 0x74 1990 && pbLdrLoadDll[8] == 0x24 1991 && pbLdrLoadDll[9] == 0x10) 1992 { 1993 offJmpBack = 10; /* the 3rd instruction. */ 1994 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2; 1995 } 1996 /* 1997 Pattern #3: 1998 Windows 7: 1999 ntdll_w7_64!LdrLoadDll: 2000 00000000`58be4a20 48895c2410 mov qword ptr [rsp+10h],rbx 2001 00000000`58be4a25 48896c2418 mov qword ptr [rsp+18h],rbp 2002 00000000`58be4a2a 56 push rsi 2003 00000000`58be4a2b 57 push rdi 2004 00000000`58be4a2c 4154 push r12 2005 00000000`58be4a2e 4883ec50 sub rsp,50h 2006 00000000`58be4a32 f605976e100009 test byte ptr [ntdll_w7_64!ShowSnaps (00000000`58ceb8d0)],9 2007 00000000`58be4a39 498bf1 mov rsi,r9 2008 2009 */ 2010 else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+10h],rbx */ 2011 && pbLdrLoadDll[1] == 0x89 2012 && pbLdrLoadDll[2] == 0x5c 2013 && pbLdrLoadDll[3] == 0x24 2014 && pbLdrLoadDll[4] == 0x10) 2015 { 2016 offJmpBack = 5; /* the 2nd instruction. */ 2017 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type3; 2018 } 2019 /* 2020 Pattern #4: 2021 Windows Vista: 2022 0:000> u ntdll_vista_64!LdrLoadDll 2023 ntdll_vista_64!LdrLoadDll: 2024 00000000`58c11f60 fff3 push rbx 2025 00000000`58c11f62 56 push rsi 2026 00000000`58c11f63 57 push rdi 2027 00000000`58c11f64 4154 push r12 2028 00000000`58c11f66 4155 push r13 2029 00000000`58c11f68 4156 push r14 2030 00000000`58c11f6a 4157 push r15 2031 00000000`58c11f6c 4881ecb0020000 sub rsp,2B0h 2032 00000000`58c11f73 488b05367b0e00 mov rax,qword ptr [ntdll_vista_64!_security_cookie (00000000`58cf9ab0)] 2033 00000000`58c11f7a 4833c4 xor rax,rsp 2034 00000000`58c11f7d 48898424a0020000 mov qword ptr [rsp+2A0h],rax 2035 2036 */ 2037 else if ( pbLdrLoadDll[0] == 0xff /* push rbx */ 2038 && pbLdrLoadDll[1] == 0xf3 2039 && pbLdrLoadDll[2] == 0x56 /* push rsi */ 2040 && pbLdrLoadDll[3] == 0x57 /* push rdi */ 2041 && pbLdrLoadDll[4] == 0x41 /* push r12 */ 2042 && pbLdrLoadDll[5] == 0x54) 2043 { 2044 offJmpBack = 6; /* the 5th instruction. */ 2045 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type4; 2046 } 2047 /* 2048 Pattern #5: 2049 Windows XP64: 2050 0:000> u ntdll!LdrLoadDll 2051 ntdll!LdrLoadDll: 2052 00000000`78efa580 4c8bdc mov r11,rsp 2053 00000000`78efa583 4881ece8020000 sub rsp,2E8h 2054 00000000`78efa58a 49895bf8 mov qword ptr [r11-8],rbx 2055 00000000`78efa58e 498973f0 mov qword ptr [r11-10h],rsi 2056 00000000`78efa592 49897be8 mov qword ptr [r11-18h],rdi 2057 00000000`78efa596 4d8963e0 mov qword ptr [r11-20h],r12 2058 00000000`78efa59a 4d896bd8 mov qword ptr [r11-28h],r13 2059 00000000`78efa59e 4d8973d0 mov qword ptr [r11-30h],r14 2060 00000000`78efa5a2 4d897bc8 mov qword ptr [r11-38h],r15 2061 00000000`78efa5a6 488b051bd10a00 mov rax,qword ptr [ntdll!_security_cookie (00000000`78fa76c8)] 2062 00000000`78efa5ad 48898424a0020000 mov qword ptr [rsp+2A0h],rax 2063 00000000`78efa5b5 4d8bf9 mov r15,r9 2064 00000000`78efa5b8 4c8bf2 mov r14,rdx 2065 00000000`78efa5bb 4c8be9 mov r13,rcx 2066 00000000`78efa5be 4c89442458 mov qword ptr [rsp+58h],r8 2067 00000000`78efa5c3 66c74424680000 mov word ptr [rsp+68h],0 2068 2069 */ 2070 else if ( pbLdrLoadDll[0] == 0x4c /* mov r11,rsp */ 2071 && pbLdrLoadDll[1] == 0x8b 2072 && pbLdrLoadDll[2] == 0xdc 2073 && pbLdrLoadDll[3] == 0x48 /* sub rsp,2e8h */ 2074 && pbLdrLoadDll[4] == 0x81 2075 && pbLdrLoadDll[5] == 0xec 2076 && pbLdrLoadDll[6] == 0xe8 2077 && pbLdrLoadDll[7] == 0x02 2078 && pbLdrLoadDll[8] == 0x00 2079 && pbLdrLoadDll[9] == 0x00) 2080 { 2081 offJmpBack = 10; /* the 3rd instruction. */ 2082 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type5; 2083 } 2084 else 2085 supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll); 2086 # else 2087 /* Just use the disassembler to skip 6 bytes or more. */ 2088 DISSTATE Dis; 2089 uint32_t cbInstr; 2090 offJmpBack = 0; 2091 while (offJmpBack < 6) 2092 { 2093 cbInstr = 1; 2094 int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr); 2095 if ( RT_FAILURE(rc) 2096 || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)) 2097 || (Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */) ) 2098 supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll); 2099 offJmpBack += cbInstr; 2100 } 2101 # endif 2102 2103 /* Assemble the code for resuming the call.*/ 2104 *(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage]; 2105 2106 memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack); 2107 offExecPage += offJmpBack; 2108 2109 g_abSupHardReadWriteExecPage[offExecPage++] = 0xff; /* jmp qword [$+8 wrt RIP] */ 2110 g_abSupHardReadWriteExecPage[offExecPage++] = 0x25; 2111 *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = RT_ALIGN_32(offExecPage + 4, 8) - (offExecPage + 4); 2112 offExecPage = RT_ALIGN_32(offExecPage + 4, 8); 2113 *(uint64_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack]; 2114 offExecPage = RT_ALIGN_32(offJmpBack + 8, 16); 2115 2116 /* Patch the function. */ 2117 *puJmpTab = (uintptr_t)supR3HardenedMonitor_LdrLoadDll; 2118 2119 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READWRITE, &dwOldProt)); 2120 2121 Assert(offJmpBack >= 6); 2122 pbLdrLoadDll[0] = 0xff; 2123 pbLdrLoadDll[1] = 0x25; 2124 *(uint32_t *)&pbLdrLoadDll[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbLdrLoadDll[2+4]); 2125 2126 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt)); 2127 puJmpTab++; 2128 2129 #else 2130 /* 2131 * Patch 32-bit hosts. 2132 */ 2133 # if 0 2134 /* Pattern #1: 2135 Windows 7: 2136 0:000> u ntdll!LdrLoadDll 2137 ntdll!LdrLoadDll: 2138 77aff585 8bff mov edi,edi 2139 77aff587 55 push ebp 2140 77aff588 8bec mov ebp,esp 2141 77aff58a 51 push ecx 2142 77aff58b 51 push ecx 2143 77aff58c a1f8bdaf77 mov eax,dword ptr [ntdll!LdrpLogLevelStateTable+0x24 (77afbdf8)] 2144 2145 Windows 8 rtm: 2146 0:000:x86> u ntdll_67150000!LdrLoadDll 2147 ntdll_67150000!LdrLoadDll: 2148 67189f3f 8bff mov edi,edi 2149 67189f41 55 push ebp 2150 67189f42 8bec mov ebp,esp 2151 67189f44 8b0d10eb2467 mov ecx,dword ptr [ntdll_67150000!LdrpDebugFlags (6724eb10)] 2152 2153 Windows 8.1: 2154 0:000:x86> u ntdll_w81_32!LdrLoadDll 2155 ntdll_w81_32!LdrLoadDll: 2156 6718aade 8bff mov edi,edi 2157 6718aae0 55 push ebp 2158 6718aae1 8bec mov ebp,esp 2159 6718aae3 83ec14 sub esp,14h 2160 6718aae6 f6050040246709 test byte ptr [ntdll_w81_32!LdrpDebugFlags (67244000)],9 2161 2162 Pattern #2: 2163 Windows XP: 2164 0:000:x86> u ntdll_xp!LdrLoadDll 2165 ntdll_xp!LdrLoadDll: 2166 77f569d2 6858020000 push 258h 2167 77f569d7 68d866f777 push offset ntdll_xp!`string'+0x12c (77f766d8) 2168 77f569dc e83bb20200 call ntdll_xp!_SEH_prolog (77f81c1c) 2169 77f569e1 33db xor ebx,ebx 2170 77f569e3 66895de0 mov word ptr [ebp-20h],bx 2171 77f569e7 33c0 xor eax,eax 2172 77f569e9 8d7de2 lea edi,[ebp-1Eh] 2173 77f569ec ab stos dword ptr es:[edi] 2174 2175 Windows Server 2003: 2176 0:000:x86> u ntdll_w2k3_32!LdrLoadDll 2177 ntdll_w2k3_32!LdrLoadDll: 2178 7c833f63 6840020000 push 240h 2179 7c833f68 68b040837c push offset ntdll_w2k3_32!`string'+0x12c (7c8340b0) 2180 7c833f6d e8a942ffff call ntdll_w2k3_32!_SEH_prolog (7c82821b) 2181 7c833f72 a13077887c mov eax,dword ptr [ntdll_w2k3_32!__security_cookie (7c887730)] 2182 7c833f77 8945e4 mov dword ptr [ebp-1Ch],eax 2183 7c833f7a 8b4508 mov eax,dword ptr [ebp+8] 2184 7c833f7d 8985b0fdffff mov dword ptr [ebp-250h],eax 2185 7c833f83 8b450c mov eax,dword ptr [ebp+0Ch] 2186 2187 Windows Vista SP0 & SP1: 2188 0:000:x86> u ntdll_vista_sp0_32!LdrLoadDll 2189 ntdll_vista_sp0_32!LdrLoadDll: 2190 69b0eb00 6844020000 push 244h 2191 69b0eb05 6838e9b269 push offset ntdll_vista_sp0_32! ?? ::FNODOBFM::`string'+0x39e (69b2e938) 2192 69b0eb0a e835420300 call ntdll_vista_sp0_32!_SEH_prolog4_GS (69b42d44) 2193 69b0eb0f 8b4508 mov eax,dword ptr [ebp+8] 2194 69b0eb12 8985acfdffff mov dword ptr [ebp-254h],eax 2195 69b0eb18 8b450c mov eax,dword ptr [ebp+0Ch] 2196 69b0eb1b 8985c0fdffff mov dword ptr [ebp-240h],eax 2197 69b0eb21 8b4510 mov eax,dword ptr [ebp+10h] 2198 */ 2199 2200 if ( pbLdrLoadDll[0] == 0x8b /* mov edi, edi - for hot patching */ 2201 && pbLdrLoadDll[1] == 0xff 2202 && pbLdrLoadDll[2] == 0x55 /* push ebp */ 2203 && pbLdrLoadDll[3] == 0x8b /* mov ebp,esp */ 2204 && pbLdrLoadDll[4] == 0xec) 2205 { 2206 offJmpBack = 5; /* the 3rd instruction. */ 2207 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1; 2208 } 2209 else if (pbLdrLoadDll[0] == 0x68 /* push dword XXXXXXXX */) 2210 { 2211 offJmpBack = 5; 2212 pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2; 2213 g_supR3HardenedJmpBack_LdrLoadDll_Type2_PushDword = *(uint32_t const *)&pbLdrLoadDll[1]; 2214 } 2215 else 2216 supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll); 2217 2218 g_pfnLdrLoadDllJmpBack = (PFNRT)(uintptr_t)(pbLdrLoadDll + offJmpBack); 2219 *(PFNRT *)&g_pfnLdrLoadDllReal = pfnCallReal; 2220 2221 # else 2222 /* Just use the disassembler to skip 6 bytes or more. */ 2223 DISSTATE Dis; 2224 uint32_t cbInstr; 2225 offJmpBack = 0; 2226 while (offJmpBack < 5) 2227 { 2228 cbInstr = 1; 2229 int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_32BIT, &Dis, &cbInstr); 2230 if ( RT_FAILURE(rc) 2231 || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)) ) 2232 supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll); 2233 offJmpBack += cbInstr; 2234 } 2235 2236 /* Assemble the code for resuming the call.*/ 2237 *(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage]; 2238 2239 memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack); 2240 offExecPage += offJmpBack; 2241 2242 g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9; 2243 *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack] 2244 - (uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage + 4]; 2245 offExecPage = RT_ALIGN_32(offJmpBack + 4, 16); 2246 2247 # endif 2248 2249 /* Patch LdrLoadDLl. */ 2250 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, 2251 PAGE_EXECUTE_READWRITE, &dwOldProt)); 2252 Assert(offJmpBack >= 5); 2253 pbLdrLoadDll[0] = 0xe9; 2254 *(uint32_t *)&pbLdrLoadDll[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4]; 2255 2256 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt)); 1274 2257 #endif 1275 , 1276 pbNtCreateSection[0], pbNtCreateSection[1], pbNtCreateSection[2], pbNtCreateSection[3], 1277 pbNtCreateSection[4], pbNtCreateSection[5], pbNtCreateSection[6], pbNtCreateSection[7], 1278 pbNtCreateSection[8], pbNtCreateSection[9], pbNtCreateSection[10], pbNtCreateSection[11], 1279 pbNtCreateSection[12], pbNtCreateSection[13], pbNtCreateSection[14], pbNtCreateSection[15]); 2258 2259 /* 2260 * Seal the rwx page. 2261 */ 2262 SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), g_abSupHardReadWriteExecPage, PAGE_SIZE, 2263 PAGE_EXECUTE_READ, &dwOldProt)); 1280 2264 } 1281 2265 -
trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
r52374 r52403 151 151 %include "import-template-kernel32.h" 152 152 153 154 ; 155 ; For simplified LdrLoadDll patching we define a special writable, readable and 156 ; exectuable section of 4KB where we can put jump back code. 157 ; 158 section .rwxpg bss execute read write align=4096 159 GLOBALNAME g_abSupHardReadWriteExecPage 160 resb 4096 161 -
trunk/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
r52366 r52403 11 11 SUPHARNT_IMPORT_STDCALL(GetProcAddress, 8) 12 12 SUPHARNT_IMPORT_STDCALL(GetProcessHeap, 0) 13 SUPHARNT_IMPORT_STDCALL(GetSystemDirectoryW, 8) 13 14 SUPHARNT_IMPORT_STDCALL(GetTickCount, 0) 14 15 SUPHARNT_IMPORT_STDCALL(HeapAlloc, 12) … … 18 19 SUPHARNT_IMPORT_STDCALL(LoadLibraryExW, 12) 19 20 SUPHARNT_IMPORT_STDCALL(OutputDebugStringA, 4) 21 SUPHARNT_IMPORT_STDCALL(SetLastError, 4) 20 22 SUPHARNT_IMPORT_STDCALL(Sleep, 4) 21 23 SUPHARNT_IMPORT_STDCALL(VirtualProtectEx, 20) 22 24 SUPHARNT_IMPORT_STDCALL(WriteFile, 20) 25 -
trunk/src/VBox/Runtime/common/ldr/ldrEx.cpp
r52213 r52403 590 590 RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf) 591 591 { 592 return RTLdrQueryPropEx(hLdrMod, enmProp, pvBuf, cbBuf, NULL);592 return RTLdrQueryPropEx(hLdrMod, enmProp, NULL /*pvBits*/, pvBuf, cbBuf, NULL); 593 593 } 594 594 RT_EXPORT_SYMBOL(RTLdrQueryProp); 595 595 596 596 597 RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvB uf, size_t cbBuf, size_t *pcbRet)597 RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBits, void *pvBuf, size_t cbBuf, size_t *pcbRet) 598 598 { 599 599 AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID); … … 629 629 AssertReturn(cbBuf == sizeof(bool), VERR_INVALID_PARAMETER); 630 630 break; 631 case RTLDRPROP_IMPORT_COUNT: 632 *pcbRet = sizeof(uint32_t); 633 AssertReturn(cbBuf == sizeof(uint32_t), VERR_INVALID_PARAMETER); 634 break; 635 case RTLDRPROP_IMPORT_MODULE: 636 *pcbRet = sizeof(uint32_t); 637 AssertReturn(cbBuf >= sizeof(uint32_t), VERR_INVALID_PARAMETER); 638 break; 631 639 632 640 default: … … 640 648 if (!pMod->pOps->pfnQueryProp) 641 649 return VERR_NOT_SUPPORTED; 642 return pMod->pOps->pfnQueryProp(pMod, enmProp, pvB uf, cbBuf, pcbRet);650 return pMod->pOps->pfnQueryProp(pMod, enmProp, pvBits, pvBuf, cbBuf, pcbRet); 643 651 } 644 652 RT_EXPORT_SYMBOL(RTLdrQueryPropEx); -
trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp
r52213 r52403 310 310 && pThis->paSections[0].SizeOfRawData > 0) 311 311 offFirstRawData = pThis->paSections[0].PointerToRawData; 312 if (offFile > offFirstRawData)312 if (offFile >= offFirstRawData) 313 313 cbToRead = 0; 314 314 else if (offFile + cbToRead > offFirstRawData) 315 cbToRead = offFile + cbToRead- offFirstRawData;315 cbToRead = offFile - offFirstRawData; 316 316 } 317 317 else 318 318 { 319 319 /* Find the matching section and its mapping size. */ 320 uint32_t j = 0; 321 uint32_t cbMapping = 0; 320 uint32_t j = 0; 321 uint32_t cbMapping = 0; 322 uint32_t offSection = 0; 322 323 while (j < pThis->cSections) 323 324 { 324 325 cbMapping = (j + 1 < pThis->cSections ? pThis->paSections[j + 1].VirtualAddress : pThis->cbImage) 325 326 - pThis->paSections[j].VirtualAddress; 326 if (uRva - pThis->paSections[j].VirtualAddress < cbMapping) 327 offSection = uRva - pThis->paSections[j].VirtualAddress; 328 if (offSection < cbMapping) 327 329 break; 328 330 j++; … … 332 334 333 335 /* Adjust the sizes and calc the file offset. */ 334 if (cbToAdv > cbMapping) 335 cbToAdv = cbToRead = cbMapping; 336 if (offSection + cbToAdv > cbMapping) 337 cbToAdv = cbToRead = cbMapping - offSection; 338 336 339 if ( pThis->paSections[j].PointerToRawData > 0 337 340 && pThis->paSections[j].SizeOfRawData > 0) 338 341 { 339 offFile = uRva - pThis->paSections[j].VirtualAddress;342 offFile = offSection; 340 343 if (offFile + cbToRead > pThis->paSections[j].SizeOfRawData) 341 344 cbToRead = pThis->paSections[j].SizeOfRawData - offFile; … … 366 369 367 370 /* Advance */ 368 if (cbMem == cbToRead)371 if (cbMem <= cbToAdv) 369 372 break; 370 cbMem -= cbTo Read;371 pbMem += cbTo Read;372 uRva += cbTo Read;373 cbMem -= cbToAdv; 374 pbMem += cbToAdv; 375 uRva += cbToAdv; 373 376 } 374 377 … … 433 436 uint32_t cbMem, void const **ppvMem) 434 437 { 435 if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage) 438 if ( uRva == NIL_RTLDRADDR 439 || uRva > pThis->cbImage 440 || cbMem > pThis->cbImage 441 || uRva + cbMem > pThis->cbImage) 436 442 { 437 443 if (offFile < 0 || offFile >= UINT32_MAX) … … 455 461 return; 456 462 457 if (pvBits && (uintptr_t)pv Bits - (uintptr_t)pvMem< pThis->cbImage)463 if (pvBits && (uintptr_t)pvMem - (uintptr_t)pvBits < pThis->cbImage) 458 464 return; 459 if (pThis->pvBits && (uintptr_t)p This->pvBits - (uintptr_t)pvMem< pThis->cbImage)465 if (pThis->pvBits && (uintptr_t)pvMem - (uintptr_t)pThis->pvBits < pThis->cbImage) 460 466 return; 461 467 … … 1723 1729 } 1724 1730 1731 /** 1732 * Worker for rtLdrPE_QueryProp that retrievs the name of an import DLL. 1733 * 1734 * @returns IPRT status code. If VERR_BUFFER_OVERFLOW, pcbBuf is required size. 1735 * @param pThis The PE module instance. 1736 * @param pvBits Image bits if the caller had them available, NULL if 1737 * not. Saves a couple of file accesses. 1738 * @param iImport The index of the import table descriptor to fetch 1739 * the name from. 1740 * @param pvBuf The output buffer. 1741 * @param cbBuf The buffer size. 1742 * @param pcbRet Where to return the number of bytes we've returned 1743 * (or in case of VERR_BUFFER_OVERFLOW would have). 1744 */ 1745 static int rtLdrPE_QueryImportModule(PRTLDRMODPE pThis, void const *pvBits, uint32_t iImport, 1746 void *pvBuf, size_t cbBuf, size_t *pcbRet) 1747 { 1748 /* 1749 * Check the index first, converting it to an RVA. 1750 */ 1751 int rc; 1752 if (iImport < pThis->ImportDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR)) 1753 { 1754 uint32_t offEntry = iImport * sizeof(IMAGE_IMPORT_DESCRIPTOR) + pThis->ImportDir.VirtualAddress; 1755 1756 /* 1757 * Retrieve the import table descriptor. 1758 */ 1759 PCIMAGE_IMPORT_DESCRIPTOR pImpDesc; 1760 rc = rtldrPEReadPartByRva(pThis, pvBits, offEntry, sizeof(*pImpDesc), (void const **)&pImpDesc); 1761 if (RT_SUCCESS(rc)) 1762 { 1763 if ( pImpDesc->Name >= pThis->cbHeaders 1764 && pImpDesc->Name < pThis->cbImage) 1765 { 1766 /* 1767 * Limit the name to 1024 bytes (more than enough for everyone). 1768 */ 1769 uint32_t cchNameMax = pThis->cbImage - pImpDesc->Name; 1770 if (cchNameMax > 1024) 1771 cchNameMax = 1024; 1772 char *pszName; 1773 rc = rtldrPEReadPartByRva(pThis, pvBits, pImpDesc->Name, cchNameMax, (void const **)&pszName); 1774 if (RT_SUCCESS(rc)) 1775 { 1776 /* 1777 * Make sure it's null terminated and valid UTF-8 encoding. 1778 * 1779 * Which encoding this really is isn't defined, I think, 1780 * but we need to make sure we don't get bogus UTF-8 into 1781 * the process, so making sure it's valid UTF-8 is a good 1782 * as anything else since it covers ASCII. 1783 */ 1784 size_t cchName = RTStrNLen(pszName, cchNameMax); 1785 if (cchName < cchNameMax) 1786 { 1787 rc = RTStrValidateEncodingEx(pszName, cchName, 0 /*fFlags*/); 1788 if (RT_SUCCESS(rc)) 1789 { 1790 /* 1791 * Copy out the result and we're done. 1792 * (We have to do all the cleanup code though, so no return success here.) 1793 */ 1794 *pcbRet = cchName + 1; 1795 if (cbBuf >= cchName + 1) 1796 memcpy(pvBuf, pszName, cchName + 1); 1797 else 1798 rc = VERR_BUFFER_OVERFLOW; 1799 } 1800 } 1801 else 1802 rc = VERR_BAD_EXE_FORMAT; 1803 rtldrPEFreePart(pThis, pvBits, pszName); 1804 } 1805 } 1806 else 1807 rc = VERR_BAD_EXE_FORMAT; 1808 rtldrPEFreePart(pThis, pvBits, pImpDesc); 1809 } 1810 } 1811 else 1812 rc = VERR_NOT_FOUND; 1813 1814 if (RT_SUCCESS(rc)) 1815 return VINF_SUCCESS; 1816 1817 *pcbRet = 0; 1818 return rc; 1819 } 1820 1725 1821 1726 1822 /** @interface_method_impl{RTLDROPS,pfnQueryProp} */ 1727 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet) 1823 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits, 1824 void *pvBuf, size_t cbBuf, size_t *pcbRet) 1728 1825 { 1729 1826 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod; … … 1765 1862 && (pModPe->fDllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY); 1766 1863 break; 1864 1865 case RTLDRPROP_IMPORT_COUNT: 1866 Assert(cbBuf == sizeof(uint32_t)); 1867 Assert(*pcbRet == cbBuf); 1868 *(uint32_t *)pvBuf = pModPe->ImportDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); 1869 if (*(uint32_t *)pvBuf > 0) 1870 *(uint32_t *)pvBuf -= 1; /* The last entry is a NULL entry. */ 1871 /** @todo Is there some linkers out there that doesn't generiate a 1872 * terminator entry? */ 1873 break; 1874 1875 case RTLDRPROP_IMPORT_MODULE: 1876 Assert(cbBuf >= sizeof(uint32_t)); 1877 return rtLdrPE_QueryImportModule(pModPe, pvBits, *(uint32_t *)pvBuf, pvBuf, cbBuf, pcbRet); 1767 1878 1768 1879 default: -
trunk/src/VBox/Runtime/common/ldr/ldrkStuff.cpp
r52213 r52403 840 840 841 841 /** @interface_method_impl{RTLDROPS,pfnQueryProp} */ 842 static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet) 842 static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits, 843 void *pvBuf, size_t cbBuf, size_t *pcbRet) 843 844 { 844 845 PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod; -
trunk/src/VBox/Runtime/include/internal/ldr.h
r52213 r52403 359 359 * @param pMod Pointer to the loader module structure. 360 360 * @param enmLdrProp The property to query (valid). 361 * @param pvBuf Pointer to the return buffer (valid). 362 * @param cbBuf The size of the return buffer (valid as per 361 * @param pvBits Pointer to the bits returned by 362 * RTLDROPS::pfnGetBits(), optional. 363 * @param pvBuf Pointer to the input / output buffer. This is valid. 364 * Normally only used for returning data, but in some 365 * cases it also holds input. 366 * @param cbBuf The size of the buffer (valid as per 363 367 * property). 364 368 * @param pcbRet The number of bytes actually returned. If … … 366 370 * required buffer size. 367 371 */ 368 DECLCALLBACKMEMBER(int, pfnQueryProp)(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet); 372 DECLCALLBACKMEMBER(int, pfnQueryProp)(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits, 373 void *pvBuf, size_t cbBuf, size_t *pcbRet); 369 374 370 375 /** -
trunk/src/VBox/Runtime/tools/RTSignTool.cpp
r52049 r52403 153 153 void *pvBuf = RTMemAlloc(cbBuf); 154 154 size_t cbRet = 0; 155 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, pvBuf, cbBuf, &cbRet);155 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet); 156 156 if (rc == VERR_BUFFER_OVERFLOW && cbRet < _4M && cbRet > 0) 157 157 { … … 159 159 cbBuf = cbRet; 160 160 pvBuf = RTMemAlloc(cbBuf); 161 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, pvBuf, cbBuf, &cbRet);161 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet); 162 162 } 163 163 if (RT_SUCCESS(rc))
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器