前话:先记录下angr的使用。参考了大佬的文章:https://blog.csdn.net/Breeze_CAT/article/details/106139253
在cmd中使用,不能在pycharm中使用。
>>> import angr
>>> p = angr.Project(r'C:\Users\ASUS\Desktop\signal.exe') #地址前必须加r
>>> state = p.factory.entry_state()
>>> simgr = p.factory.simgr(state)
>>> simgr.explore(find=0x004017A5 ,avoid=0x004016E6) #这行之后会进行运算
>>> flag = simgr.found[0].posix.dumps(0)[:15]
>>> print(flag)
b'757515121f3d478'
正文:
打开ida后发现unk_403040赋值给v4,然后跟进unk_403040,先拿到v4数组
根据vm_operad逻辑,发现不断通过switch()去进行各种操作。大致梳理一下该函数与a1数组的值发现,case 10只在a1[0]触发一次,等价于scanf,读入的字符串在str[],case 2,3,4,5将当前a1值与其后一位的值一起去对v4的值进行修改,case 6就直接跳过,case 8以v4的值更新str[],case 11,12直接修改v4,case 1将处理好的v4赋值到Str[v6 + 100](其实视为一个新的数组)并且处理str[]中的下一个字符,case 7 就是一部检验。
总结一下,其实就是把输入的字符串,从第一个开始处理,处理完的结果由v4赋值给Str[v6 + 100],等每一个都处理完,就开始检验是否正确。
而对于a1中的数据只有后15行有7,所以可以将处理后的数据拿出:
b = [0x00000022 ,0x0000003F ,0x00000034 ,0x00000032 ,0x00000072 ,0x00000033 ,0x00000018 ,0x00000A7 ,0x00000031 ,0x00000F1 ,0x00000028 ,0x0000084 ,0x00000C1 ,0x0000001E ,0x0000007A ]
对于源代码有一个LOBYTE其实就是选取最低为的字节,跟据汇编可以看出赋值存在于al(8位),其实也就是一个字节,所以LOBYTE无影响
而每一次case1其实就可以看作一次处理完成,所以我们将每一个a1[]中的元素1,当成分界点,有说明一下如果1之前的元素为2,3,4,5那它不会做为switch的参数(在这里卡了好久)。
正向写脚本爆破比较好写,直接上脚本了:
b = [0x00000022 ,0x0000003F ,0x00000034 ,0x00000032 ,0x00000072 ,0x00000033 ,0x00000018 ,0x00000A7 ,0x00000031 ,0x00000F1 ,0x00000028 ,0x0000084 ,0x00000C1 ,0x0000001E ,0x0000007A ]
a = []
aa = [[0x0000000A,0x00000004,0x00000010,0x00000008,0x00000003,0x00000005,0x00000001],
[0x00000004,0x00000020,0x00000008,0x00000005,0x00000003,0x00000001],
[0x00000003,0x00000002,0x00000008,0x0000000B,0x00000001],
[0x0000000C,0x00000008,0x00000004,0x00000004,0x00000001],
[0x00000005,0x00000003,0x00000008,0x00000003,0x00000021,0x00000001],
[0x0000000B,0x00000008,0x0000000B,0x00000001],
[0x00000004,0x00000009,0x00000008,0x00000003,0x00000020,0x00000001],
[0x00000002,0x00000051,0x00000008,0x00000004,0x00000024,0x00000001],
[0x0000000C,0x00000008,0x0000000B,0x00000001],
[0x00000005,0x00000002,0x00000008,0x00000002,0x00000025,0x00000001],
[0x00000002,0x00000036,0x00000008,0x00000004,0x00000041,0x00000001],
[0x00000002,0x00000020,0x00000008,0x00000005,0x00000001,0x00000001],
[0x00000005,0x00000003,0x00000008,0x00000002,0x00000025,0x00000001],
[0x00000004,0x00000009,0x00000008,0x00000003,0x00000020,0x00000001],
[0x00000002,0x00000041,0x00000008,0x0000000C,0x00000001]
]
flag = []
v9 = 0
cnt = 0
v4 = 0
ans =0
bi = 0
for j in range(15):
a = aa[j]
v4 = 0
bi = 0
for i in range(128):
if bi == 1:
break
v9 = 0
v4 = 0
ans = i
while True:
if a[v9] == 1:
if v4 == b[cnt]:
cnt += 1
bi = 1
print(chr(i),end='')
break
else:
break
elif a[v9] == 2:
v4 = a[v9 + 1] + ans
v9 += 2
elif a[v9] == 3:
v4 = ans - a[v9 + 1]
v9 += 2
elif a[v9] == 4:
v4 = a[v9 + 1] ^ ans
v9 += 2
elif a[v9] == 5:
v4 = a[v9 + 1] * ans
v9 += 2
elif a[v9] == 6:
v9 += 1
elif a[v9] == 8:
ans = v4
v9 += 1
elif a[v9] == 10:
v9 += 1
elif a[v9] == 11:
v4 = ans - 1
v9 += 1
elif a[v9] == 12:
v4 = ans + 1
v9 += 1
看大佬的wp,get了一项新技能----符号执行自动秒题。
找到能够证明运行成功的地址:
运行到此处则证明,运算正确
再找一下运行失败的点:
运行到此处则,输入不正确
于是构造语句:
simgr.explore(find=0x004017A5 ,avoid=0x004016E6)
导入angr跑的程序,windows环境下要加r不然会报错
p = angr.Project(r’C:\Users\ASUS\Desktop\signal.exe’)
新建一个SimState的对象,得到一个初始化到二进制入口函数的SimState对象。
state = p.factory.entry_state()
创建simulation manager,angr的主要入口
simgr = p.factory.simgr(state)
完整脚本
import angr
p = angr.Project(r'C:\Users\ASUS\Desktop\signal.exe')
state = p.factory.entry_state()
simgr = p.factory.simgr(state)
simgr.explore(find=0x004017A5 ,avoid=0x004016E6)
flag = simgr.found[0].posix.dumps(0)[:15]
print(flag)
参考博客:https://blog.csdn.net/Breeze_CAT/article/details/106139253