吃鸡杯RE
- 1、ezmore
- 2、有手就行
题目地址:https://ctf.show/challenges
1、ezmore
1、初步分析
exe文件,直接运行,可知要得到与flag相关的信息需要输入正确的文件下载码。
查下壳:32二位文件,直接ida32打开
2、静态分析
最开始的输入,然后跟一个if判断,其中i=2时为主要逻辑。
str内存储着我们输入的下闸码,接着进入了e2edef40ecaa776b8d32d58416998这个函数进行检验,v2是我们输入的编号,毫无疑问v2=8
函数主要是生成了一个str2,和我们的输入str1最终进行比较,可知前几句主要进行赋值操作,if上面的函数是主要的生成函数,可知他的第一个参数与a2和一个数组有关,其余参数都相同。
如果选择为8,a2为 8-1 作为下标格式索引字符串也就是flag,即我们选择下载的文件,生成对应的下载码,接着进入这个函数。
下载码的生成函数,可以根据算法逆向,但是上文已知,下载码的生成只是与我们选择的下载文件有关,所以动调一下,看一下str2的值即可。
在比较处下个断点,依次选(2下载文件) (8 flag) 运行到断点处便能看到str2的值,加个md5包上ctfshow{}格式即可。
总结:题目本身难度不大,找到主要比较的地方下个断直接能跑出,当然逆向算法也可。
关于ida中显示中文的方法: 一般直接打开,ida可能将中文显示成乱码。
解决方法,打开IDA -> Options - >general ->选择string一栏,第一个选着UTF-8,保存后F5刷新一下就正常显示
2、有手就行
1、初步分析
exe文件,直接运行无明显提示。
查看文件结构:32位EXE文件,直接IDA中打开。
2、静态分析
查看主函数,发现主函数出乎意料的简洁,跟进sub4013f0函数。
首先对buf2进行赋值,注意v1=buf1+1 (buf1是一个字符串的首地址)
j接着就进行运算 简化为:
v2 = *v1 ++ -> v2 = v1 = buf1 +1
v1+1 之后 *(v1 - 1) 实际和是哪个就为v2,所以最终为
buf1[i]=~(buf1[i-1]&buf1[i])&(buf1[i-1]^buf1[i]) i从1开始
对加密后的buf1和buf2进行比较,buf2为加密后的结果
v2=[99,23,113,2,106,5,114,9,109,2,93,36,75,62,97,13,100,15,106,53,83,50,89,60,3,60,65]
f=[99]
for i in range(1,len(v2)):for k in range(32,128): #通过爆破来解决tmp=~(v2[i-1]&k)&(v2[i-1]^k)if v2[i] == tmp:f.append(k)break
for i in f:print(chr(i),end='')
#ctfshow{do_you_like_fake??}
flag内容有点奇怪,提交一下,结果错误,反观整个步骤,主函数内就这些操作,所以猜测真正的内容放在了别的函数下
shift + F12 查看字符串,发现 eykeykey比较可疑,继续跟踪。
按a转为字符串,发现keykeykey,并且被sub_4014D0调用。
观察4014D0函数,从第一个循环确定是RC4加密,刚才‘keykeykey’字符串为秘钥
在sub_4014D0处按 x 查看交叉引用,看哪个函数调用了RC4加密
是401F20函数,在往上就到内存代码段了。发现406060不就是存放输入的地址吗,这里进行了不同处理,对该函数下的函数进行分析。
在401600里面可获得Buf2加密后的密文,看下401570函数内容
如果buf2和那片地址内的数相等,传入的参数a1 = 1,主体是将v4和 a1==1 异或后输出。
下面展示一些 内联代码片
。
v4='xnt!fnu!hu '
for i in range(len(v4)):print(chr(ord(v4[i])^1),end='')
#you got it!!
得到you get it! 那么这就应该是真正的信息处了
sub_401350函数,是rc4加密的主要过程,并且结果保存到了 v4 == buf2中
将地址&unk_403000内的值提取出来,进行RC4解密,注意s盒的初始化方式是256-i。
import requests
import base64
import hashlib
def crypt(data,key) :s = [0] * 256for i in range(256) : #初始化s盒s[i] = 256-i #初始化的方式 #注意 不同的可能不大一样j = 0for i in range(256) :j = (j + s[i] + key[i % len(key)]) % 256s[i], s[j] = s[j], s[i]#重新排列s盒i = 0j = 0res = ""mm=[] #明文列表for c in data :i = (i + 1) % 256 #生成秘钥流操作j = (j + s[i]) % 256s[i], s[j] = s[j], s[i]mm.append((c ^ s[(s[i] + s[j]) % 256])&0xff)res = res + chr((c ^ s[(s[i] + s[j]) % 256]))#加密核心 异或 s[(s[i]+s[j])%256]就是秘钥流print(mm)return resif __name__ =='__main__':data = [220, 71, 127, 110, 154, 216, 96, 119, 244, 176, 140, 84, 176, 170, 38, 35, 2, 66, 142, 186, 144, 140, 171, 134, 36, 110, 248]str='keykeykey'key=[]for i in range(len(str)):key.append(ord(str[i]))print(crypt(data,key))
#[106, 123, 109, 122, 111, 118, 126, 130, 128, 55, 124, 102, 110, 55, 123, 102, 123, 59, 108, 102, 60, 108, 106, 121, 108, 123, 132]
#j{mzov~??7|fn7{f{;lf<ljyl{?
得到结果仍然不是flag,但看列表的ascii码值比较接近
发现是sub_4013D0()函数对buf2进行过移位,所以每一位再-7即可
f=[106, 123, 109, 122, 111, 118, 126, 130, 128, 55, 124, 102, 110, 55, 123, 102, 123, 59, 108, 102, 60, 108, 106, 121, 108, 123, 132]
for i in f:print(chr(i-7),end='')
#ctfshow{y0u_g0t_t4e_5ecret}
总结:要善于捕捉字符串,存在即合理,同时要熟练掌握一些常见加密算法如RC4,Tea加密等。
吃鸡杯的EZAUTORE也看了下,nc端口后会得到程序的base64的结构,解密存为二进制文件便能拿到背后的ELF,ELF加了个UPX壳子,并且主函数非常大,需要去改IDA的cfg文件夹的hexrays.cfg中的MAX_FUNCSIZE = 1024 ,将64改为1024后便可反编译,F5等待3min后会有很多组数据。
s为输入,中间过程也有用到s,慢屏幕的判断等式,应该是z3解方程吧,太多了,没有具体去尝试。