-- Synthetic loaded-module images; verifies the layout-v2 compatibility contract. local N=dofile(SOURCE..'/native.lua') local count=0 local function C(v,m)if not v then error((m or 'check')..' @'..debug.getinfo(2,'l').currentline,2)end;count=count+1 end local function le(v,n)local t={};for i=1,n do t[i]=string.char(v%256);v=math.floor(v/256)end;return table.concat(t)end local function hex(h)return (h:gsub('..',function(x)return string.char(tonumber(x,16))end))end local BASE=0x7ff600000000 local function image(o) o=o or {} local mem={} local mz='MZ'..string.rep('\0',0x3a)..le(0x80,4);mz=mz..string.rep('\0',512-#mz) mem[#mem+1]={BASE,mz} local pe='PE\0\0'..le(o.machine or 0x8664,2)..le(o.sections or 16,2)..le(o.timestamp or 0x6AB3B43F,4)..le(0,8)..le(o.optional or 0xF0,2)..le(0x22,2) pe=pe..le(o.magic or 0x20B,2)..string.rep('\0',80-26)..le(o.size or 0x4744000,4)..le(0x400,4)..le(o.checksum or 0xECDA6F,4) pe=pe..string.rep('\0',112-#pe) mem[1]={BASE,mz:sub(1,0x80)..pe..mz:sub(0x80+#pe+1)} for i,g in ipairs(N.guards)do local b=hex(g[2]) if o.flip==i then b=string.char((b:byte(1)+1)%256)..b:sub(2)end mem[#mem+1]={BASE+g[1],b} end return function(p,n) for _,m in ipairs(mem)do if p>=m[1] and p+n<=m[1]+#m[2] then return m[2]:sub(p-m[1]+1,p-m[1]+n)end end return nil end end C(#N.guards==14,'guard count') C(N.version=='r4-layout-v2') -- current build 25480438 image (upstream-reviewed metadata) local ok,why=N.check_module(image(),BASE);C(ok,why);C(why:find('PE=6AB3B43F/04744000/00ECDA6F',1,true),why);C(N.image_size==0x4744000) -- previous build 25327279 image still accepted when guards match ok,why=N.check_module(image{timestamp=0x6AA96B14,size=0x4770000,checksum=0xF05B12},BASE);C(ok,why);C(why:find('6AA96B14',1,true)) -- a hypothetical future image with different metadata but identical guards ok,why=N.check_module(image{timestamp=0x7000AAAA,size=0x4800000,checksum=1,sections=17},BASE);C(ok,why) -- any guard byte change rejects, for every guard for i=1,#N.guards do ok,why=N.check_module(image{flip=i},BASE);C(not ok and why==string.format('native code guard 0x%X',N.guards[i][1]),tostring(why));C(N.image_size==nil) end -- roots must lie inside the image ok,why=N.check_module(image{size=0x3000000},BASE);C(not ok and why=='native root outside module',why) -- structure checks ok,why=N.check_module(image{magic=0x10B},BASE);C(not ok and why=='unsupported game.dll PE structure') ok,why=N.check_module(image{machine=0x14c},BASE);C(not ok and why=='unsupported game.dll PE structure') ok,why=N.check_module(image{optional=64},BASE);C(not ok and why=='unsupported game.dll PE structure') ok,why=N.check_module(image{sections=0},BASE);C(not ok and why=='unsupported game.dll PE structure') ok,why=N.check_module(image{size=0x9000000},BASE);C(not ok and why=='unsupported game.dll PE structure') -- unreadable header ok,why=N.check_module(function()return nil end,BASE);C(not ok and why=='module header unreadable') -- missing guard memory counts as mismatch local short=image();ok,why=N.check_module(function(p,n)if p==BASE+N.guards[5][1] then return nil end;return short(p,n)end,BASE) C(not ok and why==string.format('native code guard 0x%X',N.guards[5][1])) -- roots are unchanged from the upstream-reviewed layout C(N.roots.network==0x346BF98 and N.roots.health==0x3326688 and N.roots.synced==0x3326C98 and N.roots.seater==0x3326D78) return count