LuaDec51 - Reversing lua compilado

Utilidades y herramientas que nos hacen la vida mas fácil al programar en AMS.
Hola, desde hace un tiempo veo usuarios utilizando "luac" como si se tratase de la panacea en cuanto a seguridad, obfuscación o lo que coño penseis que hace luac, en realidad luac es una simplificacion de tiempo en la carga de lua. Al cargar un archivo lua, internamente lo convierte a luac, lo cual funciona mediante una serie de opcodes como cualquier otro binario. Al abrir un archivo compilado ahorramos ese tiempo.

Os traigo una herramienta muy sencillita para revertir un archivo luac a lua generico.

LuaDec51 - https://github.com/sztupy/luadec51
[Download] http://files.luaforge.net/releases/luad ... -win32-bin

Para usarlo solo hay que utilizar un cmd "luadec file.luac > file.lua"

Y generará el archivo. Como nota al margen, los nombres de variables funciones y tablas se pierden, pero luadec regenera nombres que pueden ser sustituidos, ademas el orden numerico es bastante comodo.

Como ejemplo, podemos ver parte del codigo de PeekMi (thedary)

dben.lib

Código: Seleccionar todo

LuaQ     @data\dben.lua              @     €  AÀ  @ @   À € @   @ € À À       € @ $   € [email protected]  À $€    $À  @ $  €  €       sFileDB    pm.db    require    luasql.sqlite3    PMDAT       ð?   PMCAT        @   PMKEY       @   ENCODE    DECODE    EDITAR    NUEVO 
   BetaToPeekMi    CrearDB    Listar    Guardar 	   Eliminar           ?     W   B   G   E€  FÀÀ \€€ [email protected]  [email protected]  [email protected]Á À   \€€G  EÀ …  ‹ BA œ €\€  G€ E€ Z   €€E€ …€ ‹ÀBœ  \  À € Ã@ €‚€ ‡  a€  @þE€ [email protected]à \@ E   [email protected]   
