难度等级:5

拿到这个题,给了你三个附件。第一次遇到。

asong加密程序、out加密结果、that_girl加密引用的数据

out:一堆乱码二进制

that_girl:66行英语文字

asong

用IDA打开

main函数

image-20231012214540692

sub_400AAA函数

image-20231012214626271

sub_400936

image-20231012214739042

所以sub_400AAA这个函数的作用就是“词频统计”

image-20231012215559479

sub_400E54

image-20231012221259118

sub_400D33

image-20231012221539071

sub_400DB4

image-20231012221700477


上面就是对这个的主要分析了。

就是给了一篇文章,统计了里面的字符出现的次数,然后遍历flag中的字符,找出flag每个字符出现的词频,放在一个数组中。将这个词频进行了加密。

我们现在已经知道了这个“文章”所以我们可以得出每个字符对应的词频。通过逆向加密算法,得出词频,通过找表,就能找出flag。

解题

获取词频

打开that_girl

image-20231012222302446

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
s = """there's_a_girl_but_i_let_her_get_away
it's_all_my_fault_cause_pride_got_in_the_way
and_i'd_be_lying_if_i_said_i_was_ok
about_that_girl_the_one_i_let_get_away
i_keep_saying_no
this_can't_be_the_way_we're_supposed_to_be
i_keep_saying_no
there's_gotta_be_a_way_to_get_you_close_to_me
now_i_know_you_gotta
speak_up_if_you_want_somebody
can't_let_him_get_away_oh_no
you_don't_wanna_end_up_sorry
the_way_that_i'm_feeling_everyday
no_no_no_no
there's_no_hope_for_the_broken_heart
no_no_no_no
there's_no_hope_for_the_broken
there's_a_girl_but_i_let_her_get_away
it's_my_fault_cause_i_said_i_needed_space
i've_been_torturing_myself_night_and_day
about_that_girl_the_one_i_let_get_away
i_keep_saying_no
this can't be the way we're supposed to be
i keep saying no
there's gotta be a way to get you
there's gotta be a way
to_get_you_close_to_me
you_gotta
speak_up_if_you_want_somebody
can't_let_him_get_away_oh_no
you_don't_wanna_end_up_sorry
the_way_that_i'm_feeling_everyday
no_no_no_no
there's_no_hope_for_the_broken_heart
no no no no
there's no hope for the broken
no home for me
no home cause i'm broken
no room to breathe
and i got no one to blame
no home for me
no_home_cause_i'm_broken
about_that_girl
the_one_i_let_get_away
so_you_better
speak_up_if_you_want_somebody
you_can't_let_him_bet_away_no_no
you_don't_wanna_end_up_sorry
the_way_that_i'm_feeling_everyday
don't_you_know
no_no_no_no
there's_no_hope_for_the_broken_hearty
don't you know
no no no no
there's no hope for the broken
oh
you don't wanna lose at love
it's only gonna hurt too much
i'm telling you
you_don't_wanna_lose_at_love
it's_only_gonna_hurt_too_much
i'm_telling_you
you_don't_wanna_lose_at_love
cause_there's_no_hope_for_the_broken_heart
that_girl
the_one_i_let_get_away
"""
out = {}
for i in s:
out.update({i:s.count(i)})
out = sorted(out.items())
print(out)


'''
[('\n', 66), (' ', 71), ("'", 40), ('_', 245), ('a', 104), ('b', 30), ('c', 15), ('d', 29), ('e', 169), ('f', 19), ('g', 38), ('h', 67), ('i', 60), ('k', 20), ('l', 39), ('m', 28), ('n', 118), ('o', 165), ('p', 26), ('r', 61), ('s', 51), ('t', 133), ('u', 45), ('v', 7), ('w', 34), ('y', 62)]
没有数字,没有case以外的统计,根据规则重新整理一下数组排序:

[('a', 104), ('b', 30), ('c', 15), ('d', 29), ('e', 169), ('f', 19), ('g', 38), ('h', 67), ('i', 60), ('k', 20), ('l', 39), ('m', 28), ('n', 118), ('o', 165), ('p', 26), ('r', 61), ('s', 51), ('t', 133), ('u', 45), ('v', 7), ('w', 34), ('y', 62),(' ', 71),('_', 245)]
'''

逆向算法

经过网上大量的WP。花费1天时间,弄懂了它:

image-20231013181223796

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enc = [0xEC, 0x29, 0xE3, 0x41, 0xE1, 0xF7, 0xAA, 0x1D, 0x29, 0xED,
0x29, 0x99, 0x39, 0xF3, 0xB7, 0xA9, 0xE7, 0xAC, 0x2B, 0xB7,
0xAB, 0x40, 0x9F, 0xA9, 0x31, 0x35, 0x2C, 0x29, 0xEF, 0xA8,
0x3D, 0x4B, 0xB0, 0xE9, 0xE1, 0x68, 0x7B, 0x41]
#print(len(enc))

binary_enc = [bin(x)[2:].zfill(8) for x in enc] # 转成二进制
binary_string = ''.join(binary_enc) # 将所有的二进制连接在一起成字符串
shifted_binary_string = binary_string[-3:] + binary_string[:-3] # 将字符串循环右移3位
binary_groups = [shifted_binary_string[i:i+8] for i in range(0, len(shifted_binary_string), 8)] # 重新8个8个的划分
int_values = [int(group, 2) for group in binary_groups]#将划分出来的8位8位的二进制转成10进制

#print(binary_enc)
#print(binary_string)
#print(shifted_binary_string)
#print(binary_groups)
print(int_values)

#[61, 133, 60, 104, 60, 62, 245, 67, 165, 61, 165, 51, 39, 62, 118, 245, 60, 245, 133, 118, 245, 104, 19, 245, 38, 38, 165, 133, 61, 245, 7, 169, 118, 29, 60, 45, 15, 104]

ok,这样就第一层的解密完成了。

然后一个顺序的转化,那个地方就是

1
2
3
?从0开始
flag[?] = flag[s[?]]
? = s[?]

知道了这个样子的加密,手动一下就恢复了【主要是我也不会】

1
2
3
4
5
6
7
8
9
10
11
#抄的:
s = [22, 0, 6, 2, 30, 24, 9, 1, 21, 7, 18, 10, 8, 12, 17, 23, 13, 4, 3, 14, 19, 11, 20, 16, 15, 5, 25, 36, 27, 28, 29, 37, 31, 32, 33, 26, 34, 35]
#从程序data区复制出来的s数组值
enc =[61, 133, 60, 104, 60, 62, 245, 67, 165, 61, 165, 51, 39, 62, 118, 245, 60, 245, 133, 118, 245, 104, 19, 245, 38, 38, 165, 133, 61, 245, 7, 169, 118, 29, 60, 45, 15, 104]
i = 37
temp = enc[37]
while s.index(i) != 37:
enc[i] = enc[s.index(i)]
i = s.index(i)
print(enc)
#[133, 67, 104, 133, 245, 38, 60, 61, 39, 245, 51, 104, 62, 60, 118, 38, 245, 118, 165, 245, 19, 165, 61, 245, 62, 165, 45, 61, 245, 7, 60, 118, 29, 60, 15, 45, 133, 169]

然后通过上面的key:value就能求解了