"""Dump every string reachable from the decoded prototype tree at load time.

Runs stage2 with the real payload, hooks the moment the load pass returns
(``y,... = W:KS(...)``), then walks all 488 prototypes and prints each distinct
string with its hex bytes. User strings in this VM are encrypted at rest, so
whatever comes out here is what the loader materialises before execution.
"""

import re
from pathlib import Path

STAGE2 = Path("/root/luad/samples/boulder/stage2.lua")
PAYLOAD = Path("/root/luad/samples/boulder/payload.bin")
OUT = Path("/tmp/opencode/strings_run.luau")

HOOK = r'''
local __seen, __out, __n = {}, {}, 0
local function __emit(path, s)
  if __seen[s] then return end
  __seen[s] = true
  __n = __n + 1
  __print("S", path, #s, (s:gsub(".", function(c) return string.format("%02x", string.byte(c)) end)))
end
local function __walk(v, path, depth)
  if type(v) == "string" then
    if #v >= 4 then __emit(path, v) end
    return
  end
  if type(v) ~= "table" or depth <= 0 or __seen[v] then return end
  __seen[v] = true
  for k, x in pairs(v) do
    __walk(x, path .. "." .. tostring(k), depth - 1)
  end
end
function __SCANSTR(y)
  __print("SCAN_BEGIN", #y)
  for i = 1, #y do __walk(y[i], "p" .. i, 4) end
  __print("SCAN_END", __n)
end
'''

SHIM = r'''
local __print = print
local function __proxy(name)
  local t = {}
  return setmetatable(t, {
    __index = function(self, k)
      local v = __proxy(name .. "." .. tostring(k)); rawset(self, k, v); return v
    end,
    __call = function() return __proxy(name .. "()") end,
    __tostring = function() return "<" .. name .. ">" end,
  })
end
game = __proxy("game")
workspace = __proxy("workspace")
Instance = {new = function(c) return __proxy("Instance:" .. tostring(c)) end}
Enum = setmetatable({}, {__index = function(t, k) local v = __proxy("E." .. k); rawset(t, k, v); return v end})
task = {wait = function() end, spawn = function() end}
typeof = function(v) return type(v) end
tick = function() return 0 end
'''


def main() -> None:
    stage2 = STAGE2.read_text()
    payload = PAYLOAD.read_bytes()

    needle = "y,A,m,P,e=W:KS(e,P,A,G,y);"
    assert stage2.count(needle) == 1
    stage2 = stage2.replace(needle, needle + "__SCANSTR(y);", 1)
    assert stage2.startswith("local R=...;")
    lit = '"' + "".join("\\x%02x" % b for b in payload) + '"'
    stage2 = "local R=buffer.fromstring(" + lit + ");" + stage2[len("local R=...;"):]

    body = (
        SHIM
        + HOOK
        + "\nlocal __ok, __err = pcall(function()\n"
        + stage2
        + "\nend)\n"
        + '__print("EXEC", __ok, tostring(__err))\n'
    )
    OUT.write_text(body)
    print("wrote", OUT, len(body))


if __name__ == "__main__":
    main()
