2020moectf—flower

flower

题目:moectf Re flower

运行程序,看程序是如何运作的,发现给了一首诗,还抛出了一个经典的不能在经典的一个问题。然后输入任意字符串,emm竟然被教育了一顿。
在这里插入图片描述但看它的报错是提示我们输入的字符串太长,因此输入一个短的,看来这阅卷老师是真厉害,直接把我高中的底给透出来了。
在这里插入图片描述
直接奖励它给他拖入ida中,查找程序出现的字符串,发现了一处让人一看就兴奋的字符串。

在这里插入图片描述
直接查看它在代码段中的位置,并使用F5插件得到主函数的伪代码,通过分析,前面一串伪代码是判断你输入的长度,如果不等于16的话程序就会退出,并输出一句话。

在这里插入图片描述
我们先查看off_4032A4函数,发现在它的地址上声明了两个函数,第一个函数就先命名为Swapposition,第二个函数就命名为encryption

在这里插入图片描述
我们先看第一个Swapposition函数,发现它并不能被ida转化为伪代码,但可以看到在红色位置出现明显错误,又因首字节是E8,猜测很有可能是为了防止反汇编而添加的一个字节,因此将其首字节E8patch为90(nop),并创建函数就可以转化成伪代码了。

在这里插入图片描述

分析汇编指令和伪代码,是先将Str2[result] xor(异或)16,然后将异或后的结果传给寄存器dl,然后将cl向左移动四位,再将dl向右移动四位,最后在进行or(或)运算相加。由于cl,dl寄存器只能存储两个16进制,因此在向左移动四位时相当于16进制数向左移动一位,并舍弃最左边的16进制,右边补0;向右移动时舍弃最右边的一位,左边补0。最后的结果就是将两个16进制位置互换了一下。

在这里插入图片描述
接着分析第二个函数,发现在代码段有一串数据,这是因为ida是递归分析的,当分析到jmp这个无条件跳转命令时,jmp所跳过的区域ida是不会进行反汇编的。但OD并不是递归分析,而是线性分析,它是逐条指令依次向下分析。
在这里插入图片描述

F5转化成伪代码,查看off_404018,发现有三个函数,分别命名为sub,xor,abs函数。for循环的作用就是依次调用这三个函数,并传递两个参数。

在这里插入图片描述在这里插入图片描述
先看第一个函数sub,又是相同的问题,直接将E8patch成90,然后创建函数F5(后面两个函数也是如此)。发现他是将 我们的输入与参数a2相加。
在这里插入图片描述
第二个函数xor
在这里插入图片描述
第三个函数abs,这就有点意思了,abs()是取绝对值的意思,但通过X32debug动态分析后发现,并不是我们想象中的取法。

在这里插入图片描述
现在来动态调试看一下这个取绝对值的过程是咋样的。同意我们先通过字符串找到主函数在哪,并按 F2 设置断点,然后运行。输入长度为16的字符串,程序运行到断点处。步过函数,因为要分析第二个encryption函数,知道第二次到达call eax处然后进入此函数。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里原本是要跳过两次call ecx但在步过的时候直接跳到了其他地方,并且不能在调试了,猜测函数里有反调试的东西,于是在第一次就直接进入函数,发现这处与ida的所反汇编出来的代码不一样,在ida中是8b 45 0c因此修改X32中的90为8b,这样第一个函数sub就修改完成了(后面两个函数也是如此)。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
修改完后,查看第三个函数abs的取值过程,将数据段中的37给了寄存器eax,将77给了ecx,然后神奇的一步就来了,当sub eax,ecx时,eax的值变为了0xFFFFFFc0。接着执行cdq后edx值变为0xFFFFFFFF,然后xor eax,edx sub eax,edx得到37-77后的绝对值。对于相减后结果大于0的情况cdq后edx值变为0。弄清取绝对值的过程后,编写脚本就方便了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
回到ida中的encryption函数,在for循环结束后,又调用了递归函数,
在这里插入图片描述
因为传入的参数dword_404390是定值65,且与我们输入的字符串无关,且并不知道dword_404394的值,因此在这可以用动态调试查看这个函数是如何运行的。
继续之前的动态调试,进入函数,这时一定要一直点步进,并且每当执行到mov byte ptr ds:[ecx+54398],al时,要记录一下al的值。
在这里插入图片描述在这里插入图片描述
在执行到这一步时,在点步进没有反应,因为这时候*ds:[esi]*的地址调试器没有找到,所以就没有这个值,默认不存在,需要手动跳出。

在这里插入图片描述
在这里插入图片描述
继续点步进,直至跳出digui函数,发现记录了15个数据,并且Str的前15个数据分别与记录的15个数据进行xor(异或)操作。
最后用Str2与byte_4032AC比较,相同即原来输入的字符串套上moectf{}就为flag。程序的逻辑分析到这就结束了,接下来编写脚本。
由于本人能力不足(惭愧),在解密abs函数时,并不知道Str[a1] (key1[a1])Str[a2] (key1[a2]) 谁大谁小,就采用了最笨的方法将Str[a1] 可能的两个值都解出来,再代入检验,才将flag解出来。

key='3EFE99768BDC0D1832786FBF43743373'#最后对比的值
key1=[int (a,16) for a in [key[i:i+2] for i in range(0,len(key),2)]]
key3='4d4c47504b46434a454e4948444241'#递归函数中需要异或的数
key4=[int(a,16) for a in [key3[i:i+2] for i in range(0,len(key3),2)]]

#三个函数
def sub(a1,a2):
    key1[a1] -= a2
def abs1(a1,a2):
    temp2 = key1[a1] + key1[a2] - 0xff - 1 #key1[a2]大
    key1[a1] = temp2
def abs2(a1,a2):
    temp1 = key1[a2] - key1[a1] + 0xff + 1  # key1[a2]小
    key1[a1] = temp1
def xor(a1,a2):
    key1[a1] ^= key1[a2]

#逆着来,先异或
for v4 in range(0, 15):
    key1[v4] ^= key4[v4]

#调用七次函数,逆着来
d=[6, 5, 4, 3, 2, 1, 0]
for i in d :
    if i==0 or i==5 or i==6:
        sub(i,i+1)
    if i==1 or i==3:
        xor(i,i+1)
    if i==4:
        abs1(i,i+1)
    if i==2:
        abs2(i,i+1)
        
#将10进制变为16进制
for x in range(16):
    key1[x]=hex(key1[x])
print(key1)

key1=[0x27,0x62,0x49,0x27,0x45,0x49,0x74,0x25,0x77,0x63,0x62,0x7f,0x70,0x63,0x27,0x37] #将数字颠倒

for x in range(0,16):
    key1[x] ^= 0x16
    key1[x] = (chr(key1[x]))
print(''.join(key1)) # 得到flag moectf{1t_1S_b3autifu1!}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值