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