跳转至

2019 RCTF

标签:xxtea, Blowfish, RISC-V, 算法, VM, SG11

比赛时间:5月18日-5月19日

XCTF联赛内的RCTF,由福州大学RIOS战队主办。

De1ta最终排第7名。re再次ak

不过为啥rios的人这么喜欢xxtea呢。。。

继续加油!

题目下载地址

babyre

输入长度16,0-9a-z,然后hex转字节

之后用xxtea解密。根据提示,解密后要为Bingo!。xxtea最后一段逻辑,根据解密的最后一个字节的大小x,把明文倒数第x位用\0截断。

得到的明文先CRC16/CCITT,结果要为0x69E2。

明文每一位再异或0x17,然后输出。

即解密完应该是Bingo!异或0x17。

由于输出Bingo!,所以最后一位应该是\x02,这样截断完再异或0x17就是Bingo!了。

这样我们得到了明文的前六位和最后一位,还差1位,这时可以用题目给出的hint爆出来。

也可以不爆破。因为根据用最后一位截断,可以推断出加密时的padding是用剩余字节数padding。即明文最后两位都是\x02。

网上抄的xxtea代码:

 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
#include<pch.h>
#include<iostream>

using namespace std;
#define MX ((z>>5^y<<2) + (y>>3^z<<4) ^ (sum^y) + (k[p&3^e]^z))

long btea(long* v, long n, long* k) {
    unsigned long z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x9e3779b9;
    long p, q;
    if (n > 1) {          /* Coding Part */
        q = 6 + 52 / n;
        while (q-- > 0) {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p = 0; p < n - 1; p++) y = v[p + 1], z = v[p] += MX;
            y = v[0];
            z = v[n - 1] += MX;
        }
        return 0;
    }
    else if (n < -1) {  /* Decoding Part */
        n = -n;
        q = 6 + 52 / n;
        sum = q * DELTA;
        while (sum != 0) {
            e = (sum >> 2) & 3;
            for (p = n - 1; p > 0; p--) z = v[p - 1], y = v[p] -= MX;
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        return 0;
    }
    return 1;
}

int main()
{
    long cipher[] = { 0,0 };
    char cipher1[] = "Bingo!\x02\x02";
    long key[] = { 0xE0C7E0C7, 0xC6F1D3D7, 0xC6D3C6D3, 0xC4D0D2CE };
    int i = 0;
    for (i = 0; i < 6; i++)
        cipher1[i] ^= 0x17;
    memcpy(cipher, cipher1, 8);
    btea(cipher, 2, key);
    char *b = (char *)cipher;
    cout << "rctf{";
    for (i = 0; i < 8; i++)
    {
        char c1 = *(b + i) >> 4 & 0xF;
        char c2 = *(b + i) & 0xF;
        if (c1 < 10)
            cout << char(c1 + 0x30);
        else
            cout << char(c1 + 0x61 - 10);
        if (c2 < 10)
            cout << char(c2 + 0x30);
        else
            cout << char(c2 + 0x61 - 10);
    }
    cout << "}";
}

rctf{05e8a376e4e0446e}

babyre2

输入account,password,data。

还是xxtea,先用account作为key,加密一组常量。

password的每一位减去十位和个位,减去的结果作为下标从data取数据,得到data2.

用data2异或0xCC作为key密之前的密文。

于是直接构造account:'A'*16,data'8D'*256,password随便16位。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from pwn import *
p = process('./babyre2')
#p = remote('139.180.215.222','20000')
p.recvuntil('Please input the account:')
p.send('A'*16)
p.recvuntil('Please input the password:')
p.send('a'*16)
p.recvuntil('Please input the data:')
p.send('8D'*256)
p.interactive()

DontEatMe

开始有个反调试,直接跳过。

做的时候不清楚是啥加密,搜了一些常量也搜不到,于是自己逆。由于是Feistel密码结构,所以直接反向就可以了。

得到密文后,根据常量生成了一个迷宫,密文应是wasd来控制方向:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
1111111111111111
1000000000111111
1011111110111111
1011111110111111
101111000!000111
1011110111110111
1011110111110111
1011110000110111
1011111110110111
1011111110110111
10000>0000110111
1111101111110111
1111100000000111
1111111111111111
1111111111111111
1111111111111111

密文:

ddddwwwaaawwwddd

解密:

 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
