刚做这道题的时候就是刚学完 gdb 调试,还没有实例练一下,刚好这道题可以学习一下 gdb
装 peda gdb
我就是按照网上查的办法装的,唯一注意的地方就是,我第一装的时候用的 root 权限装的(比较蠢),所以 user 权限打不开,后来又 user 权限下装,就可以显示红色的 gdb-peda$
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
reversemeplz 题目分析
现在回到题目,先用 linux 看一下是什么类型文件,linux 环境下运行一下,然后 IDA32 打开。找到关键函数
我把函数名字改为 key,只有返回 v1=1 才能得到答案 再看 key 函数
func 我感觉也是关键函数,所以把它也标记了一下,然后打开 func 的时候,发现复杂,所以先不准备处理它,我进行对于 key 函数的整理
for i = 0; i < 15; i++:
if a1[i] <= 96:
a1[i] = func(a1[1] & 1) #这里我特意去查,并且试了一下是 *优先级 > &
if a1[i] > 122:
a1[i] = func(a1[1] & 2)
if 97 <= a1[i] <= 122: #97 - 122 是 a - z
a1[i] = a1[i] # 这里很重要
v3 = func(a1[i])
v9[i] = v3
if v3 > 0xCCu && v3 != 0XCFu #这里我也被坑了一下,由于 v3 是char型,所以 -49 只是因为上溢产
v1 = 1 生的负数,这里也是一个关键位置
# 输入长度必须为 15
v4 = 0
# v1 必不为 1
for i = 1; i <= 14; i++
v9[i] - v9[i-1] = diff[i] #看 IDA 就可以发现 v8 的起始刚好在 v9 上面一位
# 因为若 a1[15] == 1 则必 return 0
# 因为若 func(0) == 1 则必 return 0
# 所以 a1[15] != 1 && func(0) != 1 但是这好像没什么卵用(嘿嘿嘿)
return func(a1[0]) == 98
# 为了能 return 一个非零数, 则 func(a1[0]) == 98, 这里是突破口
# 接下来就是练调试的部分,需要调试出 diff [1 - 14],通过 v9[0] = func(a1[0]) = 98, 可以求出 fun(a1[0 - 15]),但是总觉得差点什么,我们并没有搞清楚 func 的函数怎么运行,或者存在什么运算规律
调试
大致流程:
- 先输 gdb
- 再 file ./[ file ]
- 开始 start
- 设断点 b *[ 地址 ]
- run
- p $参数
- n 或者 c
调试出 diff 数组
可以看到你想要的那个地址和地址上的数据,之后我会写一点关于今天学会用的 x 的知识,就是别忘了p 时 ‘$‘ 号
根据上面的汇编可以知道是每隔四个是 diff 数组内容,且 eax 从 0x1 开始取
调试尝试 a-z 输入时 func 的规律
为什么选 a-z 呢 因为 a-z 输入时 a[ i ] = a[ i ] 更好控,若是 func 有规律,就更容易找到 func 的规律
然后我就开始了一波新的调试,这里可以 之前有调试的内容
- 可以直接 q 退出,再开新的 gdb (这样显得比较蠢)
- 就用我查的新技巧
- info b 查询 break 情况
- delete 数字 ,是删除第几个断点 (还有其他的办法使断点不可用)
- 新设断点,再次 start, run
这里新设断点,我设到了 if ( (unsigned __int8)v3 > 0xCCu && v3 != 0xCFu ) 这里,因为这里汇编比较清楚
第一个箭头指向的是:处理的字符串即 func( char ) 是什么
第二个箭头指向的是:汇编中调试当前位置
第三个箭头指向我打印出来的 func( ‘a‘ )
然后在不断 c 和 print 的过程中发现
func( a-m ) == n-z func( n-z ) = a-m
这里规律出来之后就比较清晰了,我们如果能找到 只由 a-z 组成的15位字符串,就可以满足条件,从而得到满足输入的字符串,如果不能就还要研究 func() (我也不想啊)
然后写了一发脚本,跑出来可以,而且语义比较符合,交一发就出来了
附上脚本
# /usr/bin/env python
# -*-coding:utf-8-*-
__Author__= ‘Vangelis‘
diff = [-1, 17, -11, 3, -8, 5, 14, -3, 1, 6, -11, 6, -8, -10]
#a:0x6e b:0x6f c:0x70 d:0x71 e:0x72 f:0x73 g:0x74 h:0x75 i:0x76 j:0x77 k:0x78 l:0x79 m:0x7a
#n:0x61 o:0x62 p:0x63 q:0x64 ...
#according to gdb, find the rule of ‘func‘ -- send ‘a-z‘ out ‘n-za-m‘ ‘m‘ is break
#so the first could ‘o‘
map = {‘n‘:‘a‘, ‘o‘:‘b‘, ‘p‘:‘c‘, ‘q‘:‘d‘, ‘r‘:‘e‘, ‘s‘:‘f‘, ‘t‘:‘g‘, ‘u‘:‘h‘, ‘v‘:‘i‘, ‘w‘:‘j‘, ‘x‘:‘k‘, ‘y‘:‘l‘, ‘z‘:‘m‘, ‘a‘:‘n‘, ‘b‘:‘o‘, ‘c‘:‘p‘, ‘d‘:‘q‘, ‘e‘:‘r‘, ‘f‘:‘s‘, ‘g‘:‘t‘, ‘h‘:‘u‘, ‘i‘:‘v‘, ‘j‘:‘w‘, ‘k‘:‘x‘, ‘l‘:‘y‘, ‘m‘:‘z‘}
key = ord(‘b‘)
flag = ‘o‘
for i in range(14):
key += diff[i]
flag += map[chr(key)]
print(‘flag{‘ + flag + ‘}‘)
关于 x 的使用问题
x/<n f u> < addr >
正如我使用的一样 n 代表个数:当前地址向后显示几个内存单元的值
f 代表按照什么格式:就像 C 中的 数据类型一样 ,注意一下 t 和 a
? x d u o t(binary) a(address) c f
u 代表按照几个字节来分开:b表示单字节,h表示双字节,w表示四字 节,g表示八字节
我需要一个字节一个字节的 所以用的 b 需要10进制,所以用的 d
有人问了为什么你 db 写反了,还可以出来(这么尴尬的问题,你也问???喵喵喵???)
实话实说,我也是写到这里才发现,我之前截屏的那一次操作写反了(=.=)
去试了一波,发现对于 db 正反都可以用,可能是当 f u 没产生冲突的时候可以用吧,就像 f 中无 b 所以认为是属于u 中的吧
关于 x 的用法的参考资料: