CISCN Little_evil

CISCN little_evil

比赛的时候差一点点出,非常可惜

第一次做 ruby 的逆向题,学到很多东西。这道题总体来说,要进行两种不同策略的反混淆,最后还有一层是类似于 brainfuck 的 vm,需要写 decompiler

题目: littile_evil

提取 out.rb

题目的 elf 文件是典型的 ruby 解释器。问题是源码在哪里? 最开始,我以为是内存加载,分析源码过程中发现是用 Ruby packer 打包的 ruby 程序。Ruby packer 会把源程序相关的打包成 squashfs 文件系统并塞进 ruby 解释器。ruby packer 用了一个内存虚拟文件系统 __enclose_io_memfs__

squashfs 用 binwalk 就可以直接提取

1
binwalk -Me little_evil

提取出主程序(节选)

enclose_io_memfs/local/out.rb

1
2
3
$l1Il="";$l1lI="";def llIl()$lI1lll = $lI1lll|7;end;def l1lll()$lI1lll=10;end;def llI1l()$lI1lll=$lI1lll|4;end;def lIlI()$lI1lll=$lI1lll+3;
end;def l111()$lI1lll=$lI1lll%3;end;def lI1IlI()$lI1lll=$lI1lll|3;end;def ll1l1()$lI1lll=$lI1lll*8;end;def l1lI()$lI1lll=$lI1lll-3;end;def lI1lII()$lI1lll=$lI1lll%1;end;def lIlIl()$lI1lll=$lI1lll&10;end;def lIll()$lI1lll=$lI1lll-4;end;def lII1()$lI1lll=$lI1lll%2;end;def l1III()$lI1lll=$lI1lll|1;end;def l1l111()$lI1lll=$lI1lll|5;end;def l1IIII()$lI1lll=$lI1lll%10;end;def l11I()$l1Il=$l1Il+$lI1lll.chr;end;def lIlll()$lI1lll=$lI1lll*9;end;def l11IlI()$lI1lll=$lI1lll-8;end;def lI1I1()$lI1lll=$lI1lll+5;end;def ll11lI()$lI1lll=$lI1lll&9;end;def lII1l1()send($l1Il[0,4], $l1Il[4,$l1Il.length]);end;l1lll;lIlI;ll1l1;l1lI;l11I;l1lll;llI1l;lIlll;l11IlI;l11I;l1lll;lIlll;llI1l;lIlI;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;llI1l;l1IIII;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;l1lI;ll1l1;l1l111;l11I;l1lll;llI1l;lI1I1;lI1I1;llIl;lIlI;l11I;l1lll;llI1l;lI1I1;lI1I1;llIl;lIlI;l11I;l1lll;l1lI;ll1l1;lIlI;l11I;l1lll;llI1l;l1IIII;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;llIl;l1lI;lIlll;l11I;l1lll;ll1l1;l1lI;lIll;l11I;l1lll;ll1l1;l1lI;lIll;l11I;l1lll;l1lI;ll1l1;l1l111;l11I;l1lll;llI1l;lI1I1;
......[节选]

第一层 ruby 程序

提取出来的 rb 程序高度混淆,难以阅读,尝试过各种在线美化工具,均无效果,于是尝试手搓反混淆。

思路:

  • 分号 ; 替换成 ;\n
  • 解析函数名,替换所有函数名为 funcX,x是序号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
data = open("out.rb", "r").read()
data = data.replace(";", ";\n")
data = data.replace("()", "()\n\t")
data = data.replace("end;", "end;\n")


names = {}
iidx = 1
for line in data.splitlines():
if line.startswith("def"):
idx = line.find("(")
funcName = line[4:idx]
names[funcName] = "func" + str(iidx)
iidx += 1

for k in names:
data = data.replace(k + "()", names[k] + "()", -1)
data = data.replace(k + ";", names[k] + ";", -1)

open("out2.rb","w").write(data)

简单处理后效果

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
79
80
81
82
83
84
85
86
87
88
89
90
$l1Il="";

$l1lI="";

def func1()
$lI1lll = $lI1lll|7;
end;

def func2()
$lI1lll=10;
end;

def func3()
$lI1lll=$lI1lll|4;
end;

def func4()
$lI1lll=$lI1lll+3;

end;

def func5()
$lI1lll=$lI1lll%3;
end;

def func6()
$lI1lll=$lI1lll|3;
end;

def func7()
$lI1lll=$lI1lll*8;
end;

def func8()
$lI1lll=$lI1lll-3;
end;

def func9()
$lI1lll=$lI1lll%1;
end;

def func10()
$lI1lll=$lI1lll&10;
end;

def func11()
$lI1lll=$lI1lll-4;
end;

def func12()
$lI1lll=$lI1lll%2;
end;

def func13()
$lI1lll=$lI1lll|1;
end;

def l1func5()
$lI1lll=$lI1lll|5;
end;

def func15()
$lI1lll=$lI1lll%10;
end;

def func16()
$l1Il=$l1Il+$lI1lll.chr;
end;

def func17()
$lI1lll=$lI1lll*9;
end;

def func18()
$lI1lll=$lI1lll-8;
end;

def func19()
$lI1lll=$lI1lll+5;
end;

def func20()
$lI1lll=$lI1lll&9;
end;

def func21()
send($l1Il[0,4], $l1Il[4,$l1Il.length]);
end;

func2;

func21() 中有一个 send,ruby 中的 send 貌似可以执行代码,修改代码,在 func21 调用时输出 $l1Il[4,$l1Il.length]

1
2
3
4
def func21()
print $l1Il[4,$l1Il.length]
send($l1Il[0,4], $l1Il[4,$l1Il.length]);
end;

输出得到另外一个 ruby 程序。总结一下,第一层 ruby 程序计算出第二层 ruby 程序的字符串并调用第二层 ruby 程序。

第二层 ruby 程序

第二层 ruby 程序混淆规则也类似第一层的 ruby 程序。

节选第二层 ruby 程序

1
2
$llll="";$llII="";def l1llI()$l1lI1l=$l1lI1l|7;end;def ll1III()$l1lI1l=$l1lI1l%7;end;def lllI()$l1lI1l=$l1lI1l/4;end;def lIl1l()$l1lI1l=$l1lI1l-3;end;def l1lll()$l1lI1l=$l1lI1l|10;end;def l11I1I()$l1lI1l=10;end;def l1l1()$l1lI1l=$l1lI1l&7;end;def l1II()$l1lI1l=$l1lI1l%8;end;def ll1I()$l1lI1l=$l1lI1l|8;end;def ll11()$l1lI1l=$l1lI1l^6;end;def ll1l1I()$l1lI1l=$l1lI1l|1;end;def lI1Il()$l1lI1l=$l1lI1l|3;end;def llI1I()$l1lI1l=$l1lI1l+6;end;def llIl1()$l1lI1l=$l1lI1l*4;end;def lI1ll()$l1lI1l=$l1lI1l*5;end;def l1111()$l1lI1l=$l1lI1l^7;end;def l1lII()$l1lI1l=$l1lI1l^4;end;def lIIl()$l1lI1l=$l1lI1l%5;end;def lII11()$l1lI1l=$l1lI1l+9;end;def lI11I()$llll=$llll+$l1lI1l.chr;end;def l1IlI()send($llll[0,4], $llll[4,$llll.length]);end;l11I1I;lII11;lI1ll;llI1I;lI11I;l11I1I;l1llI;lII11;lI1ll;l1llI;lIl1l;lIl1l;lIl1l;lI11I;l11I1I;ll1l1I;lII11;lI1ll;lIl1l;lI11I;l11I1I;lII11;l1lll;llIl1;lI11I;l11I1I;lII11;lI1ll;llI1I;lIl1l;lI11I;l11I1I;lII11;lI1ll;llI1I;lI11I;l11I1I;l1llI;lII11;llIl1;l1llI;lI11I;l11I1I;l1llI;llI1I;lI1ll;lI11I;l11I1I;llI1I;ll11;lI1ll;lI11I;l11I1I;l1llI;l1111;llIl1;lI11I;l11I1I;l1llI;ll11;llIl1;lI11I;l11I1I;lII11;lI1ll;lI11I;l11I1I;l1llI;llIl1;ll1l1I;lI11I;l11I1I;l1llI;ll11;llIl1;lI11I;l11I1I;l1llI;ll11;llIl1;lI11I;l11I1I;lI1ll;lIl1l;lI11I;l11I1I;l1llI;ll11;llIl1;lI11I;l11I1I;l1llI;ll1
......【节选】

