这道题其实不算难,只不过我想的有点复杂了,看来学逆向还是需要具有发散性思维的,有些问题确实想不到啊!!
查壳发现有aspack壳:
根据日常习惯,直接手动脱壳(其实是脱壳工具没找着。。),32位程序,x32dbg打开:
首先看到程序中有一个pushad指令,按照我习惯的脱壳方法,直接F8执行pushad,然后在栈中下一个硬件断点,F9运行,即可找到popad的位置
继续往下执行,一直到地址为0x726425的ret指令执行完:
看到一个关键的jmp指令(jmp的距离比较远,极有可能跳转过去就是OEP的位置),一直执行到jmp指令,jmp指令执行完之后:
现在程序已经执行到OEP的位置了,dump出内存然后进行修复即可得到:
其中Windows_Reverse2_dump_SCY.exe这个文件是不能运行的,程序运行之后会直接退出,因为程序的重定位信息并没有被修复,我们可以通过CFF Explorer修改NT Header的"Characteristics",勾选"Relocation info stripped from file",程序即可正常运行:
勾选完保存之后,就可以正常分析程序了,可以结合动态调试对程序进行分析:
其中,关键函数为decrypt函数,进入:
经过分析,该函数将输入的每两位数为一组变成一个十六进制数,例如,输入"AE",就会得到ascll值为0xae对应的字符。
sub_D51000函数为base64加密,函数中有关键的特征算法和特征值:
综上,整个程序的流程就是输入一个偶数长度的字符串,且必须是"A"-"F"或者"0"-"9",之后每两个数为一组,组成一个十六进制数,然后根据ascll表转化为字符,进行base64加密,如果加密后的值为reverse+,我们输入的字符串就是flag。
先将reverse进行解密:
#密码表
base64_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
#加密
def btoa(): # base64编码函数
s = input( "input string to encode:\n" )
n = len( s ) % 3
x = ''
asc = []
for i in range( len( s ) ):
asc.append( ord( s[i] ) ) # 取各字符ascii值
x += '{:08b}'.format( asc[i] ) # 将各字符ascii值转为二进制
if n:
x += '0' * 2 * (3 - n) # 长度非3倍的结尾补零
i = 0
out = ''
while i < len( x ):
out += base64_table[int( x[i:i + 6], 2 )]
i += 6
if n:
out += '=' * (3 - n) # 补上'='使编码后长度为4倍
print( out )
#解密
def atob(): # base64解码函数
s = input( "input string to decode:\n" )
b64 = []
x = ''
for i in range( len( s ) ):
if s[i] == '=':
b64.append( 0 )
else:
for j in range( 64 ):
if (s[i] == base64_table[j]):
b64.append( j )
break
x += '{:06b}'.format( b64[i] )
#print( x )
i = 0
out = ''
while i < len( x ):
if int( x[i:i + 8], 2 ):
out += chr( int( x[i:i + 8], 2 ) )
i += 8
print( out )
def main():
m = input( 'Input 1/2 to encode/decode:\n' )
if m == '1':
btoa()
elif m == '2':
atob()
else:
print( 'Error! Please restart the process!' )
main()
得到:
Input 1/2 to encode/decode:
2
input string to decode:
reverse+
ëޮǾ
将解密后的字符转化为十六进制数:
a = 'ëޮǾ'
for i in range(len(a)):
b = 0
b = hex(ord(a[i]))
print(b,end=',')
得到:
我们可以得到正确的输入字符:
ADEBDEAEC7BE
验证程序:
正确!得到flag:
flag{ADEBDEAEC7BE}