我一开始很好奇,它对栈顶数据的操作方式,因为[esp]没有单独出现,而是出现了[esp+104h+var_114+10h]、[esp+108h+var_114+0Ch]等这种偏移的访问方式,这个阻碍了我进一步的分析。。
动态调试下,对应的指令就直接是 [esp]:
scanf(""%63s", 0xffffd190)
此时 [esp+4] = 0xffffd190
此时,edi = [esp+4]
在0x402910里面,如果验证不正确,则最后的返回地址为start函数里的地址,如果正确,则为其他地址:
sub_402910 这个核心函数的逻辑为:
将传入参数与call指令下一个位置的地址相减,然后与dl相乘,再加回减去的地址,然后跳转到计算后的地址中
经过验证,当dl为1的时候,传入参数即可作为地址被调用成功。
[Python] 纯文本查看 复制代码 esp_4 = 0x40119C
esp = 0x40117A
ret_addr = 0x40119C
#dl = [esp ^ ((buffer[esi] ^ 0x0CC84881E) & 0xff)]
#ret_addr = (dl * ([esp+4] - [esp])) & 0xff + [esp]
temp1 = esp_4 - esp
print((ret_addr - esp)/temp1)
我没看懂的地方
官方题解说:
start函数中,只有一处向内存中写入1
而在这里,又将[edx]的值赋给了edx,再向下就是校验函数了。显而易见,我们的目的就是让程序在执行到xor byte ptr [eax], 1这条指令时,让eax与edx相等。
于是有:
[Python] 纯文本查看 复制代码 (esp ^ input[i] ^ 0x0CC84881E) & 0xFF == esp ^ 0x3E ^ 0x46
即
input[i] ^ 0x1E == 0x3E ^ 0x46
然后写脚本匹配,批量提取信息反推flag。
它的信息可能是指,如果你的输入是正确的,就会导致dl为1,输入错误就不能,应该是在xor edx, [eax] 这一步,将[edx]赋值给edx。它是怎么搞的我实在没看懂。
脚本
[Python] 纯文本查看 复制代码 import idc
import idaapi
import idautils
import re
idaapi.auto_wait()
flag = ""
count = 0
for func in idautils.Functions():
# Ignore Library Code
flags = idc.get_func_flags(func) # 获取函数的标志,分为lib和普通函数等
#print("flags: ", flags)
if flags & FUNC_LIB: # 跳过系统函数
continue
instuction_generator = idautils.FuncItems(func) # <class 'generator'>
instuction_list = list(instuction_generator)
len_list = len(instuction_list)
opnd1 = 0
opnd2 = 0
opnd3 = 0
for i,instruction in enumerate(instuction_list): # 当前函数中的每个指令地址
# 匹配指令 xor bl, [esi] 对应操作码 32 1E ; xor ebx, XXh 对应操作码81 F3 XX XX XX XX
if idaapi.get_byte(instuction_list[i]) == 0x32 and idaapi.get_byte(instuction_list[i]+1) == 0x1E:
if i+1 < len_list: # 防止越界访问
if idaapi.get_byte(instuction_list[i+1]) == 0x81 and idaapi.get_byte(instuction_list[i+1]+1) == 0xF3:
opnd3 = idaapi.get_dword(instuction_list[i+1] + 2)
print(hex(opnd3))
#count += 1
if i+1 < len_list:
insText = idc.generate_disasm_line(instuction_list[i], 0) # 获取指令
nextInsText = idc.generate_disasm_line(instuction_list[i+1], 0) # 获取指令
if "xor eax," in insText and 'h' in insText and "xor eax," in nextInsText and 'h' in nextInsText:
opnd1 = idc.get_operand_value(instuction_list[i], 1)
opnd2 = idc.get_operand_value(instuction_list[i+1], 1)
print("opnd1: ", hex(opnd1))
print("opnd2: ", hex(opnd2))
flag += chr(int((opnd3 ^ opnd1 ^ opnd2) & 0xFF))
print(flag)
题目文件:
Petition.zip
|