#include<pch.h>
#include<iostream>
using namespace std;
/*
unsigned int const0[] = { 0x459FC5A5, ... };
unsigned int const1[] = { 0x3B928883, ...};
unsigned int const2[] = { 0x5E476C95, ... };
unsigned int const3[] = { 0x0DA579091, ... };
unsigned int delta[] = { 0x0CDC56A63, ... };
*/

int main()
{
    int i, j;
    int a, b;
    int tmp;
    /*
    //encrypt
    int plain[] = { 0x11223344,0x55667788 };
    a = plain[0];
    b = plain[1];
    for (i = 0; i < 16; i++)
    {
        unsigned int i0, i1, i2, i3;
        tmp = delta[15-i] ^ a;
        i0 = (tmp >> 24)&0xff;
        i1 = (tmp >> 16) & 0xff;
        i2 = (tmp >> 8) & 0xff;
        i3 = tmp & 0xff;
        a = b ^ (const3[i3] + (const2[i2] ^ (const1[i1] + const0[i0])));
        b = tmp;
    //  cout<<hex << a <<' '<< b << endl;
    }
    b ^= 0xC12083C0;
    a ^= 0x6809DCE2;
    cout << hex << a << ' ' << b<<endl;
    */
    //decrypt
    int cipher[] = { 0x77646464, 0x61617777 ,0x77777761, 0x64646464 };
    for (j = 1; j >= 0; j--)
    {
        a = cipher[j * 2];
        b = cipher[j * 2 + 1];
        a ^= 0x6809DCE2;
        b ^= 0xC12083C0;
        for (i = 0; i < 16; i++)
        {
            tmp = b;
            unsigned int i0, i1, i2, i3;
            i0 = (tmp >> 24) & 0xff;
            i1 = (tmp >> 16) & 0xff;
            i2 = (tmp >> 8) & 0xff;
            i3 = tmp & 0xff;
            b = a ^ (const3[i3] + (const2[i2] ^ (const1[i1] + const0[i0])));
            a = tmp ^ delta[i];
        }
        cout << hex << a << b;
    }
    return 0;
}

RCTF{db824ef8605c5235b4bbacfa2ff8e087}

const和delta常量应该是开头某个的函数生成的,直接在调试过程中dump下来。

后面学习了一下密码算法,这是标准的blowfish算法,似乎当年是aes的备选算法之一。

asm

RISC-V架构。工具下载:https://github.com/riscv/riscv-gnu-toolchain

很大,慢慢下载。编译完总共3.6g...

指令手册没找到特别齐全的,官方的:http://crva.io/documents/RISC-V-Reader-Chinese-v2p1.pdf

讲的也不是特别细,没intel白皮书讲的那么详细,总之一条一条指令搜+连蒙带猜

用工具的objdump搞出汇编。一开始看到1w多行有点吓人,不过应该是静态编译的,所以很多都不用看。

