63 lines
3.3 KiB
C
63 lines
3.3 KiB
C
#pragma once
|
|
#include <cstring>
|
|
|
|
// 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;i<nt->FileHeader.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;i<nt->FileHeader.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+8*sizeof(uintptr_t))return false;
|
|
out.secondary=out.primary-8*sizeof(uintptr_t);
|
|
for(unsigned i=0;i<6;i++) {
|
|
auto target=((uintptr_t*)out.secondary)[i];
|
|
if(target<base || target>=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;
|
|
}
|