#pragma once #include // Conservative fingerprint discovery: no module-relative code/data RVAs. // These relocation-free prefixes describe a supported compiler layout, not // every possible WebView release. Ambiguous/changed layouts fail closed. struct CoreLayout { uintptr_t primary, secondary, query; }; static bool discoverCoreLayout(uintptr_t base, CoreLayout& out) { const BYTE query[] = {0x48,0x89,0x5c,0x24,0x08,0x48,0x89,0x6c,0x24,0x10, 0x48,0x89,0x74,0x24,0x18,0x57,0x48,0x83,0xec,0x20, 0x48,0x8d,0x99,0x08,0x01,0x00,0x00,0x33,0xed,0x48,0x85,0xdb}; const BYTE execute[] = {0x40,0x53,0x56,0x57,0x41,0x56,0x41,0x57, 0x48,0x83,0xec,0x30,0x4d,0x8b,0xf0,0x45,0x33,0xff,0x4d,0x89,0x38, 0x48,0x8d,0x71,0xf0}; auto dos=(IMAGE_DOS_HEADER*)base; if(dos->e_magic!=IMAGE_DOS_SIGNATURE || dos->e_lfanew<=0 || dos->e_lfanew>0x100000)return false; auto nt=(IMAGE_NT_HEADERS64*)(base+dos->e_lfanew); if(nt->Signature!=IMAGE_NT_SIGNATURE || nt->FileHeader.Machine!=IMAGE_FILE_MACHINE_AMD64 || nt->OptionalHeader.Magic!=IMAGE_NT_OPTIONAL_HDR64_MAGIC || nt->FileHeader.NumberOfSections>96)return false; auto sections=IMAGE_FIRST_SECTION(nt); unsigned nq=0,ne=0,np=0; for(unsigned i=0;iFileHeader.NumberOfSections;i++) { auto& s=sections[i];size_t size=s.Misc.VirtualSize; if(s.VirtualAddress>=nt->OptionalHeader.SizeOfImage || size>nt->OptionalHeader.SizeOfImage-s.VirtualAddress)return false; if(!(s.Characteristics&IMAGE_SCN_MEM_EXECUTE))continue; const BYTE* start=(BYTE*)(base+s.VirtualAddress); for(size_t j=0;j+sizeof(query)<=size;j++)if(!memcmp(start+j,query,sizeof(query))){out.query=(uintptr_t)(start+j);nq++;} for(size_t j=0;j+sizeof(execute)<=size;j++)if(!memcmp(start+j,execute,sizeof(execute)))ne++; } if(nq!=1 || ne==0)return false; for(unsigned i=0;iFileHeader.NumberOfSections;i++) { auto& s=sections[i];size_t size=s.Misc.VirtualSize; if(!(s.Characteristics&IMAGE_SCN_MEM_READ) || (s.Characteristics&(IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE)))continue; auto start=base+s.VirtualAddress; for(size_t j=0;j+sizeof(uintptr_t)*6<=size;j+=sizeof(uintptr_t)) { auto v=(uintptr_t*)(start+j); if(v[0]==out.query){out.primary=(uintptr_t)v;np++;} } } // The secondary table immediately precedes this implementation's primary // table (eight ABI entries). Keep this structural requirement explicit. if(np!=1 || out.primary=base+nt->OptionalHeader.SizeOfImage)return false; MEMORY_BASIC_INFORMATION m{}; if(!VirtualQuery((void*)target,&m,sizeof(m)) || m.State!=MEM_COMMIT || (m.Protect!=PAGE_EXECUTE_READ && m.Protect!=PAGE_EXECUTE_READWRITE))return false; } return true; } static bool supportedExecute(void* code) { const BYTE prefix[]={0x40,0x53,0x56,0x57,0x41,0x56,0x41,0x57, 0x48,0x83,0xec,0x30,0x4d,0x8b,0xf0,0x45,0x33,0xff,0x4d,0x89,0x38, 0x48,0x8d,0x71,0xf0}; MEMORY_BASIC_INFORMATION m{}; if(!VirtualQuery(code,&m,sizeof(m)) || m.State!=MEM_COMMIT || (m.Protect!=PAGE_EXECUTE_READ && m.Protect!=PAGE_EXECUTE_READWRITE))return false; return memcmp(code,prefix,sizeof(prefix))==0; }