€E  K  Á€ \@€E  K  ÁÀ \@€EÀ …  ‹ BA œ €\€  G  E  Z   €€E  KÀÄ Ê    \€ G€ E€ Z   €€E  K  Å@ Æ€ÅÁ E FÆÜ €\@    €@üE  [email protected]à \@ E  [email protected]à \@ [email protected]  [email protected]à \@  €       bNumeroExiste    env    luasql    sqlite3    con    connect    cur1    assert    execute    SELECT * FROM PM_SYSTEM    pairs    getcolnames    numero    close 3   ALTER TABLE 'PM_SYSTEM' RENAME to 'PM_SYSTEM_BETA' D   CREATE TABLE 'PM_SYSTEM' ('numero' INTEGER PRIMARY KEY, 'key' text)    cur2    SELECT key FROM PM_SYSTEM_BETA    row    fetch    a    string    format +   INSERT INTO PM_SYSTEM ('key') VALUES('%s')    key     W                                         !   !   !   !   !   !   !   $   $   $   %   %   %   %   %   %   &   &   '   '   %   (   *   *   *   -   -   -   .   .   .   .   /   /   /   /   1   1   1   1   1   1   1   3   3   3   4   4   4   4   4   4   6   6   6   7   7   7   7   7   7   7   7   7   8   8   :   :   :   =   =   =   >   >   >   ?         sFileDB     V      (for generator)    !      (for state)    !      (for control)    !      i          v               A   P     +   [email protected]  F€À \€€ G   E   K Á À   \€€GÀ  E€ …À  ‹ÀA œ €\€  [email protected] E€ …À  ‹ÀAA œ €\€  [email protected] E€ …À  ‹ÀA œ €\€  [email protected] [email protected] À € €B € ^  ÀÿEÀ  K à \@ E   K à \@  € 
      env    luasql    sqlite3    con    connect    res    assert    execute     CREATE TABLE 'PM_DATOS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text, 'sitioweb' text, 'usuario' text, 'password' text, 'comentarios' text, 'categoria' text) M   CREATE TABLE 'PM_CATEGORIAS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text) F   CREATE TABLE 'PM_SYSTEM' 	 ('numero' INTEGER PRIMARY KEY, 'key' text)            close     +   C   C   C   C   D   D   D   D   D   E   E   E   E   E   E   E   F   F   F   F   F   F   F   G   G   G   G   G   G   G   I   I   I   J   J   J   N   N   N   O   O   O   P         sFile     *           R   ¢     	¡   ‚   ‡   …@  €  € €À  ‡€  €€…  €  € €@ ‡€   €…€ €  @ €À ‡€    Å€  •À Ê   A E €€ \ Z   €E €€ \ @ €  €[email protected] Z    €@€„€€@ Á Å  € ܁ B • ‚EÁ FÄ\€ G E KÄÅÁ \€GA EA KAÅÀ \€G E KÁÅÊ   \ G E Z  @€E Z  À€AFEA  @ À€JÁ … Ł ÆÇœ I… †AGIŽ… †GI… †ÁGI… †HI… Ł ÆAÈœ I… †ÁHI‘G €€E @ €€J  … Ł ÆÇœ I… †AGIŽG  €E @ @€J  … Ł ÆÇœ I… †II’G E É@E KÁÅŁ  \ G  îE KAÉ\A EA KAÉ\A E KAÉ\A @B  €Ã €E  ZA  @ €AÁ	 G	 @€…	 ^€ € (      error    PMDAT    sTabla 	   PM_DATOS    PMCAT    PM_CATEGORIAS    PMKEY 
   PM_SYSTEM    SELECT * FROM          	   tonumber     WHERE categoria LIKE ' 	   tostring    '    env    luasql    sqlite3    con    connect    sFileDB    cur    execute    row    fetch    a       ð?   tData 	   recordid    numero 	   etiqueta 	   sitioweb    usuario 	   password 
   categoria    comentario    comentarios    ke
dben.lua

Código: Seleccionar todo

-- Decompiled using luadec 2.0 standard by sztupy (http://luadec51.luaforge.net)
-- Command line was: dben.lib 

sFileDB = "pm.db"
require("luasql.sqlite3")
PMDAT = 1
PMCAT = 2
PMKEY = 3
ENCODE = 1
DECODE = 2
EDITAR = false
NUEVO = true
BetaToPeekMi = function(l_1_0)
  bNumeroExiste = false
  env = luasql.sqlite3()
  con = env:connect(l_1_0)
  cur1 = assert(con:execute("SELECT * FROM PM_SYSTEM"))
  if cur1 then
    for i,v in pairs(cur1:getcolnames()) do
      if v == "numero" then
        bNumeroExiste = true
      end
    end
    cur1:close()
  end
  if not bNumeroExiste then
    con:execute("ALTER TABLE 'PM_SYSTEM' RENAME to 'PM_SYSTEM_BETA'")
    con:execute("CREATE TABLE 'PM_SYSTEM' ('numero' INTEGER PRIMARY KEY, 'key' text)")
    cur2 = assert(con:execute("SELECT key FROM PM_SYSTEM_BETA"))
    if cur2 then
      row = cur2:fetch({}, "a")
      repeat
        if row then
          con:execute(string.format("INSERT INTO PM_SYSTEM ('key') VALUES('%s')", row.key))
          do return end
        else
          cur2:close()
        end
      end
      con:close()
      env:close()
       -- Warning: missing end command somewhere! Added here
    end
     -- Warning: missing end command somewhere! Added here
  end
end

CrearDB = function(l_2_0)
  env = luasql.sqlite3()
  con = env:connect(l_2_0)
  res = assert(con:execute("CREATE TABLE 'PM_DATOS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text, 'sitioweb' text, 'usuario' text, 'password' text, 'comentarios' text, 'categoria' text)"))
  res = assert(con:execute("CREATE TABLE 'PM_CATEGORIAS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text)"))
  res = assert(con:execute("CREATE TABLE 'PM_SYSTEM' \t ('numero' INTEGER PRIMARY KEY, 'key' text)"))
  if res == 0 then
    return true
  else
    con:close()
    env:close()
     -- Warning: missing end command somewhere! Added here
  end
end

Listar = function(l_3_0, l_3_1)
  error = false
  if l_3_0 == PMDAT then
    sTabla = "PM_DATOS"
  elseif l_3_0 == PMCAT then
    sTabla = "PM_CATEGORIAS"
  elseif l_3_0 == PMKEY then
    sTabla = "PM_SYSTEM"
  end
  local sQuery = "SELECT * FROM " .. sTabla
  local tReturn = {}
  do
    local nCount = 0
    if tonumber(l_3_1) then
      l_3_1 = tonumber(l_3_1)
    else
      l_3_1 = 0
    end
    if l_3_1 and l_3_1 > 0 then
      sQuery = sQuery .. " WHERE categoria LIKE '" .. tostring(l_3_1) .. "'"
    end
    env = luasql.sqlite3()
    con = env:connect(sFileDB)
    cur = con:execute(sQuery)
    row = cur:fetch({}, "a")
    if cur then
      if row then
        nCount = nCount + 1
        if l_3_0 == PMDAT then
          tData = {recordid = tonumber(row.numero), etiqueta = row.etiqueta, sitioweb = row.sitioweb, usuario = row.usuario, password = row.password, categoria = tonumber(row.categoria), comentario = row.comentarios}
        elseif l_3_0 == PMCAT then
          tData = {recordid = tonumber(row.numero), etiqueta = row.etiqueta}
        elseif l_3_0 == PMKEY then
          tData = {recordid = tonumber(row.numero), key = row.key}
        end
        tReturn[nCount] = tData

Para los mas expertos, por si fallara el interpreter, es posible solo hacer un dissasamble del codigo, lo cual nos dice como se comporta en el stack este archivo

Código: Seleccionar todo

; This file has been disassembled using luadec 2.0 standard by sztupy (http://luadec51.luaforge.net)
; Command line was: -dis dben.lib 

; Name:            
; Defined at line: 0
; #Upvalues:       0
; #Parameters:     0
; Is_vararg:       2
; Max Stack Size:  2

  1 [-]: LOADK     R0 K1        ; R0 := "pm.db"
  2 [-]: SETGLOBAL R0 K0        ; sFileDB := R0
  3 [-]: GETGLOBAL R0 K2        ; R0 := require
  4 [-]: LOADK     R1 K3        ; R1 := "luasql.sqlite3"
  5 [-]: CALL      R0 2 1       ; R0(R1)
  6 [-]: LOADK     R0 K5        ; R0 := 1
  7 [-]: SETGLOBAL R0 K4        ; PMDAT := R0
  8 [-]: LOADK     R0 K7        ; R0 := 2
  9 [-]: SETGLOBAL R0 K6        ; PMCAT := R0
 10 [-]: LOADK     R0 K9        ; R0 := 3
 11 [-]: SETGLOBAL R0 K8        ; PMKEY := R0
 12 [-]: LOADK     R0 K5        ; R0 := 1
 13 [-]: SETGLOBAL R0 K10       ; ENCODE := R0
 14 [-]: LOADK     R0 K7        ; R0 := 2
 15 [-]: SETGLOBAL R0 K11       ; DECODE := R0
 16 [-]: LOADBOOL  R0 0 0       ; R0 := false
 17 [-]: SETGLOBAL R0 K12       ; EDITAR := R0
 18 [-]: LOADBOOL  R0 1 0       ; R0 := true
 19 [-]: SETGLOBAL R0 K13       ; NUEVO := R0
 20 [-]: CLOSURE   R0 0         ; R0 := closure(Function #1)
 21 [-]: SETGLOBAL R0 K14       ; BetaToPeekMi := R0
 22 [-]: CLOSURE   R0 1         ; R0 := closure(Function #2)
 23 [-]: SETGLOBAL R0 K15       ; CrearDB := R0
 24 [-]: CLOSURE   R0 2         ; R0 := closure(Function #3)
 25 [-]: SETGLOBAL R0 K16       ; Listar := R0
 26 [-]: CLOSURE   R0 3         ; R0 := closure(Function #4)
 27 [-]: SETGLOBAL R0 K17       ; Guardar := R0
 28 [-]: CLOSURE   R0 4         ; R0 := closure(Function #5)
 29 [-]: SETGLOBAL R0 K18       ; Eliminar := R0
 30 [-]: RETURN    R0 1         ; return 


; Function #1:
;
; Name:            
; Defined at line: 29
; #Upvalues:       0
; #Parameters:     1
; Is_vararg:       0
; Max Stack Size:  7

  1 [-]: LOADBOOL  R1 0 0       ; R1 := false
  2 [-]: SETGLOBAL R1 K0        ; bNumeroExiste := R1
  3 [-]: GETGLOBAL R1 K2        ; R1 := luasql
  4 [-]: GETTABLE  R1 R1 K3     ; R1 := R1["sqlite3"]
  5 [-]: CALL      R1 1 2       ; R1 := R1()
  6 [-]: SETGLOBAL R1 K1        ; env := R1
  7 [-]: GETGLOBAL R1 K1        ; R1 := env
  8 [-]: SELF      R1 R1 K5     ; R2 := R1; R1 := R1["connect"]
  9 [-]: MOVE      R3 R0        ; R3 := R0
 10 [-]: CALL      R1 3 2       ; R1 := R1(R2,R3)
 11 [-]: SETGLOBAL R1 K4        ; con := R1
 12 [-]: GETGLOBAL R1 K7        ; R1 := assert
 13 [-]: GETGLOBAL R2 K4        ; R2 := con
 14 [-]: SELF      R2 R2 K8     ; R3 := R2; R2 := R2["execute"]
 15 [-]: LOADK     R4 K9        ; R4 := "SELECT * FROM PM_SYSTEM"
 16 [-]: CALL      R2 3 0       ; R2,... := R2(R3,R4)
 17 [-]: CALL      R1 0 2       ; R1 := R1(R2,...)
 18 [-]: SETGLOBAL R1 K6        ; cur1 := R1
 19 [-]: GETGLOBAL R1 K6        ; R1 := cur1
 20 [-]: TEST      R1 0         ; if not R1 then PC := 37
 21 [-]: JMP       37           ; PC := 37
 22 [-]: GETGLOBAL R1 K10       ; R1 := pairs
 23 [-]: GETGLOBAL R2 K6        ; R2 := cur1
 24 [-]: SELF      R2 R2 K11    ; R3 := R2; R2 := R2["getcolnames"]
 25 [-]: CALL      R2 2 0       ; R2,... := R2(R3)
 26 [-]: CALL      R1 0 4       ; R1,R2,R3 := R1(R2,...)
 27 [-]: JMP       32           ; PC := 32
 28 [-]: EQ        0 R5 K12     ; if R5 ~= "numero" then PC := 32
 29 [-]: JMP       32           ; PC := 32
 30 [-]: LOADBOOL  R6 1 0       ; R6 := true
 31 [-]: SETGLOBAL R6 K0        ; bNumeroExiste := R6
 32 [-]: TFORLOOP  R1 2         ; R4,R5 :=  R1(R2,R3); if R4 ~= nil then begin PC = 28; R3 := R4 end
 33 [-]: JMP       28           ; PC := 28
 34 [-]: GETGLOBAL R1 K6        ; R1 := cur1
 35 [-]: SELF      R1 R1 K13    ; R2 := R1; R1 := R1["close"]
 36 [-]: CALL      R1 2 1       ; R1(R2)
 37 [-]: GETGLOBAL R1 K0        ; R1 := bNumeroExiste
 38 [-]: TEST      R1 1         ; if R1 then PC := 81
 39 [-]: JMP       81           ; PC := 81
 40 [-]: GETGLOBAL R1 K4        ; R1 := con
 41 [-]: SELF      R1 R1 K8     ; R2 := R1; R1 := R1["execute"]
 42 [-]: LOADK     R3 K14       ; R3 := "ALTER TABLE 'PM_SYSTEM' RENAME to 'PM_SYSTEM_BETA'"
 43 [-]: CALL      R1 3 1       ; R1(R2,R3)
 44 [-]: GETGLOBAL R1 K4        ; R1 := con
 45 [-]: SELF      R1 R1 K8     ; R2 := R1; R1 := R1["execute"]
 46 [-]: LOADK     R3 K15       ; R3 := "CREATE TABLE 'PM_SYSTEM' ('numero' INTEGER PRIMARY KEY, 'key' text)"
 47 [-]: CALL      R1 3 1       ; R1(R2,R3)
 48 [-]: GETGLOBAL R1 K7        ; R1 := assert
 49 [-]: GETGLOBAL R2 K4        ; R2 := con
 50 [-]: SELF      R2 R2 K8     ; R3 := R2; R2 := R2["execute"]
 51 [-]: LOADK     R4 K17       ; R4 := "SELECT key FROM PM_SYSTEM_BETA"
 52 [-]: CALL      R2 3 0       ; R2,... := R2(R3,R4)
 53 [-]: CALL      R1 0 2       ; R1 := R1(R2,...)
 54 [-]: SETGLOBAL R1 K16       ; cur2 := R1
 55 [-]: GETGLOBAL R1 K16       ; R1 := cur2
 56 [-]: TEST      R1 0         ; if not R1 then PC := 81
 57 [-]: JMP       81           ; PC := 81
 58 [-]: GETGLOBAL R1 K16       ; R1 := cur2
 59 [-]: SELF      R1 R1 K19    ; R2 := R1; R1 := R1["fetch"]
 60 [-]: NEWTABLE  R3 0 0       ; R3 := {}
 61 [-]: LOADK     R4 K20       ; R4 := "a"
 62 [-]: CALL      R1 4 2       ; R1 := R1(R2,R3,R4)
 63 [-]: SETGLOBAL R1 K18       ; row := R1
 64 [-]: GETGLOBAL R1 K18       ; R1 := row
 65 [-]: TEST      R1 0         ; if not R1 then PC := 78
 66 [-]: JMP       78           ; PC := 78
 67 [-]: GETGLOBAL R1 K4        ; R1 := con
 68 [-]: SELF      R1 R1 K8     ; R2 := R1; R1 := R1["execute"]
 69 [-]: GETGLOBAL R3 K21       ; R3 := string
 70 [-]: GETTABLE  R3 R3 K22    ; R3 := R3["format"]
 71 [-]: LOADK     R4 K23       ; R4 := "INSERT INTO PM_SYSTEM ('key') VALUES('%s')"
 72 [-]: GETGLOBAL R5 K18       ; R5 := row
 73 [-]: GETTABLE  R5 R5 K24    ; R5 := R5["key"]
 74 [-]: CALL      R3 3 0       ; R3,... := R3(R4,R5)
 75 [-]: CALL      R1 0 1       ; R1(R2,...)
 76 [-]: JMP       78           ; PC := 78
 77 [-]: JMP       64           ; PC := 64
 78 [-]: GETGLOBAL R1 K16       ; R1 := cur2
 79 [-]: SELF      R1 R1 K13    ; R2 := R1; R1 := R1["close"]
 80 [-]: CALL      R1 2 1       ; R1(R2)
 81 [-]: GETGLOBAL R1 K4        ; R1 := con
 82 [-]: SELF      R1 R1 K13    ; R2 := R1; R1 := R1["close"]
 83 [-]: CALL      R1 2 1       ; R1(R2)
 84 [-]: GETGLOBAL R1 K1        ; R1 := env
 85 [-]: SELF      R1 R1 K13    ; R2 := R1; R1 := R1["close"]
 86 [-]: CALL      R1 2 1       ; R1(R2)
 87 [-]: RETURN    R0 1         ; return 


; Function #2:
;
; Name:            
; Defined at line: 65
; #Upvalues:       0
; #Parameters:     1
; Is_vararg:       0
; Max Stack Size:  5

  1 [-]: GETGLOBAL R1 K1        ; R1 := luasql
  2 [-]: GETTABLE  R1 R1 K2     ; R1 := R1["sqlite3"]
  3 [-]: CALL      R1 1 2       ; R1 := R1()
  4 [-]: SETGLOBAL R1 K0        ; env := R1
  5 [-]: GETGLOBAL R1 K0        ; R1 := env
  6 [-]: SELF      R1 R1 K4     ; R2 := R1; R1 := R1["connect"]
  7 [-]: MOVE      R3 R0        ; R3 := R0
  8 [-]: CALL      R1 3 2       ; R1 := R1(R2,R3)
  9 [-]: SETGLOBAL R1 K3        ; con := R1
 10 [-]: GETGLOBAL R1 K6        ; R1 := assert
 11 [-]: GETGLOBAL R2 K3        ; R2 := con
 12 [-]: SELF      R2 R2 K7     ; R3 := R2; R2 := R2["execute"]
 13 [-]: LOADK     R4 K8        ; R4 := "CREATE TABLE 'PM_DATOS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text, 'sitioweb' text, 'usuario' text, 'password' text, 'comentarios' text, 'categoria' text)"
 14 [-]: CALL      R2 3 0       ; R2,... := R2(R3,R4)
 15 [-]: CALL      R1 0 2       ; R1 := R1(R2,...)
 16 [-]: SETGLOBAL R1 K5        ; res := R1
 17 [-]: GETGLOBAL R1 K6        ; R1 := assert
 18 [-]: GETGLOBAL R2 K3        ; R2 := con
 19 [-]: SELF      R2 R2 K7     ; R3 := R2; R2 := R2["execute"]
 20 [-]: LOADK     R4 K9        ; R4 := "CREATE TABLE 'PM_CATEGORIAS' ('numero' INTEGER PRIMARY KEY, 'etiqueta' text)"
 21 [-]: CALL      R2 3 0       ; R2,... := R2(R3,R4)
 22 [-]: CALL      R1 0 2       ; R1 := R1(R2,...)
 23 [-]: SETGLOBAL R1 K5        ; res := R1
 24 [-]: GETGLOBAL R1 K6        ; R1 := assert
 25 [-]: GETGLOBAL R2 K3        ; R2 := con
 26 [-]: SELF      R2 R2 K7     ; R3 := R2; R2 := R2["execute"]
 27 [-]: LOADK     R4 K10       ; R4 := "CREATE TABLE 'PM_SYSTEM' \t ('numero' INTEGER PRIMARY KEY, 'key' text)"
 28 [-]: CALL      R2 3 0       ; R2,... := R2(R3,R4)
 29 [-]: CALL      R1 0 2       ; R1 := R1(R2,...)
 30 [-]: SETGLOBAL R1 K5        ; res := R1
 31 [-]: GETGLOBAL R1 K5        ; R1 := res
 32 [-]: EQ        0 R1 K11     ; if R1 ~= 0 then PC := 37
 33 [-]: JMP       37           ; PC := 37
 34 [-]: LOADBOOL  R1 1 0       ; R1 := true
 35 [-]: RETURN    R1 2         ; return R1
 36 [-]: JMP       37           ; PC := 37
 37 [-]: GETGLOBAL R1 K3        ; R1 := con
 38 [-]: SELF      R1 R1 K12    ; R2 := R1; R1 := R1["close"]
Los opcodes en lua son muy sencillitos y el stack es bastante basico asi que no hay perdida.

Un saludo :D

Si, ya conocia luadec :( jajajajajaja

De hecho luac solo hace algo asi:

Código: Seleccionar todo

string.dump(assert(loadfile())
Con solo ver eso ya sabia que no era seguro, es un honor que revise mi código master :yes:

¿Alternativas?

Gracias