题目分析
把安卓文件解压,可以看到有一个lua的文件夹
assets文件夹中也有lua文件,可以基本猜到是加载这些lua脚本。
Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译、运行。其设计目的是为了通过灵活嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。
获取 Lua 脚本的几种方法:
直接在 assets 目录提取
这种一般是没有对 lua 脚本做任何加密,assets 目录存放的是 Lua 或 Luac 源码
Lua源码类型可以直接修改再用 APKtool 重打包
Luac源码类型可以使用 Unluac 等工具还原为 Lua 源码修改后再用 APKtool 重打包
在 luaL_loadbuffer函数处获取
luaL_loadbuffer是一个被频繁调用的加载点, Cocos2d-x引擎的 Lua 加载器为 cocos2dx_lua_loader,最终都是调用 luaL_loadbuffer 函数来加载,Lua脚本会在 luaL_loadbuffer函数上层进行解密,luaL_loadbuffer函数的第2个参数就是解密后的 Lua 脚本
这里assets里的lua脚本显然被加密过了。
ida打开libluajava.so文件,查找luaL_loadbuffer
luaL_loadbuffer函数第二个参数是lua字节数据,第三个是加密字节的大小。
照着这个逻辑写解密脚本。
def key(t):
t1 = t
t2 = (0xFFFFFFFF80808081 * t1) >> 32
t3 = (t2 + t1) >> 7
t4 = 0
if t2 + t1 < 0:
t4 = 1
tf = (t + t3 + t4) & 0xFF
return tf
def decrypt(s):
out = bytearray(len(s))
out[0] = 27
t = 0
for i in range(1, len(s)):
t += len(s)
out[i] = s[i] ^ key(t)
return bytes(out)
with open("pz.lua",'rb') as f:
data = f.read()
with open("pz_decry.lua",'wb') as f:
f.write(decrypt(data))
解密后使用unluac或是在线网站反编译->https://luadec.metaworm.site/
把解密后的文件丢到网站里,发现main.lua,root.lua基本没做什么事。
最后调用了pz.lua,pz.lua解密后反编译的代码。
-- filename:
-- version: lua53
-- line: [0, 0] id: 0
edrawable = GradientDrawable()
edrawable.setShape(GradientDrawable.RECTANGLE)
edrawable.setColor(4294967295)
edrawable.setCornerRadii({
dp2px(8),
dp2px(8),
dp2px(8),
dp2px(8),
dp2px(8),
dp2px(8),
dp2px(8),
dp2px(8)
})
edrawable.setStroke(2, 555819297, 0, 0)
local r0_0 = {
DrawerLayout,
{
LinearLayout,
{
layout_height = 状态栏高度,
layout_width = "-1",
TextView
},
{
LinearLayout,
{
LinearLayout,
{
layout_width = "0dp",
layout_height = "0dp",
BackgroundColor = primaryc,
id = "_menu_1",
TextView
},
{
layout_width = "0dp",
layout_height = "0dp",
BackgroundColor = primaryc,
layout_marginTop = "6",
id = "_menu_2",
TextView
},
{
layout_width = "0dp",
layout_height = "0dp",
BackgroundColor = primaryc,
layout_marginTop = "6",
id = "_menu_3",
TextView
}
},
{
text = "ezAndroid",
textColor = primaryc,
textSize = "22sp",
id = "_title",
SingleLine = true,
layout_width = "-1",
gravity = "center|left",
paddingLeft = "0dp",
layout_weight = "1",
Typeface = 字体("product-Bold"),
TextView
},
{
id = "_more_lay",
layout_width = "0",
layout_height = "0",
layout_gravity = "top",
TextView
}
},
home,
_tool
}
}
root = r0_0
设置视图(root)
沉浸状态栏()
ddddddddddddd = function(r0_2)
-- line: [94, 97] id: 2
return r0_2 .. string.rep("\0", 8 - #r0_2 % 8)
end
aaaaaaaaaaaaaa = function(r0_3, r1_3, r2_3, r3_3)
-- line: [99, 101] id: 3
return (r0_3 or 0) << 24 | (r1_3 or 0) << 16 | (r2_3 or 0) << 8 | (r3_3 or 0)
end
asjdhnbvcvvaas = function(r0_4)
-- line: [103, 110] id: 4
local r1_4 = {}
for r5_4 = 1, #r0_4, 8 do
table.insert(r1_4, aaaaaaaaaaaaaa(r0_4:byte(r5_4, r5_4 + 3)))
table.insert(r1_4, aaaaaaaaaaaaaa(r0_4:byte(r5_4 + 4, r5_4 + 7)))
end
return r1_4
end
wqwe = function(r0_5)
-- line: [112, 114] id: 5
return string.char(r0_5 >> 24 & 255, r0_5 >> 16 & 255, r0_5 >> 8 & 255, r0_5 & 255)
end
izKMncba = function(r0_6)
-- line: [116, 122] id: 6
local r1_6 = {}
for r5_6, r6_6 in ipairs(r0_6) do
table.insert(r1_6, wqwe(r6_6))
end
return table.concat(r1_6)
end
aijusbndbv = function(r0_7, r1_7)
-- line: [124, 147] id: 7
local r2_7 = r0_7[1]
local r3_7 = r0_7[2]
local r4_7 = 0
local r6_7 = load("return " .. "(114514+114514)*((1+1)*4514+((1+1)*4*51-4+11-4*5+14))+(114514+(114*514+(114*51*4+((1+1)*4*514+(11*(45-1)/4)))))")()
for r12_7 = 1, load("return " .. "-11 + 45 * 1 + 4")(), 1 do
r4_7 = r4_7 + r6_7 & 4294967295
r2_7 = r2_7 + ((r3_7 << 4 ~ r3_7 >> 5) + r3_7 ~ r4_7 + r1_7[(r4_7 & 3) + 1]) & 4294967295
r3_7 = r3_7 + ((r2_7 << 4 ~ r2_7 >> 5) + r2_7 ~ r4_7 + r1_7[(r4_7 >> 11 & 3) + 1]) & 4294967295
end
return {
r2_7 ~ 14,
r3_7 ~ 17
}
end
oianxasdavsdvasd = {
load("return (114514 + 114514) * ((1 + 1) * 451 * 4 + 114 + 51 - 4 + 11 * -4 + 51 - 4) + (114 * 51 * 4 + ((1 + 1) * 45 * 14 - 11 + 45 * 1 + 4))")(),
load("return (114514 + 114514) * (1 * -(1 - 4) * 514 + 114 - 51 - 4) + (114514 + (114 * 51 * 4 + (1 + 14514 + ((1 + 1) * 45 * 14 + 11 - 4 + 5 * 14))))")(),
load("return (114514 + 114514) * (11451 + 4 + (11 * (4 + 5) * 14 + 1 + 14 - 5 + 1 + 4)) + (114514 + (114 * 514 + (11451 * 4 + ((1 + 1) * 4 * 51 * 4 + 1 - 14 + 5 + 14))))")(),
load("return (114514 + 114514) * (1145 * (1 + 4) - 11 + 4 + 5 + 14) + (114514 + (1 + 14514 + (11 * -45 * (1 - 4) + 11 - 4 + 5 / 1 - 4)))")(),
load("return (114514 + 114514) * ((1 + 1) * 4514 + 1 + 145 * 14 + 11 - 4 * 5 + 14) + 114 * 514 + 1 + 14514 + 1145 - 14")(),
load("return (114514 + 114514) * (114 * (51 - 4) + (1 + 1 * 4 * 5 * (1 + 4))) + (11 * (451 - 4) + 1 - 14 + 51 - 4)")(),
load("return (114514 + 114514) * (1 + 14514 + (1 - 14 * -(5 + 1) * 4 + 11 * -4 + 51 - 4)) + 114 * 514 + 114 * 5 * 14 - 11 + 45 * 14 + 11 - 4 + 5 / 1 - 4")(),
load("return (114514 + 114514) * (114 * 51 + 4 + 114 + 5 + 1 + 4) + (114514 + (114 * 51 * 4 + (1145 * 14 + (114 * -5 * (1 - 4) + 11 * 4 + 5 + 1 - 4))))")(),
load("return (114514 + 114514) * (11451 + 4 + (11 * (45 + 1) * 4 + 11 * -4 + 51 - 4)) + (114514 + (114 * 51 * 4 + (11451 + 4 + (114 * (5 + 1) * 4 + 11 + 4 * 5 / 1 - 4))))")(),
load("return (114514 + 114514) * (11451 + 4 + (11 * 4 * (51 - 4) + 114 - 5 * 14)) + 11451 * 4 + 11 * 4 * 5 * 14 + 11 * 4 + 5 * 14")()
}
local r8_0 = {
load("return " .. "114 * 51 + 4 - 1 + 145 + 14")(),
load("return " .. "114 * 51 * 4 + (1145 * 14 + (1 * -(1 - 4) * 514 - 11 + 45 - 1 - 4))")(),
load("return " .. "(114514 + 114514) * (11451 + 4 + (1 + 14 * 51 * 4 + (1 * 14 * (5 + 1) + 4))) +(114514 + (114 * 514 + (11 * 4514 + (-1145 * (1 - 4) + 1 * 14 + 5 * 14))))")(),
load("return " .. "(114514 + 114514) * (114 * (51 + 4) + (1 + 1 + 4 * 5 * 14 + (11 / (45 - 1) * 4))) +(114514 + ((1 + 1) * 4514 + 114 * 5 * 1 * 4 + 1 * 14 - 5 + 14))")()
}
local function r9_0(r0_8, r1_8)
-- line: [183, 193] id: 8
if #r0_8 ~= #r1_8 then
return false
end
for r5_8 = 1, #r0_8, 1 do
if r0_8[r5_8] ~= r1_8[r5_8] then
return false
end
end
return true
end
A = function(r0_9)
-- line: [196, 230] id: 9
str = r0_9
if str:sub(1, 5) == "flag{" and str:sub(-1) == "}" then
pp = str:sub(6, -2)
local r2_9 = asjdhnbvcvvaas(ddddddddddddd(pp))
local r3_9 = {}
for r7_9 = 1, #r2_9, 2 do
local r9_9 = aijusbndbv({
r2_9[r7_9],
r2_9[r7_9 + 1]
}, r8_0)
table.insert(r3_9, r9_9[1])
table.insert(r3_9, r9_9[2])
end
local r5_9 = asjdhnbvcvvaas(izKMncba(r3_9))
if r9_0(r5_9, oianxasdavsdvasd) then
提示("Congratulations, you are right!")
end
if not r9_0(r5_9, oianxasdavsdvasd) then
提示("Error")
end
else
提示("Error")
end
end
可以看到就是一个魔改的xtea加密算法,对照着写出解密脚本,魔改了常数,加密的最后还xor了14和17,注意最后是大端序。
exp
#include <stdio.h>
#include <stdint.h>
void encrypt (uint32_t *v,uint32_t *k ){
uint32_t v0=v[0],v1=v[1],sum=0xC6EF3720,i;
uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
uint32_t delta=2161537835;
for(i=0;i<32;i++){
v1 -= ((v0 << 4) + k[2] ^ v0 + sum ^ (v0 >> 5) + k[3]);
v0 -= (v1 << 4) + k[0] ^ v1 + sum ^ (v1 >> 5) + k[1];
sum+=delta;
}
v[0]=v0;v[1]=v1;
}
void decrypt (uint32_t *v,uint32_t *k){
uint32_t v0=v[0]^14,v1=v[1]^17,sum=2161537835*38,i;
uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
uint32_t delta=2161537835;
for (i=0;i<38;i++){
v1-=(k[sum>>11 & 3]+sum)^(v0 + ((v0 >> 5) ^ (16 * v0)));
v0-=(k[sum & 3]+sum)^(v1 + ((v1 >> 5) ^ (16 * v1)));
sum-=delta;
}
v[0]=v0;v[1]=v1;
}
int main()
{
uint32_t v[10]={863918170,366827450,2944604520,1314064158,2534040034,1250268803,3402278143,1361039932,3087907484,3107271874};
uint32_t k[]={5976,40857,3298229483,1500946329};
for(int i=0; i<10; i+=2) decrypt(v+i, k);
for(int i=0; i<10; i++) printf("%x", v[i]);
return 0;
}
flag{7a5e-55e45-1671e-df3b7-cd7a1-6f1e-27fc}