genshin

IDA分析

main

进行了一次异或操作,然后让输入的v5进入函数sub_A84输出s2;

function

进入函数之后可以发现运算中存在移位2,4,6,而且有长度控制的判断(v5<=5)让输入的长度变长了;

进入sub_7FA之后是一个有64个case的switch,对应着不同的ascii码,这样的特色让人能联想到base64,因为base64的码表也是64个字符;

把sub_7FA中的码表换成base64的标准码表后,用比较的数据进行一次解码,得到数据:

0xD2,0x51,0xD2,0x34,0xD7,0x1B,0xE5,0x08,0xA0,0x13,0xCE,0x11,0xF0,0x13,0xA2,0x56,0xA5,0x3F,0xF8,0x13,0xCE,0x11,0xF2,0x0A,0xFD,0x24,0xE6,0x07,0xC2,0x1D

再用一次异或便能得到flag:C1CTF{th1s_qas364_is_qcjlDwgS}

1
2
3
4
5
6
7
8
9
10
key = [0xD2,0x51,0xD2,0x34,0xD7,0x1B,0xE5,0x08,0xA0,0x13,0xCE,0x11,0xF0,0x13,0xA2,0x56,0xA5,0x3F,0xF8,0x13,0xCE,0x11,0xF2,0x0A,0xFD,0x24,0xE6,0x07,0xC2,0x1D]
for i in range(len(key)):
if((i&1)!=0):
key[i] ^= 0x60
else:
key[i] ^= 0x91
for i in range(len(key)):
key[i] = chr(key[i])
key = ''.join(key)
print(key)

没看出是base64的时候,想过根据加密函数的样子来逆推导,考虑到或运算的不可逆性,采用了走迷宫式的算法,用ascii码0~128来模拟129条路径,每个加密数据为一个节点,走出一条明文,经过几次修改代码,但很可惜失败了;

main

用输入的字符串与生成好的String1运算得到密文v3,之后使用crpyto函数打印出v3的hex值与字符串比较;

在检查sub_7FF7798A12A0的时候,发现了一个常数表:

box

对应着标准的aes加密表;

比较字符串有64个字节,打印了32个16进制数,而aes加密的长度是16个16进制数,所以后面的是未加密的数据,而前16个是加密的16进制数据,对前面32字节hex进行解密得到数据:

68 78 62 32 30 31 38 7B 38 35 33 65 63 66 65 35

数据很正常,有数字有字母,还有 7B ( { )应该是flag没错了;

之后加上后32位hex得到flag:hxb2018{853ecfe52aeb60989e8d3351}

flag

AES

不懂AES之前根本就不明白它的内部算法;所以去学习了一下最简单的AES加密;

即为16字节明文配合16字节密钥运算得暗文;

分为很多个步骤,总体的思路便是矩阵运算,让明文和密钥都构成4*4的矩阵;

明文矩阵与密钥矩阵对应异或得到矩阵0;

密钥矩阵用自身产生很多个轮密钥,特点在于是列的运算;且关于列是从0开始计算,且若列是4的倍数,就会复杂一些,动用到BOX里的数据;

②.⑤ 矩阵0对照BOX表里的值进行替换成为矩阵1;

**③ **矩阵1进行hang行变换,第一行左移0字节,第二行左移1字节,第三行左移2字节,第四行左移3字节,得到矩阵2;

矩阵2左乘一个规定好的特殊矩阵,变为矩阵3;

矩阵3与轮密钥运算得到暗文;

循环9次执行 ②.⑤ ~ ⑤ ,每次的轮密钥不同;

最后执行一遍 ②.⑤,③和⑤(不执行④),得到总共的暗文;

main

input和output和i都是全局变量;

使用cry1函数让input变换为output;

cry1

变换的规则就是依次读取input的第a1位,然后继续调用cry1,不断读取64个数据;

按照这个思路,output增长是不会有变换的,i一直都会顺着顺序变大,而读取input会有些许顺序;

1
2
3
4
//跟踪数据
a1 0 1 3 7 15 31 63 32 16 33 34
v1 0 1 2 3 4 5 6 7
return 2 4 8 16 32 64 128 x-

但是没关系,因为i顺着变大,所以只需要将赋值顺序变一下,输入比较的数据,不就可以得到输入的数据了吗?

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

char output[64] = {0};
char input[64] = {0};
int i = 0;

int cry1(int a1)
{
int v1;
int result = 0;
if(a1 <= 63)
{
v1 = i++;
input[a1] = output[v1]; //交换
cry1(2*a1+1);
return cry1(2*(a1+1));
}
return result;
}


int main()
{
scanf("%s",output);
cry1(0);
printf("%s",input);
return 0;
}

按着思路试了一下,果然用得到的数据就能进入if判断框了,下面的if同理;

得到的flag:nctf{bc2e3b4c2eb03258c5102bf9de77f57dddad9edb70c6c20febc01773e5d81947}

genshin