KCTF 2019 Finals

一鼓作气,再而衰,三而竭orz
开始准备AK,后面因为参加D3CTF Finals时间断层,陆陆续续就没有怎么做了
Emmmm

0x01 无限流

1
2
3
4
5
6
7
#kanxue1
key1="cuk!ogl"
key2="goluck!"
ans=""
for i in key2:
ans+=str(key1.index(i))
print ans

0x02 南充茶坊

首先看到南充茶坊.exe本身没有什么操作,并且可以看到新进程CM.exe
直接binwalk即可提取出CM.exe,同时可以看到压缩包,提取后是一些pyc,同时可以看到CM.exe中只是解压了一段数据(python的bootloader)并运行新的进程,可以看到是pyinstaller
直接使用pyinstxtractor.py提取失败,打开winhex,发现CM.exe的py数据最后四字节有问题:
DEADCODE
去掉后重新提取,即可在提取的资源中发现主程序的pyc数据(\CM.exe_extracted\CM),添加pyc文件头,再使用uncompyle6.exe反编译,其他几个引用库,修复pyc文件头再反编译即可:
Header
得到三个主要文件:
CM.py:

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
from CMpub import pub_n_list, pub_e_list
from general import valid_serial, valid_username, get_enc_seq, enc0
from Crypto.Util.number import bytes_to_long
from os import system

def check(serial, seq):
now = serial
for j in range(len(seq)):
i = seq[j]
n = pub_n_list[i]
e = pub_e_list[i]
if now > pub_n_list[i]:
return False
if i > 0:
now = pow(now, e, n)
else:
now = enc0(now, e, n)
if 0 == now:
return False

return now


def main():
username0 = input('Please input Username:\t')
serial0 = input('Please input Serial:\t')
try:
valid_serial(serial0)
valid_username(username0)
except:
print('\nInvalid Input\n')
return
else:
serial = int(serial0, 16)
username = username0.encode('utf-8')
seq = get_enc_seq(username)
username = bytes_to_long(username)
check_value = check(serial, seq)
if check_value == username:
print('\nCorrect!\n')
else:
print('\nOops! The encrypted Serial is not "' + username0 + '".\n')
system('pause')


if __name__ == '__main__':
main()

CMpub.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pub_n_list = [
1230179032923966355216193664456989083993912178939747632284136330115404600706909248395341278324517175820853286404743710145952644302282044037365125019184623573863075946389644423629304167773956447181872440665027369039751736977631813405,
1230197346433601576871359147146318345794660644587556813317361121112259736906064757424819981626600536503633922734399282271582600808051530362336101942259823441839299355603967188517947938968081105138847731565260537550727639211683197879,
1230175103148238074642625667635930176506433011031372989302833308622794392947506662903737049730958209740476679577696669046125817578949235076594181707520951908118478466754559490593457625240572006099913042624607335165510041897534435209,
1230195419889872144876656964938566328205499234259210834822623032535100815525647028091967713768075507813160118981470260555950945392043292242406398016007295386079663975352275199434079009613722639414793342879897781273997830701207001839,
1230174827420484335136670743465041112031290639257519417607166302989196920558878232997045073571925815302061150702941267642751824310540753494973942944709182841639107639574372312103384805313053886702823094137071927771880443876497834223,
1230185988420782350445684618408731075592594374149632568516959143947765502111474165779039038375448460747737995123102271976521803891348006321134167925739699715318653372703575221067707929872597815216923462345784043188962130180912008349,
1230182067416272799574586563163545941454653137377618375202713428977357995541722463977983142958255155175313052685136009571171283284447072364958073918526788611457558644331357136872625495927467161960356807765452292242153097362794537297,
1230175667673121302771605367336364266247327534138626737357715728447532125946735363769285915448580252805827932111511713836998047583507066247536863749820566853793525683889378074234787827092004094825431802398656705570322640700888234457,
1230196215847264556140155304337951587143228841840811940425256504477922246092127337047231112435502675187836322205816125340569108923142351137471846665258392302281836567949024626839375922984390501852966755563575130612920367863203222919,
1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413]
pub_e_list = [
516522834974778788822737622050071002228140433403308439492366176194856535110473049678585760137133115927927751389873437178270126066640141239601219481836725664034890696476089482771855782560150644578106217444113872365843767702019835165,
763019398230639020385095590111745749325105506404934257293148841704076883985487416392986296273940405033341623636375465706381388882972769884442281412068657916633528090146878551371406807944205178239005601520958614234641039656871416589,
758988267473789691400810521950661631157749425185051374867090671651749645717430551141709267885532654476900928589359256799354189000242807872593092025777838259738748452497031844208902096380110211365512236965688511597330444132995706089,
1160624249765899561934599801255171381291816170997589163041066264243942985094428544791715385847964978883555709070528078257993944356365754193784103706700609561770247555832359683008614876192584738534198649251915489100192910235497240729,
969584864618350548573879514405798110739020997255786147754353418263140741786718203172013471748696400657712445258494301947449205093259143099235572291402265831321039275001497928579686310419303799571460516007736804962510266314260484877,
977635869919691501956476862485989771461480520535754082824505449124021204549179419508424215127475063873127952064971338143136691515421466871627243381628988777601672460858098249144471775030169367579800220246847826510445608881346258241,
78547544255936347746865903259860321812178052069796003154571672431430356709336862994676369608681727972743046653319757142976388460246409300441314120923213061705641045744824531268088986356203751782848608006264879618324460588039470689,
917852167599983949701460374746950168138446186550074700858636881546192542929330983597633909534315139846805451671216776221152853388795036676315895948093016056124384137235869660229554239964598066970045657946753074761366723500887474273,
512767915836808239407587704603826045022417741229198687031456060058182528147222248648359114235863620155721720617193551963387219761946115199232261616095015003006138489919312964841684835736418589367746436759162173805823822810793395319,
1528664914065178933673821962753205462549978186396819666317790993639228285768444490202530533489915241541000489357324333513953018274712260336841857865516134868397620862505815431605074038377372062941322744934135683316080403207986149067]

