[Windows Mobile Development and Hacking General] sztupy:
Hi!

Good to hear you managed to decompile the 27a13690, decompiling >20kb files are always hard and time consuming :)

The one string I sent you the last time was in LDS2 form :) LDS2 allows you to specify where locals were declared and where they were released, because unfortunately knowing where to release locals is important too.

Let's consider a code like this one:

if something then
local x = someotherthing
x.stuff = stuff
end
foo.bar = true

In this code the local x is declared in line 2 (which might be around opcode 6), but it's gone at line 4. After line 4 there is no more local variable x anymore. In an LDS2 string you can specify where locals have been derefenced by using the - character. So a string like

-l2 ;10-20,30-40

means declare a local at opcode 10, then release it at opcode 20, next decalre a local at opcode 30, and release it at opcode 40.

The best thing about LDS2 strings are, that you can actually use my modifyed luac to print them out after you have succesfully decompiled a script. So running "luac -p -l2" on a script you've decompiled you can get it's LDS2 string, running luadec with this string on the compiled file will get you a nicer result for sure.

The other good part about LDS2 strings are, that they cause luadec to crash less. If you get any LDS output from luadecguess, then try removing all 0-s from it's output (so ;0,0,0,10 will get ;10) then use -l2 instead of -l when running luadec. Most of the time it won't crash when using the -l2 option.

But your question was not this. You asked me how to determine where you have to decrease the numbers in an LDS string.

Let's look at an example (written in pseudoluadisassembly):

[1] R2:= 0
[2] if R1 > 5 then PC := 5
[3] R2 := R1
[4] JMP 6
[5] R2 := 10
[6] do something with R2

This translates to something like this:

local l_2 = 0
if l_1<=5 then
l_2 = l_1
else
l_2 = 10
end
somethinginvolving l_2

luadecguess -fg will always check for the last assignment of a register and will think that there was a local declared (in 75% of the cases this is just fine). In the case above the last opcode where R2 was assigned a value to was [5], so it will output a string like: -l ;0,0,5

But looking at the disassembly we see, that on opcode line 5 R2 was already a local. luadec usually crash if it encounters things like this, that's why you have to run it using -d to know where it crashed (in the above example it would crash around opcode 4, 5 or 6)

Then you know that the value of 5 is wrong. Now look at the disasembly. You can see that R2 is probably declared on line [1] and not on line [3] or line [5] (locals are always(*) declared on opcode lines where there are assignments to them). So change the string to -l ;0,0,1 (or to -l2 ;1 if you want to try out LDS2. LDS2 doesn''t need the 0's before the appropriate lines) and run luadec. Now it shouldn't crash (or crash at another position :) You might have more than one place where there are things like the one I mentioned in a large script) and should decompile the function just fine.

(*) There is one exception to this rule: nil assignments at the beginning of the script will not show up, because they get optimized away. So things like

local a = nil
local b = nil
dosomething()

will translate to this pseudoluadisassemlby:

[1] R2 := dosomething
[2] R2()

As you see, there is no mention of a (R0) and b (R1) in the disassembly (it's some king of optimization). If you have things like this you have to use -l 0,0 (if using LDS), or -l2 1,1 (if using LDS2) to tell the decompiler there are locals defined before the first command