继续用第一层处理方法处理第二层代码,得到如下代码:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
$llll="";
$llII="";
def func1()
$l1lI1l=$l1lI1l|7;
end;

def func2()
$l1lI1l=$l1lI1l%7;
end;

def func3()
$l1lI1l=$l1lI1l/4;
end;

def func4()
$l1lI1l=$l1lI1l-3;
end;

def func5()
$l1lI1l=$l1lI1l|10;
end;

def func6()
$l1lI1l=10;
end;

def func7()
$l1lI1l=$l1lI1l&7;
end;

def func8()
$l1lI1l=$l1lI1l%8;
end;

def func9()
$l1lI1l=$l1lI1l|8;
end;

def func10()
$l1lI1l=$l1lI1l^6;
end;

def func11()
$l1lI1l=$l1lI1l|1;
end;

def func12()
$l1lI1l=$l1lI1l|3;
end;

def func13()
$l1lI1l=$l1lI1l+6;
end;

def func14()
$l1lI1l=$l1lI1l*4;
end;

def func15()
$l1lI1l=$l1lI1l*5;
end;

def func16()
$l1lI1l=$l1lI1l^7;
end;

def func17()
$l1lI1l=$l1lI1l^4;
end;

def func18()
$l1lI1l=$l1lI1l%5;
end;

def func19()
$l1lI1l=$l1lI1l+9;
end;

def func20()
$llll=$llll+$l1lI1l.chr;
end;

def func21()
send($llll[0,4], $llll[4,$llll.length]);
end;

func6;
func19;
func15;
func13;
.....[节选]

继续输出 func21 中 send 的参数得到第三层 ruby 程序

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
begin $_=$$/$$;
@_=$_+$_;
$-_=$_-@_;
$__=->_{_==[]||_==''?$.:$_+$__[_[$_..$-_]]}
@__=->_,&__{_==[]?[]:[__[_[$.]]]+@__[_[$_..$-_],&__]}
$_____=->_{@__[[*_],&->__{__[$.]}]}
@_____=->_{@__[[*_],&->__{__[$-_]}]}
$______=->_{___,______=$_____[_],@_____[_];_____=$__[___];____={};__=$.;(_=->{
____[______[__]]=___[__];(__+=$_)==_____ ?____:_[]})[]}
@______=->_,__{_=[*_]+[*__];____=$__[_];___={};__=$.;(_____=->{
___[_[__][$.]]=_[__][$_];(__+=$_)==____ ?___:_____[]})[]}
$_______=->_{$___=[];@___=$__[_];__=___=____=$.;$____,@____={},[]
(_____=->{
_[____]=='5'?(@____<<____):$.
_[____]=='6'?($____[@____[$-_]]=____;@____=@____[$...$.-@_]):$.
(____+=$_)==@___?$.:_____[]})[]
$____=$____=={}?{}:@______[$____,$______[$____]]
(______=->{_[__]==
'0'?($___[___]||=$.;$___[___]+=$_):_[__]==
'1'?($___[___]||=$.;$___[___]-=$_):_[__]==
'2'?($___[___]||=$.;$___[___]=STDIN.getc.ord):_[__]==
'3'?(___+=$_):_[__]==
'4'?(___-=$_):_[__]==
'5'?(__=($___[___]||$.)==$.?$____[__]:__):_[__]==
'6'?(__=($___[___]||$.)!=$.?$____[__]:__):_[__]==
'7'?($><<(''<<$___[___])):$.
(__+=$_)==@___?_:______[]})[]}
$_______['3351635164300000000540000000003164073000000540000003164070070000071730000000541111111131641175160343516445163530440316354031643451634235163516000000054000000000003164344354131645335163435164444516333530444403331635403164344451665163423516351600000054000000000316413443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000316403443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000031640344354131645335163435164444516333530444403331635403164344451665163423516351600000540000000000031643443541316453351634351644445163335304444033316354031643444516651635164453030441633544033164533516351643000000005400000000003164171111744516644'];rescue Exception;end