general.py:

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
from hashlib import sha256

def valid_serial(serial):
assert type(serial) == str
assert len(serial) > 0
if not '0' != serial[0]:
assert 1 == len(serial)
for c in serial:
if not ord('0') <= ord(c) <= ord('9'):
if not ord('A') <= ord(c) <= ord('F'):
raise AssertionError

return serial


def valid_username(username):
assert type(username) == str
assert len(username) > 0
for c in username:
assert ord(c) > 0

return username


def get_enc_seq(username):
h = sha256()
h.update(username)
hash_value = int(h.hexdigest(), 16)
T = 9
S = 10
stat = [0] * (T + 1)
seq = [0]
n = hash_value
while n > 0:
if S * T > len(seq):
now = n % T + 1
if stat[now] < S:
seq.append(now)
stat[now] += 1
n //= T

return seq


def enc0(m, e, n):
nbit = 192
T = (n.bit_length() - 1) // nbit + 1
ans = 0
for i in range(T - 1, -1, -1):

def xxx(x, t):
return x >> t * nbit & (1 << nbit) - 1

now_n = xxx(n, i)
now_e = xxx(e, i)
now_m = xxx(m, i)
if now_m >= now_n:
return 0
ans = (ans << nbit) + pow(now_m, now_e, now_n)

return ans

可以看到是多重RSA
解九个n需要
其中大部分可以靠factordb/yafu/RSACTFTools解出
注意其中:
pub_n_list[0]需要分块求解
pub_n_list[3]需要msieve
pub_n_list[7]和pub_n_list[8]共模求解
pub_n_list[5]利用循环:

1
2
3
4
5
6
7
8
n = pub_n_list[5]
e = pub_e_list[5]
c = pow(2,e,n)
print("start")
for i in range(1,2000):
c = pow(c,e,n)
if c == 2:
print(i)