先找主逻辑。strings一下发现有东西,能看到 flag plz 和%80s字符串。在010 editor中定位到字符串的位置在二进制文件的CF00处。结合反汇编的地址猜测偏移是0x10000,因此在寻找0x1cf00。刚好在0x101b6附近找到了0x1cf00的引用,以及0x1cf10的引用也找到了。

  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
   1017c:    000007b7            lui     a5,0x0
   10180:    00078793            mv      a5,a5
   10184:    cf99                beqz    a5,0x101a2
   10186:    0001f537            lui     a0,0x1f
   1018a:    1141                addi    sp,sp,-16
   1018c:    8c018593            addi    a1,gp,-1856
   10190:    b8850513            addi    a0,a0,-1144 # 0x1eb88
   10194:    e406                sd      ra,8(sp)
   10196:    00000097            auipc   ra,0x0
   1019a:    000000e7            jalr    zero # 0x0
   1019e:    60a2                ld      ra,8(sp)
   101a0:    0141                addi    sp,sp,16
   101a2:    f6fff06f            j       0x10110
   101a6:    df010113            addi    sp,sp,-528
   101aa:    20113423            sd      ra,520(sp)
   101ae:    20813023            sd      s0,512(sp)
   101b2:    0c00                addi    s0,sp,528
   101b4:    67f5                lui     a5,0x1d
   101b6:    f0078513            addi    a0,a5,-256 # 0x1cf00
   101ba:    31c000ef            jal     ra,0x104d6 //printf?
   101be:    f8040793            addi    a5,s0,-128
   101c2:    85be                mv      a1,a5
   101c4:    67f5                lui     a5,0x1d
   101c6:    f1078513            addi    a0,a5,-240 # 0x1cf10
   101ca:    316000ef            jal     ra,0x104e0 //scanf
   101ce:    f8040793            addi    a5,s0,-128 
   101d2:    853e                mv      a0,a5
   101d4:    358000ef            jal     ra,0x1052c //? scanf?
   101d8:    87aa                mv      a5,a0
   101da:    fef42423            sw      a5,-24(s0) //len?
   101de:    fe042623            sw      zero,-20(s0) // i
   101e2:    a041                j       0x10262

   101e4:    fec42783            lw      a5,-20(s0)
   101e8:    ff040713            addi    a4,s0,-16
   101ec:    97ba                add     a5,a5,a4
   101ee:    f907c703            lbu     a4,-112(a5)
   101f2:    fec42783            lw      a5,-20(s0)
   101f6:    2785                addiw   a5,a5,1
   101f8:    2781                sext.w  a5,a5
   101fa:    86be                mv      a3,a5
   101fc:    47fd                li      a5,31
   101fe:    02f6e7bb            remw    a5,a3,a5
   10202:    2781                sext.w  a5,a5
   10204:    ff040693            addi    a3,s0,-16
   10208:    97b6                add     a5,a5,a3
   1020a:    f907c783            lbu     a5,-112(a5)
   1020e:    8fb9                xor     a5,a5,a4
   10210:    0ff7f793            andi    a5,a5,255
   10214:    0007869b            sext.w  a3,a5
   10218:    fec42703            lw      a4,-20(s0)
   1021c:    87ba                mv      a5,a4     //a4 = i
   1021e:    0017979b            slliw   a5,a5,0x1 //
   10222:    9fb9                addw    a5,a5,a4  //
   10224:    0057979b            slliw   a5,a5,0x5
   10228:    9fb9                addw    a5,a5,a4  //((((i<<1)+i)<<5)+i)
   1022a:    2781                sext.w  a5,a5
   1022c:    873e                mv      a4,a5     // a4 = ((((i<<1)+i)<<5)+i)
   1022e:    41f7579b            sraiw   a5,a4,0x1f //((((i<<1)+i)<<5)+i)>>0x1f
   10232:    0187d79b            srliw   a5,a5,0x18 //((((((i<<1)+i)<<5)+i)>>0x1f)<<0x18)
   10236:    9f3d                addw    a4,a4,a5   //((((((((i<<1)+i)<<5)+i)>>0x1f)<<0x18)+((((i<<1)+i)<<5)+i))&0xff)
   10238:    0ff77713            andi    a4,a4,255
   1023c:    40f707bb            subw    a5,a4,a5
   10240:    2781                sext.w  a5,a5
   10242:    8fb5                xor     a5,a5,a3
   10244:    0007871b            sext.w  a4,a5
   10248:    fec42783            lw      a5,-20(s0)
   1024c:    078a                slli    a5,a5,0x2 //i<<2
   1024e:    ff040693            addi    a3,s0,-16 
   10252:    97b6                add     a5,a5,a3    b[i<<2] = 
   10254:    e0e7a023            sw      a4,-512(a5)
   10258:    fec42783            lw      a5,-20(s0)
   1025c:    2785                addiw   a5,a5,1
   1025e:    fef42623            sw      a5,-20(s0)
   10262:    fec42703            lw      a4,-20(s0)
   10266:    fe842783            lw      a5,-24(s0)
   1026a:    2701                sext.w  a4,a4
   1026c:    2781                sext.w  a5,a5
   1026e:    f6f74be3            blt     a4,a5,0x101e4

   10272:    fe042623            sw      zero,-20(s0) //i = 0
   10276:    a825                j       0x102ae      //
   10278:    fec42783            lw      a5,-20(s0)
   1027c:    078a                slli    a5,a5,0x2  //
   1027e:    ff040713            addi    a4,s0,-16
   10282:    97ba                add     a5,a5,a4
   10284:    e007a683            lw      a3,-512(a5) //b[i]
   10288:    0001f7b7            lui     a5,0x1f
   1028c:    fec42703            lw      a4,-20(s0)
   10290:    070a                slli    a4,a4,0x2
   10292:    ba078793            addi    a5,a5,-1120 # 0x1eba0 
   10296:    97ba                add     a5,a5,a4      //const[i]
   10298:    439c                lw      a5,0(a5)
   1029a:    8736                mv      a4,a3
   1029c:    00f70463            beq     a4,a5,0x102a4
   102a0:    4781                li      a5,0
   102a2:    a025                j       0x102ca
   102a4:    fec42783            lw      a5,-20(s0)
   102a8:    2785                addiw   a5,a5,1
   102aa:    fef42623            sw      a5,-20(s0)
   102ae:    fec42703            lw      a4,-20(s0)
   102b2:    fe842783            lw      a5,-24(s0)
   102b6:    2701                sext.w  a4,a4
   102b8:    2781                sext.w  a5,a5
   102ba:    faf74fe3            blt     a4,a5,0x10278

   102be:    67f5                lui     a5,0x1d
   102c0:    f1878513            addi    a0,a5,-232 # 0x1cf18
   102c4:    212000ef            jal     ra,0x104d6
   102c8:    4781                li      a5,0
   102ca:    853e                mv      a0,a5
   102cc:    20813083            ld      ra,520(sp)
   102d0:    20013403            ld      s0,512(sp)
   102d4:    21010113            addi    sp,sp,528
   102d8:    8082                ret

