i春秋百度杯12月第3周WriteUp

这是i春秋百度杯12月份第三场,同样是逆向专场,还加了三个杂项。
传送门:百度杯

0x00 MISC1

图片下载后直接用记事本打开,拉到最后会看到:flag{stego_is_s0_bor1ing},过关。

0x01 MISC2

很明显是猪圈密码,两个符号分别表示NS,试下就知道正确结果:flag{NSN}.

0x02 MISC3

根据提示,是键盘坐标密码,将26键键位表示为坐标形式,横坐标表示行数,纵坐标表示列数,都从1开始,对应查找即可,最后结果为flag{QAZIJCV}

0x03 RE1

这一题比较简单,湖湘杯开始前已经看完,只是由于验证算法时手抖了下,打错个东西,致使我怀疑AES是不是变形了,更让我怀疑题目是不是有问题。

直接OD载入,看下导入函数,直接下断GetWindowTextW,运行输入注册码确定,预期中断下:

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
00B01EC2 > \6A 64 push 0x64 ; /Count = 64 (100.)
00B01EC4 . 8D8D C4FEFFFF lea ecx,dword ptr ss:[ebp-0x13C] ; |
00B01ECA . 51 push ecx ; |Buffer = 00000002
00B01ECB . 8B15 1449B000 mov edx,dword ptr ds:[0xB04914] ; |
00B01ED1 . 52 push edx ; |hWnd = 0000000A
00B01ED2 . FF15 D830B000 call dword ptr ds:[<&USER32.GetWindowTextW>] ; \GetWindowTextW
00B01ED8 . 85C0 test eax,eax
00B01EDA . 74 33 je short Ichunqiu.00B01F0F
00B01EDC . 33C0 xor eax,eax
00B01EDE . 74 03 je short Ichunqiu.00B01EE3
00B01EE0 . C3 retn
00B01EE1 . EB 2C jmp short Ichunqiu.00B01F0F
00B01EE3 > 8D55 8C lea edx,dword ptr ss:[ebp-0x74]
00B01EE6 . 8D8D C4FEFFFF lea ecx,dword ptr ss:[ebp-0x13C]
00B01EEC . E8 4FF9FFFF call Ichunqiu.00B01840 ; unicode转ascii
00B01EF1 . 8D4D 8C lea ecx,dword ptr ss:[ebp-0x74]
00B01EF4 . E8 87F9FFFF call Ichunqiu.00B01880 ; 关键
00B01EF9 . 6A 00 push 0x0 ; /Style = MB_OK|MB_APPLMODAL
00B01EFB . 68 4035B000 push Ichunqiu.00B03540 ; |Title = "CrackMe"
00B01F00 . 68 8043B000 push Ichunqiu.00B04380 ; |Text = ""
00B01F05 . 8B4D 08 mov ecx,dword ptr ss:[ebp+0x8] ; |
00B01F08 . 51 push ecx ; |hOwner = 00000002
00B01F09 . FF15 E830B000 call dword ptr ds:[<&USER32.MessageBoxW>] ; \MessageBoxW
00B01F0F > 33C0 xor eax,eax
00B01F11 . EB 22 jmp short Ichunqiu.00B01F35
00B01F13 > 6A 00 push 0x0 ; /ExitCode = 0x0
00B01F15 . FF15 C030B000 call dword ptr ds:[<&USER32.PostQuitMessage>] ; \PostQuitMessage
00B01F1B . 33C0 xor eax,eax

取输入,双字节转成单字节后进入call Ichunqiu.00B01880,此调用为主要算法及验证流程,下面就是正确与错误的弹窗了。
关键流程中,主要过程是取出输入前6位,检查其不大于Z,再三三分为两部分分别计算CRC32检验值,其结果串接为密钥,再结合明文IV对输入进行CBC模式的AES加密,加密后的结果转换为hex字串,进行变形base64编码,与程序中的明文base64比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
00B019D2 . 8BCB mov ecx,ebx
00B019D4 . C745 D4 04030>mov dword ptr ss:[ebp-0x2C],0x1020304 ; IV
00B019DB . C745 D8 00090>mov dword ptr ss:[ebp-0x28],0x7080900
00B019E2 . C745 DC 06050>mov dword ptr ss:[ebp-0x24],0xE0F0506
00B019E9 . C745 E0 0D0C0>mov dword ptr ss:[ebp-0x20],0xA0B0C0D
00B019F0 . 8D51 01 lea edx,dword ptr ds:[ecx+0x1]
00B019F3 > 8A01 mov al,byte ptr ds:[ecx]
00B019F5 . 41 inc ecx
00B019F6 . 84C0 test al,al
00B019F8 .^ 75 F9 jnz short Ichunqiu.00B019F3
00B019FA . 8D45 D4 lea eax,dword ptr ss:[ebp-0x2C]
00B019FD . 2BCA sub ecx,edx
00B019FF . 50 push eax
00B01A00 . 8D45 C0 lea eax,dword ptr ss:[ebp-0x40]
00B01A03 . 8BD3 mov edx,ebx
00B01A05 . 50 push eax
00B01A06 . 51 push ecx
00B01A07 . 8D8D D8FEFFFF lea ecx,dword ptr ss:[ebp-0x128]
00B01A0D . E8 6EF9FFFF call Ichunqiu.00B01380 ; 密钥 IV AES cbc模式加密
00B01A12 . 8BCB mov ecx,ebx

变形base64只是将转换表换了,如下:

