本题主要考察的知识点是脱UPX壳和一个变形的base64加密。首先我们之前提到过有些人为了保护自己的程序有时会对程序进行加壳,一般都是病毒作者为了让自己的病毒逃过杀毒软件的查杀而进行加壳的,UPX就是其中的一种,这种壳现在已经被破解了,网上搜一下都能找到自动破解的工具,但最开始的破解方法是手动脱壳的,通过看汇编代码去跟踪程序的运行,等程序运行到程序入口时再将其保存出来;然后是这个变形的base64加密,在逆向解题过程中我们也会见到一些常见的加密方式,比如我们在学习MISC时见到的base64,rot13,DES,Uuencode等等,对于这些首先我们需要保证自己能认出来它是那种加密,然后可以再上网找一些在线工具解密,也可以用一些脚本进行解密,因此这一部分是需要我们去积累的。下面我们结合本题来具体看一下。
解题步骤
还是按照上一题的步骤,先把程序放进pe中查看信息:
可以看出这个程序是32位的,并且加了UPX壳。这个时候如果我们不脱壳直接放进ida中逆向的话会发现这种情况:
这种情况是程序被加壳了,系统没有找到程序的入口,所以我们要先对它进行脱壳。这里我用的是在网上下的upx脱壳工具,脱完壳之后再放进pe中查看:
然后我们就可以把它用ida打开,还是照上一题的步骤,先是shift+F12查找字符串,然后找到可疑字符串:
首先是最上面的,一串由所有字母的大小写+9个数字+“+/”组成的字符串,我们由此可以想到base64加密,因为base64加密的码表就是:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/。这个字符串的顺序跟正常的base64加密的码表不同,说明是经过变形后的base64加密,这个我们可以在网上找一个base64码表替换的脚本。然后是下面的那个字符串:please input flag:,这个我们可以尝试追踪一下,还是先双击字符串跳转到字符串的地址,然后Ctrl+X查找引用,跳转到引用的地方之后按F5生成引用函数的伪代码:
先分析一下这个函数的逻辑输入的flag存放在变量v0中,v1是v0的长度,然后把v0和v1传入函数sub_401005中,返回值赋给v4,这里我们先双击这个函数进行跟踪,一直跟踪到这里:
这里我们注意看有个byte_43501C,双击后进去发现就是我们之前看到的变换后的码表:
然后我们会发现这里少了一个大写的A,其实是在上面,就是那个41h,我们点一下41h移动一下光标,然后按A可以把字符串拼接起来:
这样我们就可以确定是一个变形的base64加密,那么这个函数的返回值就是经过变形base64加密的flag的结果。
回到主函数,下面是一个for循环,也是一个遍历异或,只不过是每一位跟它的位数异或,解法我会写在下面的解题脚本中。先往下看,经过了for循环后用strcmp函数比较unk_4350B0和v4,那么unk_4350B0应该也是个字符串,我们点进去后可以看到:
得到与v4进行比较的字符数组,然后就是写脚本进行逆向,先将遍历异或这一层逆向:
list1 = [0x58,0x4D,0x48,0x71,0x5E,0x31,0x40,0x7F,0x5E,0x45,0x7B,0x66,0x59,0x38,0x48,0x45,0x56,0x59,0x43,0x71,0x43,0x21,0x24,0x75,0x41,0x52,0x29,0x6C,0x4A,0x28,0x5C,0x65,0x76,0x14,0x5A,0x1E]
str2 = ""
for i in range(0,len(list1)):
str2 += chr(list1[i] ^ i)
print(str2)
运行后得到了一串字符串:XLJrZ4FxVLqmU5FJFHQbW42bYK3wV5BzV5x=
然后就是变形base64加密这一层,这里贴出来我在网上找到的base64码表替换的脚本:
import base64
OLD_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" # 原码表
NEW_STR = "AdefghijkBCDEFGOPQRST345UVWXYZabclmHIJKLMNnopqrstuvwxyz0126789+/" # 新码表
def encode_demo(str_data):
str_data = base64.b64encode(str_data)
encode_tab = str.maketrans(OLD_STR, NEW_STR)
return str_data.translate(encode_tab)
def decode_demo(str_date):
decode_tab = str.maketrans(NEW_STR, OLD_STR)
str_date = str_date.translate(decode_tab)
return base64.b64decode(str_date)
\# 解码
str1 = "XLJrZ4FxVLqmU5FJFHQbW42bYK3wV5BzV5x=" # 待解码字符串
str2 = decode_demo(str1)
print((str2).decode("utf-8"))
\# 编码
\# str1 = "" # 待编码字符串
\# str2 = encode_demo(str1)
\# print((str2).decode("utf-8"))
把这个程序中变形后的码表和待解密的字符串放入到脚本中的对应位置,运行后就可以得到flag。