带符号的字节码加载

时间:2016-11-02 04:56:45

标签: security lua bytecode

所以我正在考虑保护Lua的load函数以进行字节码加载。目前我有这个:

local nativeload = load
load = function(chunk, chunkname, mode, ...)
  if mode == nil then
    mode = "bt"
  elseif not (mode == "b" or mode == "t" or mode == "bt") then
    error("Invalid mode")
  end
  local targetenv = [[snip]]
  if select('#', ...) > 0 then targetenv = ... end
  if mode == "t" then
    return nativeload(chunk, chunkname, mode, targetenv)
  elseif type(chunk) == "string" then
    if chunk:sub(1,4) == "\27Lua" then
      local code = chunk:sub(1,-33)
      if HMAC_SHA256(code, getkey()) == chunk:sub(-32) then
        return nativeload(code, chunkname, mode, targetenv)
      else
        error("Invalid signature")
      end
    else
      return nativeload(chunk, chunkname, mode, targetenv)
    end
  elseif type(chunk) == "function" then
    -- How do I do this?!
  end
end

而且,虽然文本模式和字符串块的处理相当简单,但我不知道如何处理函数块。

我是否只是以某种方式将所有内容收集到字符串中,然后执行HMAC内容并使用此字符串调用nativeload?但是在没有程序崩溃的情况下我失去能够load()大文件(例如2GB文件)(函数load以8k字节为增量编译文件,当文件大多是空行时,这意味着它在编译期间只需要几千字节 - 将整个文件加载到一个字符串中显然会使用2GB的RAM。

我该怎么做?

1 个答案:

答案 0 :(得分:1)

local function extract_code(data)
   local code = data:sub(1,-33)
   assert(HMAC_SHA256(code, getkey()) == data:sub(-32), "Invalid signature")
   return code
end

local nativeload = load
load = function(chunk, chunkname, mode, ...)
   local targetenv = [[snip]]
   if select('#', ...) ~= 0 then targetenv = ... end
   local new_chunk
   if type(chunk) == "string" then
      new_chunk = chunk:match"^\27Lua" and extract_code(chunk) or chunk
   elseif type(chunk) == "function" then
      local buffer = ""
      repeat
         local next_part = chunk() or ""
         buffer = buffer..next_part
      until next_part == "" or #buffer >= 4
      if buffer:match"^\27Lua" then -- Bytecode can't be very large, collect it in a string
         local t = {buffer}
         while t[#t] ~= "" do t[#t+1] = chunk() or "" end
         new_chunk = extract_code(table.concat(t))
      else                          -- Source code can be very large, use a function
         local function f()
            f = chunk
            return buffer
         end
         function new_chunk()
            return f()
         end
      end
   end
   return nativeload(new_chunk, chunkname, mode, targetenv)
end