主逻辑并不长,慢慢看不难发现是两个循环,第一个加密,第二个对比。

另外提一句,最终对比常量的地址0x1eba0(objdump生成的)有问题,附近找一下应该是0x1dba0,即二进制文件中0xdba0的地方。

脚本:

1
2
3
4
5
6
7
cipher = [0x11, 0x76, 0xD0, 0x1E, 0x99, 0xB6, 0x2C, 0x91, 0x12, 0x45, 0xFB, 0x2A, 0x97, 0xC6, 0x63, 0xB8, 0x14, 0x7C, 0xE1, 0x1E, 0x83, 0xE6, 0x45, 0xA0, 0x19, 0x63, 0xDD, 0x32, 0xA4, 0xDF, 0x71]
plain = [ord('R')]
for i in range(30):
   plain.append(0)
for i in range(30):
   plain[i+1] = cipher[i]^plain[i]^(((((((((i<<1)+i)<<5)+i)>>0x1f)<<0x18)+((((i<<1)+i)<<5)+i))&0xff)-((((((i<<1)+i)<<5)+i)>>0x1f)<<0x18))
print(''.join(map(chr,plain)))

flag很秀:

RCTF{f5_is_not_real_reversing_}

所以真正的逆向应该是对着机器码逆向。

crack

通过字符串查找引用很容易找到主逻辑在sub_4025E0。

算法本质是这个问题:

https://projecteuler.net/problem=18

https://projecteuler.net/problem=67

总共有0x200*0x200行数据,每行的前n个元素是金字塔中对应元素,其余的元素根据输入的过程拼接起来变成一个函数,在00402762会被调用。

相加总和要为0x100758E540F。其实如果他没说这时最大值还真不好算。知道是要算最大值就好办了,可以用简单的动态规划来求出结果与过程。

 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
from copy import deepcopy
f = open('data.mem','rb')
data = []
for i in range(0x200):
   tmp = []
   for j in range(0x200):
       i1 = ord(f.read(1))
       i2 = ord(f.read(1))
       i3 = ord(f.read(1))
       i4 = ord(f.read(1))
       tmp.append((i4<<24)+(i3<<16)+(i2<<8)+i1)
   data.append(tmp)
A = deepcopy(data)
B = ['' for i in range(len(A))]

for i in range(0,len(A)-1)[::-1]:
   for j in range(i+1):
       if A[i+1][j]>A[i+1][j+1]:
           A[i][j]+=A[i+1][j]
           B[i] += '0'
       else:
           A[i][j]+=A[i+1][j+1]
           B[i] += '1'

print(hex(A[0][0]))
x = 0
y = 0
res = '0'
for x in range(0,0x1FF):
   res+=B[x][y]
   if B[x][y]=='1':
       y+=1
print(res)
print(len(res))

得到512位的结果:

1
00000000010101000000000111100111111110100111100101001000101010010011101100111101011111111111111111001110111011011000000101110111001111100100011000000000000110001111110100000000001101110111010101011111000101110000011000111001110000000000000000000000011001000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011100011111110000100111000000000000000000000000000000010000000000000001000001100000000000000101000000000100000010000000000000000010000000000000000000000

到这里还没完,进入第二部分。把之前生成的函数dump下来,分析一遍发现是个vm。bytecode就是搜字符串时的一大堆的一大堆01。实际上他把bytecode转成了六位二进制数。

写了个脚本解析了opcode:

 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
