很直来直去的算法逆向题目，总共两部分。
第一部分，首先判断输入长度是否为32字节，接着根据输入的第七位、第十六位、第三十位计算得到一个种子 seed，然后生成33个随机数放在数组 a 中，使用这个数组 a 的值和输入进行计算得到大小为64的数组 b，数据类型是 unsigned int。
第一部分题目代码如下。
```        char *input = (char*)malloc(33);
        scanf("%s", input);
        int length = strlen(input);
        if (length != 32) {
               exit(0);
        }
        int value = (input[6] + input[15] + input[29]) * 53;     
        unsigned int *tmp = myrandint((~value)&0xfff, input);
        unsigned long long int * tmp2 = (unsigned long long int *)tmp;
        unsigned long long int * data = (unsigned long long int *)malloc(sizeof(unsigned long long int) * 32);
```
```
unsigned int * myrandint(unsigned int seed, char * input)
{
        unsigned long long int a = 32310901;
        unsigned long long int b = 1729;
        unsigned int c = seed;
        int m = 254;
        unsigned int * ret1 = (unsigned int*)malloc(33 * sizeof(int));
        memset(ret1, 0, 33 * sizeof(int));
        for (int i = 0; i < 33; i++) {
               ret1[i] = (a * c + b) % m;
               c = ret1[i];
        }
        unsigned int  * ret2 = (unsigned int*)malloc(64 * sizeof(int));
        memset(ret2, 0, 64 * sizeof(unsigned int));
        for (int i = 0; i < 32; i++)
        {
               for (int j = 0; j < 33; j++)
               {
                       unsigned int tmp = (unsigned int)input[i] ^ ret1[j];
                       ret2[i + j] += tmp;
               }
        }
        return ret2;
}
```
第二部分，使用 unsigned long long int 类型指针指向数组b，可以理解为把数组 b 转化为大小为32、数据类型为 unsigned long long int 的数组 c，接着就是进一步处理和加密数组 c。每次处理数组 c 两个值，第一个当作 key，第二个当作 data。
然后首先是已经很常见的算法套路，就是64重循环对 key 不断乘二，并且对乘二后的值进行判断，如果溢出了 key 就异或一个奇数，逆向的时候从 key 异或奇数这里入手，因为乘二后一定是偶数，偶数异或奇数后一定是奇数。
我在这里的基础上加了 DES 加密，用了两种模式。如果没有溢出就使用 key 对 data 进行 DES-ECB 加密，如果溢出了就使用 key 对 data 进行 DES-CBC 加密，最后再对得到的32位数据进行比较。DES-CBC 加密的 iv 是“syclover”。
第二部分题目代码如下。
```        unsigned long long int * tmp2 = (unsigned long long int *)tmp;
        unsigned long long int * data = (unsigned long long int *)malloc(sizeof(unsigned long long int) * 32);
        for (int i = 0; i < 16; i++) {
               unsigned long long int* ret = encrypt(tmp2[2 * i], tmp2[2 * i + 1]);
               data[2 * i] = ret[0];
               data[2 * i + 1] = ret[1];
        }
        unsigned long long int cmp_data[32] = { 2153387829194836539,4968037865209379450,8168265158727502467,7752938936513403525,14501680424383085918,17239894214146562937,8631814439533536846,14038875394924393076,4195845133744611697,5882449358190368069,16593579054240177091,6042071195929524833,4901359238874180132,5391991813165233830,1262912001997768975,10592048914693378762,16027373129319566784,8683865403612614472,1074685249143409626,14830847864020240442,839851004411889868,6756767667889788695,10980352984506363454,15143378206568444148,9137722182184199592,16483482195781840874,213411729123350449,8809840326310832316,6556887299588007217,4475244256249997594,4953583337191211260,6316604661095411857 };
        for (int i = 0; i < 32; i++) {
               if (cmp_data[i] != data[i]) {                             
                       exit(0);
               }
        }
        printf("Success!\n");
```
```
unsigned char * llu2key(unsigned long long int key) {
        unsigned char * ckey = (unsigned char *)malloc(9);
        memset(ckey, 0, 9);
        memcpy(ckey, &key, 8);
        return ckey;
}
unsigned char * llu2data(unsigned long long int data) {
        unsigned char * cdata = (unsigned char *)malloc(17);
        memset(cdata, 0, 17);
        memcpy(cdata, &data, 16);
        return cdata;
}
unsigned long long int* encrypt(unsigned long long int key, unsigned long long int data) {//,unsigned char * data 64 * 4   8 * 32  16 * 16
        unsigned char * ckey = 0;
        unsigned char * cdata;
        cdata = llu2data(data);
        for (int i = 0; i < 64; i++) {
               unsigned long long int temp = key;
               key = key * 2;
               if (key < temp) {
                       key = key ^ 0x3FD99AEBAD576BA5;
                       ckey = llu2key(key);
                       des_cbc_encrypt(cdata, cdata, 8, ckey);
               }
               else {
                       ckey = llu2key(key);
                       des_ecb_encrypt(cdata, cdata, 8, ckey);
               }
        }
        unsigned long long int* retarr = (unsigned long long int*)malloc(sizeof(unsigned long long int) * 2);
        retarr[0] = *(unsigned long long int*)ckey;
        retarr[1] = *(unsigned long long int*)cdata;
        return retarr;
}
```
编译的话是用 Visual Studio 2017 进行的 release x86 方式进行的编译，优化得还是比较厉害的，比如CBC模式加密的 iv 我本来藏得还是比较深的，然后程序生成后进行反编译是能直接看到的，还有就是 unsigned long long int 型的整数会使用两个寄存器来表示等等。
然后说下我自己的解题思路。
第一部分我自己的逆向解题思路是爆破中使用z3，因为在计算种子 seed 时候最后有 &0xfff，范围就这么大，随机数数组 a 是根据种子 m 生成的，可以爆破所有可能的种子 m ，然后剩下的交给 z3 来求解。听别的师傅说这个题被花样爆破了，甚至是用汇编爆破的，真是太强了，期待看到师傅分享出来不同的解题思路...
然后第二部分就是直接逆了，前面有说到64重循环 key 乘二从异或奇数入手，然后进行 DES 的两种模式解密。
放出我自己的解题脚本，python3 装下 z3-solver 和 pycryptodome 库就可以运行了。
```from Crypto.Cipher import DESimport structfrom z3 import *
def des_ecb_decrypt(cipher,key):    des = DES.new(key, mode=DES.MODE_ECB)    cipher = bytes(cipher)    if (len(cipher) != 8):        cipher = b'\0' * (8 - len(cipher)) + cipher    plain = des.decrypt(cipher)    return plain
def des_cbc_decrpt(cipher,key):    iv = b"syclover"    des = DES.new(key, mode=DES.MODE_CBC, iv=iv)    if (len(cipher) != 8):        cipher = b'\0' * (8 - len(cipher)) + cipher    cipher = bytes(cipher)    plain = des.decrypt(cipher)    return plain
def myfun(key,data):    #print("%x %x" % (key, data))    data = struct.pack(">Q", data)[::-1].strip()    #print(data)    #print(list(data))    for i in range(64):        if(key%2==0):            ckey = struct.pack(">Q", key)[::-1]            data = des_ecb_decrypt(data,ckey)            key = key // 2        else:            ckey = struct.pack(">Q", key)[::-1]            data = des_cbc_decrpt(data,ckey)            key ^= 0x3FD99AEBAD576BA5            key = (key // 2) + (0xffffffffffffffff - 1) // 2 + 1
    key_str = "%x"%key    if(len(key_str)%2 !=0):        key_str = "0"+key_str
    key_arr = list(bytes.fromhex(key_str))[::-1]    for i in range(8-len(key_arr)):        key_arr.append(0)
    tmp = []    tmp+=key_arr    tmp+=list(data)    return tmp
def myrandint( start,end,seed):    a=32310901    b=1729    rOld=seed    m=end-start    while True:        rNew=int((a*rOld+b)%m)        yield rNew        rOld = rNew
def Z3(xor_data,cmp_data):    s = Solver()    flag =  [BitVec(('x%d' % i),8) for i in range(32) ]
    xor_result = [0 for i in range(64)]    for i in range(32):        for j in range(33):            a = flag[i] ^ xor_data[j]            xor_result[i + j] += a
    for i in range(0,64):        s.add(xor_result[i] == cmp_data[i])
    if s.check() == sat:        model = s.model()        str = [chr(model[flag[i]].as_long().real) for i in range(32)]        print( "".join(str))        time.sleep(5)        exit()    else:        print ("unsat")
if __name__ == "__main__":    key = 2153387829194836539    data = 4968037865209379450    cmp_data = [2153387829194836539,4968037865209379450,8168265158727502467,7752938936513403525,14501680424383085918,17239894214146562937,8631814439533536846,14038875394924393076,4195845133744611697,5882449358190368069,16593579054240177091,6042071195929524833,4901359238874180132,5391991813165233830,1262912001997768975,10592048914693378762,16027373129319566784,8683865403612614472,1074685249143409626,14830847864020240442,839851004411889868,6756767667889788695,10980352984506363454,15143378206568444148,9137722182184199592,16483482195781840874,213411729123350449,8809840326310832316,6556887299588007217,4475244256249997594,4953583337191211260,6316604661095411857]    sum = []    for i in range(16):        sum+=(myfun(cmp_data[2*i],cmp_data[2*i+1]))    value = []    for i in range(len(sum)//4):        value.append(sum[4*i]+0x100*sum[4*i+1]+0x1000*sum[4*i+2]+0x10000*sum[4*i+3])
    for seed in range(0xfff):        print(seed)        xor_data = []        #r = myrandint(1, 255, 99)        r = myrandint(1, 255, seed)        for i in range(33):            xor_data.append(next(r))        Z3(xor_data,value)
```
爆破到 99 时候就出来 flag了，flag 为 SCTF{b5c0b187fe309af0f4d35982fd}。 
![](https://i.loli.net/2020/07/08/lKpejGkhon6HiAT.png)
