104 lines
4.5 KiB
C++
104 lines
4.5 KiB
C++
|
|||
|
|
#define WIN32_LEAN_AND_MEAN
|
||
|
|
#include <windows.h>
|
||
|
|
#include <inspectable.h>
|
||
|
|
#include <winstring.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <wchar.h>
|
||
|
|
struct Packet { volatile LONG state; LONG hr; DWORD thread; DWORD reserved;
|
||
|
|
wchar_t script[8192]; wchar_t result[32768]; };
|
||
|
|
static const UINT Wake = WM_APP + 0x497;
|
||
|
|
static Packet* packet=nullptr;
|
||
|
|
static HANDLE mapping=nullptr;
|
||
|
|
static IUnknown* core=nullptr;
|
||
|
|
static IUnknown* operation=nullptr;
|
||
|
|
static IUnknown* info=nullptr;
|
||
|
|
static const GUID CoreIID={0x3a3f559a,0xe5e9,0x5338,{0xbb,0x67,0x4e,0xb0,0x50,0x4a,0x4f,0x14}};
|
||
|
|
static const GUID InfoIID={0x00000036,0,0,{0xc0,0,0,0,0,0,0,0x46}};
|
||
|
|
static void** table(void* p) { return *(void***)p; }
|
||
|
|
static void clearAsync() {
|
||
|
|
if(info){info->Release();info=nullptr;}
|
||
|
|
if(operation){operation->Release();operation=nullptr;}
|
||
|
|
}
|
||
|
|
static void fail(HRESULT hr) { clearAsync();packet->hr=hr;InterlockedExchange(&packet->state,-1); }
|
||
|
|
static HRESULT findCore() {
|
||
|
|
auto module=(uintptr_t)GetModuleHandleW(L"Microsoft.Web.WebView2.Core.dll");
|
||
|
|
if(!module)return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
|
||
|
|
MEMORY_BASIC_INFORMATION mbi;
|
||
|
|
uintptr_t address=0,scanned=0;
|
||
|
|
while(VirtualQuery((void*)address,&mbi,sizeof(mbi))) {
|
||
|
|
uintptr_t end=(uintptr_t)mbi.BaseAddress+mbi.RegionSize;
|
||
|
|
if(end<=address)break;
|
||
|
|
address=end;
|
||
|
|
if(mbi.State!=MEM_COMMIT||mbi.Type!=MEM_PRIVATE||mbi.Protect!=PAGE_READWRITE||
|
||
|
|
mbi.RegionSize>64*1024*1024)continue;
|
||
|
|
if(scanned+mbi.RegionSize>256*1024*1024)break;
|
||
|
|
scanned+=mbi.RegionSize;
|
||
|
|
for(uintptr_t p=(uintptr_t)mbi.BaseAddress;p+0x118<=end;p+=8) {
|
||
|
|
if(*(uintptr_t*)p!=module+0xa6ef0 || *(uintptr_t*)(p+0x108)!=module+0xa6eb0)continue;
|
||
|
|
if(table((void*)p)[0]!=(void*)(module+0x5ac50))continue;
|
||
|
|
auto hr=((IUnknown*)p)->QueryInterface(CoreIID,(void**)&core);
|
||
|
|
if(FAILED(hr))continue;
|
||
|
|
if(table(core)[49]!=(void*)(module+0x59060)) { core->Release();core=nullptr;continue; }
|
||
|
|
return S_OK;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
||
|
|
}
|
||
|
|
static void runProbe() {
|
||
|
|
if(!packet) {
|
||
|
|
wchar_t name[96];swprintf_s(name,L"Local\\WhatsAppLocalProbe-%lu",GetCurrentProcessId());
|
||
|
|
mapping=OpenFileMappingW(FILE_MAP_ALL_ACCESS,FALSE,name);
|
||
|
|
if(!mapping)return;
|
||
|
|
packet=(Packet*)MapViewOfFile(mapping,FILE_MAP_ALL_ACCESS,0,0,sizeof(Packet));
|
||
|
|
if(!packet){CloseHandle(mapping);mapping=nullptr;return;}
|
||
|
|
}
|
||
|
|
if(packet->thread!=GetCurrentThreadId()) { fail(RPC_E_WRONG_THREAD);return; }
|
||
|
|
LONG state=packet->state;
|
||
|
|
if(state==6) {
|
||
|
|
clearAsync();if(core){core->Release();core=nullptr;}
|
||
|
|
InterlockedExchange(&packet->state,7);
|
||
|
|
UnmapViewOfFile(packet);packet=nullptr;CloseHandle(mapping);mapping=nullptr;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if(state==0) {
|
||
|
|
if(!core){auto hr=findCore();if(FAILED(hr)){fail(hr);return;}}
|
||
|
|
HSTRING text=nullptr;
|
||
|
|
auto hr=WindowsCreateString(packet->script,(UINT32)wcsnlen_s(packet->script,8192),&text);
|
||
|
|
if(FAILED(hr)){fail(hr);return;}
|
||
|
|
using Execute=HRESULT(STDMETHODCALLTYPE*)(void*,HSTRING,IUnknown**);
|
||
|
|
hr=((Execute)table(core)[49])(core,text,&operation);
|
||
|
|
WindowsDeleteString(text);
|
||
|
|
if(FAILED(hr)){fail(hr);return;}
|
||
|
|
hr=operation->QueryInterface(InfoIID,(void**)&info);
|
||
|
|
if(FAILED(hr)){fail(hr);return;}
|
||
|
|
InterlockedExchange(&packet->state,1);
|
||
|
|
}
|
||
|
|
if(packet->state==1) {
|
||
|
|
using Status=HRESULT(STDMETHODCALLTYPE*)(void*,INT32*);
|
||
|
|
INT32 status=0;auto hr=((Status)table(info)[7])(info,&status);
|
||
|
|
if(FAILED(hr)){fail(hr);return;}
|
||
|
|
if(status==0)return;
|
||
|
|
if(status!=1){fail(E_ABORT);return;}
|
||
|
|
using Results=HRESULT(STDMETHODCALLTYPE*)(void*,HSTRING*);
|
||
|
|
HSTRING value=nullptr;hr=((Results)table(operation)[8])(operation,&value);
|
||
|
|
if(FAILED(hr)){fail(hr);return;}
|
||
|
|
UINT32 length=0;auto raw=WindowsGetStringRawBuffer(value,&length);
|
||
|
|
if(length>=32768){WindowsDeleteString(value);fail(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));return;}
|
||
|
|
wmemcpy(packet->result,raw,length);packet->result[length]=0;
|
||
|
|
WindowsDeleteString(value);clearAsync();packet->hr=S_OK;
|
||
|
|
InterlockedExchange(&packet->state,2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
extern "C" __declspec(dllexport) LRESULT CALLBACK ProbeHook(int code,WPARAM wParam,LPARAM lParam) {
|
||
|
|
if(code>=0 && wParam==PM_REMOVE && ((MSG*)lParam)->message==Wake) {
|
||
|
|
((MSG*)lParam)->message=WM_NULL;
|
||
|
|
__try {runProbe();}
|
||
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
|
if(packet){packet->hr=(LONG)GetExceptionCode();InterlockedExchange(&packet->state,-1);}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return CallNextHookEx(nullptr,code,wParam,lParam);
|
||
|
|
}
|
||
|
|
BOOL WINAPI DllMain(HINSTANCE,DWORD,LPVOID) {return TRUE;}
|