[*] Support for further Win32 API degradation / historical OSes / emulators

This commit is contained in:
Reece Wilson 2023-08-27 17:43:29 +01:00
parent 5cf7533eab
commit 4674f45dd3
10 changed files with 377 additions and 60 deletions

View File

@ -59,15 +59,10 @@
},
"then": {
"links": [
"Bcrypt.lib",
"UxTheme.lib",
"Aux_ulib.lib",
"Dbghelp.lib",
"ws2_32.lib",
"Ntdll.lib",
"wintrust.lib",
"Winmm.lib",
"Iphlpapi.lib"
"Winmm.lib"
]
}
},

View File

@ -337,6 +337,7 @@ namespace Aurora
@warning: 0 = 3 * 1024 * 1024
*/
bool bWin32VerifyTrustFailMissingAPI { true }; // just to not be annoying in the future
};
struct ThreadingConfig

View File

@ -31,6 +31,9 @@ namespace Aurora
ADD_LOAD_LIB(Theme);
ADD_LOAD_LIB(Shell);
ADD_LOAD_LIB(PSAPILegacy);
ADD_LOAD_LIB(DbgHelper);
ADD_LOAD_LIB(WinTrust);
ADD_LOAD_LIB(IPHelper);
#define ADD_GET_PROC(name, proc) \
if (h ## name) \
@ -88,6 +91,7 @@ namespace Aurora
ADD_GET_PROC(Nt, NtQueryInformationProcess)
ADD_GET_PROC(Nt, NtNotifyChangeDirectoryFile)
ADD_GET_PROC(Nt, NtTerminateProcess)
ADD_GET_PROC(Nt, VerSetConditionMask)
ADD_GET_PROC_BI(Kernel32, KernelBase, VirtualAlloc2)
ADD_GET_PROC_BI(Kernel32, KernelBase, MapViewOfFile3)
@ -110,19 +114,33 @@ namespace Aurora
ADD_GET_PROC(Kernel32, LCIDToLocaleName)
ADD_GET_PROC(Kernel32, GetLocaleInfoW)
ADD_GET_PROC(Kernel32, GetThreadId)
ADD_GET_PROC(Kernel32, VerifyVersionInfoW)
ADD_GET_PROC_BI2(Kernel32, PSAPILegacy, K32GetProcessMemoryInfo, GetProcessMemoryInfo)
ADD_GET_PROC(Sync, WaitOnAddress)
ADD_GET_PROC(Sync, WakeByAddressSingle)
ADD_GET_PROC(Sync, WakeByAddressAll)
ADD_GET_PROC(DbgHelper, UnDecorateSymbolName)
ADD_GET_PROC(DbgHelper, MiniDumpWriteDump)
ADD_GET_PROC(DbgHelper, SymInitialize)
ADD_GET_PROC(DbgHelper, SymGetModuleBase64)
ADD_GET_PROC(DbgHelper, SymGetLineFromAddr64)
ADD_GET_PROC(DbgHelper, SymFunctionTableAccess64)
ADD_GET_PROC(DbgHelper, StackWalk64)
ADD_GET_PROC(WS2, GetAddrInfoExW)
ADD_GET_PROC(WS2, GetAddrInfoExCancel)
ADD_GET_PROC(WS2, FreeAddrInfoExW)
ADD_GET_PROC(WS2, getaddrinfo)
ADD_GET_PROC(WS2, freeaddrinfo)
ADD_GET_PROC(WinTrust, WinVerifyTrust)
ADD_GET_PROC(IPHelper, GetAdaptersAddresses)
ADD_GET_PROC(IPHelper, GetAdaptersInfo)
ADD_GET_PROC(AdvancedApi, CryptAcquireContextW)
ADD_GET_PROC(AdvancedApi, CryptReleaseContext)
ADD_GET_PROC(AdvancedApi, CryptGenRandom)

View File

@ -8,6 +8,30 @@
#pragma once
struct _PROCESS_MEMORY_COUNTERS;
struct _tagSTACKFRAME64;
struct _MINIDUMP_EXCEPTION_INFORMATION;
struct _MINIDUMP_USER_STREAM_INFORMATION;
struct _IMAGEHLP_LINE64;
struct _tagADDRESS64;
struct _MINIDUMP_CALLBACK_INFORMATION;
struct _MIB_IPADDRTABLE;
struct _IP_ADAPTER_INFO;
enum _MINIDUMP_TYPE;
#if defined(AURORA_COMPILER_MSVC)
struct _IP_ADAPTER_ADDRESSES_LH;
struct _IP_ADAPTER_ADDRESSES_XP;
#if (NTDDI_VERSION >= NTDDI_VISTA)
typedef _IP_ADAPTER_ADDRESSES_LH IP_ADAPTER_ADDRESSES;
typedef _IP_ADAPTER_ADDRESSES_LH *PIP_ADAPTER_ADDRESSES;
#elif (NTDDI_VERSION >= NTDDI_WINXP)
typedef _IP_ADAPTER_ADDRESSES_XP IP_ADAPTER_ADDRESSES;
typedef _IP_ADAPTER_ADDRESSES_XP *PIP_ADAPTER_ADDRESSES;
#else
typedef _IP_ADAPTER_ADDRESSES_XP IP_ADAPTER_ADDRESSES;
typedef _IP_ADAPTER_ADDRESSES_XP *PIP_ADAPTER_ADDRESSES;
#endif
#endif
namespace Aurora
{
@ -23,7 +47,10 @@ namespace Aurora
static const wchar_t *kThemeDllName { L"UxTheme.dll" };
static const wchar_t *kShellDllName { L"Shell32.dll" };
static const wchar_t *kPSAPILegacyDllName { L"psapi.dll" };
static const wchar_t *kDbgHelperDllName { L"dbghelp.dll" };
static const wchar_t *kWinTrustDllName { L"WINTRUST.dll" };
static const wchar_t *kIPHelperDllName { L"IPHLPAPI.dll" };
struct WIN32_MEMORY_RANGE_ENTRY2
{
PVOID VirtualAddress;
@ -275,6 +302,18 @@ namespace Aurora
);
#endif
inline ULONGLONG(__stdcall *pVerSetConditionMask)(
ULONGLONG ConditionMask,
DWORD TypeMask,
BYTE Condition
);
inline BOOL(__stdcall *pVerifyVersionInfoW)(
LPOSVERSIONINFOEXW dwTypeMask,
DWORD TypeMask,
DWORDLONG dwlConditionMask
);
inline HRESULT(__stdcall *pSetWindowTheme)(
HWND hwnd,
LPCWSTR pszSubAppName,
@ -351,6 +390,107 @@ namespace Aurora
PWSTR * ppszPath
);
// dbghelp
inline DWORD(__stdcall *pUnDecorateSymbolName)(
PCSTR name,
PSTR outputString,
DWORD maxStringLength,
DWORD flags
);
inline BOOL(__stdcall *pMiniDumpWriteDump)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
enum _MINIDUMP_TYPE DumpType,
_MINIDUMP_EXCEPTION_INFORMATION * ExceptionParam,
_MINIDUMP_USER_STREAM_INFORMATION * UserStreamParam,
_MINIDUMP_CALLBACK_INFORMATION * CallbackParam
);
inline BOOL(__stdcall *pSymInitialize)(
HANDLE hProcess,
PCSTR UserSearchPath,
BOOL fInvadeProcess
);
inline DWORD64(__stdcall *pSymGetModuleBase64)(
HANDLE hProcess,
DWORD64 qwAddr
);
inline BOOL(__stdcall *pSymGetLineFromAddr64)(
HANDLE hProcess,
DWORD64 qwAddr,
PDWORD pdwDisplacement,
_IMAGEHLP_LINE64 * Line64
);
inline PVOID(__stdcall *pSymFunctionTableAccess64)(
HANDLE hProcess,
DWORD64 AddrBase
);
typedef BOOL(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
);
typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
HANDLE hProcess,
DWORD64 AddrBase
);
typedef DWORD64(__stdcall *PGET_MODULE_BASE_ROUTINE64)(
HANDLE hProcess,
DWORD64 Address
);
typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
HANDLE hProcess,
HANDLE hThread,
_tagADDRESS64 * lpaddr
);
inline BOOL(__stdcall *pStackWalk64)(
DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
_tagSTACKFRAME64 * StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
// WINTRUST
inline BOOL(__stdcall *pWinVerifyTrust)(
HWND hwnd,
GUID * pgActionID,
LPVOID pWVTData
);
// IP Helper
inline ULONG(__stdcall *pGetAdaptersAddresses)(
ULONG Family,
ULONG Flags,
PVOID Reserved,
IP_ADAPTER_ADDRESSES *AdapterAddresses,
PULONG SizePointer
);
inline ULONG(__stdcall *pGetAdaptersInfo)(
_IP_ADAPTER_INFO * AdapterInfo,
PULONG SizePointer
);
inline bool gUseNativeWaitMutex {};
inline bool gUseNativeWaitCondvar {};
inline bool gUseNativeWaitSemapahore {};

View File

@ -51,13 +51,20 @@ namespace Aurora::Debug
// On failure, the undecorated name is assigned the dname docorated name, which is offset by +1 (the '?' or '_' hint)
if (strcmp(pInfo->_UndecoratedName, pInfo->_DecoratedName + 1) == 0)
{
auto characters = UnDecorateSymbolName(pName.c_str(), poll.name, AuArraySize(poll.name), UNDNAME_32_BIT_DECODE);
if (!characters)
if (pUnDecorateSymbolName)
{
auto characters = pUnDecorateSymbolName(pName.c_str(), poll.name, AuArraySize(poll.name), UNDNAME_32_BIT_DECODE);
if (!characters)
{
return ret;
}
ret.type = AuString(poll.name, characters);
}
else
{
return ret;
}
ret.type = AuString(poll.name, characters);
}
#else

View File

@ -390,7 +390,12 @@ namespace Aurora::Debug
goto miniDumpOut;
}
ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
if (!pMiniDumpWriteDump)
{
goto miniDumpOut;
}
ok = pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
if (!ok)
{
AuLogWarn("Couldn't write minidump: {:x}", GetLastError());
@ -473,7 +478,12 @@ namespace Aurora::Debug
goto miniMiniDumpOut;
}
ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
if (!pMiniDumpWriteDump)
{
goto miniMiniDumpOut;
}
ok = pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)flags, &info, nullptr, nullptr);
if (!ok)
{
AuLogWarn("Couldn't write minidump: {:x}", GetLastError());
@ -499,7 +509,10 @@ namespace Aurora::Debug
static void CacheInternalBuildSymbols()
{
#if defined(AU_CFG_ID_INTERNAL) || defined(AU_CFG_ID_DEBUG)
SymInitialize(GetCurrentProcess(), NULL, TRUE);
if (pSymInitialize)
{
pSymInitialize(GetCurrentProcess(), NULL, TRUE);
}
#endif
}

View File

@ -65,25 +65,29 @@ namespace Aurora::Debug
for (ULONG frame = 0; ; frame++)
{
StackTraceEntry frameCurrent;
bool bResult {};
auto result = StackWalk64
(
#if defined(AURORA_ARCH_X64)
IMAGE_FILE_MACHINE_AMD64,
#else
IMAGE_FILE_MACHINE_I386,
#endif
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE,
&stack,
&cpy,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL
);
if (pSymGetModuleBase64 && pStackWalk64)
{
bResult = pStackWalk64
(
#if defined(AURORA_ARCH_X64)
IMAGE_FILE_MACHINE_AMD64,
#else
IMAGE_FILE_MACHINE_I386,
#endif
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE,
&stack,
&cpy,
NULL,
pSymFunctionTableAccess64,
pSymGetModuleBase64,
NULL
);
}
if (!result)
if (!bResult)
{
break;
}
@ -109,9 +113,12 @@ namespace Aurora::Debug
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, &line))
if (pSymGetLineFromAddr64)
{
frameCurrent.file = AuMakeTuple(line.FileName, line.LineNumber, 0);
if (pSymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, &line))
{
frameCurrent.file = AuMakeTuple(line.FileName, line.LineNumber, 0);
}
}
#endif

