打ctf的时候遇到了lua逆向,浅记一下遇到的知识点和逆向思路
luac命令可以把.lua代码预编译为字节码文件
因为lua程序执行的核心是在JIT虚拟机上运行字节码,所以luac的作用就是把所有字节码打包成一个二进制文件
1
2
|
-
o : 把所有字节码打包成一个文件,
-
o 后跟打包成的文件名
-
l : 把所有字节码打包成一个文件,默认名为luac.out,并打印出所有字节码文件的信息,如下图
|
=>
https://sourceforge.net/projects/unluac/
处理lua5.0 - lua5.4
1
2
|
java
-
jar unluac.jar luac.out >
3.lua
java
-
jar unluac.jar
-
-
rawstring luac.out >
3.lua
|
https://github.com/viruscamp/luadec
主要针对lua5.1,对lua5.2和lua5.3是实验性的 , 依赖lua源码
1
2
3
4
5
6
7
|
git clone https:
/
/
github.com
/
viruscamp
/
luadec
cd luadec
git submodule update
-
-
init lua
-
5.3
# lua5.2 就替换成 lua-5.2 下面也是一样
cd lua
-
5.3
make linux
cd ..
/
luadec
make LUAVER
=
5.3
|
参数介绍
1
2
3
|
-
pn : 打印函数嵌套结构
-
dis : 反汇编luac.out或lua源码
# 这里的反汇编指的是生成字节码
luadec abc.lua 或 luadec luac.out : 反编译lua源码或luac二进制文件
#这里的反编译指的是生成lua源码
|
API文档
https://www.runoob.com/manual/lua53doc/manual.html
https://pgl.yoyo.org/luai/i/lua_pushcclosure
https://www.bookstack.cn/read/lua-5.3/spilt.23.spilt.1.5.md
API积累
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
1
、lua_pushcclosure
lua_pushcclosure()函数是Lua C API提供注册C函数最基础的。其他注册方式都是在该函数上面拓展的
void lua_pushcclosure (lua_State
*
L, lua_CFunction fn,
int
n);
fn为要注册的函数指针
2
、luaL_dofile
加载并运行指定的文件。 它是用下列宏定义出来
(luaL_loadfile(L, filename) || lua_pcall(L,
0
, LUA_MULTRET,
0
))
3
、luaL_loadfilex
int
luaL_loadfilex (lua_State
*
L, const char
*
filename, const char
*
mode);
把一个文件加载为 Lua 代码块,代码块的名字被命名为 filename , 如果 filename 为 NULL,它从标准输入加载
4
、lua_load
int
lua_load (lua_State
*
L,lua_Reader reader,void
*
data,const char
*
chunkname,const char
*
mode);
加载一段 Lua 代码块,但不运行它。 如果没有错误, lua_load 把一个编译好的代码块作为一个 Lua 函数压到栈顶。 否则,压入错误消息
参数 reader , 用来读取数据,比如 luaL_loadfilex 内部调用 lua_load 函数,reader 就是getF函数,其通过fread函数读取文件
参数 data , 是指向可选数据结构的指针,可以传递给reader函数。
参数 chunkname是一个字符串,标识了正在加载的块了名字
参数 mode是一个字符串,指定如何编译数据块。可能取值为:
"b"
(二进制):该块是预编译的二进制块,加载速度比源块快。
"t"
(text): chunk是一个文本块,在执行前被编译成字节码。
"bt"
(both):数据块可以是二进制数据块也可以是文本数据块,函数首先尝试将其作为二进制数据块加载,如果加载失败,则尝试将其作为文本数据块加载。
5
、lua_pushfstring
const char
*
lua_pushfstring (lua_State
*
L, const char
*
fmt, ...);
把一个格式化过的字符串压栈,然后返回这个字符串的指针。 它和 C 函数 sprintf 比较像
6
、lua_pushstring
const char
*
lua_pushstring (lua_State
*
L, const char
*
s);
将指针 s 指向的零结尾的字符串压栈。
7
、lua_tolstring
const char
*
lua_tolstring (lua_State
*
L,
int
index, size_t
*
len
);
把给定索引处的 Lua 值转换为一个 C 字符串。 如果
len
不为 NULL , 它还把字符串长度设到
*
len
中。 这个 Lua 值必须是一个字符串或是一个数字; 否则返回返回 NULL 。 如果值是一个数字, lua_tolstring 还会 把堆栈中的那个值的实际类型转换为一个字符串。
|
(这里以读入text类型的代码块为例
其中lua_load 函数通过 luaD_protectedparser 保护方式来进行文件读取和语法树解析
1
2
3
4
5
6
7
|
/
*
*
*
文件解析函数(保护方式调用)
*
调用:luaD_pcall方法
*
/
int
luaD_protectedparser (lua_State
*
L, ZIO
*
z, const char
*
name, const char
*
mode) {
status
=
luaD_pcall(L, f_parser, &p, savestack(L, L
-
>top), L
-
>errfunc);
}
|
luaD_protectedparser 函数内部调用 luaD_pcall 函数
而 luaD_pcall 函数 回调了 f_parser 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
static void f_parser (lua_State
*
L, void
*
ud) {
/
/
通过数据头的signature来判断读取的数据是binary还是text的,如果是binary的数据,
/
/
则调用luaU_undump来读取预编译好的lua chunks,如果是text数据,则调用luaY_parser来parse lua代码
/
/
也就是说,读取text源码文件要多了一步paser工作
if
(c
=
=
LUA_SIGNATURE[
0
]) {
checkmode(L, p
-
>mode,
"binary"
);
cl
=
luaU_undump(L, p
-
>z, &p
-
>buff, p
-
>name);
}
else
{
checkmode(L, p
-
>mode,
"text"
);
cl
=
luaY_parser(L, p
-
>z, &p
-
>buff, &p
-
>dyd, p
-
>name, c);
}
}
|
f_parser 函数中真正做语法树解析的是luaY_parser 函数(如果是text数据的话)
1
2
3
4
5
6
|
LClosure
*
luaY_parser (lua_State
*
L, ZIO
*
z, Mbuffer
*
buff, Dyndata
*
dyd, const char
*
name,
int
firstchar) {
LexState lexstate;
FuncState funcstate;
mainfunc(&lexstate, &funcstate);
}
|
该函数最后执行mainfunc方法,用于执行语法树的解析工作。
1
2
3
4
|
static void mainfunc (LexState
*
ls, FuncState
*
fs) {
luaX_next(ls);
/
*
读取第一个token read first token
*
/
statlist(ls);
/
*
语法树遍历解析 parse main body
*
/
}
|
mainfunc函数中,有两个函数比较关键。luaX_next:主要用于语法TOKEN的分割,是语法分割器;statlist:主要根据luaX_next分割器分割出来的TOKEN,组装成语法块语句statement,最后将语句逐个组装成语法树
而luaX_next函数内部真正执行Token分割的函数是llex...
...
参考:
https://zhuanlan.zhihu.com/p/429597744
https://blog.csdn.net/initphp/article/details/104428729
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
LClosure
*
luaU_undump(lua_State
*
L, ZIO
*
Z, const char
*
name) {
LoadState S;
LClosure
*
cl;
if
(
*
name
=
=
'@'
||
*
name
=
=
'='
)
/
/
加载的 chunkname
S.name
=
name
+
1
;
else
if
(
*
name
=
=
LUA_SIGNATURE[
0
])
S.name
=
"binary string"
;
else
S.name
=
name;
S.L
=
L;
S.Z
=
Z;
checkHeader(&S);
cl
=
luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L
-
>top, cl);
luaD_inctop(L);
cl
-
>p
=
luaF_newproto(L);
LoadFunction(&S, cl
-
>p, NULL);
lua_assert(cl
-
>nupvalues
=
=
cl
-
>p
-
>sizeupvalues);
luai_verifycode(L, buff, cl
-
>p);
return
cl;
}
|
正常情况下,luaU_undump 函数调用 checkHeader 函数进行一系列的检查(不只是检查头部魔数)
checkHeader 函数源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
static void checkHeader (LoadState
*
S) {
checkliteral(S, LUA_SIGNATURE
+
1
,
"not a"
);
/
*
1st
char already checked
*
/
if
(LoadByte(S) !
=
LUAC_VERSION)
error(S,
"version mismatch in"
);
if
(LoadByte(S) !
=
LUAC_FORMAT)
error(S,
"format mismatch in"
);
checkliteral(S, LUAC_DATA,
"corrupted"
);
checksize(S,
int
);
checksize(S, size_t);
checksize(S, Instruction);
checksize(S, lua_Integer);
checksize(S, lua_Number);
if
(LoadInteger(S) !
=
LUAC_INT)
error(S,
"endianness mismatch in"
);
if
(LoadNumber(S) !
=
LUAC_NUM)
error(S,
"float format mismatch in"
);
}
|
我们从上往下逐个分析
checkliteral(S, LUA_SIGNATURE + 1, "not a");
LUA_SIGNATURE 的宏定义为:
1
|
#define LUA_SIGNATURE "\x1bLua"
|
刚好对应luac文件的开头四字节
if (LoadByte(S) != LUAC_VERSION)
LUAC_VERSION 的宏定义如下:
1
|
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
|
MYINT(s) 宏定义如下
1
|
#define MYINT(s) (s[0]-'0')
|
LUA_VERSION_MAJOR 代表了主版本号,LUA_VERSION_MINOR 代表了子版本号
比如,我们的lua版本号为5.3
那么 LUAC_VERSION 就等于5*16+3=83 <=> 0x53
那么luac文件开头的第4个字节应该为 0x53
if (LoadByte(S) != LUAC_FORMAT)
lua5.3.3源码给出的LUAC_FORMAT的宏定义为
1
|
#define LUAC_FORMAT 0 /* this is the official format */
|
这个值应该一般都为0
检查地址在开头的第5字节
checkliteral(S, LUAC_DATA, "corrupted");
lua5.3.3源码给出的LUAC_DATA的宏定义为
1
|
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
|
这个值,不同版本应该也不怎么会变
检查地址在开头的第6 ~ 11 字节,检查长度为6字节
checksize(S, int);
checksize(S, size_t);
checksize(S, Instruction);
checksize(S, lua_Integer);
checksize(S, lua_Number);
程序用一个巧妙的宏定义完成了检测,#define后面加上一个#号表示将参数字符串化,将其转换成一个字符串常量
1
2
3
4
5
6
|
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
static void fchecksize (LoadState
*
S, size_t size, const char
*
tname) {
if
(LoadByte(S) !
=
size)
error(S, luaO_pushfstring(S
-
>L,
"%s size mismatch in"
, tname));
}
|
if (LoadInteger(S) != LUAC_INT)
if (LoadNumber(S) != LUAC_NUM)
1
2
3
4
|
#define LUAC_INT 0x5678
#define LUAC_NUM cast_num(370.5)
#define cast_num(i) cast(lua_Number, (i))
#define cast(t, exp) ((t)(exp))
|
LUAC_INT :
LUAC_NUM:
题目中给了一个lua5.33打包的elf文件和一个被魔改的 luac文件
分析elf文件,其读入的代码块类型为binary,我们直接沿着Lua的文件读取过程寻找哪里被魔改了
luaU_undump
查看 luaU_undump 源码
对比程序的checksize的函数和源码:
可以发现,程序魔改了LoadByte函数,添加了这样一句判断
1
2
|
if
( (unsigned __int8)(b
-
1
) <
=
0xFDu
)
/
/
<
=
> b <
=
0xfe
return
~b;
|
经过一番研究,发现程序还魔改了 LoadInterger、LoadNumber、LoadInt等函数,既然有load,肯定有dump
对照源码,不难发现程序同样魔改了DumpByte、DumpInt、DumpNumber、DumpInteger函数
下面,我们有一种通用的思路来处理这道题目--魔改lua源码
如下图:
之后重新编译luadec,再进行反编译即可
这里我想介绍的是第二种方法--修复 picstore.bin 代码块
唯一的难题就是: 怎样知道哪些字节被修改了
已知:
(1)、程序load代码块的核心函数有且只有 一个函数 -- LoadBlock
(2)、程序dump代码块的核心函数有且只有 一个函数 --DumpBlock
(3)、这两个函数就像堆栈一样,Load代表 push ,Dump代表 pop
我们只需要记录 LoadBlock 和 DumpBlock 函数的执行次数和函数参数,就可以知道到哪些字节被改变了
我使用gdb_python 脚本进行了记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
import
gdb
import
time
startt
=
time.time()
fp
=
open
(r
"./log.log"
,
"w"
)
strr
=
""
def
pt(p):
global
strr
strr
+
=
p
+
"\n"
Esp
=
0
gdb.execute(
'b *0x55555559C078'
)
# LoadBlock 断点
gdb.execute(
'b *0x55555559C184'
)
# LoadByte
gdb.execute(
'b *0x55555559C1D1'
)
# LoadInt
gdb.execute(
'b *0x55555559C111'
)
# LoadNumber
gdb.execute(
'b *0x55555559C0A1'
)
# LoadInteger
gdb.execute(
'r'
)
while
1
:
frame
=
gdb.selected_frame()
rip
=
frame.read_register(
"rip"
)
if
rip
=
=
0x55555559C078
:
rdx
=
frame.read_register(
"rdx"
)
Esp
+
=
rdx
elif
rip
=
=
0x55555559C184
:
pt(f
"{hex(Esp).ljust(10,' ')} => 1"
)
elif
rip
=
=
0x55555559C1D1
:
pt(f
"{hex(Esp).ljust(10,' ')} => 4"
)
elif
rip
=
=
0x55555559C111
:
pt(f
"{hex(Esp).ljust(10,' ')} => 8"
)
elif
rip
=
=
0x55555559C0A1
:
pt(f
"{hex(Esp).ljust(10,' ')} => 8"
)
if
Esp
=
=
0x19f0
:
fp.write(strr)
fp.close()
print
(
"finish!!!"
)
enddd
=
time.time()
print
(enddd
-
startt)
break
gdb.execute(
'c'
)
/
/
尝试过用 frida ,但发现他Hook不了LoadBlock 函数
/
/
实践发现,程序运行过程中没有执行过一次 DumpBlock 函数,比想象中的还要简单
|
修复 picstore.bin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import
struct
fp
=
open
(r
"C:\Users\Administrator\Desktop\RCTF\picstore\log.log"
,
"r"
)
fps
=
open
(r
"C:\Users\Administrator\Desktop\RCTF\picstore\picStore.bin"
,
"rb"
)
fix_bin
=
open
(r
"C:\Users\Administrator\Desktop\RCTF\picstore\fix_picStore.bin"
,
"wb"
)
data
=
fp.readlines()
data_bin
=
fps.read()
fix_data
=
b""
ans
=
0
for
i
in
range
(
len
(data)):
op_str
=
data[i]
loa
=
int
(op_str[
2
:
6
],
16
)
+
1
step
=
int
(op_str[
14
:
15
],
16
)
for
j
in
range
(ans,loa):
fix_data
+
=
struct.pack(
"B"
,data_bin[j])
for
j
in
range
(loa,loa
+
step):
if
data_bin[j] !
=
0
and
data_bin[j] !
=
0xff
:
t
=
data_bin[j] ^
0xff
fix_data
+
=
struct.pack(
"B"
,t)
else
:
fix_data
+
=
struct.pack(
"B"
,data_bin[j])
ans
=
loa
+
step
fix_bin.write(fix_data)
fix_bin.close()
|
反编译
1
|
java
-
jar .
/
unluac.jar .
/
fix_picStore.
bin
> .
/
oplua.lua
|
剩下的问题就比较常规了,z3求解即可
exp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
from
z3
import
*
solver
=
Solver()
a1
=
[
Int
(f
'c{i}'
)
for
i
in
range
(
30
)]
v1
=
a1[
0
]
v2
=
a1[
1
]
v3
=
a1[
2
]
v4
=
a1[
3
]
v5
=
a1[
4
]
v6
=
a1[
5
]
v7
=
a1[
6
]
v8
=
a1[
7
]
v10
=
a1[
8
]
v24
=
a1[
9
]
v25
=
a1[
10
]
v26
=
a1[
11
]
v27
=
a1[
12
]
v28
=
a1[
13
]
v29
=
a1[
14
]
v30
=
a1[
15
]
v31
=
a1[
16
]
v32
=
a1[
17
]
v33
=
a1[
18
]
v34
=
a1[
19
]
v35
=
a1[
20
]
v36
=
a1[
21
]
v37
=
a1[
22
]
v38
=
a1[
23
]
v39
=
a1[
24
]
v40
=
a1[
25
]
v20
=
a1[
26
]
v41
=
a1[
27
]
v22
=
a1[
28
]
solver.add(
255036
*
v7
+
-
90989
*
v3
+
-
201344
*
v4
+
122006
*
v5
+
-
140538
*
v6
+
109859
*
v2
-
109457
*
v1
-
9396023
=
=
0
)
solver.add(
277432
*
v6
+
110191
*
v3
+
-
186022
*
v4
+
175123
*
v2
-
75564
*
v5
-
252340
*
v1
-
12226612
=
=
0
)
solver.add(
127326
*
v4
+
260948
*
v2
+
-
102835
*
v1
+
225038
*
v5
-
129683
*
v3
-
45564209
=
=
0
)
solver.add(
-
170345
*
v2
+
217412
*
v3
-
26668
*
v1
+
38500
*
v4
-
27440782
=
=
0
)
solver.add(
25295
*
v2
+
69369
*
v3
+
191287
*
v1
-
24434293
=
=
0
)
solver.add(
72265
*
v1
-
2384745
=
=
0
)
solver.add(
264694
*
v1
-
190137
*
v2
+
19025100
=
=
0
)
solver.add(
101752
*
v24
+
67154
*
v8
+
-
20311
*
v1
+
-
30496
*
v6
+
-
263329
*
v7
+
-
99420
*
v10
+
255348
*
v3
+
169511
*
v4
-
121471
*
v2
+
231370
*
v5
-
33888892
=
=
0
)
solver.add(
17253
*
v8
+
-
134891
*
v7
+
144501
*
v4
+
220594
*
v2
+
263746
*
v3
+
122495
*
v6
+
74297
*
v10
+
205480
*
v1
-
32973
*
v5
-
115484799
=
=
0
)
solver.add(
251337
*
v3
+
-
198187
*
v6
+
-
217900
*
v2
+
-
62192
*
v8
+
-
138306
*
v7
+
-
165151
*
v4
-
118227
*
v1
-
22431
*
v5
+
72699617
=
=
0
)
solver.add(
243012
*
v27
+
-
233931
*
v4
+
66595
*
v7
+
-
273948
*
v5
+
-
266708
*
v24
+
75344
*
v8
-
108115
*
v3
-
17090
*
v25
+
240281
*
v10
+
202327
*
v1
-
253495
*
v2
+
233118
*
v26
+
154680
*
v6
+
25687761
=
=
0
)
solver.add(
41011
*
v8
+
-
198187
*
v1
+
-
117171
*
v7
+
-
178912
*
v3
+
9797
*
v24
+
118730
*
v10
-
193364
*
v5
-
36072
*
v6
+
10586
*
v25
-
110560
*
v4
+
173438
*
v2
-
176575
*
v26
+
54358815
=
=
0
)
solver.add(
-
250878
*
v24
+
108430
*
v1
+
-
136296
*
v5
+
11092
*
v8
+
154243
*
v7
+
-
136624
*
v3
+
179711
*
v4
+
-
128439
*
v6
+
22681
*
v25
-
42472
*
v10
-
80061
*
v2
+
34267161
=
=
0
)
solver.add(
65716
*
v30
+
-
18037
*
v26
+
-
42923
*
v7
+
-
33361
*
v4
+
161566
*
v6
+
194069
*
v25
+
-
154262
*
v2
+
173240
*
v3
-
31821
*
v27
-
80881
*
v5
+
217299
*
v8
-
28162
*
v10
+
192716
*
v1
+
165565
*
v24
+
106863
*
v29
-
127658
*
v28
-
75839517
=
=
0
)
solver.add(
-
236487
*
v24
+
-
45384
*
v1
+
46984
*
v26
+
148196
*
v7
+
15692
*
v8
+
-
193664
*
v6
+
6957
*
v10
+
103351
*
v29
-
217098
*
v28
+
78149
*
v4
-
237596
*
v5
-
236117
*
v3
-
142713
*
v25
+
24413
*
v27
+
232544
*
v2
+
78860648
=
=
0
)
solver.add(
-
69129
*
v10
+
-
161882
*
v3
+
-
39324
*
v26
+
106850
*
v1
+
136394
*
v5
+
129891
*
v2
+
15216
*
v27
+
213245
*
v24
-
73770
*
v28
+
24056
*
v25
-
123372
*
v8
-
38733
*
v7
-
199547
*
v4
-
10681
*
v6
+
57424065
=
=
0
)
solver.add(
-
268870
*
v30
+
103546
*
v24
+
-
124986
*
v27
+
42015
*
v7
+
80222
*
v2
+
-
77247
*
v10
+
-
8838
*
v25
+
-
273842
*
v4
+
-
240751
*
v28
-
187146
*
v26
-
150301
*
v6
-
167844
*
v3
+
92327
*
v8
+
270212
*
v5
-
87705
*
v33
-
216624
*
v1
+
35317
*
v31
+
231278
*
v32
-
213030
*
v29
+
114317949
=
=
0
)
solver.add(
-
207225
*
v1
+
-
202035
*
v3
+
81860
*
v27
+
-
114137
*
v5
+
265497
*
v30
+
-
216722
*
v8
+
276415
*
v28
+
-
201420
*
v10
-
266588
*
v32
+
174412
*
v6
+
249222
*
v24
-
191870
*
v4
+
100486
*
v2
+
37951
*
v25
+
67406
*
v26
+
55224
*
v31
+
101345
*
v7
-
76961
*
v29
+
33370551
=
=
0
)
solver.add(
175180
*
v29
+
25590
*
v4
+
-
35354
*
v30
+
-
173039
*
v31
+
145220
*
v25
+
6521
*
v7
+
99204
*
v24
+
72076
*
v27
+
207349
*
v2
+
123988
*
v5
-
64247
*
v8
+
169099
*
v6
-
54799
*
v3
+
53935
*
v1
-
223317
*
v26
+
215925
*
v10
-
119961
*
v28
-
83559622
=
=
0
)
solver.add(
43170
*
v3
+
-
145060
*
v2
+
199653
*
v6
+
14728
*
v30
+
139827
*
v24
+
59597
*
v29
+
2862
*
v10
+
-
171413
*
v31
+
-
15355
*
v25
-
71692
*
v7
-
16706
*
v26
+
264615
*
v1
-
149167
*
v33
+
75391
*
v27
-
2927
*
v4
-
187387
*
v5
-
190782
*
v8
-
150865
*
v28
+
44238
*
v32
-
276353
*
v34
+
82818982
=
=
0
)
solver.add(
-
3256
*
v27
+
-
232013
*
v25
+
-
261919
*
v29
+
-
151844
*
v26
+
11405
*
v4
+
159913
*
v32
+
209002
*
v7
+
91932
*
v34
+
270180
*
v10
+
-
195866
*
v3
-
135274
*
v33
-
261245
*
v1
+
24783
*
v35
+
262729
*
v8
-
81293
*
v24
-
156714
*
v2
-
93376
*
v28
-
163223
*
v31
-
144746
*
v5
+
167939
*
v6
-
120753
*
v30
-
13188886
=
=
0
)
solver.add(
-
240655
*
v35
+
103437
*
v30
+
236610
*
v27
+
100948
*
v8
+
82212
*
v6
+
-
60676
*
v5
+
-
71032
*
v3
+
259181
*
v7
+
100184
*
v10
+
7797
*
v29
+
143350
*
v24
+
76697
*
v2
-
172373
*
v25
-
110023
*
v37
-
13673
*
v4
+
129100
*
v31
+
86759
*
v1
-
101103
*
v33
-
142195
*
v36
+
28466
*
v32
-
27211
*
v26
-
269662
*
v34
+
9103
*
v28
-
96428951
=
=
0
)
solver.add(
-
92750
*
v28
+
-
151740
*
v27
+
15816
*
v35
+
186592
*
v24
+
-
156340
*
v29
+
-
193697
*
v2
+
-
108622
*
v8
+
-
163956
*
v5
+
78044
*
v4
+
-
280132
*
v36
-
73939
*
v33
-
216186
*
v3
+
168898
*
v30
+
81148
*
v34
-
200942
*
v32
+
1920
*
v1
+
131017
*
v26
-
229175
*
v10
-
247717
*
v31
+
232852
*
v25
+
25882
*
v7
+
144500
*
v6
+
175681562
=
=
0
)
solver.add(
234452
*
v34
+
-
23111
*
v29
+
-
40957
*
v2
+
-
147076
*
v8
+
16151
*
v32
+
-
250947
*
v35
+
-
111913
*
v30
+
-
233475
*
v24
+
-
2485
*
v28
+
207006
*
v26
+
71474
*
v3
+
78521
*
v1
-
37235
*
v36
+
203147
*
v5
+
159297
*
v7
-
227257
*
v38
+
141894
*
v25
-
238939
*
v10
-
207324
*
v37
-
168960
*
v33
+
212325
*
v6
+
152097
*
v31
-
94775
*
v27
+
197514
*
v4
+
62343322
=
=
0
)
solver.add(
-
142909
*
v34
+
-
111865
*
v31
+
258666
*
v36
+
-
66780
*
v2
+
-
13109
*
v35
+
-
72310
*
v25
+
-
278193
*
v26
+
-
219709
*
v24
+
40855
*
v8
+
-
270578
*
v38
+
96496
*
v5
+
-
4530
*
v1
+
63129
*
v28
-
4681
*
v7
-
272799
*
v30
-
225257
*
v10
+
128712
*
v37
-
201687
*
v39
+
273784
*
v3
+
141128
*
v29
+
93283
*
v32
+
128210
*
v33
+
47550
*
v6
-
84027
*
v4
+
52764
*
v40
-
140487
*
v27
+
105279220
=
=
0
)
solver.add(
216020
*
v38
+
-
248561
*
v29
+
-
86516
*
v33
+
237852
*
v26
+
-
132193
*
v31
+
-
101471
*
v3
+
87552
*
v25
+
-
122710
*
v8
+
234681
*
v5
+
-
24880
*
v7
+
-
245370
*
v1
+
-
17836
*
v36
-
225714
*
v34
-
256029
*
v4
+
171199
*
v35
+
266838
*
v10
-
32125
*
v24
-
43141
*
v32
-
87051
*
v30
-
68893
*
v39
-
242483
*
v28
-
12823
*
v2
-
159262
*
v27
+
123816
*
v37
-
180694
*
v6
+
152819799
=
=
0
)
solver.add(
-
116890
*
v3
+
67983
*
v27
+
-
131934
*
v4
+
256114
*
v40
+
128119
*
v24
+
48593
*
v33
+
-
41706
*
v2
+
-
217503
*
v26
+
49328
*
v6
+
223466
*
v7
+
-
31184
*
v5
+
-
208422
*
v36
+
261920
*
v1
+
83055
*
v20
+
115813
*
v37
+
174499
*
v29
-
188513
*
v35
+
18957
*
v25
+
15794
*
v10
-
2906
*
v28
-
25315
*
v8
+
232180
*
v32
-
102442
*
v39
-
116930
*
v34
-
192552
*
v38
-
179822
*
v31
+
265749
*
v30
-
54143007
=
=
0
)
solver.add(
-
215996
*
v4
+
-
100890
*
v40
+
-
177349
*
v7
+
-
159264
*
v6
+
-
227328
*
v27
+
-
91901
*
v24
+
-
28939
*
v10
+
206392
*
v41
+
6473
*
v25
+
-
22051
*
v20
+
-
112044
*
v34
+
-
119414
*
v30
+
-
225267
*
v35
+
223380
*
v3
+
275172
*
v5
+
95718
*
v39
-
115127
*
v29
+
85928
*
v26
+
169057
*
v38
-
204729
*
v1
+
178788
*
v36
-
85503
*
v31
-
121684
*
v2
-
18727
*
v32
+
109947
*
v33
-
138204
*
v8
-
245035
*
v28
+
134266
*
v37
+
110228962
=
=
0
)
solver.add(
-
165644
*
v32
+
4586
*
v39
+
138195
*
v25
+
155259
*
v35
+
-
185091
*
v3
+
-
63869
*
v31
+
-
23462
*
v30
+
150939
*
v41
+
-
217079
*
v8
+
-
122286
*
v6
+
5460
*
v38
+
-
235719
*
v7
+
270987
*
v26
+
157806
*
v34
+
262004
*
v29
-
2963
*
v28
-
159217
*
v10
+
266021
*
v33
-
190702
*
v24
-
38473
*
v20
+
122617
*
v2
+
202211
*
v36
-
143491
*
v27
-
251332
*
v4
+
196932
*
v5
-
155172
*
v22
+
209759
*
v40
-
146511
*
v1
+
62542
*
v37
+
185928391
=
=
0
)
solver.add(
57177
*
v24
+
242367
*
v39
+
226332
*
v31
+
15582
*
v26
+
159461
*
v34
+
-
260455
*
v22
+
-
179161
*
v37
+
-
251786
*
v32
+
-
66932
*
v41
+
134581
*
v1
+
-
65235
*
v29
+
-
110258
*
v28
+
188353
*
v38
+
-
108556
*
v6
+
178750
*
v40
+
-
20482
*
v25
+
127145
*
v8
+
-
203851
*
v5
+
-
263419
*
v10
+
245204
*
v33
+
-
62740
*
v20
+
103075
*
v2
-
229292
*
v36
+
142850
*
v30
-
1027
*
v27
+
264120
*
v3
+
264348
*
v4
-
41667
*
v35
+
130195
*
v7
+
127279
*
a1[
29
]
-
51967523
=
=
0
)
assert
solver.check()
=
=
sat
flag2
=
[]
mol
=
solver.model()
for
i
in
a1:
flag2.append(mol[i].as_long())
mappp
=
[
105
,
244
,
63
,
10
,
24
,
169
,
248
,
107
,
129
,
138
,
25
,
182
,
96
,
176
,
14
,
89
,
56
,
229
,
206
,
19
,
23
,
21
,
22
,
198
,
179
,
167
,
152
,
66
,
28
,
201
,
213
,
80
,
162
,
151
,
102
,
36
,
91
,
37
,
50
,
17
,
170
,
41
,
3
,
84
,
85
,
226
,
131
,
38
,
71
,
32
,
18
,
142
,
70
,
39
,
112
,
220
,
16
,
219
,
159
,
222
,
11
,
119
,
99
,
203
,
47
,
148
,
185
,
55
,
93
,
48
,
153
,
113
,
1
,
237
,
35
,
75
,
67
,
155
,
161
,
74
,
108
,
76
,
181
,
233
,
186
,
44
,
125
,
232
,
88
,
8
,
95
,
163
,
200
,
249
,
120
,
243
,
174
,
212
,
252
,
234
,
58
,
101
,
228
,
86
,
109
,
144
,
104
,
121
,
117
,
87
,
15
,
132
,
12
,
20
,
165
,
115
,
136
,
135
,
118
,
69
,
68
,
2
,
82
,
123
,
250
,
251
,
53
,
255
,
51
,
221
,
211
,
195
,
145
,
140
,
254
,
0
,
116
,
43
,
29
,
217
,
197
,
183
,
168
,
188
,
34
,
218
,
146
,
147
,
98
,
149
,
246
,
180
,
103
,
33
,
40
,
207
,
208
,
192
,
143
,
26
,
154
,
225
,
100
,
141
,
175
,
124
,
230
,
62
,
177
,
205
,
110
,
202
,
253
,
173
,
46
,
52
,
114
,
164
,
166
,
137
,
158
,
122
,
13
,
83
,
178
,
133
,
189
,
187
,
7
,
184
,
77
,
245
,
216
,
190
,
194
,
72
,
157
,
172
,
171
,
199
,
160
,
45
,
49
,
27
,
204
,
81
,
6
,
92
,
59
,
209
,
239
,
130
,
97
,
61
,
214
,
215
,
73
,
90
,
126
,
42
,
30
,
240
,
79
,
224
,
78
,
223
,
111
,
60
,
4
,
5
,
196
,
231
,
106
,
64
,
139
,
235
,
150
,
227
,
238
,
191
,
127
,
31
,
156
,
54
,
241
,
242
,
134
,
247
,
128
,
65
,
94
,
57
,
210
,
236
,
9
,
193
]
flag
=
""
for
i
in
range
(
len
(flag2)):
ttt
=
mappp.index(flag2[i])
ttt &
=
0xFF
flag
+
=
chr
(ttt ^
0xFF
^ i)
print
(flag)
|
flag即为
flag{U_90t_th3_p1c5t0re_fl49!}
新人第一次发帖,若有不足,欢迎提出
更多【lua 逆向学习 & RCTF picstore 还原代码块】相关视频教程:www.yxfzedu.com