最终求解即可:

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
from Crypto.Util.number import long_to_bytes
from gmpy2 import invert
e = [False,True,False,True,True,False,False,True,True,True]
pub_n_list = [
1230179032923966355216193664456989083993912178939747632284136330115404600706909248395341278324517175820853286404743710145952644302282044037365125019184623573863075946389644423629304167773956447181872440665027369039751736977631813405,
1230197346433601576871359147146318345794660644587556813317361121112259736906064757424819981626600536503633922734399282271582600808051530362336101942259823441839299355603967188517947938968081105138847731565260537550727639211683197879,
1230175103148238074642625667635930176506433011031372989302833308622794392947506662903737049730958209740476679577696669046125817578949235076594181707520951908118478466754559490593457625240572006099913042624607335165510041897534435209,
1230195419889872144876656964938566328205499234259210834822623032535100815525647028091967713768075507813160118981470260555950945392043292242406398016007295386079663975352275199434079009613722639414793342879897781273997830701207001839,
1230174827420484335136670743465041112031290639257519417607166302989196920558878232997045073571925815302061150702941267642751824310540753494973942944709182841639107639574372312103384805313053886702823094137071927771880443876497834223,
1230185988420782350445684618408731075592594374149632568516959143947765502111474165779039038375448460747737995123102271976521803891348006321134167925739699715318653372703575221067707929872597815216923462345784043188962130180912008349,
1230182067416272799574586563163545941454653137377618375202713428977357995541722463977983142958255155175313052685136009571171283284447072364958073918526788611457558644331357136872625495927467161960356807765452292242153097362794537297,
1230175667673121302771605367336364266247327534138626737357715728447532125946735363769285915448580252805827932111511713836998047583507066247536863749820566853793525683889378074234787827092004094825431802398656705570322640700888234457,
1230196215847264556140155304337951587143228841840811940425256504477922246092127337047231112435502675187836322205816125340569108923142351137471846665258392302281836567949024626839375922984390501852966755563575130612920367863203222919,
1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413]
pub_e_list = [
516522834974778788822737622050071002228140433403308439492366176194856535110473049678585760137133115927927751389873437178270126066640141239601219481836725664034890696476089482771855782560150644578106217444113872365843767702019835165,
763019398230639020385095590111745749325105506404934257293148841704076883985487416392986296273940405033341623636375465706381388882972769884442281412068657916633528090146878551371406807944205178239005601520958614234641039656871416589,
758988267473789691400810521950661631157749425185051374867090671651749645717430551141709267885532654476900928589359256799354189000242807872593092025777838259738748452497031844208902096380110211365512236965688511597330444132995706089,
1160624249765899561934599801255171381291816170997589163041066264243942985094428544791715385847964978883555709070528078257993944356365754193784103706700609561770247555832359683008614876192584738534198649251915489100192910235497240729,
969584864618350548573879514405798110739020997255786147754353418263140741786718203172013471748696400657712445258494301947449205093259143099235572291402265831321039275001497928579686310419303799571460516007736804962510266314260484877,
977635869919691501956476862485989771461480520535754082824505449124021204549179419508424215127475063873127952064971338143136691515421466871627243381628988777601672460858098249144471775030169367579800220246847826510445608881346258241,
78547544255936347746865903259860321812178052069796003154571672431430356709336862994676369608681727972743046653319757142976388460246409300441314120923213061705641045744824531268088986356203751782848608006264879618324460588039470689,
917852167599983949701460374746950168138446186550074700858636881546192542929330983597633909534315139846805451671216776221152853388795036676315895948093016056124384137235869660229554239964598066970045657946753074761366723500887474273,
512767915836808239407587704603826045022417741229198687031456060058182528147222248648359114235863620155721720617193551963387219761946115199232261616095015003006138489919312964841684835736418589367746436759162173805823822810793395319,
1528664914065178933673821962753205462549978186396819666317790993639228285768444490202530533489915241541000489357324333513953018274712260336841857865516134868397620862505815431605074038377372062941322744934135683316080403207986149067]
n0 = [3 , 5 , 7185931 , 158808094450561 , 71865654341558562052460445666991255437082533473043601769875791167176804170025423671296979603455163675313185119614191555444054006826175580211227699148166547437793831583944982630043047905318718417096260894067097]
phi = 1
for i in n0:
phi*=i-1
d0 = invert(pub_e_list[0]//5,phi)
e0 = 5 * 269 * 100479347467620083 * 3821997825858167173910810789124613195528533611172697535969177289820154015727992167281727873897740742740733210910948103694567722741818071770351352777527509949808410647489867809691490251021126067129368597541181679

n1 = [3012613441, 408348887278831461892610983390456945715612189153595698014201723503582993177671598068402822885301113712860820610804438839912419021850712894809826330539771179969086301239790288951959814006579380835620367785931463468740342519]
e1 = 763019398230639020385095590111745749325105506404934257293148841704076883985487416392986296273940405033341623636375465706381388882972769884442281412068657916633528090146878551371406807944205178239005601520958614234641039656871416589
phi = 1
for i in n1:
phi*=i-1
d1 = invert(pub_e_list[1],phi)
p2 = 36796059015915981995743432427927902530578158826788662547913509800095517347118062478922356654842254755916234587213077
q2 = pub_n_list[2]//p2
phi2 = (p2-1)*(q2-1)
e2 = 7537 * 9255264980309 * 10880470858007751390324652265533378235468341001689138251269957159180985184462655657188218085336892458554427149527946369954194849737545474019636015673163686687177842336952960193593542624177105956374331546420180666133
d2 = invert(e2,phi2)
print(d2)
n7 = pub_n_list[7]
n8 = pub_n_list[8]
p4 = 35073848198058968264749790689745197012385911613318747771531468291963621262770461817935405298684967674641247961569207
q4 = 35073848198058968264749790689745197012385911613318747864444430571453140176920442860760331340059929469925220710756489
d4 = invert(pub_e_list[4],(p4-1)*(q4-1))
e5 = 11 * 13 * 191 * 733657391 * 4026960893339 * 12115379258185536246641740189808027591877771839170387403121796053010686218208201487072073319275818512067594227149411425111528971256589583807806340652926403236922622238967009523050297874688181255609871957293
p = gcd(n7,n8)
p6 = 26153324138194530872309557862464074525306735281010877795840958405693838446634362256045094682633541743845611502925341
q6 = 47037312003475104493787837223043052957997925611039410248119470723357078273788416725476266555402464778755414193496517
phi6 = (p6-1)*(q6-1)
d5 = 1
d6 = invert(pub_e_list[6],phi6)
d7 = invert(pub_e_list[7],(p-1)*(n7//p-1))
d8 = invert(pub_e_list[8],(p-1)*(n8//p-1))
p9 = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489
q9 = pub_n_list[9]//p9
phi9 = (p9-1)*(q9-1)
d9 = invert(pub_e_list[9],phi9)
print(0,d1,d2,0,d4,0,d6,d7,d8,d9)
c = pow(2,pub_e_list[9],pub_n_list[9])
assert 2 == pow(c,d9,pub_n_list[9])
def solve_n5(n,e,c,iteration=972):
for i in range(iteration):
c = pow(c,e,n)
return c
# solve_n5(pub_n_list[5],pub_e_list[5],c,972)
from gmpy2 import gcd,is_prime,next_prime
pub_n_list = [
1230179032923966355216193664456989083993912178939747632284136330115404600706909248395341278324517175820853286404743710145952644302282044037365125019184623573863075946389644423629304167773956447181872440665027369039751736977631813405,
1230197346433601576871359147146318345794660644587556813317361121112259736906064757424819981626600536503633922734399282271582600808051530362336101942259823441839299355603967188517947938968081105138847731565260537550727639211683197879,
1230175103148238074642625667635930176506433011031372989302833308622794392947506662903737049730958209740476679577696669046125817578949235076594181707520951908118478466754559490593457625240572006099913042624607335165510041897534435209,
1230195419889872144876656964938566328205499234259210834822623032535100815525647028091967713768075507813160118981470260555950945392043292242406398016007295386079663975352275199434079009613722639414793342879897781273997830701207001839,
1230174827420484335136670743465041112031290639257519417607166302989196920558878232997045073571925815302061150702941267642751824310540753494973942944709182841639107639574372312103384805313053886702823094137071927771880443876497834223,
1230185988420782350445684618408731075592594374149632568516959143947765502111474165779039038375448460747737995123102271976521803891348006321134167925739699715318653372703575221067707929872597815216923462345784043188962130180912008349,
1230182067416272799574586563163545941454653137377618375202713428977357995541722463977983142958255155175313052685136009571171283284447072364958073918526788611457558644331357136872625495927467161960356807765452292242153097362794537297,
1230175667673121302771605367336364266247327534138626737357715728447532125946735363769285915448580252805827932111511713836998047583507066247536863749820566853793525683889378074234787827092004094825431802398656705570322640700888234457,
1230196215847264556140155304337951587143228841840811940425256504477922246092127337047231112435502675187836322205816125340569108923142351137471846665258392302281836567949024626839375922984390501852966755563575130612920367863203222919,
1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413]
def enc0(m, e, n):
nbit = 192
T = (n.bit_length() - 1) // nbit + 1
ans = 0
for i in range(T - 1, -1, -1):

def xxx(x, t):
return x >> t * nbit & (1 << nbit) - 1

now_n = xxx(n, i)
print(now_n)
now_e = xxx(e, i)
print(now_e)
now_m = xxx(m, i)
if now_m >= now_n:
return 0
ans = (ans << nbit) + pow(now_m, now_e, now_n)

return ans
enc0(1,pub_e_list[0],pub_n_list[0])
n0 = [4973828634074084070222279013150769733596223651485114564273,6277087998938792861042405062580257456598525084583043892593,6277031389885428580574088212602983156224270664268963309877,6277052177355867862708971469565390229110991711310599757597]
e0 = [2088392012863598836930805392926351714650188437587735488361,3784482471495320575589048728247975381653380680141800804337,5452515267665389664275951067811576469767027838421869719869,2513827307676496129699780837261567723809491022362599687453]
p00,q00 = 66428487199875098638682243347, 74874934591065563984140844459
p11,q11 = 62221071216704155848060102353, 100883637587609016545825234081
p22,q22 = 46189403453019724968918893779, 135897650123798146894617474263
p33,q33 = 50652156588134490618159573691, 123924677647906847227542543367
phi00 = (p00-1)*(q00-1)
phi11 = (p11-1)*(q11-1)
phi22 = (p22-1)*(q22-1)
phi33 = (p33-1)*(q33-1)
p3 = 34508357350889186927005771176009938286558270433215942821530479444470024241863567490529149148811494601012847563892119
q3 = pub_n_list[3]//p3
phi3 = (p3-1)*(q3-1)
d3 = invert(pub_e_list[3],phi3)
phi = [phi00,phi11,phi22,phi33]
d0 = [invert(e0[i],phi[i]) for i in range(4)]
pub_d_list = [0,1229061379053482744823152709690434888605435342198642793057361495153090878523561729157374272032362247153476832905266577597936263875922635915871109425948662301015976854125739243408750974498511602088546684816889116185016023460221241669,777757116197429014363243483536399809327489478672765799132008796613164652485176625704586327714092043960999487185568710834915265226900792279774759093092549483626423808502139519027474793822444064402879491357824424416255246538629615833,d3,201419093613711761798540120588879041236840801068737686325195769604622639638393093247553615834885873886104026065263583851481439063609372020322699902282368593094548575688163522138303256348801329176798576662806247524508598547117027909,0,922636550562204599680939922372659456090989853033213781402035071733018496656291847983487357218691366381484789513851952285401356211108779700672241308549478980097499945532484886375918716118514969665502334756552044884230174523807259329,627567627354326605515830278366021138159090868181225778581524414114680017539982571880336309158282300554534438008003322761037932916796881232969829716072515736525821134512405811777096389132413642826921797756179543381108933388795804769,87763698610259057934268676955169084425464093902524300758830437447338976666426976224860384022223934601405128988601223084334832120115000652985202766336425151725676233383146800117094745887838499800523801384784235875984207816521259103,476133969086427941368462698171675198835788633664060460402567958612344234273279077792246479357026462298849835811290909092037603283477920353500979549470973082158764663458247740861805650589884280458476962517272738918503674157481390819]
from Crypto.Util.number import long_to_bytes
def dec0(pub_n,n0,d0,m):
nbit = 192
T = (pub_n.bit_length() - 1) // nbit + 1
ans = 0
for i in range(T - 1, -1, -1):
idx = 3-i
def xxx(x, t):
return x >> t * nbit & (1 << nbit) - 1
now_m = xxx(m, i)
ans = (ans << nbit) + pow(now_m, d0[idx], n0[idx])
return hex(ans)[2:].upper()
def reverse(serial, seq):
now = serial
for j in range(len(seq)):
i = seq[j]
n = pub_n_list[i]
e = pub_e_list[i]
d = pub_d_list[i]
if i > 0 and i!=5:
now = pow(now, d, n)
elif i==5:
now = solve_n5(n,e,now,iteration=972)
else:
now = dec0(pub_n_list[0],n0,d0, now)
if 0 == now:
return False
return now
username = "KCTF"
sec = get_enc_seq(username.encode('utf-8'))
from Crypto.Util.number import long_to_bytes,bytes_to_long
name = bytes_to_long(username.encode('utf-8'))
#"89F3A5FD45E2A383"
#A7E477BED7F21984189BF0E42F92252C5B8EAC3D816F0A354A60FA97ACCA5E45EF94D1BD557C0BFD4AE6AF65236BDC205B084D3B9D7771C630611D5B2C3D4F10F14CE7C206DCDFDBD3578335BE68AD23018D2FC95D2F1F16ABD7FC78D22E2DB9
#CA1F4C8740C8E620C4AC306F2C3BCB3FD7ABCC1378D94779DD78481EDC412ACE40A2092B4726A259367C43F3AA3DDDDF54C2513318A11C61867BC43882498F32EBD694C77786A9091FC1333E810888C01049E97F15E4B64123A913E5794B0614
t = hex(bytes_to_long(b'\xa7\xe4w\xbe\xd7\xf2\x19\x84\x18\x9b\xf0\xe4/\x92%,[\x8e\xac=\x81o\n5J`\xfa\x97\xac\xca^E\xef\x94\xd1\xbdU|\x0b\xfdJ\xe6\xafe#k\xdc [\x08M;\x9dwq\xc60a\x1d[,=O\x10\xf1L\xe7\xc2\x06\xdc\xdf\xdb\xd3W\x835\xbeh\xad#\x01\x8d/\xc9]/\x1f\x16\xab\xd7\xfcx\xd2.-\xb9'))
print("a7e477bed7f21984189bf0e42f92252c5b8eac3d816f0a354a60fa97acca5e45ef94d1bd557c0bfd4ae6af65236bdc205b084d3b9d7771c630611d5b2c3d4f10f14ce7c206dcdfdbd3578335be68ad23018d2fc95d2f1f16abd7fc78d22e2db9".upper())
print(reverse(name,sec[::-1]))

0x03 街机少年

XYLearn tqllllll ! 7feilee tqllllll !
应该是非预期了
IDA载入程序,看到主程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if ( get_input() )
{
SetUnhandledExceptionFilter(TopLevelExceptionFilter);
if ( GAME((unsigned __int8 *)name, name_len) )
output("You Win! You are very clever!");
else
output("Game Over");
system("pause");
result = 0;
}
else
{
output("Game Over");
system("pause");
result = 0;
}

程序读入name和serial,而后走过一个判断,通过GAME函数返回值来判断是否正确
首先读入name和serial:

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
for ( i = 0; i < 32; ++i )
{
v4 = read_input();
if ( (v4 < 97 || v4 > 122) && (v4 < 65 || v4 > 90) && (v4 < 48 || v4 > 57) )
{
if ( v4 != 13 && v4 != 10 )
return 0;
name_len = i;
break;
}
name[i] = v4;
}
if ( name_len < 4 || name_len > 16 )
return 0;
output("Please input your KEY: ( : to z )");
for ( j = 0; j < 128; ++j )
{
v3 = read_input();
if ( v3 < ':' || v3 > 'z' )
{
if ( v3 != 13 && v3 != 10 )
return 0;
serial_len = j;
break;
}
serial[j] = v3;
}
if ( !serial_len || serial_len > 128 )
return 0;
dec_len = dec1((int)decode_serial, (int)serial, serial_len);

简单判断name和serial合法后decode并存入全局变量数组
decode类似一个base64,只是对应处理位不同,直接对照求逆即可:

1
2
3
4
5
6
7
8
9
10
11
12
def dec1(str1):
ans=[]
for i in range(len(str1)/3):
ans.append(ord(str1[i*3])>>2)
ans.append(((ord(str1[i*3])&0b11)<<4)+((ord(str1[i*3+1])&0b11110000)>>4))
ans.append((ord(str1[i*3+1])&0b1111)+((ord(str1[i*3+2])&0b11000000)>>2))
ans.append(ord(str1[i*3+2])&0b00111111)
s=""
for i in ans:
s+=chr(i+ord(":"))
return s
#后面不足对应相同位置并补'z'即可

在GAME中,首先使用大量数组查表隐藏了算法和计算过程
首先将第一轮table扣下来:

1
2
3
4
5
6
7
8
def func1(x, m):
s = x
none_primitive_root = 0
for i in range(1, m):
y = min(x, s)
z = max(x, s)
s = y * y % 17 ^ triangle_at(xor_table, y, z)
......

根据返回值发现是一个乘方运算(取模意义下),计算pow(x,m)
故而在第一层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for ( i = 1; i < 16; ++i )
{
v35 = v38;
v27 = v51;
if ( v38 > (signed int)v51 )
{
v35 = v51; // 乘方
v27 = v38;
}
v38 = v35 * v35 % 17 ^ table[(unsigned __int8)(v27 + (v35 - 1) * (34 - v35) / 2 - v35)];
if ( v38 == 1 && i != 15 ) // (p-1)/2不满足
{
v51 = (v51 + 1) % 16 + 1;
v38 = 0;
break;
}
}

其实际计算的是相对v51步长2的模17下最近的非二次剩余
而后其根据输入name初始化了一个256长度数组(前16参与运算)
而后大致流程可以取下:

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
from base64 import b64decode,b64encode
import os
from functools import reduce

xor_table = [0,3,2,5,4,7,6,9,8,11,10,13,12,15,14,17,0,2,12,14,8,10,20,5,7,1,3,13,15,9,11,0,5,6,8,13,14,3,4,25,11,12,1,2,7,0,19,23,27,31,18,22,26,30,17,21,25,29,0,5,9,14,3,24,12,1,6,10,15,4,0,10,12,1,11,13,6,8,18,7,9,0,10,3,13,6,31,9,2,12,5,0,9,1,14,6,15,7,12,4,0,8,3,11,2,10,29,5,0,7,14,4,11,1,8,0,15,5,3,14,4,0,11,7,2,13,0,28,24,20,0,15,10,0,6,0]


with open('E:/Totoro.exe', 'rb') as f:
f.seek(0x16088, os.SEEK_SET)
bytes_397288 = f.read(65536)
bytes_397288 = [i for i in bytes_397288]
f.seek(0x26088, os.SEEK_SET)
bytes_3A7288 = f.read(256)
bytes_3A7288 = [i for i in bytes_3A7288]
f.seek(0x14E88, os.SEEK_SET)
bytes_396088 = f.read(256)
bytes_396088 = [i for i in bytes_396088]
f.seek(0x14F88, os.SEEK_SET)
bytes_396188 = f.read(4096)
bytes_396188 = [i for i in bytes_396188]
f.seek(0x15F88, os.SEEK_SET)
bytes_417188 = f.read(256)
bytes_417188 = [i for i in bytes_417188]

def quadratic_residues(x, m):
while True:
s = x
for i in range(1, m):
y = s
z = x
if s > x:
y = x
z = s
idx = (z + (y - 1) * (34 - y) // 2 - y)%256
s = (y * y % 17) ^ xor_table[idx]
if s == 1 and i != 15:
x = (x + 1) % 16 + 1
s = 0
break
if s == 1:
break
return x

def _pow(x, m):
s = x
global flag
for i in range(1, m):
y = s
z = x
if s > x:
y = x
z = s
idx = (z + (y - 1) * (34 - y) // 2 - y)%256
s = (y * y % 17) ^ xor_table[idx]
if s == 1 and i != 15:
flag = 1
return s

def triangle_index(y, z):
return z + (y - 1) * (34 - y) // 2 - y

def triangle_at(mat, y, z):
return mat[triangle_index(y, z)]

def get_inv(x):
while True:
s = x
for i in range(1, 16):
y = min(x, s)
z = max(x, s)
s = y * y % 17 ^ triangle_at(xor_table, y, z)
if s == 1 and i != 16 - 1:
x = (x + 1) % 16 + 1
s = 0
break
if s == 1:
break
return x

def pows(x, m):
s = x
none_primitive_root = 0
for i in range(1, m):
y = min(x, s)
z = max(x, s)
s = y * y % 17 ^ triangle_at(xor_table, y, z)
if s == 1 and i != m-1:
none_primitive_root = 1
return s,none_primitive_root

def map_username(username,bytes_417188):
for i in range(len(username) - 1):
ch = username[i + 1]
if i >= 7:
if i >= 10:
if i >= 13:
bytes_417188[i] = ch % 8 + 8
else:
bytes_417188[i] = 7 - ch % 7
else:
bytes_417188[i] = ch % 8 + 8
else:
bytes_417188[i] = 7 - ch % 7
return bytes_417188



def get_idx(a, b, c):
lo = ((b >> 2) ^ ((c << 4) & 0xC0)) ^ ((a << 2) & 0x3C) ^ 0xC7
hi = (c & 3) ^ ((b << 2) & 0xf) ^ 2
x = lo | (hi << 8)
return x


def unknown(a, b, c):
'''a^b^c'''
return bytes_397288[((a + b + c) % 16) | (a << 4) | (b << 8) | (c << 12)]


def check(username, key):
#key= [61, 136, 200, 67, 168, 249, 66, 246, 42, 33, 212, 253, 243, 246, 246, 244, 246, 249, 244, 255, 237]
key_len = len(key)
ch = username[0] % 16 + 1
username = map_username(username,bytes_417188)
primitive_root = quadratic_residues(ch,16)
kidx = 0
x = 5
while kidx < key_len:
key_low = key[kidx] % 16 + 1
key_high = (key[kidx]>>4) % 16 + 1
flag = 1
if primitive_root and key_low <= 16 and key_high <=16:
flag = 0
key_low = _pow(primitive_root, key_low)
r2 = quadratic_residues(key_low,16)
key_high = _pow(r2, key_high)
if flag:
break
primitive_root = quadratic_residues(key_high,16)
primitive_flag = (key_high * bytes_396088[username[key_low - 1] - key_high])&0xff
for i in range(key_low, 128):
v4 = int(username[i] == 0)
v5 = (((v4 + bytes_396188[get_idx(username[key_low - 1], username[i], key_high)])%256) * primitive_flag)&0xff
primitive_flag = (((v5 + 1) & int(v5 != 0)) + v5)&0xff
username[key_low - 1] = (username[key_low - 1] + ((((2 * ((primitive_flag + 1) & 1) - 1)&0xff) * key_high)&0xff))&0xff
#print("test xor is {}".format(reduce(lambda x, y: x ^ y, username)))
if not primitive_flag:
break
if not any(username):
return kidx == key_len - 1
key_low_ = (key[kidx] >> 4) % 16 + 1
key_high_ = key[kidx + 1] % 16 + 1
bytes_396088[key_low_ // 2] = (bytes_396088[key_low_ // 2] + key_high_) % 127 + 1
kidx += 1
tmp = unknown(username[2], username[1], username[0])
tmp = unknown(username[4], username[3], tmp)
tmp = unknown(username[6], username[5], tmp)
tmp = unknown(username[8], username[7], tmp)
tmp = unknown(username[10], username[9], tmp)
tmp = unknown(username[12], username[11], tmp)
tmp = unknown(username[14], username[13], tmp)
if tmp:
for i in range(15):
val = bytes_3A7288[tmp | (username[i] << 4)]
if val & 1:
username[i] = val >> 1
break
else:
print(kidx)
fflag = 0
while True:
if username[x] == 1:
username[x] = (username[x] - 1)%256
x = (x + 4) % 15
fflag = 1
break
if username[x] > 1:
break
x = (x + 4) % 15
if fflag == 0:
username[x] = username[x] - ((x * x + 1) % username[x] + 1)
x = (x + 4) % 15
if not reduce(lambda x, y: x | y, username):
break
return False

在循环过程中,每轮12bit key参与运算,首先根据第一步结果进行乘方,再进行一次求非平方剩余,再进行一次乘方(不出现单位元),根据结果更新一位username数组,而后进行一轮变换(unknown),根据变换结果更新一位username
通过观察数组及结果发现unknown操作是进行一组异或
若异或后不为0则依赖第二个数组将其每位异或结果调整为0
通过观察正确序列号发现:

1
2
正确退出应该是循环过每一位序列号经由最后: 循环次数==序列号长度-1来return
在正确序列号变换下tmp每轮是0

其实到这里也没猜到具体的数学背景是什么,最开始肖神通过unknown中变换的数组搜索到AES的add field,不过后来发现只是一组异或,遂失败
不过从上面分析可以看到,每轮参与计算的只有12bit,而且通过正确序列号的程序流可以猜测到每一轮tmp=0即为控制条件,以此进行逐位爆破即可得到可能解
最后肖神用unicorn成功解出(tqlll !!!)(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
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
import sys
import os
import struct
from base64 import b64decode, b64encode
from capstone import *
from capstone.x86_const import *
from unicorn import *
from unicorn.x86_const import *

def p32(n):
return struct.pack("<I", n)
to = b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
base = b':;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxy'
def base64_enc(data):
data = b64encode(data)
res = []
for i in data:
res.append(base[to.index(i)])
return ("".join([chr(i) for i in res])).encode()
def base64_dec(data):
res = []
for i in data:
res.append(to[base.index(i)])
return b64decode("".join([chr(i) for i in res]).encode())

cs = Cs(CS_ARCH_X86, CS_MODE_32)

last_addr = 0
def hook_code(mu, addr, size, user_data):
global last_addr
last_addr = addr
code = mu.mem_read(addr, 10)
ins = next(cs.disasm(code, addr, 1))
disasm = "{:08x}: {} {}".format(addr, ins.mnemonic, ins.op_str)
print(disasm)

mu = None
with open("./Totoro.exe", 'rb') as f:
f.seek(0x400, os.SEEK_SET)
text = f.read(0xf13b - 0x400)
f.seek(0xf320, os.SEEK_SET)
rdata = f.read(0x14c68 - 0xf320)
f.seek(0x14E00, os.SEEK_SET)
data = f.read(0x26C00-0x14E00)
def check(username, key, addr_points=None):
global mu
mu = Uc(UC_ARCH_X86, UC_MODE_32)
text_start , text_end = 0x401000, 0x410000
idata_start, idata_end = 0x410000, 0x410120
rdata_start, rdata_end = 0x410120, 0x416000
data_start , data_end = 0x416000, 0x429000
stack_start, stack_end = 0x7ffa0000, 0x80000000
cache_start, cache_end = 0x100000, 0x110000
stack_curr = 0x7fff0000
mu.mem_map(text_start, data_end - text_start)
mu.mem_write(text_start, text)
mu.mem_write(rdata_start, rdata)
mu.mem_write(data_start, data)
mu.mem_map(stack_start, stack_end - stack_start)
mu.mem_map(cache_start, cache_end - cache_start)
mu.reg_write(UC_X86_REG_ESP, stack_curr)
# key
key_addr = 0x427E38
key_len_addr = 0x427F38
mu.mem_write(key_addr, key)
mu.mem_write(key_addr + len(key), b'\0' * (256 - len(key)))
mu.mem_write(key_len_addr, p32(len(key)))
# username
mu.mem_write(stack_curr + 4, p32(cache_start))
mu.mem_write(cache_start, username)
mu.mem_write(stack_curr + 8, p32(len(username)))
# hook
# mu.hook_add(UC_HOOK_CODE, hook_code)
# execute
check_addr = 0x401480
check_ret_addr = 0x402088
try:
if not addr_points:
mu.emu_start(check_addr, check_ret_addr)
else:
start = check_addr
for addr in addr_points:
mu.emu_start(start, addr)
mu.emu_start(addr, 0, count=1)
start = mu.reg_read(UC_X86_REG_EIP)
except UcError as e:
return False
return True

username = b'KCTF'
key = [0 for i in range(0x20)]

# key = [61, 136, 200, 67, 168, 249, 66, 246, 42, 33, 212, 253, 243, 246, 246, 244, 246, 249, 244, 255, 237, 249]
end = False
for i in range(21):
for ch in range(256):
key[i] = ch
if not check(username, bytes(key), [0x401F00] * (i+1)):
continue
if mu.reg_read(UC_X86_REG_EAX) == 0:
print(i, ch)
break
key[i] = 0x100
if key[i] == 0x100:
break
i += 1
for ch in range(256):
key[i] = ch
if not check(username, bytes(key)):
continue
if mu.reg_read(UC_X86_REG_EAX) == 0:
print(i, ch)
break
print(key)
#Output:[61, 136, 200, 67, 168, 249, 66, 246, 42, 33, 212, 253, 243, 246, 246, 244, 246, 249, 244, 255, 237, 249]
-------------------------------------------------------------------------------
def dec1(str1):
ans=[]
for i in range(len(str1)/3):
ans.append(ord(str1[i*3])>>2)
ans.append(((ord(str1[i*3])&0b11)<<4)+((ord(str1[i*3+1])&0b11110000)>>4))
ans.append((ord(str1[i*3+1])&0b1111)+((ord(str1[i*3+2])&0b11000000)>>2))
ans.append(ord(str1[i*3+2])&0b00111111)
ans.append(ord(str1[21])>>2)
ans.append((ord(str1[21])&0b11)<<4)
s=""
for i in ans:
s+=chr(i+ord(":"))
return s+"zz"
s=""
final_key=[61, 136, 200, 67, 168, 249, 66, 246, 42, 33, 212, 253, 243, 246, 246, 244, 246, 249, 244, 255, 237, 249]
for i in final_key:
s+=chr(i)
print dec1(s)
#Output:IRrBJtrsJi@dBWnwvyppwIpswIygxJzz

0x04 小虎还乡

1
2
3
4
5
Windows 10 64位驱动程序
由于我用的是驱动测试签名,因此请打开测试驱动签名,请做如下操作:
管理员运行cmd,然后输入:
bcdedit /set testsigning on
回车,重启即可。

可以看到关键判断:

1
2
3
4
5
6
scanf(&input_format, &v8);                    // %d
if ( (signed __int64)v8 <= 96000 && (signed __int64)v8 >= 90000 )
{
v15 = 66i64;
v16 = 169i64;
v12 = 231i64;

其他地方没有输入的程序流
所以猜测答案在90000-96000之间,由此确定了应该使用爆破,接下来patch掉输入在90000-96000时的弹窗即可
经过几次patch可以发现在:

1
2
3
4
5
6
7
8
__int64 sub_140002050()
{
__int64 v0; // rax

MessageBoxW(0i64, L"wrong!", L"err", 0);
v0 = sub_1400014D0(aKerneloadriven);
return sub_140001E70(v0);
}

将这里的MessageBoxW patch掉,而后爆破直到程序本身弹出”ok”即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
import time
from subprocess import Popen, PIPE

for i in range(90000, 96000):
p = Popen("./ConsoleApplication1.exe", stdin=PIPE, stdout=PIPE, stderr=PIPE)
# time.sleep(0.01)
p.stdin.write(str(i)+"\n")
res = p.communicate()
# if len(res[0])!=len("Enter pass word: "):
# print str(i),res
# if i %100==0:
print i
#输出ok时为:91024