第三层 ruby 程序

主要是变量名的反混淆,用正则表达式匹配后替换

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import re
data = open("3.rb", "r").read()

target = '1'
for i in re.findall(r"\$_[^_]", data, re.M | re.S):
if i[-1] != "=":
print(i)
data = data.replace(i, target + i[-1])

# @_
target = '2'
for i in re.findall(r"@_[^_]", data, re.M | re.S):
if i[-1] != "=":
print(i)
data = data.replace(i, target + i[-1])

# $-_ => -1

target = '-1'
for i in re.findall(r"\$-_[^_]", data, re.M | re.S):
if i[-1] != "=":
print(i)
data = data.replace(i, target + i[-1])

# $__ -> proc1

target = '$proc1'
for i in re.findall(r"\$__[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# @__
target = '@proc2'
for i in re.findall(r"@__[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# $_____
target = '$proc3'
for i in re.findall(r"\$_____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# @_____
target = '@proc4'
for i in re.findall(r"@_____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# $______
target = '$proc5'
for i in re.findall(r"\$______[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])


# @______
target = '@proc6'
for i in re.findall(r"@______[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

target = '@varX'
for i in re.findall(r"@___[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# $_______
target = '$proc7'
for i in re.findall(r"\$_______[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# $___
target = '$arr1'
for i in re.findall(r"\$___[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])



# $____
target = '$var3'
for i in re.findall(r"\$____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# @____
target = '@var4'
for i in re.findall(r"@____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, target + i[-1])

# [^_]____[^_]
target = 'var5'
for i in re.findall(r"[^_]____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, i[0] + target + i[-1])

# [^_]___[^_]
target = 'var6'
for i in re.findall(r"[^_]___[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, i[0] + target + i[-1])


# ______
target = 'var7'
for i in re.findall(r"[^_]______[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, i[0] + target + i[-1])

# _____
target = 'var8'
for i in re.findall(r"[^_]_____[^_]", data, re.M | re.S):
print(i)
data = data.replace(i, i[0] + target + i[-1])
data = data.replace(i, i[0] + target + i[-1])

data = data.replace(";", ";\n", -1)
try:
open("out4.rb","w").write(data)
except Exception as e:
print(e)

处理后结果如下

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
begin $_=$$/$$;
@_=1+1;
$-_=1-2;
$proc1=->_{_==[]||_==''?$.:1+$proc1[_[1..-1]]}
@proc2=->_,&__{_==[]?[]:[__[_[$.]]]+@proc2[_[1..-1],&__]}
$proc3=->_{@proc2[[*_],&->__{__[$.]}]}
@proc4=->_{@proc2[[*_],&->__{__[-1]}]}
$proc5=->_{var6,var7=$proc3[_],@proc4[_];
var8=$proc1[var6];
var5={};
__=$.;
(_=->{
var5[var7[__]]=var6[__];
(__+=1)==var8 ?var5:_[]})[]}
@proc6=->_,__{_=[*_]+[*__];
var5=$proc1[_];
var6={};
__=$.;
(var8=->{
var6[_[__][$.]]=_[__][1];
(__+=1)==var5 ?var6:var8[]})[]}
$proc7=->_{$arr1=[];
@varX=$proc1[_];
__=var6=var5=$.;
$var3,@var4={},[]
(var8=->{
_[var5]=='5'?(@var4<<var5):$.
_[var5]=='6'?($var3[@var4[-1]]=var5;
@var4=@var4[$...$.-2]):$.
(var5+=1)==@varX?$.:var8[]})[]
$var3=$var3=={}?{}:@proc6[$var3,$proc5[$var3]]
(var7=->{_[__]==
'0'?($arr1[var6]||=$.;
$arr1[var6]+=1):_[__]==
'1'?($arr1[var6]||=$.;
$arr1[var6]-=1):_[__]==
'2'?($arr1[var6]||=$.;
$arr1[var6]=STDIN.getc.ord):_[__]==
'3'?(var6+=1):_[__]==
'4'?(var6-=1):_[__]==
'5'?(__=($arr1[var6]||$.)==$.?$var3[__]:__):_[__]==
'6'?(__=($arr1[var6]||$.)!=$.?$var3[__]:__):_[__]==
'7'?($><<(''<<$arr1[var6])):$.
(__+=1)==@varX?_:var7[]})[]}
$proc7['3351635164300000000540000000003164073000000540000003164070070000071730000000541111111131641175160343516445163530440316354031643451634235163516000000054000000000003164344354131645335163435164444516333530444403331635403164344451665163423516351600000054000000000316413443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000316403443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000031640344354131645335163435164444516333530444403331635403164344451665163423516351600000540000000000031643443541316453351634351644445163335304444033316354031643444516651635164453030441633544033164533516351643000000005400000000003164171111744516644'];
rescue Exception;
end

虚拟机,指令集如下

1
2
3
4
5
6
7
8
# 0: arr1[var6]+=1
# 1: $arr1[var6]-=1
# 2: $arr1[var6]=STDIN.getc.ord
# 3: var6+=1
# 4: var6-=1
# 5: if(arr1[var6] == 0) goto $var3[__]
# 6: if(arr1[var6] != 0) goto $var3[__]
# 7: putchar(arr1[var6])

$var3 是跳转表,是 load 虚拟机字节码的时候生成的,可以直接 print 输出获得。

编写 decompiler

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
a = '3351635164300000000540000000003164073000000540000003164070070000071730000000541111111131641175160343516445163530440316354031643451634235163516000000054000000000003164344354131645335163435164444516333530444403331635403164344451665163423516351600000054000000000316413443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000316403443541316453351634351644445163335304444033316354031643444516651634235163516000000005400000000000031640344354131645335163435164444516333530444403331635403164344451665163423516351600000540000000000031643443541316453351634351644445163335304444033316354031643444516651635164453030441633544033164533516351643000000005400000000003164171111744516644'

addr = 0
var3 = {2: '_5', 6: '_9',
19: '_21',
43: '_36',
76: '_59',
93: '_60',
100: '_67',
105: '_6c',
109: '_76',
119: '_7d',
128: '_83',
135: '_8a',
139: '_8e',
149: '_a5',
170: '_b0',
180: '_b7',
186: '_bd',
193: '_c4',
199: '_d4',
213: '_db',
224: '_e3',
177: '_e4',
228: '_e7',
235: '_ee',
239: '_f2',
248: '_106',
268: '_112',
278: '_119',
284: '_11f',
291: '_126',
297: '_136',
311: '_13d',
322: '_145',
275: '_146',
326: '_149',
333: '_150',
337: '_154',
348: '_16c',
370: '_178',
380: '_17f',
386: '_185',
393: '_18c',
399: '_19c',
413: '_1a3',
424: '_1ab',
377: '_1ac',
428: '_1af',
435: '_1b6',
439: '_1ba',
450: '_1d3',
473: '_1df',
483: '_1e6',
489: '_1ec',
496: '_1f3',
502: '_203',
516: '_20a',
527: '_212',
480: '_213',
531: '_216',
538: '_21d',
542: '_221',
550: '_236',
571: '_241',
581: '_248',
587: '_24e',
594: '_255',
600: '_265',
614: '_26c',
625: '_274',
578: '_275',
629: '_278',
633: '_27c',
638: '_287',
649: '_291',
661: '_298',
665: '_29c',
678: '_2b5',
703: '_2c2',
658: '_2c3',
4: '_3',
8: '_7',
32: '_14',
53: '_2c',
88: '_4d',
95: '_5e',
102: '_65',
107: '_6a',
117: '_6e',
124: '_78',
130: '_81',
137: '_88',
141: '_8c',
164: '_96',
175: '_ab',
182: '_b5',
188: '_bb',
195: '_c2',
211: '_c8',
218: '_d6',
226: '_e1',
227: '_b2',
230: '_e5',
237: '_ec',
241: '_f0',
261: '_f9',
273: '_10d',
280: '_117',
286: '_11d',
293: '_124',
309: '_12a',
316: '_138',
324: '_143',
325: '_114',
328: '_147',
335: '_14e',
339: '_152',
363: '_15d',
375: '_173',
382: '_17d',
388: '_183',
395: '_18a',
411: '_190',
418: '_19e',
426: '_1a9',
427: '_17a',
430: '_1ad',
437: '_1b4',
441: '_1b8',
466: '_1c3',
478: '_1da',
485: '_1e4',
491: '_1ea',
498: '_1f1',
514: '_1f7',
521: '_205',
529: '_210',
530: '_1e1',
533: '_214',
540: '_21b',
544: '_21f',
565: '_227',
576: '_23c',
583: '_246',
589: '_24c',
596: '_253',
612: '_259',
619: '_267',
627: '_272',
628: '_243',
631: '_276',
635: '_27a',
646: '_27f',
656: '_28a',
663: '_296',
667: '_29a',
692: '_2a7',
705: '_2c0',
706: '_293'}
var6 = 0
for op in a:
if op == '0':
print("_%x: arr1[var6]+=1;" % addr)

elif op == '1':
print("_%x: arr1[var6]-=1;" % addr)

elif op == "2":
print("_%x: arr1[var6]=getchar();" % addr)

elif op == "3":
print("_%x: var6+=1;"% addr)
var6 += 1

elif op == "4":
print("_%x: var6-=1;" % addr)
var6 -= 1

elif op == "5":
print(("_%x: if(arr1[var6] == 0) goto " + var3[addr] + ";") % addr)

elif op == "6":
print(("_%x: if(arr1[var6] != 0) goto " + var3[addr] + ";") % addr)

elif op == "7":
print("_%x: putchar(arr1[var6]);" % addr)
else:
print(op)
raise
addr += 1

第四层 vm 分析

decompiler 结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
_0: var6+=1;
_1: var6+=1;
_2: if(arr1[var6] == 0) goto _5;
_3: arr1[var6]-=1;
_4: if(arr1[var6] != 0) goto _3;
_5: var6+=1;
_6: if(arr1[var6] == 0) goto _9;
_7: arr1[var6]-=1;
_8: if(arr1[var6] != 0) goto _7;
_9: var6-=1;

............ 节选


_2bd: var6-=1;
_2be: var6-=1;
_2bf: if(arr1[var6] == 0) goto _2c2;
_2c0: arr1[var6]-=1;
_2c1: if(arr1[var6] != 0) goto _2c0;
_2c2: if(arr1[var6] != 0) goto _293;
_2c3: var6-=1;
_2c4: var6-=1;

用 C 语言重新编译处理

用 IDA 调试分析

逻辑很简单,就是逐个字节比较输入的五位 flag,经过调试得出输入为: M5Ya7


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!