2021年11月深育杯REVERSE的press

99 篇文章 34 订阅

2021年11月深育杯REVERSE的press

下载附件,是两个文件:
在这里插入图片描述
.
猜想是题目类型是与本地文件相关的操作类型,照例扔入exeinfope中查看信息:
在这里插入图片描述
在这里插入图片描述
.
然后两个文件可以简单猜想一下press程序应该是输出了一些信息到out文件中,在linux下照例运行一下press程序看一下回显:
在这里插入图片描述
.
.
那么这个程序没有输入,根据经验这种类型的题目通常直接利用程序外部的一些东西来作为条件继续执行的,如本地环境文件读取等。所以照例扔入IDA查看伪代码,有main函数看main函数:
在这里插入图片描述
在这里插入图片描述
.
.
知道大致逻辑之后我们找一下s数组在哪里,前面打开文件的关键自定义函数还没看,现在看一下。因为是环境准备函数,所以不用过意深究:
在这里插入图片描述
.
.
继续回到关键自定义函数sub_40094B中,因为比较绕,所以我们慢慢分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
.
.
好了,第一个阶段++++++++++[->++++++++++++++++<]总算是分析完了,涉及一个负数循环的系统特殊操作数和一个修改6020A0而变形形成的一个总共加了160的循环。(那个负数循环的系统特殊操作数我之所以手算不出来是因为前面环境准备函数中有对 dword_602360[i]的操作,这里就干扰了系统特殊操作数,难以手动分析)
那我们继续分析后半部分:
在这里插入图片描述
在这里插入图片描述
.
.
到这里第二阶段,[->-<]也分析完了,我们继续往下走:
在这里插入图片描述
.
.
那么第三阶段的>>[-]+++++<*++.<也分析完了。总得来说改自定义函数应该就是读入一个flag,生成(160-flag)*5+2的值,现在再看看外层函数是怎么操作的:
在这里插入图片描述
.
.
总的流程梳理完了,out中的内容就是每个flag字符进行(x+160-single_flag)*5+2而来的,注意这里第一个x是前一个flag字符。因为前面最后的分析中加密的160-single_flag)*5+2的值是放在了6021A0[1]中的,而且是一直存在的。
6021A0[0]6021A0[2]在遍历S数组中已经被置0了,只有这个6021A0[1]保留了值,外面的while循环重置的只是6020A0S数组下标的值。
.
.
.
首先我们写一个爆破的脚本,因为原本的结果一看就是base64加密的,所以直接内嵌base64解密代码。

还有需要注意的就是((b-j)*5+2)&0xff这里之所以要&0xff是因为字符的ASCII码都是255内的,但是python中没有变量大小概念,所以必须截取一个byte大小,不然就有大量超出255的数出现,结果就显示不了了。所以这里涉及了我笔记中的>> 、%、&运算符算法积累

out=[0x60, 0xE1, 0x2F, 0x05, 0x79, 0x80, 0x5E, 0xE1, 0xC5, 0x57,
  0x8B, 0xCC, 0x5C, 0x9A, 0x67, 0x26, 0x1E, 0x19, 0xAF, 0x93,
  0x3F, 0x09, 0xE2, 0x97, 0x99, 0x7B, 0x86, 0xC1, 0x25, 0x87,
  0xD6, 0x0C, 0xDD, 0xCF, 0x2A, 0xF5, 0x65, 0x0E, 0x73, 0x59,
  0x1D, 0x5F, 0xA4, 0xF4, 0x65, 0x68, 0xD1, 0x3D, 0xD2, 0x98,
  0x5D, 0xFE, 0x5B, 0xEF, 0x5B, 0xCC]

flag=""
b=0
for i in range(len(out)):
	b+=160		#这里就是说的(x+160-single_flag)
	for j in range(127):
		if (((b-j)*5+2)&0xff==out[i]):		#这里之所以要&0xff是因为字符的ASCII码都是255内的,但是python中没有变量大小概念,所以必须截取一个byte大小,不然就有大量超出255的数出现,结果就显示不了了
			flag+=chr(j)
			b=out[i]
			break
import base64
print(base64.b64decode(flag))

结果:
在这里插入图片描述
.
.
当然我们也可以不用爆破的方法,直接写出逆向逻辑脚本,只是因为*5的逆向/5会有余数,所以要不断加256没有余数为止,就比较麻烦:

out=[0x60, 0xE1, 0x2F, 0x05, 0x79, 0x80, 0x5E, 0xE1, 0xC5, 0x57,
  0x8B, 0xCC, 0x5C, 0x9A, 0x67, 0x26, 0x1E, 0x19, 0xAF, 0x93,
  0x3F, 0x09, 0xE2, 0x97, 0x99, 0x7B, 0x86, 0xC1, 0x25, 0x87,
  0xD6, 0x0C, 0xDD, 0xCF, 0x2A, 0xF5, 0x65, 0x0E, 0x73, 0x59,
  0x1D, 0x5F, 0xA4, 0xF4, 0x65, 0x68, 0xD1, 0x3D, 0xD2, 0x98,
  0x5D, 0xFE, 0x5B, 0xEF, 0x5B, 0xCC]
flag=""
for i in range(len(out)):
   c = out[i] - 2
   while c != c // 5 * 5:
       c += 256
   c = c // 5

   if i == 0:
       flag+= chr(160 - c)
   else:
       flag+= chr((out[i-1] + 160 - c)&0xff)

import base64
print(base64.b64decode(flag))

结果:
在这里插入图片描述

.
.
然后后来还在水番正文的博客中发现了z3库破解的方法,也不失为一个好方法,修改后如下:

博客地址:https://blog.csdn.net/weixin_50166464/article/details/121318120?spm=1001.2014.3001.5501

from z3 import *
enflag = [0x60, 0xE1, 0x2F, 0x05, 0x79, 0x80, 0x5E, 0xE1, 0xC5, 0x57, 0x8B, 0xCC, 0x5C, 0x9A, 0x67, 0x26,
        0x1E, 0x19, 0xAF, 0x93, 0x3F, 0x09, 0xE2, 0x97, 0x99, 0x7B, 0x86, 0xC1, 0x25, 0x87, 0xD6, 0x0C,
        0xDD, 0xCF, 0x2A, 0xF5, 0x65, 0x0E, 0x73, 0x59, 0x1D, 0x5F, 0xA4, 0xF4, 0x65, 0x68, 0xD1, 0x3D,
        0xD2, 0x98, 0x5D, 0xFE, 0x5B, 0xEF, 0x5B, 0xCC]
parameter = [BitVec(i, 8) for i in range(56)]		#这里定义的是56个char类型的参数准备求解

s = Solver()
 
s.add( ((160 - parameter[0]) * 5 + 2) == enflag[0] )	#第一台液压机
for i in range(1, 56):				#之后的液压机
    s.add( (((160 + enflag[i - 1]) - parameter[i]) * 5 + 2) == enflag[i] )
    
if sat == s.check():
    ans = s.model()		#model方法返回结果数组,索引是前面定义的参数名。
    
flag = ""
for i in range(56):
    flag += chr(ans[parameter[i]].as_long())   #as_long()转成整数后把结果集附在在flag上

import base64
print(base64.b64decode(flag))

.
.
附录,后面从别人团队的博客和水番正文博客中发现数组S是类似于第五空间的brainfuck,把brainfuck对应的操作流程翻译过来,就可以了,这样反而更好理解一点:(多重水印是比较难看哈~)
在这里插入图片描述
在这里插入图片描述
.
.
.

解毕!敬礼!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐一 · 林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值