微软在UWP中提供了一组丰富的API能够满足99%的应用的需求
,然而在那剩下1%的情况下找不到桌面API的替代品是很棘手的,正如我上一篇文章里提到的CreateFile,就不属于微软在UWP中允许使用的API。
实际上WACK的API检测是个没什么用的东西,因为它是通过读取PE导入表,以及 .NET程序的P/Invoke签名的方法来判断一个App是否使用了不允许使用的API。因此只要调用LoadLibrary就能轻松绕过。
问题在于LoadLibrary(Ex)本身不被允许调用,微软表示替代品是LoadPackagedLibrary,而这个API在调用时会检测路径是否在appx内,如果不在就直接报错。(
)因此首先我们要设法获得LoadLibraryEx的地址,在此之前先获取kernel32.dll或kernelbase.dll的地址。
方法1:使用VirtualQuery获取
MEMORY_BASIC_INFORMATION info = {}; if (VirtualQuery(VirtualQuery, &info, sizeof(info))) { auto kernelAddr = (HMODULE)info.AllocationBase; auto loadlibraryPtr = GetProcAddress(kernelAddr, "LoadLibraryExW"); // load your library here ... }
方法2:使用Thread Environment Block获取
首先定义结构
typedef struct _PEB_LDR_DATA { ULONG Length; UCHAR Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID EntryInProgress; } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PVOID ProcessParameters; PVOID Reserved4[3]; PVOID AtlThunkSListPtr; PVOID Reserved5; ULONG Reserved6; PVOID Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; PVOID Reserved9[45]; BYTE Reserved10[96]; PVOID PostProcessInitRoutine; BYTE Reserved11[128]; PVOID Reserved12[1]; ULONG SessionId; } PEB, *PPEB; typedef struct _TEB { PVOID Reserved1[12]; PPEB ProcessEnvironmentBlock; PVOID Reserved2[399]; BYTE Reserved3[1952]; PVOID TlsSlots[64]; BYTE Reserved4[8]; PVOID Reserved5[26]; PVOID ReservedForOle; // Windows 2000 only PVOID Reserved6[4]; PVOID TlsExpansionSlots; } TEB, *PTEB;
然后计算地址
auto teb = NtCurrentTeb(); auto peb = teb->ProcessEnvironmentBlock; auto pebldr = peb->Ldr; auto ioml = *(DWORD*)pebldr->InInitializationOrderModuleList.Flink; auto kernelAddr = (HMODULE)*(DWORD*)(ioml + 8); auto loadlibraryPtr = GetProcAddress(kernelAddr, "LoadLibraryExW"); // load your library here ...
方法3:直接搜索(方法来自 XDA )
HMODULE SearchKernelAddress() { char *Tmp = (char*)GetTickCount64; Tmp = (char*)((~0xFFF)&(DWORD_PTR)Tmp); while (Tmp) { __try { if (Tmp[0] == 'M' && Tmp[1] == 'Z') break; } __except (EXCEPTION_EXECUTE_HANDLER) { } Tmp -= 0x1000; } if (Tmp == 0) return nullptr; else return (HMODULE)Tmp; }
上述方法不仅适用于UWP,还适用于Windows Phone 8/8.1应用,以及Windows 8/8.1的应用。
个人最推荐的方式是VirtualQuery,它使用的全是公开的API和结构,而使用TEB获取的方式里使用了私有结构,因此将来的系统更新可能会导致兼容性出现问题。
项目示例与源码: https://github.com/hjc4869/WACKBypass