微软在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