View File

@ -35,22 +35,28 @@ namespace Aurora::IO::Net
}
#if defined(AURORA_PLATFORM_WIN32)
AuSPtr<IP_ADAPTER_ADDRESSES> GetAddressesForFamily(ULONG uFamily)
AuSPtr<IP_ADAPTER_ADDRESSES_XP> GetAddressesForFamilyXP(ULONG uFamily)
{
static const auto kDefSize = 15 * 1024;
AuSPtr<IP_ADAPTER_ADDRESSES> pAddresses;
if (!pGetAdaptersAddresses)
{
return {};
}
AuSPtr<IP_ADAPTER_ADDRESSES_XP> pAddresses;
DWORD outBufLen { kDefSize };
DWORD dwRetVal;
DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS;
DWORD dwFlags = AuSwInfo::IsWindowsXPSP1OrGreater() ? GAA_FLAG_INCLUDE_PREFIX : 0;
DWORD dwIterations {};
do
{
pAddresses = AuReinterpretCast<IP_ADAPTER_ADDRESSES>(AuMakeSharedArray<AuUInt8>(kDefSize));
pAddresses = AuReinterpretCast<IP_ADAPTER_ADDRESSES_XP>(AuMakeSharedArray<AuUInt8>(kDefSize));
SysAssert(pAddresses);
dwRetVal = ::GetAdaptersAddresses(uFamily, dwFlags, NULL, pAddresses.get(), &outBufLen);
dwRetVal = pGetAdaptersAddresses(uFamily, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)(pAddresses.get()), &outBufLen);
if (dwRetVal == 0)
{
@ -70,10 +76,54 @@ namespace Aurora::IO::Net
}
while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (dwIterations < 5));
return dwRetVal == NO_ERROR ? pAddresses : AuSPtr<IP_ADAPTER_ADDRESSES> {};
return dwRetVal == NO_ERROR ? pAddresses : AuSPtr<IP_ADAPTER_ADDRESSES_XP> {};
}
AuSPtr<IP_ADAPTER_ADDRESSES_LH> GetAddressesForFamilyLH(ULONG uFamily)
{
static const auto kDefSize = 15 * 1024;
if (!pGetAdaptersAddresses)
{
return {};
}
AuSPtr<IP_ADAPTER_ADDRESSES_LH> pAddresses;
DWORD outBufLen { kDefSize };
DWORD dwRetVal;
DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS;
DWORD dwIterations {};
do
{
pAddresses = AuReinterpretCast<IP_ADAPTER_ADDRESSES_LH>(AuMakeSharedArray<AuUInt8>(kDefSize));
SysAssert(pAddresses);
dwRetVal = pGetAdaptersAddresses(uFamily, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)(pAddresses.get()), &outBufLen);
if (dwRetVal == 0)
{
break;
}
else if (dwRetVal != ERROR_BUFFER_OVERFLOW)
{
}
else
{
SysPushErrorNet("Fail");
break;
}
dwIterations++;
}
while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (dwIterations < 5));
return dwRetVal == NO_ERROR ? pAddresses : AuSPtr<IP_ADAPTER_ADDRESSES_LH> {};
}
AU_NOINLINE void AddressesToList(AuSPtr<IP_ADAPTER_ADDRESSES> pAddresses, AuList<AuSPtr<INetAdapter>> &adaptersOut)
template <typename T>
AU_NOINLINE void AddressesToList(AuSPtr<T> pAddresses, AuList<AuSPtr<INetAdapter>> &adaptersOut)
{
auto pCurrAddresses = pAddresses.get();
@ -125,18 +175,29 @@ namespace Aurora::IO::Net
adapter.anycast = ep.ip;
}
auto pGateway = pCurrAddresses->FirstGatewayAddress;
if (pGateway)
if constexpr (!AuIsSame_v<T, _IP_ADAPTER_ADDRESSES_XP>)
{
NetEndpoint ep;
if (pGateway->Address.iSockaddrLength <= sizeof(ep.hint))
auto pGateway = pCurrAddresses->FirstGatewayAddress;
if (pGateway)
{
AuMemcpy(ep.hint, pGateway->Address.lpSockaddr, pGateway->Address.iSockaddrLength);
DeoptimizeEndpoint(ep);
}
NetEndpoint ep;
if (pGateway->Address.iSockaddrLength <= sizeof(ep.hint))
{
AuMemcpy(ep.hint, pGateway->Address.lpSockaddr, pGateway->Address.iSockaddrLength);
DeoptimizeEndpoint(ep);
}
adapter.gateway = ep.ip;
adapter.gateway = ep.ip;
}
}
if (adapter.address.ip == EIPProtocol::eIPProtocolV4)
{
adapter.index = pCurrAddresses->IfIndex;
}
else
{
adapter.index = adaptersOut.size();
}
auto pDnsServers = pCurrAddresses->FirstDnsServerAddress;
@ -153,7 +214,7 @@ namespace Aurora::IO::Net
adapter.dns.push_back(ep.ip);
}
while (pDnsServers = pDnsServers->Next);
while ((pDnsServers = pDnsServers->Next));
}
adaptersOut.push_back(pAdapter);
@ -162,14 +223,69 @@ namespace Aurora::IO::Net
}
}
static void FixupXPGatewaysIPv4()
{
IP_ADAPTER_INFO info[128];
DWORD size { sizeof(info) };
IP_ADAPTER_INFO *pAdapter {};
if (!pGetAdaptersInfo)
{
return;
}
ULONG error;
if ((error = pGetAdaptersInfo(info, &size)) != NO_ERROR)
{
if (error == ERROR_NO_DATA)
{
return;
}
SysPushErrorNet("GetAdaptersInfo failed");
return;
}
if (size == 0)
{
return;
}
auto pIPAddrTable = info;
while (pIPAddrTable)
{
for (auto &pAdapter : gIpv4Adapters)
{
auto pAdapterEx = AuStaticCast<NetAdapter>(pAdapter);
if (pAdapterEx->device == AuString(pIPAddrTable->AdapterName))
{
pAdapterEx->gateway = IPAddress(pIPAddrTable->GatewayList.IpAddress.String);
}
}
pIPAddrTable = pIPAddrTable->Next;
}
}
#endif
static void PrecacheAdapters()
{
auto pAdaptersV4 = GetAddressesForFamily(AF_INET);
auto pAdaptersV6 = GetAddressesForFamily(AF_INET6);
AddressesToList(pAdaptersV4, gIpv4Adapters);
AddressesToList(pAdaptersV6, gIpv6Adapters);
if (!AuSwInfo::IsWindowsVistaOrGreater())
{
auto pAdaptersV4 = GetAddressesForFamilyXP(AF_INET);
auto pAdaptersV6 = GetAddressesForFamilyXP(AF_INET6);
AddressesToList(pAdaptersV4, gIpv4Adapters);
AddressesToList(pAdaptersV6, gIpv6Adapters);
FixupXPGatewaysIPv4();
}
else
{
auto pAdaptersV4 = GetAddressesForFamilyLH(AF_INET);
auto pAdaptersV6 = GetAddressesForFamilyLH(AF_INET6);
AddressesToList(pAdaptersV4, gIpv4Adapters);
AddressesToList(pAdaptersV6, gIpv6Adapters);
}
}
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv4s()