1
2
3
4
00B03470 30 39 38 37 36 35 34 33 32 31 5A 59 58 57 56 55 0987654321ZYXWVU
00B03480 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 48 47 46 45 TSRQPONMLKJIHGFE
00B03490 44 43 42 41 7A 79 78 77 76 75 74 73 72 71 70 6F DCBAzyxwvutsrqpo
00B034A0 6E 6D 6C 6B 6A 69 68 67 66 65 64 63 62 61 2B 2F nmlkjihgfedcba+/

最终的验证base64串为:

1
2
3
00B034F0 00 00 00 00 58 51 58 67 57 6B 35 79 4C 41 44 69 ....XQXgWk5yLADi
00B03500 58 78 36 68 56 51 43 41 4B 78 54 6A 56 51 58 69 Xx6hVQCAKxTjVQXi
00B03510 57 78 50 68 58 41 53 43 4B 41 4C 68 56 37 58 3D WxPhXASCKALhV7X=

算法验证过程就这样,要想获取正确注册码,必须枚举密钥,反解AES再比较解密结果前6位与密钥是否一致。脚本如下:

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
# -*- coding:utf-8 -*-
from Crypto.Cipher import AES
import string
from zlib import crc32
def crack():
atable = '0987654321ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba+/'
btable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
base = 'XQXgWk5yLADiXx6hVQCAKxTjVQXiWxPhXASCKALhV7X='
transtab = string.maketrans(atable,btable)
iv = '\x04\x03\x02\x01\x00\x09\x08\x07\x06\x05\x0f\x0e\x0d\x0c\x0b\x0a'
table = list(string.uppercase)
c = base.translate(transtab).decode('base64').decode('hex')
count = 0
for i1 in table:
for i2 in table:
for i3 in table:
for i4 in table:
for i5 in table:
for i6 in table:
key = '%08x'%(crc32(i1+i2+i3)&0xffffffff)+'%08x'%(crc32(i4+i5+i6)&0xffffffff)
cryptor = AES.new(key,AES.MODE_CBC,iv)
m = cryptor.decrypt(c)
count += 1
if count % 5000000 == 0:
print count
if m[:6] == i1+i2+i3+i4+i5+i6:
print '==================================================='
print 'flag:'+m
print '==================================================='
return
if __name__ == '__main__':
crack()

跑了很长时间,出来flag:LITTLE_For7un4t3

0x04 RE3

拖进IDA一看,立马不淡定了,有壳。

开始花了很长时间去脱壳,如果有没有弄错的话,此题有两个壳:PeCancer和ZProtect,而且程序分为两部分,分别对应一个线程,(事实证明只有一个壳),程序先解码(解码后的另一部分代码基本就是完整的PE,这是程序二合一么。),带着ZProtect的一部分在新进程中运行,窗体及消息循环由主线程完成,验证由新线程完成。
似乎新线程很像ZProtect程序啊,没接触过,乱猜的。

ZProtect不太会弄,最后没法带壳进行追码。

OD载入后,直接F9运行,随便输入注册码,bpx GetDlgItemTextW下断,点Generate,程序会停在如下位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
00402CC4 |. 8D85 F4FDFFFF lea eax,[local.131]
00402CCA |. 68 04010000 push 0x104 ; /Count = 104 (260.)
00402CCF |. 50 push eax ; |Buffer = NULL
00402CD0 |. 68 E8030000 push 0x3E8 ; |ControlID = 3E8 (1000.)
00402CD5 |. FF76 20 push dword ptr ds:[esi+0x20] ; |hWnd
00402CD8 |. FF15 FC875400 call dword ptr ds:[0x5487FC] ; \GetDlgItemTextW
00402CDE |. 66:83BD F4FDF>cmp word ptr ss:[ebp-0x20C],0x0
00402CE6 |. 5E pop esi ; 00B61658
00402CE7 |. 74 0B je short CrackMe2.00402CF4
00402CE9 |. 8D8D F4FDFFFF lea ecx,[local.131]
00402CEF |. E8 3CF7FFFF call CrackMe2.00402430
00402CF4 |> 8B4D FC mov ecx,[local.1]
00402CF7 |. 33CD xor ecx,ebp
00402CF9 |. E8 84DC1100 call CrackMe2.00520982
00402CFE |. 8BE5 mov esp,ebp
00402D00 |. 5D pop ebp ; 00B61658
00402D01 \. C3 retn

单步跟进call CrackMe2.00402430,进入新线程代码区,一路F7,F8,一不小心就错过了关键点。

跟了一段时间发现

1
2
0030F695 FF15 88102F00 call dword ptr ds:[0x2F1088] ; ntdll.RtlEnterCriticalSection
0030F69B E9 0C4F0000 jmp 003145AC

程序循环进入ntdll.RtlEnterCriticalSectionntdll.RtlEnterCriticalSection,直接在0030F695下断,不断F9运行,观察栈区。
不久就发现如下字串进入栈区:

1
2
0057A464 53 00 49 00 33 00 55 00 53 00 2D 00 25 00 30 00 S.I.3.U.S.-.%.0.
0057A474 36 00 73 00 2D 00 25 00 30 00 35 00 75 00 00 00 6.s.-.%.0.5.u...

最终形成类似SI3US-000558-00437的字串,开始以为是flag,提交不对,粗跟了两次发现后面的%06s-%05u不是固定的,又细跟了下,此字串后面与输入进行比较,于是乎直接将输入改为此字串,清除断点,F9就能出结果。

flag

我的天,浪费我了多少时间。此时已无力去跟具体算法了,这和ZProtect注册很相似啊。

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 0x00 MISC1
  2. 2. 0x01 MISC2
  3. 3. 0x02 MISC3
  4. 4. 0x03 RE1
  5. 5. 0x04 RE3
,