code = '000000010101100100000000000000110000010000010110100000000011000000000000000000001100110000000000110000000000000000000000101000000000000000000000000000000000110000000000010000000000000000000000101000000000111000000000000000000000110000011000110000111000010010110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000000000011000000000000000000000110000011000111000110100110000000000011000000000000000000000101000100000111000000000000000000000011000100000100000000000000000000000110100110000000000111000000000000000000000101000000000000000000000000000000000100110100000011000000000000000000000011000100000111000000000000000000000101100100000111111000100001011110000011010100000011011000011000000000000010110100000011000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000110100000000000000000000011000111000100010110000000000110100000000000000000000101000100000001100000000000000000000011000111000100010110000000000001100000000000000000000101000100000101100000000000000000000011000111000100010110000000000101100000000000000000000101000000000111000000000000000000000100000000000000000000000000000101000100000101100000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000111000000000000000000000011000111000101010100000011011111001000000000000010110100000011000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000111000000000000000000000011000111000110100110000000000000010000000000000000000101000100000111000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000011100000000000000000000011000111000100100110000000000100010000000000000000000101000100000000010000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000100010000000000000000000011000111000100010110000000000001000000000000000000000101000100000111000000000000000000000011000110000000000110000000000000000000000101000000000100000000000000000000000110000000000010000000000000000000000101000100000011100000000000000000000011000111000010100100000111000000000000000000000011000100000100000000000000000000000110100110000000000111000000000000000000000101000000000000001110010000000000000100110100000110100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000000000000000000000000000010100100000001100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000100000000000000000000000010100100000101100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000010000000000000000000000010100100000011100000000000000000000011000110000000000001000000000000000000000101000100000111100000000000000000000011000100000110000000000000000000000010100'
codes = []
i = 0
j = 0
while(i<len(code)):
   op = eval('0b'+code[i:i+6][::-1])
   i+=6
   if op == 0:
       num = eval('0b'+code[i:i+24][::-1])
       print('mov r0, 0x%x'%num)
       i+=24
   elif op == 1:
       num = eval('0b'+code[i:i+24][::-1])
       print('mov r1, 0x%x'%num)
       i+=24
   elif op == 2:
       print('mov r0, input[%d]'%j)
       j+=1
   elif op == 3:
       print('mov r1, r0')
   elif op == 4:
       print('mov r3, r2')
   elif op == 5:
       print('if r0<128:')
       print('    r[r0] = r1')
   elif op == 6:
       print('if r1<128:')
       print('    r0 = r[r1]')
   elif op == 7:
       print('if r2<128:')
       print('    r[r2] = r3')
   elif op == 8:
       print('if r3<128:')
       print('    r2 = r[r3]')
   elif op == 0xB:
       print('add r0, r1')
   elif op == 0xC:
       print('sub r0, r1')
   elif op == 0xD:
       print('mul r0, r1')
   elif op == 0xE:
       print('div r0, r1')
   elif op == 0xF:
       print('and r0, r1')
   elif op == 0x10:
       print('or r0, r1')
   elif op == 0x11:
       print('xor r0, r1')
   elif op == 0x12:
       print('shl r0, r1')
   elif op == 0x13:
       print('shr r0, r1')
   elif op == 0x14:
       print('grate r0, r1')
   elif op == 0x15:
       print('below r0, r1')
   elif op == 0x16:
       print('equl r0, r1')
   elif op == 0x17:
       print('nequl r0, r1')
   elif op == 0x18:
       print('mov r0, ip')
   elif op == 0x19:
       print('mov ip, r0')
   elif op == 0x1A:
       print('cmp r0, 0')
       print('je  r1')
   else:
       print('?')

没有按照汇编标准写,因为里面有些if不知道干嘛的,可能是混淆。个别opcode也没搞懂是做什么的。

伪代码(未完成):

  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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
mov r0, 0x26a
mov r1, r0
mov r0, input[0]
cmp r0, 0
je  r1
mov r1, 0x30
sub r0, r1
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x0
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r0, 0x7
mov r1, r0
if r1<128:
    r0 = r[r1]
mov r1, r0
if r2<128:
    r[r2] = r3
shl r0, r1
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r0, 0x6
mov r1, r0
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
add r0, r1
mov r1, r0
mov r0, 0x6
if r0<128:
    r[r0] = r1
mov r1, 0x7
if r1<128:
    r0 = r[r1]
mov r1, 0x1
add r0, r1
mov r1, r0
mov r0, 0x7
if r0<128:
    r[r0] = r1
mov r0, 0x0
mov ip, r0
mov r1, 0x6
if r1<128:
    r0 = r[r1]
mov r1, 0x7
mul r0, r1
mov r1, 0xf423f
equl r0, r1
mov r1, 0xc36
cmp r0, 0
je  r1
mov r1, 0x6
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0xb
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
xor r0, r1
mov r1, r0
mov r0, 0xb
if r0<128:
    r[r0] = r1
mov r1, 0xc
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
xor r0, r1
mov r1, r0
mov r0, 0xc
if r0<128:
    r[r0] = r1
mov r1, 0xd
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
xor r0, r1
mov r1, r0
mov r0, 0xd
if r0<128:
    r[r0] = r1
mov r0, 0x7
mov r1, 0x0
if r0<128:
    r[r0] = r1
mov r1, 0xd
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0x7
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
below r0, r1
mov r1, 0x9f6
cmp r0, 0
je  r1
mov r1, 0x6
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0x7
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
add r0, r1
mov r1, r0
mov r0, 0x10
if r0<128:
    r[r0] = r1
mov r1, 0x7
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0xe
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
?
mov r1, r0
mov r0, 0x11
if r0<128:
    r[r0] = r1
mov r1, 0x10
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0x11
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
xor r0, r1
mov r1, r0
mov r0, 0x4
if r0<128:
    r[r0] = r1
mov r1, 0x7
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x3
if r0<128:
    r[r0] = r1
mov r0, 0x1
mov r1, r0
mov r0, 0x2
if r0<128:
    r[r0] = r1
mov r1, 0xe
if r1<128:
    r0 = r[r1]
if r2<128:
    r[r2] = r3
?
mov r1, 0x7
if r1<128:
    r0 = r[r1]
mov r1, 0x1
add r0, r1
mov r1, r0
mov r0, 0x7
if r0<128:
    r[r0] = r1
mov r0, 0x4e0
mov ip, r0
mov r1, 0xb
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x4
if r0<128:
    r[r0] = r1
mov r1, 0xf
if r1<128:
    r0 = r[r1]
mov r1, 0x0
?
mov r1, 0xc
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x4
if r0<128:
    r[r0] = r1
mov r1, 0xf
if r1<128:
    r0 = r[r1]
mov r1, 0x1
?
mov r1, 0xd
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x4
if r0<128:
    r[r0] = r1
mov r1, 0xf
if r1<128:
    r0 = r[r1]
mov r1, 0x2
?
mov r1, 0xe
if r1<128:
    r0 = r[r1]
mov r1, r0
mov r0, 0x4
if r0<128:
    r[r0] = r1
mov r1, 0xf
if r1<128:
    r0 = r[r1]
mov r1, 0x3
?

关键在前面有个乘法和对比,猜一下应该是输入后面再接一个二进制数,此数*7后等于0xf423f,即0x22e09 = 0b100010111000001001。测试一下是按照大端序的,即是100100000111010001,接在之前的512位后面就是最后的输入了。

flag画在一张图事实上。

13yR01sw3iy1l1n9

sourceguardian

 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
#include<pch.h>
#include<iostream>

using namespace std;
#define MX ((z>>5^y<<2) + (y>>3^z<<4) ^ (sum^y) + (k[p&3^e]^z))

long btea(long* v, long n, long* k) {
    unsigned long z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x9e3779b9;
    long p, q;
    if (n > 1) {          /* Coding Part */
        q = 6 + 52 / n;
        while (q-- > 0) {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p = 0; p < n - 1; p++) y = v[p + 1], z = v[p] += MX;
            y = v[0];
            z = v[n - 1] += MX;
        }
        return 0;
    }
    else if (n < -1) {  /* Decoding Part */
        n = -n;
        q = 6 + 52 / n;
        sum = q * DELTA;
        while (sum != 0) {
            e = (sum >> 2) & 3;
            for (p = n - 1; p > 0; p--) z = v[p - 1], y = v[p] -= MX;
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        return 0;
    }
    return 1;
}

int main()
{
    long cipher[] = { 1029560848, 2323109303, 4208702724, 3423862500, 3597800709, 2222997091, 4137082249, 2050017171, 4045896598 ,0};
    long key[] = { 1752186684, 1600069744, 1953259880, 1836016479 };
    long k[] = { 1752186684, 1600069744, 1953259880, 1836016479 };
    int i = 0;
    for (i = 0; i < 9; i++)
    {
        cipher[i] ^= key[i % 4];
    }
    btea(cipher, -9, key);
    cout << (char*)cipher << endl;
 }

评论