View File

@ -190,9 +190,14 @@ namespace Aurora::Process
// Set pFile.
WinTrustData.pFile = &FileData;
if (!pWinVerifyTrust)
{
return gRuntimeConfig.debug.bWin32VerifyTrustFailMissingAPI;
}
// WinVerifyTrust verifies signatures as specified by the GUID
// and Wintrust_Data.
lStatus = WinVerifyTrust(
lStatus = pWinVerifyTrust(
NULL,
&WVTPolicyGUID,
&WinTrustData);
@ -245,7 +250,12 @@ namespace Aurora::Process
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
lStatus = WinVerifyTrust(
if (!pWinVerifyTrust)
{
return gRuntimeConfig.debug.bWin32VerifyTrustFailMissingAPI;
}
lStatus = pWinVerifyTrust(
NULL,
&WVTPolicyGUID,
&WinTrustData);

View File

@ -25,10 +25,20 @@ namespace Aurora::SWInfo
static bool IsWindowsEnterpriseBranch()
{
OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0, VER_SUITE_ENTERPRISE, 0, 0};
DWORDLONG const dwlConditionMask = VerSetConditionMask(0, VER_SUITENAME, VER_EQUAL);
if (!pVerifyVersionInfoW)
{
return false;
}
return !VerifyVersionInfoW(&osvi, VER_SUITENAME, dwlConditionMask);
if (!pVerSetConditionMask)
{
return false;
}
OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0, VER_SUITE_ENTERPRISE, 0, 0};
DWORDLONG const dwlConditionMask = pVerSetConditionMask(0, VER_SUITENAME, VER_EQUAL);
return !pVerifyVersionInfoW(&osvi, VER_SUITENAME, dwlConditionMask);
}
auline bool Win32ReadRegistry(HKEY hKey, const wchar_t *pWideKey, AuString &strValue)