Yes, I know that there are already multiple posts discussing this topic. None of them led to any real results. I want a straight answer. How do I deobfuscate MoonSecV3?
By being the one that obfuscated it. Kind of the whole point of that. A quick glance is showing every trick in the book. Basically a master class in obfuscation.
Well, no duh xD. I was just wondering if you could deobfuscate it without the original code. If I had the original code, I wouldn’t post this.
What I was trying to say is that is professional obfuscation. So probably not. Can even see some encryption used. I wouldn’t touch this myself. Seems to be a few videos on YouTube (down a dark road).
Very unlikely you’ll be able to decrypt this.
Obfuscation is a complicated thing, and this is likely a custom VM. They basically work by removing all the unnecessary information from the code, and creating a custom bytecode format. The person behind the obfuscator creates a VM (example: FiOne) which will execute their custom format. However, because it’s all custom, they have different instruction sets than regular Lua has, so you’d have to reverse engineer what each instruction is doing, and that’s even worse if they mix up the control flow (by adding fake functions, etc). So you’d need a heavy background in obfsucators in general to learn how to do this. Which is not something I have, however, there is a GitHub repository containing a semi-working way to decompile the code of MoonSec V2, but not MoonSec V3.
Example: (using Ironbrew 2.7.1)
print("hello world")
turns into
local Byte = string.byte;
local Char = string.char;
local Sub = string.sub;
local Concat = table.concat;
local Insert = table.insert;
local LDExp = math.ldexp;
local GetFEnv = getfenv or function() return _ENV end;
local Setmetatable = setmetatable;
local Select = select;
local Unpack = unpack or table.unpack;
local ToNumber = tonumber;local function decompress(b)local c,d,e="","",{}local f=256;local g={}for h=0,f-1 do g[h]=Char(h)end;local i=1;local function k()local l=ToNumber(Sub(b, i,i),36)i=i+1;local m=ToNumber(Sub(b, i,i+l-1),36)i=i+l;return m end;c=Char(k())e[1]=c;while i<#b do local n=k()if g[n]then d=g[n]else d=c..Sub(c, 1,1)end;g[f]=c..Sub(d, 1,1)e[#e+1],c,f=d,d,f+1 end;return table.concat(e)end;local ByteString=decompress('24A24827524924D27524826G26I26P26U26K24924E27926O27126926925525524824C27923U27H27627R24F24824924827427928027Z27X27U285279275');
local BitXOR = bit and bit.bxor or function(a,b)
local p,c=1,0
while a>0 and b>0 do
local ra,rb=a%2,b%2
if ra~=rb then c=c+p end
a,b,p=(a-ra)/2,(b-rb)/2,p*2
end
if a<b then a=b end
while a>0 do
local ra=a%2
if ra>0 then c=c+p end
a,p=(a-ra)/2,p*2
end
return c
end
local function gBit(Bit, Start, End)
if End then
local Res = (Bit / 2 ^ (Start - 1)) % 2 ^ ((End - 1) - (Start - 1) + 1);
return Res - Res % 1;
else
local Plc = 2 ^ (Start - 1);
return (Bit % (Plc + Plc) >= Plc) and 1 or 0;
end;
end;
local Pos = 1;
local function gBits32()
local W, X, Y, Z = Byte(ByteString, Pos, Pos + 3);
W = BitXOR(W, 152)
X = BitXOR(X, 152)
Y = BitXOR(Y, 152)
Z = BitXOR(Z, 152)
Pos = Pos + 4;
return (Z*16777216) + (Y*65536) + (X*256) + W;
end;
local function gBits8()
local F = BitXOR(Byte(ByteString, Pos, Pos), 152);
Pos = Pos + 1;
return F;
end;
local function gBits16()
local W, X = Byte(ByteString, Pos, Pos + 2);
W = BitXOR(W, 152)
X = BitXOR(X, 152)
Pos = Pos + 2;
return (X*256) + W;
end;
local function gFloat()
local Left = gBits32();
local Right = gBits32();
local IsNormal = 1;
local Mantissa = (gBit(Right, 1, 20) * (2 ^ 32))
+ Left;
local Exponent = gBit(Right, 21, 31);
local Sign = ((-1) ^ gBit(Right, 32));
if (Exponent == 0) then
if (Mantissa == 0) then
return Sign * 0; -- +-0
else
Exponent = 1;
IsNormal = 0;
end;
elseif (Exponent == 2047) then
return (Mantissa == 0) and (Sign * (1 / 0)) or (Sign * (0 / 0));
end;
return LDExp(Sign, Exponent - 1023) * (IsNormal + (Mantissa / (2 ^ 52)));
end;
local gSizet = gBits32;
local function gString(Len)
local Str;
if (not Len) then
Len = gSizet();
if (Len == 0) then
return '';
end;
end;
Str = Sub(ByteString, Pos, Pos + Len - 1);
Pos = Pos + Len;
local FStr = {}
for Idx = 1, #Str do
FStr[Idx] = Char(BitXOR(Byte(Sub(Str, Idx, Idx)), 152))
end
return Concat(FStr);
end;
local gInt = gBits32;
local function _R(...) return {...}, Select('#', ...) end
local function Deserialize()
local Instrs = {};
local Functions = {};
local Lines = {};
local Chunk =
{
Instrs,
Functions,
nil,
Lines
};
local ConstCount = gBits32()
local Consts = {}
for Idx=1, ConstCount do
local Type =gBits8();
local Cons;
if(Type==0) then Cons = (gBits8() ~= 0);
elseif(Type==3) then Cons = gFloat();
elseif(Type==1) then Cons = gString();
end;
Consts[Idx] = Cons;
end;
Chunk[3] = gBits8();for Idx=1,gBits32() do
local Descriptor = gBits8();
if (gBit(Descriptor, 1, 1) == 0) then
local Type = gBit(Descriptor, 2, 3);
local Mask = gBit(Descriptor, 4, 6);
local Inst=
{
gBits16(),
gBits16(),
nil,
nil
};
if (Type == 0) then
Inst[3] = gBits16();
Inst[4] = gBits16();
elseif(Type==1) then
Inst[3] = gBits32();
elseif(Type==2) then
Inst[3] = gBits32() - (2 ^ 16)
elseif(Type==3) then
Inst[3] = gBits32() - (2 ^ 16)
Inst[4] = gBits16();
end;
if (gBit(Mask, 1, 1) == 1) then Inst[2] = Consts[Inst[2]] end
if (gBit(Mask, 2, 2) == 1) then Inst[3] = Consts[Inst[3]] end
if (gBit(Mask, 3, 3) == 1) then Inst[4] = Consts[Inst[4]] end
Instrs[Idx] = Inst;
end
end;for Idx=1,gBits32() do Functions[Idx-1]=Deserialize();end;return Chunk;end;
local function Wrap(Chunk, Upvalues, Env)
local Instr = Chunk[1];
local Proto = Chunk[2];
local Params = Chunk[3];
return function(...)
local Instr = Instr;
local Proto = Proto;
local Params = Params;
local _R = _R
local InstrPoint = 1;
local Top = -1;
local Vararg = {};
local Args = {...};
local PCount = Select('#', ...) - 1;
local Lupvals = {};
local Stk = {};
for Idx = 0, PCount do
if (Idx >= Params) then
Vararg[Idx - Params] = Args[Idx + 1];
else
Stk[Idx] = Args[Idx + 1];
end;
end;
local Varargsz = PCount - Params + 1
local Inst;
local Enum;
while true do
Inst = Instr[InstrPoint];
Enum = Inst[1];if Enum <= 3 then if Enum <= 1 then if Enum > 0 then do return end;else Stk[Inst[2]] = Inst[3];end; elseif Enum == 2 then
local A = Inst[2]
Stk[A](Stk[A + 1])
else
local A = Inst[2]
Stk[A](Stk[A + 1])
end; elseif Enum <= 5 then if Enum > 4 then do return end;else Stk[Inst[2]]=Env[Inst[3]];end; elseif Enum > 6 then Stk[Inst[2]] = Inst[3];else Stk[Inst[2]]=Env[Inst[3]];end;
InstrPoint = InstrPoint + 1;
end;
end;
end;
return Wrap(Deserialize(), {}, GetFEnv())();
Which is then minimized and turned into
local t=string.byte;local i=string.char;local c=string.sub;local h=table.concat;local l=table.insert;local b=math.ldexp;local g=getfenv or function()return _ENV end;local l=setmetatable;local u=select;local l=unpack or table.unpack;local f=tonumber;local function s(d)local e,n,a="","",{}local t=256;local o={}for l=0,t-1 do o[l]=i(l)end;local l=1;local function r()local e=f(c(d,l,l),36)l=l+1;local n=f(c(d,l,l+e-1),36)l=l+e;return n end;e=i(r())a[1]=e;while l<#d do local l=r()if o[l]then n=o[l]else n=e..c(e,1,1)end;o[t]=e..c(n,1,1)a[#a+1],e,t=n,n,t+1 end;return table.concat(a)end;local r=s('24A24827524924D27524826G26I26P26U26K24924E27926O27126926925525524824C27923U27H27627R24F24824924827427928027Z27X27U285279275');local o=bit and bit.bxor or function(l,n)local e,o=1,0
while l>0 and n>0 do
local a,c=l%2,n%2
if a~=c then o=o+e end
l,n,e=(l-a)/2,(n-c)/2,e*2
end
if l<n then l=n end
while l>0 do
local n=l%2
if n>0 then o=o+e end
l,e=(l-n)/2,e*2
end
return o
end
local function n(e,l,n)if n then
local l=(e/2^(l-1))%2^((n-1)-(l-1)+1);return l-l%1;else
local l=2^(l-1);return(e%(l+l)>=l)and 1 or 0;end;end;local l=1;local function e()local c,a,n,e=t(r,l,l+3);c=o(c,152)a=o(a,152)n=o(n,152)e=o(e,152)l=l+4;return(e*16777216)+(n*65536)+(a*256)+c;end;local function d()local e=o(t(r,l,l),152);l=l+1;return e;end;local function a()local e,n=t(r,l,l+2);e=o(e,152)n=o(n,152)l=l+2;return(n*256)+e;end;local function s()local l=e();local e=e();local c=1;local o=(n(e,1,20)*(2^32))+l;local l=n(e,21,31);local e=((-1)^n(e,32));if(l==0)then
if(o==0)then
return e*0;else
l=1;c=0;end;elseif(l==2047)then
return(o==0)and(e*(1/0))or(e*(0/0));end;return b(e,l-1023)*(c+(o/(2^52)));end;local f=e;local function w(e)local n;if(not e)then
e=f();if(e==0)then
return'';end;end;n=c(r,l,l+e-1);l=l+e;local e={}for l=1,#n do
e[l]=i(o(t(c(n,l,l)),152))end
return h(e);end;local l=e;local function b(...)return{...},u('#',...)end
local function h()local r={};local f={};local l={};local i={r,f,nil,l};local l=e()local o={}for n=1,l do
local e=d();local l;if(e==0)then l=(d()~=0);elseif(e==3)then l=s();elseif(e==1)then l=w();end;o[n]=l;end;i[3]=d();for i=1,e()do
local l=d();if(n(l,1,1)==0)then
local c=n(l,2,3);local t=n(l,4,6);local l={a(),a(),nil,nil};if(c==0)then
l[3]=a();l[4]=a();elseif(c==1)then
l[3]=e();elseif(c==2)then
l[3]=e()-(2^16)elseif(c==3)then
l[3]=e()-(2^16)l[4]=a();end;if(n(t,1,1)==1)then l[2]=o[l[2]]end
if(n(t,2,2)==1)then l[3]=o[l[3]]end
if(n(t,3,3)==1)then l[4]=o[l[4]]end
r[i]=l;end
end;for l=1,e()do f[l-1]=h();end;return i;end;local function i(l,e,t)local n=l[1];local e=l[2];local l=l[3];return function(...)local d=n;local e=e;local n=l;local l=b
local o=1;local l=-1;local r={};local a={...};local c=u('#',...)-1;local l={};local e={};for l=0,c do
if(l>=n)then
r[l-n]=a[l+1];else
e[l]=a[l+1];end;end;local l=c-n+1
local l;local n;while true do
l=d[o];n=l[1];if n<=3 then if n<=1 then if n>0 then do return end;else e[l[2]]=l[3];end;elseif n==2 then
local l=l[2]e[l](e[l+1])else
local l=l[2]e[l](e[l+1])end;elseif n<=5 then if n>4 then do return end;else e[l[2]]=t[l[3]];end;elseif n>6 then e[l[2]]=l[3];else e[l[2]]=t[l[3]];end;o=o+1;end;end;end;return i(h(),{},g())();
Which finally turns into
local t=string.byte;local i=string.char;local c=string.sub;local h=table.concat;local l=table.insert;local b=math.ldexp;local g=getfenv or function()return _ENV end;local l=setmetatable;local u=select;local l=unpack or table.unpack;local f=tonumber;local function s(d)local e,n,a="","",{}local t=256;local o={}for l=0,t-1 do o[l]=i(l)end;local l=1;local function r()local e=f(c(d,l,l),36)l=l+1;local n=f(c(d,l,l+e-1),36)l=l+e;return n end;e=i(r())a[1]=e;while l<#d do local l=r()if o[l]then n=o[l]else n=e..c(e,1,1)end;o[t]=e..c(n,1,1)a[#a+1],e,t=n,n,t+1 end;return table.concat(a)end;local r=s('24A24827524924D27524826G26I26P26U26K24924E27926O27126926925525524824C27923U27H27627R24F24824924827427928027Z27X27U285279275');local o=bit and bit.bxor or function(l,n)local e,o=1,0 while l>0 and n>0 do local a,c=l%2,n%2 if a~=c then o=o+e end l,n,e=(l-a)/2,(n-c)/2,e*2 end if l<n then l=n end while l>0 do local n=l%2 if n>0 then o=o+e end l,e=(l-n)/2,e*2 end return o end local function n(e,l,n)if n then local l=(e/2^(l-1))%2^((n-1)-(l-1)+1);return l-l%1;else local l=2^(l-1);return(e%(l+l)>=l)and 1 or 0;end;end;local l=1;local function e()local c,a,n,e=t(r,l,l+3);c=o(c,152)a=o(a,152)n=o(n,152)e=o(e,152)l=l+4;return(e*16777216)+(n*65536)+(a*256)+c;end;local function d()local e=o(t(r,l,l),152);l=l+1;return e;end;local function a()local e,n=t(r,l,l+2);e=o(e,152)n=o(n,152)l=l+2;return(n*256)+e;end;local function s()local l=e();local e=e();local c=1;local o=(n(e,1,20)*(2^32))+l;local l=n(e,21,31);local e=((-1)^n(e,32));if(l==0)then if(o==0)then return e*0;else l=1;c=0;end;elseif(l==2047)then return(o==0)and(e*(1/0))or(e*(0/0));end;return b(e,l-1023)*(c+(o/(2^52)));end;local f=e;local function w(e)local n;if(not e)then e=f();if(e==0)then return'';end;end;n=c(r,l,l+e-1);l=l+e;local e={}for l=1,#n do e[l]=i(o(t(c(n,l,l)),152))end return h(e);end;local l=e;local function b(...)return{...},u('#',...)end local function h()local r={};local f={};local l={};local i={r,f,nil,l};local l=e()local o={}for n=1,l do local e=d();local l;if(e==0)then l=(d()~=0);elseif(e==3)then l=s();elseif(e==1)then l=w();end;o[n]=l;end;i[3]=d();for i=1,e()do local l=d();if(n(l,1,1)==0)then local c=n(l,2,3);local t=n(l,4,6);local l={a(),a(),nil,nil};if(c==0)then l[3]=a();l[4]=a();elseif(c==1)then l[3]=e();elseif(c==2)then l[3]=e()-(2^16)elseif(c==3)then l[3]=e()-(2^16)l[4]=a();end;if(n(t,1,1)==1)then l[2]=o[l[2]]end if(n(t,2,2)==1)then l[3]=o[l[3]]end if(n(t,3,3)==1)then l[4]=o[l[4]]end r[i]=l;end end;for l=1,e()do f[l-1]=h();end;return i;end;local function i(l,e,t)local n=l[1];local e=l[2];local l=l[3];return function(...)local d=n;local e=e;local n=l;local l=b local o=1;local l=-1;local r={};local a={...};local c=u('#',...)-1;local l={};local e={};for l=0,c do if(l>=n)then r[l-n]=a[l+1];else e[l]=a[l+1];end;end;local l=c-n+1 local l;local n;while true do l=d[o];n=l[1];if n<=3 then if n<=1 then if n>0 then do return end;else e[l[2]]=l[3];end;elseif n==2 then local l=l[2]e[l](e[l+1])else local l=l[2]e[l](e[l+1])end;elseif n<=5 then if n>4 then do return end;else e[l[2]]=t[l[3]];end;elseif n>6 then e[l[2]]=l[3];else e[l[2]]=t[l[3]];end;o=o+1;end;end;end;return i(h(),{},g())();
Overall, without prior background in Lua VMs and machine code, and all of that loveliness, it’s highly unlikely you will be able to deobfuscate this any time soon. You’d likely be better off dumping the constants (something no VM can avoid), and figuring out what the script is trying to do in general.
Thank you for taking the time to write this for somebody like me with zero background on this subject whatsoever xD. Could you explain what you mean by “dumping”? I know very little, so excuse me if this sounds like a stupid question.
Note: I have never deobufscated a script, because I do not have the time or brain power for that, however I have worked a little bit with VMs.
Well, it’s complicated because what these obfuscators do, is they remove any trace of the original code, like if you were to successfully deobfuscate it, you’ll never have the original code again, just something that does it, but there’s no comments, local variable names, etc. However, something that these obfuscators DO have are constants, which are like so:
print("hello world")
local i = 0
if i < 5 then
end
function main()
end
local function test()
end
Would have the constants:
"print","hello world",0,5,"main"
(which should be in order of how they are in the original script unless there’s control flow obfuscation)
Which these are much easier to get than say the fully deobufscated code, and will let you see somewhat what the code is doing, but not fully.
Here’s a video I found, I have not tested it:
If you’re confused on the earlier part, obfuscated systems will typically be broken into chunks, an example of a chunk (likely absolutely not written explicitly in the code):
local Chunk = {
Instr = Instr; -- Instructions
Const = Const; -- Constants
Proto = Proto; -- Prototypes
Lines = {}; -- Lines
Name = gString(); -- Grab name string.
FirstL = gInt(); -- First line.
LastL = gInt(); -- Last line.
Upvals = gBits8(); -- Upvalue count.
Args = gBits8(); -- Arg count.
Vargs = gBits8(); -- Vararg type.
Stack = gBits8(); -- Stack.
};
And in the code, there’s a reference to the ‘Stack’ of each Chunk.
Example, how a script would handle addition:
elseif (Enum == 12) then -- ADD
local Stk = Stack;
Stk[Inst[1]] = (Inst[4] or Stk[Inst[2]]) + (Inst[5] or Stk[Inst[3]]);
This would handle all addition in the scripts, instead of it being done separately each time.
I got this from Rerubi
More examples?
A = 123
Would turn into:
.CONSTS[ -- this segment of data will hold all constants that the compiled script uses
"A",
123
]
.INSTRS[ -- this segment of data will hold all instructions and instruction data
[LOADK, 0, 1],
[SETGLOBAL, 1, 1],
[RETURN, 0, 1]
]
and
local A = 1
print(A + 1)
would turn into
.CONSTS[
1,
"print"
]
.INSTRS[
[LOADK, 0, 0], -- defining 'A' by loading constant 0 (1) into register 0
[GETGLOBAL, 1, 1], -- getting the global 'print' and placing it into register 1
[ADD, 2, 0, 256], -- adding register 0 and constant 0
[CALL, 1, 2, 1], -- calling the function and not storing return values
[RETURN, 0, 1] -- generated by lua
]
Genuinely heroes work xD. I hope anybody else stumbles upon this thread first instead of any other similar ones since they all either have no answers or deactivated links. Thank you! I have no more questions.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.