首先查看文件信息,发现是32位无壳程序。
接着用ida32打开查看
最开始打开是这样的:
进入main_0里查看
发现这个似乎有点问题,首先可以知道的是这个输入为unk_41A1E4,然后现在我们先进入这个sub_41100F函数里面看一下。进入到最里层
看到这里有一个*a1=0xC0000005之类的判断,这个C00000005是程序报错会出现的一个返回值,是一个错误类型
这里我们试着运行一下程序
可以看到,程序是无法正确启动的,所以这里程序就会进入这个分支。而这个函数的第四个参数就是我们的输入,说明这里肯定有对输入的处理,接着我们进入函数里面看看
这里a3是等于16的,相当于就是执行了因此sub_4119F0。而a4是我们的输入,接着进入这个函数看看
首先就是将我们的输入分割为四个32位的无符号数据,这里有点像AES,SM4算法的第一步,将128位明文分为4个32位的字
接着我们看一下这个sub_411700函数,这个好像就是传入了输入的结果,看看它在干什么,这里32轮可能可能是SM4了,因为SM4就是32轮循环,然后最后结果X32,X33,X34,X35就是最后的密文。
可以发现,32轮中还需要密钥,那么那个a1+4*v6应该就是密钥了,然后四个v5[v6]对应上面的Xi。进入这个函数
可以看到,a1相当于上面的Xi,这个sub_411760相当于上面的T函数了,而T函数又分为两个步骤,一个是S盒替换还有一个就是L函数循环左移加异或。进入这个函数看看
可以发现,首先是在进行S盒替换,然后就是L函数,看到这里差不多可以实锤SM4算法了,相当于输入第一步就是进行SM4算法,但是我们还是可以进一步看看这个sub_4119A0这个函数,看看它的S盒是不是标准的。
这里直接就是返回,替换也就是这样的
于是我也是去网上找到了SM4算法的S盒,发现和这个基本一致
所以到这里就不用去继续分析下去了,输入就是进行了SM4加密,然后我们返回到我们的main_0函数
接着看到这个sub_411136函数是在干什么
进入到最里面发现是一个比较,这个Str1是我们对输入处理的结果,Str2是最后比较的结果。这里我们对Str1点击X键查看它是怎么来的
然后直接OK,接着就到这里了
浅浅的看一下,发现我们在比较之前对结果还有一个交换的操作,接着我们看一下Str1的这个函数,这个Byte_41A180我猜应该就是输入经过Sm4的结果。
也是同样的,进入到最里层
这里由于有两个Str,为了不混淆,我直接将输入改为input了,这个就是在进行base64加密。然后多了一个sub_4110FF函数,接着看一下这个函数
发现是每次额外加了24,这个也简单,解密就是取下标,然后减去24对64取余即可。就可以还原正常base64加密的结果了
接着我们看一下这个base64表
用X键查看一下引用情况,这里主要是怕动态改变这个表从而影响解密
直接OK,接着就来到了这个地方
发现,这个表被换了,并不是标准的base64编码表。而是被改了,但是改的不多,只是将大小写交换了一下位置而已。这里看到还有一个Handler,不知道是干什么的,进入看看
这个好像是补充了我们前面的Sm4算法缺失的密钥,因为前面我们只是猜测那个结果是密钥,但是并不知道密钥怎么来的,这个函数应该就是专门产生密钥的,这里也可以看出密钥应该就是where_are_u_now?。接着进入这个sub_411172这个函数看看它是不是在搞密钥拓展
可以看到这个函数和SM4算法的密钥拓展运算基本一致。这里四个常数FK没有以明文给出,而是存储在这个byte_417A68里面,然后也是用32轮循环来拓展加密32轮每一轮需要的密钥。这里26的dword_417A78里面存储的就是CK了。这个也是32个固定的值。而且还挺有特点的,每两个相邻的字节之间相隔7,相当于就是第一个字节为07,第二个就是07+7也就是0D这样的。
接着我们进入这个sub_4114E0里面看看是不是对应上面的T函数。这个T函数也是和前面的差不多,首先替换,然后一个L函数循环左移异或。
接着我们回到这个函数的外层
可以看到,这个第9行还有一个东西,我们进去看看里面是什么
没想到,搞了一圈还回来了。说明刚刚那个函数应该是在这个函数之前进行的,然后返回到这个函数。
看到这里,整个流程基本是差不多了,这里也是把密钥生成搞懂了,然后密钥也有了,所以整个流程就是先对输入进行Sm4加密,然后加密结果进行base64加密。这里需要注意的就是base64的表换了,还有结果加了24.
下面先去提取一个str2的结果,要开始解密了
这里两个!应该相当于两个=
这里直接给出最后的脚本
s2="1UTAOIkpyOSWGv/mOYFY4R!!"
s=''
for i in range(0,len(s2),2):
s+=s2[i+1]+s2[i] #交换结果前后两位
# print(s)
table="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" #手动替换了
# print(len(s))
s1=''
for i in s:
if i=='!':
s1+='='
else:
t = table.index(i)
s1+=table[(t-24)%64]
print(s1)
还原的思路也很简单,先还原最后的结果,然后还原表,最后根据索引还原原索引结果。最后输出。
最后得到这么一串结果,这里这个结果是正常base64加密的后的结果,就是没有加24的结果。然后我们复制这个表就可以去cyberchef解密了
首先是base64解密,然后Sm4解密。这里注意两点,第一个就是base64的表需要换成上面那个。然后就是sm4的密钥为utf-8然后mode选nopad.
最后这个output套上flag就是最后的结果了。
这个题目主要就是考察对sm4算法的理解,以及base64。如果是真正比赛的时候应该就没必要搞这么透彻了,看到那些特征值就可以直接去试结果了。