-
-
[原创]看雪TSRC_2017秋季赛第三题---------WriteUp
-
2017-10-29 10:58 3381
-
0x00 流程分析
拿到题没啥可说的,直接ida看流程,程序无花无壳,就一些反调试,不影响静态分析
主要流程如下:
.text:00435076 call ds:GetDlgItemTextA .text:0043507C cmp esi, esp .text:0043507E call j___RTC_CheckEsp .text:00435083 mov [ebp+var_420], eax .text:00435089 mov [ebp+var_1038], 0 .text:00435090 push 3FFh ; size_t .text:00435095 push 0 ; int .text:00435097 lea eax, [ebp+var_1037] .text:0043509D push eax ; void * .text:0043509E call j__memset .text:004350A3 add esp, 0Ch .text:004350A6 lea eax, [ebp+var_C30] .text:004350AC push eax .text:004350AD push 400h .text:004350B2 lea ecx, [ebp+String] .text:004350B8 push ecx .text:004350B9 call base64Decode ;第一次base64解码 .text:004350BE add esp, 0Ch .text:004350C1 mov [ebp+var_1440], 0 .text:004350C8 push 3FFh ; size_t .text:004350CD push 0 ; int .text:004350CF lea eax, [ebp+var_1440+1] .text:004350D5 push eax ; void * .text:004350D6 call j__memset .text:004350DB add esp, 0Ch .text:004350DE lea eax, [ebp+var_1038] .text:004350E4 push eax .text:004350E5 push 400h .text:004350EA lea ecx, [ebp+var_C30] .text:004350F0 push ecx .text:004350F1 call base64Decode ;第二次base64解码 .text:004350F6 add esp, 0Ch .text:004350F9 push 400h ; int .text:004350FE lea eax, [ebp+var_1440] .text:00435104 push eax ; int .text:00435105 lea ecx, [ebp+var_1038] .text:0043510B push ecx ; char * .text:0043510C call transform_input ;转换解码后的值 .text:00435111 add esp, 0Ch .text:00435114 mov [ebp+var_144C], 3 .text:0043511E lea eax, [ebp+var_1474] .text:00435124 push eax ; int .text:00435125 mov ecx, [ebp+var_144C] .text:0043512B push ecx ; size_t .text:0043512C lea edx, [ebp+var_1038] .text:00435132 push edx ; void * .text:00435133 call SM3 ;计算转换后的SM3值 ... ... ... ... .text:0043518B lea eax, [ebp+var_187C] .text:00435191 push eax ; char * .text:00435192 call j__strlen ;取SM3值的串长度 .text:00435197 add esp, 4 .text:0043519A push eax ; size_t .text:0043519B lea ecx, [ebp+String] .text:004351A1 push ecx ; char * .text:004351A2 call j__strlen ;取输入的串长度 .text:004351A7 add esp, 4 .text:004351AA lea esi, [ebp+eax+String] ;取输入的串结尾地址 .text:004351B1 lea edx, [ebp+var_187C] .text:004351B7 push edx ; char * .text:004351B8 call j__strlen ;取SM3值的串长度 .text:004351BD add esp, 4 .text:004351C0 sub esi, eax ;从输入串结尾向前取SM3值的长度的数据 .text:004351C2 push esi ; void * .text:004351C3 lea eax, [ebp+var_187C] .text:004351C9 push eax ; void * .text:004351CA call j__memcmp ;比较 .text:004351CF add esp, 0Ch .text:004351D2 test eax, eax .text:004351D4 jnz short loc_435214 .text:004351D6 call sub_42D0B4 .text:004351DB lea eax, [ebp+var_1440] .text:004351E1 push eax .text:004351E2 push offset unk_49B000 .text:004351E7 call j_check ;最终校验 .text:004351EC add esp, 8 .text:004351EF movzx ecx, al .text:004351F2 cmp ecx, 1 .text:004351F5 jnz short loc_435214 .text:004351F7 mov esi, esp .text:004351F9 push 0 ; uType .text:004351FB push offset Caption ; "CrackMe" .text:00435200 push offset Text ; "ok" .text:00435205 push 0 ; hWnd .text:00435207 call ds:MessageBoxA
首先接受用户输入,并且进行两次base64的解码计算,之后将解出来的串进行一个转换计算,
然后再对转换后的串计算SM3值,并用这个值与输入的后64位进行比较,通过进行最终校验。
根据流程已经知道了key的组成方式为: base64(base64(key))+SM3(transform_input(key))
0x01 主要函数分析
先看看最终的check
函数要验证什么样的数据,代码如下:
.text:00435584 mov eax, [ebp+arg_4] .text:00435587 movsx ecx, byte ptr [eax] .text:0043558A cmp ecx, 6Ch .text:0043558D jnz short loc_4355D4 .text:0043558F mov eax, [ebp+var_8] .text:00435592 add eax, [ebp+var_44] .text:00435595 cmp eax, 0Ah .text:00435598 jge short loc_4355D4 .text:0043559A mov eax, [ebp+var_14] .text:0043559D imul eax, 28h .text:004355A0 add eax, [ebp+arg_0] .text:004355A3 mov ecx, [ebp+var_8] .text:004355A6 add ecx, [ebp+var_44] .text:004355A9 cmp dword ptr [eax+ecx*4], 0 .text:004355AD jnz short loc_4355CD .text:004355AF mov eax, [ebp+var_14] .text:004355B2 imul eax, 28h .text:004355B5 add eax, [ebp+arg_0] .text:004355B8 mov ecx, [ebp+var_8] .text:004355BB mov dword ptr [eax+ecx*4], 4 .text:004355C2 mov eax, [ebp+var_8] .text:004355C5 add eax, [ebp+var_44] .text:004355C8 mov [ebp+var_8], eax .text:004355CB jmp short loc_4355D4 .text:004355CD ; --------------------------------------------------------------------------- .text:004355CD .text:004355CD loc_4355CD: ; CODE XREF: check+1AD↑j .text:004355CD xor al, al .text:004355CF jmp loc_435665 .text:004355D4 ; --------------------------------------------------------------------------- .text:004355D4 .text:004355D4 loc_4355D4: ; CODE XREF: check+18D↑j .text:004355D4 ; check+198↑j ... .text:004355D4 mov eax, [ebp+arg_4] .text:004355D7 movsx ecx, byte ptr [eax] .text:004355DA cmp ecx, 71h .text:004355DD jnz short loc_43561E .text:004355DF mov eax, [ebp+var_14] .text:004355E2 add eax, [ebp+var_20] .text:004355E5 js short loc_43561E .text:004355E7 mov eax, [ebp+var_14] .text:004355EA add eax, [ebp+var_20] .text:004355ED imul eax, 28h .text:004355F0 add eax, [ebp+arg_0] .text:004355F3 mov ecx, [ebp+var_8] .text:004355F6 cmp dword ptr [eax+ecx*4], 0 .text:004355FA jnz short loc_43561A .text:004355FC mov eax, [ebp+var_14] .text:004355FF imul eax, 28h .text:00435602 add eax, [ebp+arg_0] .text:00435605 mov ecx, [ebp+var_8] .text:00435608 mov dword ptr [eax+ecx*4], 4 .text:0043560F mov eax, [ebp+var_14] .text:00435612 add eax, [ebp+var_20] .text:00435615 mov [ebp+var_14], eax .text:00435618 jmp short loc_43561E .text:0043561A ; --------------------------------------------------------------------------- .text:0043561A .text:0043561A loc_43561A: ; CODE XREF: check+1FA↑j .text:0043561A xor al, al .text:0043561C jmp short loc_435665 .text:0043561E ; --------------------------------------------------------------------------- .text:0043561E .text:0043561E loc_43561E: ; CODE XREF: check+1DD↑j .text:0043561E ; check+1E5↑j ... .text:0043561E mov eax, [ebp+arg_4] .text:00435621 movsx ecx, byte ptr [eax] .text:00435624 cmp ecx, 70h .text:00435627 jnz short loc_435655 .text:00435629 mov eax, [ebp+var_8] .text:0043562C add eax, [ebp+var_38] .text:0043562F js short loc_435655 .text:00435631 mov eax, [ebp+var_14] .text:00435634 imul eax, 28h .text:00435637 add eax, [ebp+arg_0] .text:0043563A mov ecx, [ebp+var_8] .text:0043563D add ecx, [ebp+var_38] .text:00435640 cmp dword ptr [eax+ecx*4], 0 .text:00435644 jnz short loc_435651 .text:00435646 mov eax, [ebp+var_8] .text:00435649 add eax, [ebp+var_38] .text:0043564C mov [ebp+var_8], eax .text:0043564F jmp short loc_435655 .text:00435651 ; --------------------------------------------------------------------------- .text:00435651 .text:00435651 loc_435651: ; CODE XREF: check+244↑j .text:00435651 xor al, al .text:00435653 jmp short loc_435665 .text:00435655 ; --------------------------------------------------------------------------- .text:00435655 .text:00435655 loc_435655: ; CODE XREF: check+141↑j .text:00435655 ; check+227↑j ... .text:00435655 mov eax, [ebp+arg_4] .text:00435658 add eax, 1 .text:0043565B mov [ebp+arg_4], eax .text:0043565E jmp loc_435528 .text:00435663 ; --------------------------------------------------------------------------- .text:00435663 .text:00435663 loc_435663: ; CODE XREF: check+131↑j .text:00435663 mov al, 1
很明显的一个循环,循环条件是当传入的串的当前字节不是0x20
时就进入循环进行计算,否则直接返回1
。
所以说只要transform_input
函数计算出来一个0x20
开头的串就可以直接成功。
此外当当前字节不是0x20
且不为z, l, q, p
时程序会一直向后读取,用12345678
生成的解可行,
但是感觉这种比较靠运气,越界后的内存中如果z, l, q, p
比0x20
先来可能就不行了。
所以还是先来看看transform_input
进行的什么样的计算,有没有机会让它给我们生成一个带有0x20
的值。
.text:00435E0D mov [ebp+var_20], 0 ... ... .text:00435E4E mov eax, [ebp+var_20] .text:00435E51 add eax, 1 .text:00435E54 mov [ebp+var_20], eax ... ... .text:00435F30 mov eax, [ebp+arg_0] .text:00435F33 add eax, [ebp+var_20] .text:00435F36 movsx ecx, byte ptr [eax] .text:00435F39 cmp ecx, 20h ;判断传入的是不是空格 .text:00435F3C jz short loc_435F6A ;成立跳转 .text:00435F3E mov eax, [ebp+arg_0] .text:00435F41 add eax, [ebp+var_20] .text:00435F44 movsx ecx, byte ptr [eax] .text:00435F47 cmp ecx, '/' ;判断是不是'/' .text:00435F4A jz short loc_435F6A ;成立跳转 .text:00435F4C mov eax, [ebp+var_14] .text:00435F4F add eax, [ebp+var_2C] .text:00435F52 mov ecx, [ebp+arg_0] .text:00435F55 add ecx, [ebp+var_20] .text:00435F58 mov dl, [ecx] .text:00435F5A mov [eax], dl .text:00435F5C mov eax, [ebp+var_2C] .text:00435F5F add eax, 1 .text:00435F62 mov [ebp+var_2C], eax .text:00435F65 jmp loc_436065 .text:00435F6A ; --------------------------------------------------------------------------- .text:00435F6A .text:00435F6A loc_435F6A: ; CODE XREF: sub_435DE0+15C↑j .text:00435F6A ; sub_435DE0+16A↑j .text:00435F6A mov eax, [ebp+arg_0] .text:00435F6D add eax, [ebp+var_20] .text:00435F70 movsx ecx, byte ptr [eax] .text:00435F73 cmp ecx, 20h ;再判断是不是空格 .text:00435F76 jnz loc_436045 ;成立跳转 .text:00435F7C mov eax, [ebp+arg_0] .text:00435F7F add eax, [ebp+var_20] .text:00435F82 movsx ecx, byte ptr [eax-1] .text:00435F86 cmp ecx, '/' ;判断 -1 的index是不是'/' .text:00435F89 jz loc_436045 ;成立跳转 ... ... ... ... .text:00436045 mov eax, [ebp+arg_0] .text:00436048 add eax, [ebp+var_20] .text:0043604B movsx ecx, byte ptr [eax] .text:0043604E cmp ecx, '/' ;判断是不是 '/' .text:00436051 jnz short loc_436065 ;不成立跳走,计算下一轮 .text:00436053 mov eax, [ebp+arg_4] .text:00436056 add eax, [ebp+var_38] .text:00436059 mov byte ptr [eax], 20h ;成立, 得到一个0x20 .text:0043605C mov ecx, [ebp+var_38] .text:0043605F add ecx, 1 .text:00436062 mov [ebp+var_38], ecx .text:00436065 .text:00436065 loc_436065: ; CODE XREF: sub_435DE0+185↑j .text:00436065 ; sub_435DE0+263↑j ... .text:00436065 jmp loc_435E4E
可以看出当输入的串为空格或/
时会有 0x20
的结果出现,所以找个在线base64计算一个全是/
的key来。
0x02 生成可用解
因为规则限制解只能是字母
和数字
,所以要找两次base64后不包含=
的值,我这里就用///////
来计算
两次base64的值为THk4dkx5OHZMdz09
, 没找到在线SM3的计算,所以就用OD调试,在SM3比较处下断点,用程序自己计算的值9aa4f168af9fcb372825d2e817379ab6ad4a7da973a38c44a0ec56a788dfb89b
补到后面,得到一个可用解。
THk4dkx5OHZMdz099aa4f168af9fcb372825d2e817379ab6ad4a7da973a38c44a0ec56a788dfb89b
[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课