Netwind · 2016/05/12 correctly

0 x00 preface


Three white hat online challenge platform, WEB and binary challenges at a suit, in the form of online challenge to network security technology and related areas white hat wisdom incisively and vividly displayed, set up a for the white hat is very perfect and harmonious online communication platform, make white hat can harmoniously between casting stunt, exchange ideas and thoughts. The challenge is a feast for the eyes and fun for the white hats, which enricks their imagination and gives them a lot to learn.

Due to the Windows platform under the binary research, in line with the purpose of learning and exchange with everyone, after communication with three white hat platform management, for “All Roads Lead to Rome series” designed a binary algorithm topic. This paper will first analyze the binary problem from the perspective of the cracker, and reverse analyze the algorithm solely as the cracker, decrypt the data, and finally obtain the Flag. In addition, it will be analyzed from the point of view of the subject designer, and describe step by step how the data corresponding to each step of the algorithm is encrypted and decrypted, what kind of effect it tries to achieve, and where it tries to trap the decoder.

0x01 Forward Decryption Algorithm


First of all, we follow the procedures of the process, step by step analysis algorithm, crack algorithm.

1. Where is flag? 2. flag is in the beautifull spring!

2. Double-click the string to the key position of the algorithm, and the relevant assembly code analysis is as follows:

004026E0  |.  57            push    edi                            ;  这里开始了一个非常初级的数独游戏
004026E1  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
004026E5  |.  897424 18     mov     dword ptr [esp+18], esi
004026E9  |.  E8 68080000   call    <jmp.&MFC42.#CString::CString_>
004026EE  |.  33DB          xor     ebx, ebx
004026F0  |.  68 60564000   push    00405660                       ;  where is flag?flag is in the beautifull spring!
004026F5  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
004026F9  |.  C78424 D00000>mov     dword ptr [esp+D0], 1
00402704  |.  895C24 18     mov     dword ptr [esp+18], ebx
00402708  |.  E8 43080000   call    <jmp.&MFC42.#CString::operator>
0040270D  |.  8BAC24 D80000>mov     ebp, dword ptr [esp+D8]
00402714  |.  83C9 FF       or      ecx, FFFFFFFF
00402717  |.  8BFD          mov     edi, ebp
00402719  |.  33C0          xor     eax, eax
0040271B  |.  F2:AE         repne   scas byte ptr es:[edi]
0040271D  |.  F7D1          not     ecx
0040271F  |.  49            dec     ecx
00402720  |.  83E9 0C       sub     ecx, 0C
00402723  |.  74 5A         je      short 0040277F
00402725  |>  BF 54564000   /mov     edi, 00405654                 ;  adf438ghi
0040272A  |.  83C9 FF       |or      ecx, FFFFFFFF
0040272D  |.  33C0          |xor     eax, eax
0040272F  |.  33D2          |xor     edx, edx
00402731  |.  F2:AE         |repne   scas byte ptr es:[edi]
00402733  |.  F7D1          |not     ecx
00402735  |.  49            |dec     ecx
00402736  |.  74 23         |je      short 0040275B
00402738  |.  8A1C2E        |mov     bl, byte ptr [esi+ebp]        ;  单个取输入的字符
0040273B  |>  3A9A 54564000 |/cmp     bl, byte ptr [edx+405654]    ;  判断取出来的字符是否在adf438ghi中
00402741  |.  74 14         ||je      short 00402757               ;  如果是就跳出循环
00402743  |.  BF 54564000   ||mov     edi, 00405654                ;  adf438ghi
00402748  |.  83C9 FF       ||or      ecx, FFFFFFFF
0040274B  |.  33C0          ||xor     eax, eax
0040274D  |.  42            ||inc     edx
0040274E  |.  F2:AE         ||repne   scas byte ptr es:[edi]
00402750  |.  F7D1          ||not     ecx                          ;  取字符串adf438ghi的长度
00402752  |.  49            ||dec     ecx
00402753  |.  3BD1          ||cmp     edx, ecx
00402755  |.^ 72 E4         |\jb      short 0040273B
00402757  |>  8B5C24 14     |mov     ebx, dword ptr [esp+14]
0040275B  |>  BF 54564000   |mov     edi, 00405654                 ;  adf438ghi
00402760  |.  83C9 FF       |or      ecx, FFFFFFFF
00402763  |.  33C0          |xor     eax, eax
00402765  |.  F2:AE         |repne   scas byte ptr es:[edi]
00402767  |.  F7D1          |not     ecx
00402769  |.  49            |dec     ecx
0040276A  |.  3BD1          |cmp     edx, ecx
0040276C  |.  74 3F         |je      short 004027AD                ;  如果上面循环次数等于adf438ghi的长度说明判断失败,跳到结束
0040276E  |.  8BFD          |mov     edi, ebp
00402770  |.  83C9 FF       |or      ecx, FFFFFFFF
00402773  |.  46            |inc     esi
00402774  |.  F2:AE         |repne   scas byte ptr es:[edi]
00402776  |.  F7D1          |not     ecx
00402778  |.  83C1 F3       |add     ecx, -0D                      ;  这个是循环次数 取输入的字符串的长度减去13
0040277B  |.  3BF1          |cmp     esi, ecx
0040277D  |.^ 72 A6         \jb      short 00402725                ;  跳回去,循环判断下一个输入的字符
0040277F  |>  B9 14000000   mov     ecx, 14
00402784  |.  BE 00564000   mov     esi, 00405600                  ;  g8azfzzd3f3zzzhazgzdzzzgzf4zzizz8fghzzfdgi3zz3gzfzzizdai3g8zzzzhfd4zzg8z84gzazd3z
00402789  |.  8D7C24 70     lea     edi, dword ptr [esp+70]
0040278D  |.  33D2          xor     edx, edx
0040278F  |.  F3:A5         rep     movs dword ptr es:[edi], dword>
00402791  |.  A4            movs    byte ptr es:[edi], byte ptr [e>
00402792  |>  33C0          xor     eax, eax
00402794  |.  8D7414 70     lea     esi, dword ptr [esp+edx+70]
00402798  |>  8A0C06        mov     cl, byte ptr [esi+eax]
0040279B  |.  8D3C02        lea     edi, dword ptr [edx+eax]
0040279E  |.  80F9 7A       cmp     cl, 7A                         ;  循环判断405600地址的字符串的字符是否为z
004027A1  |.  75 2A         jnz     short 004027CD
004027A3  |.  8A0C2B        mov     cl, byte ptr [ebx+ebp]
004027A6  |.  43            inc     ebx
004027A7  |.  884C3C 1C     mov     byte ptr [esp+edi+1C], cl      ;  如果是z就把输入的字符依次替换掉z
004027AB  |.  EB 24         jmp     short 004027D1
004027AD  |>  8BB424 D40000>mov     esi, dword ptr [esp+D4]
004027B4  |.  8D4424 10     lea     eax, dword ptr [esp+10]
004027B8  |.  50            push    eax
004027B9  |.  8BCE          mov     ecx, esi
004027BB  |.  E8 EA070000   call    <jmp.&MFC42.#CString::CString_>
004027C0  |.  C74424 18 010>mov     dword ptr [esp+18], 1
004027C8  |.  E9 A4000000   jmp     00402871
004027CD  |>  884C3C 1C     mov     byte ptr [esp+edi+1C], cl
004027D1  |>  40            inc     eax
004027D2  |.  83F8 09       cmp     eax, 9
004027D5  |.^ 7C C1         jl      short 00402798                 ;  跳回去判断下一个字符
004027D7  |.  83C2 09       add     edx, 9
004027DA  |.  83FA 51       cmp     edx, 51                        ;  要分9组每组9次循环81次
004027DD  |.^ 7C B3         jl      short 00402792                 ;  跳回去继续判断下一组
004027DF  |.  C74424 14 000>mov     dword ptr [esp+14], 0
004027E7  |.  8D5C24 1C     lea     ebx, dword ptr [esp+1C]
004027EB  |.  8D4C24 1C     lea     ecx, dword ptr [esp+1C]
004027EF  |>  33C0          /xor     eax, eax                      ;  这里有3层循环是用来检查数独结果是否正确
004027F1  |.  8BEB          |mov     ebp, ebx
004027F3  |>  8A1401        |/mov     dl, byte ptr [ecx+eax]       ;  最里面一层的第一个循环以行为单位进行检查
004027F6  |.  C60401 77     ||mov     byte ptr [ecx+eax], 77       ;  具体方法就是取出当前要检查的字符,替换为0x77即w
004027FA  |.  33F6          ||xor     esi, esi
004027FC  |>  3A1431        ||/cmp     dl, byte ptr [ecx+esi]      ;  然后对该行所有的字符进行判断是否和取出的那个字符重复
004027FF  |.  0F84 9A000000 |||je      0040289F                    ;  如果存在重复就跳没了
00402805  |.  46            |||inc     esi
00402806  |.  83FE 09       |||cmp     esi, 9
00402809  |.^ 7C F1         ||\jl      short 004027FC
0040280B  |.  881401        ||mov     byte ptr [ecx+eax], dl
0040280E  |.  8A55 00       ||mov     dl, byte ptr [ebp]
00402811  |.  C645 00 79    ||mov     byte ptr [ebp], 79           ;  这里以列为单位 取出当前字符替换为字符y,然后判断该列所有字符是否与取出的字符有重复
00402815  |.  33F6          ||xor     esi, esi
00402817  |.  8BFB          ||mov     edi, ebx
00402819  |>  3A17          ||/cmp     dl, byte ptr [edi]
0040281B  |.  0F84 85000000 |||je      004028A6                    ;  如果存在 就跳没了
00402821  |.  46            |||inc     esi
00402822  |.  83C7 09       |||add     edi, 9
00402825  |.  83FE 09       |||cmp     esi, 9
00402828  |.^ 7C EF         ||\jl      short 00402819
0040282A  |.  8855 00       ||mov     byte ptr [ebp], dl
0040282D  |.  40            ||inc     eax
0040282E  |.  83C5 09       ||add     ebp, 9
00402831  |.  83F8 09       ||cmp     eax, 9
00402834  |.^ 7C BD         |\jl      short 004027F3               ;  外边两层循环,行判断时分别控制行标和列标;列判断时分别控制列标和行标
00402836  |.  8B4424 14     |mov     eax, dword ptr [esp+14]
0040283A  |.  83C1 09       |add     ecx, 9
0040283D  |.  40            |inc     eax
0040283E  |.  43            |inc     ebx
0040283F  |.  83F8 09       |cmp     eax, 9
00402842  |.  894424 14     |mov     dword ptr [esp+14], eax
00402846  |.^ 7C A7         \jl      short 004027EF
00402848  |.  68 E0554000   push    004055E0                       ;  good !flag is waving to you!
Copy the code

3. According to the results of the above analysis, it is sorted as follows:

First, ignore the last 12 characters and determine whether the characters in the preceding string (named s) are all the characters in the string adf438ghi. Memory address 405600 string (f) as g8azfzzd3f3zzzhazgzdzzzgzf4zzizz8fghzzfdgi3zz3gzfzzizdai3g8zzzzhfd4zzg8z84gzazd3z, combine s in replace of f z character, After the replacement, check whether nine characters in a row and nine characters in a row are duplicated. Put f in tabular form as follows:

g8azfzzd3
f3zzzhazg
zdzzzgzf4
zzizz8fgh
zzfdgi3zz
3gzfzzizd
ai3g8zzzz
hfd4zzg8z
84gzazd3z
Copy the code

So clearly this is a 9X9 sudoku algorithm, and the input character is the solution to the sudoku algorithm. To make sudoku more intuitive, let’s use numbers instead of letters. The character adf438ghi corresponds to the following:

a d f 4 3 8 g h i
1 2 3 4 5 6 7 8 9
Copy the code

At the same time, according to the algorithm z is actually the empty character in the Sudoku algorithm, at this time the list becomes:

This is a very simple sudoku game with difficulty of 1. If you are interested, you can complete this sudoku game manually. The results of sudoku are as follows:

761934825
354628197
928157634
219546378
483279516
576381942
195762483
832495761
647813259
Copy the code

Take our fill of number: 9484629981562154481668142483951839, according to the previous set corresponding relation, the corresponding string as follows: i4h48diiha38da344ha88ha4d4hfi3ahfi. So here we have the string for the first part of the algorithm. Set the breakpoint at the end of the algorithm function, step by step, and wait until the function returns and we come to the following part of the algorithm.

0x02 Reverse trace algorithm


We find that the second part decrypts the last 12 characters we input, and then encrypts the result of the first part as the key. Therefore, we need to reverse encrypt the key according to the decryption process to obtain the correct input string. Specific analysis is as follows:

1. Assembly code analysis of relevant algorithms is as follows:

004029B6 . 8BF0 mov esi, eax 004029B8 . 8B06 mov eax, dword ptr [esi] 004029BA . 894424 30 mov dword ptr [esp+30], eax 004029BE . 8B4E 04 mov ecx, dword ptr [esi+4] 004029C1 . 894C24 34 mov dword ptr [esp+34], ecx 004029C5 . 8B56 14 mov edx, dword ptr [esi+14] 004029C8 . 8B0B mov ecx, dword ptr [ebx] 004029CA . 895424 24 mov dword ptr [esp+24], edx 004029CE . 8B46 18 mov eax, dword ptr [esi+18] 004029D1 . 894424 28 mov dword ptr [esp+28], eax 004029D5 . 8B69 F8 mov ebp, Dword PTR [ECX-8] 004029D8. 83C5 DE add EBP, -22 Move Length 34 004029DB. /size 004029DC . FF15 34424000 call dword ptr [<&MSVCRT.mallo>;  \malloc 004029E2 . 8BCD mov ecx, ebp 004029E4 . 8BF8 mov edi, eax 004029E6 . 8BD1 mov edx, ecx 004029E8 . 33C0 xor eax, eax 004029EA . C1E9 02 shr ecx, 2 004029ED . 897C24 1C mov dword ptr [esp+1C], edi 004029F1 . F3:AB rep stos dword ptr es:[edi] 004029F3 . 8BCA mov ecx, edx 004029F5 . 83E1 03 and ecx, 3 004029F8 . F3:AA rep stos byte ptr es:[edi] 004029FA . 8B4C24 1C mov ecx, dword ptr [esp+1C] 004029FE . 8D46 22 lea eax, dword ptr [esi+22] 00402A01 . 8B56 22 mov edx, dword ptr [esi+22] 00402A04 . 8911 mov dword ptr [ecx], edx 00402A06 . 8B50 04 mov edx, dword ptr [eax+4] 00402A09 . 8951 04 mov dword ptr [ecx+4], edx 00402A0C . 8B40 08 mov eax, dword ptr [eax+8] 00402A0F . 8941 08 mov dword ptr [ecx+8], eax 00402A12 . 8BC5 mov eax, ebp 00402A14 . 99 cdq 00402A15 . 83E2 03 and edx, 3 00402A18 . 03C2 add eax, edx 00402A1A . C1F8 02 sar eax, 2 00402A1D . 8D4440 0A lea eax, dword ptr [eax+eax*2> 00402A21 . 50 push eax ;  /size 00402A22 . FF15 34424000 call dword ptr [<&MSVCRT.mallo>;  \malloc 00402A28 . 8B4C24 20 mov ecx, dword ptr [esp+20] 00402A2C . 8BF8 mov edi, eax 00402A2E . 57 push edi 00402A2F . 55 push ebp 00402A30 . 51 push ecx 00402A31 . E8 CAE5FFFF call 00401000 ; 00402a36.c60438 00 mov Byte PTR [eAX +edi], 0; 8D5424 38 LEA EDx, Dword PTR [esp+38]; 00402a3e.6a 01 Push 1 00402a40.8d4424 48 LEA Eax, dword PTR [esp+48]; Take the first eight characters of the input string 00402A44.52 push EDX 00402A45.50 push EAX 00402A46.57 push EDI 00402A47.e8 94ECFFFF Call 004016E0; 00402a4C.8A0E mov Cl, Byte PTR [ESI] 00402A4E. 83C4 24 add ESP, 24 00402a51.33c0 xor eax, eax 00402A53 . 84C9 test cl, cl 00402A55 . 74 49 je short 00402AA0 00402A57 > 8B0B mov ecx, dword ptr [ebx] 00402A59 . 8B49 F8 mov ecx, dword ptr [ecx-8] 00402A5C . 83C1 F4 add ecx, -0C ; Take the length of the input string minus 12 00402a5f.3bc1 CMP eax, ecx; 7D 3D jGE short 00402AA0 00402a63.8bd0 mov edx, eax; The following is actually divided by 8 mod operation. After 3DES decryption, the data length is 8. After every 8 addition, Start with 00402a65.81e2 07000080 and edx, 80000007 00402A6B . 79 05 jns short 00402A72 00402A6D . 4A dec edx 00402A6E . 83CA F8 or edx, FFFFFFF8 00402A71 . 42 inc edx 00402A72 > 8A0C3A mov cl, byte ptr [edx+edi] ; Take the above 3DES decrypted bytes in turn, 8D2C3A Lea EBP, DWord PTR [EDX +edi] 00402A78.8a1430 mov DL, Byte PTR [eAX + ESI]; 00402a7d.8ACA mov Cl, dl 00402a7f.881430 mov Byte PTR [eax+esi], dl; Save the result 00402a82.80f9 3E CMP cl, 3E; 0A je short 00402A91 00402A87. 80F9 3F CMP cl, 3F 00402A8A . 74 05 je short 00402A91 00402A8C . 80F9 3B cmp cl, 3B 00402A8F . 75 06 jnz short 00402A97 00402A91 > 024D 00 add cl, byte ptr [ebp] ; PTR [eAX +esi], cl 00402A97 > 8A4C30 01 mov byte ptr [eax+esi+1] 00402A9B . 40 inc eax 00402A9C . 84C9 test cl, cl 00402A9E .^ 75 B7 jnz short 00402A57 ; Jump back and add each character in turn 00402AA0 > 68A0554000 push 004055A0;  \n\n 00402AA5 . 8D4C24 14 lea ecx, dword ptr [esp+14] 00402AA9 . C60430 00 mov byte ptr [eax+esi], 0 00402AAD . E8 E6040000 call <jmp.&MFC42.#CString::ope> 00402AB2 . BF F8564000 mov edi, 004056F8 ;  k8kbdlnjje6fji856ldfdpf5f8kmocfihm 00402AB7 > 8A16 mov dl, byte ptr [esi] 00402AB9 . 8A0F mov cl, byte ptr [edi] 00402ABB . 8AC2 mov al, dl 00402ABD . 3AD1 cmp dl, cl 00402ABF . 75 1E jnz short 00402ADF 00402AC1 . 84C0 test al, al 00402AC3 . 74 16 je short 00402ADB 00402AC5 . 8A4E 01 mov cl, byte ptr [esi+1] 00402AC8 . 8A57 01 mov dl, byte ptr [edi+1] 00402ACB . 8AC1 mov al, cl 00402ACD . 3ACA cmp cl, dl 00402ACF . 75 0E jnz short 00402ADF 00402AD1 . 83C6 02 add esi, 2 00402AD4 . 83C7 02 add edi, 2 00402AD7 . 84C0 test al, al 00402AD9 .^ 75 DC jnz short 00402AB7 ; Determine whether the results after the above addition operations with equal k8kBDlnjje6Fji856ldFDpf5f8kmoCfihm 00402 adb > 33 c0 xor eax, eax 00402ADD . EB 05 jmp short 00402AE4 00402ADF > 1BC0 sbb eax, eax 00402AE1 . 83D8 FF sbb eax, -1 00402AE4 > 85C0 test eax, eax 00402AE6 . 0F85 E3000000 jnz 00402BCF ; 8B7424 1C mov esi, dword PTR [ESP +1C] 00402AF0.6a 01 Push 1 00402AF2.8bCE mov ECX, esi 00402AF4 . E8 ED040000 call <jmp.&MFC42.#CWnd::Update> 00402AF9 . 68 E4564000 push 004056E4 ; the flag file is:Copy the code

2, the above algorithm is actually after the first 12 characters to decrypt the base64, 3 des declassified again, and then used to decrypt the encrypted sudoku operation get string, if the end result is equal to the k8kbdlnjje6fji856ldfdpf5f8kmocfihm, success! First of all, we have to be familiar with the assembly code of the Base64 decryption algorithm. Only by understanding this common algorithm can we save time and produce results quickly when tracking debugging, otherwise we will be trapped in them and unable to extricate themselves.

For the Base64 decryption algorithm, part of the C code is as follows:

#! c if( j == 4 ) { *outputBuffer++ = (b[0] << 2) | (b[1] >> 4); *outputBuffer++ = (b[1] << 4) | (b[2] >> 2 ); *outputBuffer++ = (b[2] << 6) | b[3]; } else if( j == 3 ) { *outputBuffer++ = (b[0] << 2) | (b[1] >> 4); *outputBuffer++ = (b[1] << 4) | (b[2] >> 2 ); return (i >> 2) * 3 + 2; } else if( j == 2 ) { *outputBuffer++ = (b[0] << 2) | (b[1] >> 4); return (i >> 2) * 3 + 1; } else { return -2; }Copy the code

} // End for i }

We see the following assembly code in function 401000: CMP edi,4; cmp edi,3; CMP edi, 2:

These feature codes and C codes if(j == 4); j==3 ; J == 2 is consistent, which can be roughly judged as BASE64 decryption code.

3. The same function 4011a0 is executed three times after function 4016e0 goes in:

The 4011A0 function has the following assembly code:

Here, the constants of push operation are 64, 8, 56, 48 respectively

Let’s look at part C of the DES function:

This is consistent with several constants of assembly code push, then look at the 3DES C code:

#! c void tri_des(BYTE *dat, BYTE *key1, BYTE *key2, BYTE mode) { des(dat, key1, mode); des(dat, key2, 1 - mode); des(dat, key1, mode); }Copy the code

You just change the parameters that you pass in, the same as 4016e0. Therefore, if you encounter a large and particularly complex algorithm during reverse debugging, you should first consider whether it is a common and famous encryption algorithm, and then find and remember the characteristics of these algorithms, and then quickly judge, you do not have to analyze these algorithms any more.

4, according to the result of algorithm analysis before a group take turns to add the KEY string i4h48diiha38da344ha88ha4d4hfi3ahfi eight (8 bytes) get k8kbdlnjje6fji856ldfdpf5f8kmocfihm, first of all we do subtraction operation KEY, Because you get >? ; So, when you subtract, you subtract first to get key1, and then you take key1 divided by 2 to get key2, and then you add again to verify that, if you add key2, you get > or? Or; AddKey =”\x02\x04\x03\x07\x06\x08\x05\x01\x0″. You need to consider whether the KEY has a 0 ending symbol when you reverse the encryption result. We’re going to add a zero terminator here.

5. After obtaining the KEY according to the assembly algorithm, we first encrypt it with 3DES. From the inside of the assembly algorithms and analysis into the encryption keys from i4h48diiha38da344ha88ha4d4hfi3ahfi take two groups of 8 bytes of the length of the string. So the key is known.

In the title, the 3DES decryption algorithm for data is as follows:

00402A3E . 6A 01 push 1 00402A40 . 8D4424 48 lea eax, dword ptr [esp+48] ; Take the first eight characters of the input string 00402A44.52 push EDX 00402A45.50 push EAX 00402A46.57 push EDI 00402A47.e8 94ECFFFF Call 004016E0; The two groups of characters taken out above are used as keys for 3DES decryption. Through tracking debugging, we can analyze that: a total of 4 parameters are passed in, among which 1 represents decryption, EDx eAX is the KEY, which can remain unchanged, edi is the data to be decrypted, so we can directly use this function to encrypt the KEY. The specific operation is to first select the line push 1, right-click here to select new EIP, then change push 1 to push 0 to encrypt data, change the data corresponding to EDI memory address as KEY, execute this function once to obtain the 3DES encryption result of KEY, and save it in the memory pointed to by EDI. The result BASE64 encryption is obtained after 12 characters Jji29cqJ + 8 ka, it and the result of the data before operation pieced together i4h48diiha38da344ha88ha4d4hfi3ahfiJji29cqJ + 8 ka got the final result.

0x03 program algorithm design analysis


1. First, I came across a Sudoku game with a difficulty factor of only 1, so I wanted to design an algorithm based on it. Since binary problems are just beginning to emerge, so I do not intend to use too complex algorithm, the design of the time appropriately control the difficulty. This algorithm design is relatively simple, first of all, I completed the sudoku game, and then use the code to verify the results of sudoku, the code is as follows:

#! c CString CSgbmz1Dlg::check(char *in) { CString result; // Initialize the sudoku matrix Char *key="adf438ghi",*init_table="g8azfzzd3f3zzzhazgzdzzzgzf4zzizz8fghzzfdgi3zz3gzfzzizdai3g8zzzzhfd4zzg8z84gzazd3z"; char table[9][9]={0}; char newtable[9][9]; int i=0,j=0,n=0; result="where is flag? flag is in the beautifull spring!" ; Adf438ghi for (I =0; i<strlen(in)-12; i++) { for (j=0; j<strlen(key); j++) { if (in[i]==key[j]) { break; }} if (j==strlen(key)) {// syslog->SetWindowText("where is flag? flag is in the beautifull spring!" ); return result; } } memcpy(table,init_table,81); /* {"761030025"}//g8azfzzd3=>i4h // Initialize a digital sudoku matrix, //f34,{"020007034"},{"009006378"},{"003279500"},{"570300902"},{"195760000"} , {832400760}, {" 647010250 "}}; Char *table1[9]={// Initialize a sudok result matrix, // g8AZfzzd3 => i4H,{"354628197"}//f34,{"928157634"},{"219546378"},{"483279516"} , {576381942}, {" 195762483 "}, {" 832495761 "}, {" 647813259 "}}; */ for(i=0; i<9; I++) // fill the input string into the initial sudoku matrix for(j=0; j<9; j++) { if(table[i][j]=='z')newtable[i][j]=in[n++]; else newtable[i][j]=table[i][j]; } for (i=0; i<9; i++) for (j=0; j<9; j++) { char test=newtable[i][j]; newtable[i][j]='w'; for (n=0; n<9; N ++) {if (test==newtable[I][n]) {// syslog->SetWindowText("where is flag? flag is in the beautifull spring!" ); return result; } } newtable[i][j]=test; test=newtable[j][i]; newtable[j][i]='y'; for (n=0; n<9; N ++) //// perform column check {if (test==newtable[n][I]) {// syslog->SetWindowText("where is flag? flag is in the beautifull spring!" ); return result; } } newtable[j][i]=test; } result="good ! flag is Waving to you!" ; return result; }Copy the code

This is basically all the content of the algorithm, but the feeling is not difficult, and afraid of being killed in seconds, so I decided to add oil to this topic, add vinegar. So there’s the algorithm for the next 12 characters.

2. The following 12 character algorithm part:

#! c if(m_sf.IsEmpty())return; info=check(m_sf.GetBuffer(m_sf.GetLength())); // char *temp= m_sf.getBuffer (m_sf.getLength ()); memcpy(g_key1,temp,8); Memcpy (g_key2,temp+20,8); int slen1,slen; TCHAR * tc; /* tri_des(addKey,g_key1,g_key2,0); * tri_des(addKey,g_key1,g_key2,0); Int slen1,len=9; int slen = (len / 3) * 4; slen += 10; tc = (TCHAR *)malloc(slen); slen = BASE64_Encode((BYTE *)addKey, len, tc); tc[slen]='\0'; //syslog->SetWindowText(tc); */ slen=m_sf.GetLength()-34; char * addKey; addKey= (char *)malloc(slen); memset(addKey,0,slen); memcpy(addKey,temp+34,(9/3)*4); slen1 = (slen / 4) * 3; slen1 += 10; BYTE * ct; ct = (BYTE *)malloc(slen1); int deLen=BASE64_Decode(addKey, slen, ct); // BASE64 decryption ct[deLen]='\0'; Tri_des (ct, g_key1 g_key2, 1); Int I =0,j; While (temp [I] && I < m_sf. GetLength () - 12) {/ / encryption sudoku operation results \ [I] + = ct [8] I %; if (temp[i]=='>'||temp[i]=='? '||temp[i]=='; ')temp[i]+=ct[i%8]; i++; } temp[i]='\0'; info+="\r\n"; if (! STRCMP (temp, "k8kBDlnjje6Fji856ldFDpf5f8kmoCfihm")) / / compare equal {the UpdateData (TRUE); info+="the flag file is:"; info+=m_sf.GetBuffer(m_sf.GetLength()); info+=".php\r\n"; info+="trying to get the flag.... \r\n"; httpdata.Replace("ip_addr",m_ip); httpdata.Replace("main",m_sf.GetBuffer(m_sf.GetLength())); CString rep=SentHttpData(httpdata); if (rep.Find("miao",0)>-1) { info+=rep; } else info+="so sorry! no flag !" ; }Copy the code

The above algorithm is actually an addition operation, so it is not difficult. The most important is that if the 3DES encryption algorithm can not be identified, then it will be stuck, so the understanding of the characteristics of the algorithm in the process of cracking will often be of great help, perhaps here stumped some people.

3, if the end result and k8kBDlnjje6Fji856ldFDpf5f8kmoCfihm equal, this time will be in the input string as the file name, with PHP as the suffix access servers in this file, then returns the flag

The PHP code in the file is:

#! php <? php include 'config.php'; $sql = "select flag from flag"; $result = @mysql_query($sql); while($row = mysql_fetch_array($result)) { if($row['flag']) { echo $row['flag']; break; } else { die('no! '); }}? >Copy the code

0 x04 summary


In this paper, the algorithm is analyzed and designed. The main algorithm is contained in a sudoku game. Through the result of sudoku game and the back-deduced memory string, an encrypted KEY is obtained by encrypting the KEY with 3DES and then BASE64 to obtain a string of 12 bytes. Finally, the file that can return flags is obtained by combining the result of Sudoku with the string of 12 bytes. Access the file to obtain the FLAG.

In this case, the difficulty lies in whether we can judge the performance of the algorithm is doing a sudoku game, and whether we can judge the 3DES algorithm and BASE64 decryption algorithm involved in the problem according to the assembly code. Thank you for your participation, if there are incorrect or incomplete expressions in the article, thank you for your criticism!