我的逆向之路|2019安恒二月赛逆向题目cpp详解

【我的逆向之路|2019安恒二月赛逆向题目cpp详解】本人首发在先知社区
https://xz.aliyun.com/t/4282
2019安恒二月赛的一道题目
这道题目运行,输入11111111111 回车,程序直接关闭,没有任何提示信息
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

Exeinfo PE查壳发现是一个C++程序并且没有加壳
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

IDA x32载入程序 shift + F12查看有没有什么可以字符串
发现一个’Please input:’
双击进去 接着双击引用
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

程序流程图貌似很简单的样子
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

F5查看伪代码
进行简单分析 Src是一个字符串数组 unsigned int是错误的
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

我们双击Src看下在程序中的位置
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

发现是在.data段也就是数据段(data segment),通常是指用来存放程序中已初始化的全局变量的一块内存区域,那Src是一个32位的全局字符串数组变量
双击sub_411302()进去 发现最后返回的是中间的参数 也就是result
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

双击sub_411352() 进行分析
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

接着双击sub_413910()

int __usercall sub_413910@(int a1@, char *Str) { char v2; // cl size_t i; // [esp+D0h] [ebp-8h]sub_4112F8((int)&unk_421008); for ( i = 0; i < j_strlen(Str); ++i )// 将Str这个字符串分为三组 分别与0x1f,0x20,0x21进行异或 { if ( i % 3 ) { if ( i % 3 == 1 ) v2 = Str[i] ^ 0x20; else v2 = Str[i] ^ 0x21; Str[i] = v2; } else { Str[i] ^= 0x1Fu; } } return sub_411302(1, (int)Str, a1); // 最后返回a1 }

总的分析
int __usercall sub_413E30@(int a1@) { int v1; // eax int v3; // [esp+0h] [ebp-CCh]sub_4112F8((int)&unk_421008); sub_411276(std::cout, "Please input: "); // cout输出提示信息 scanf((const char *)&my_input, (unsigned int)Src, 32); // scanf输入保存在Src if ( j_strlen(Src) >= 14 && j_strlen(Src) <= 32 )// 判断Src的长度是否满足大于等于14,小于等于32 若满足,就继续 { v1 = strcpy_s(Str, 32u, Src); // 用strcpy_s()函数拷贝Src到Str sub_411302(&v3 == &v3, v1, a1); sub_411352(a1, Str); // 对Str进行异或操作返回a1 } return sub_411302(1, 0, a1); // 返回0 相当于return 0 }

感觉程序没有结束但就是找不到下面的代码
看了官方WP
了解到可以查看Str的引用
因为后面一直是对Str进行处理 所以可以猜测后续还会对他进行处理
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

点击任意一个Str 点击X 可以查看到第三条是还未分析的
我们双击进去 可以发现有两个Str
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

这时候我们就是该找到新Str的来源 但是我的IDA好像找不到其他引用
所以换个思路
我们可以看 unk_421008 所在区域 一般都是在一块的 点击它 按X
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

可以发现向上游好多引用
一个一个看 最后可以发现最上面这个 就是我们要找的
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

双击可以看到
我的逆向之路|2019安恒二月赛逆向题目cpp详解
文章图片

那么我们就可以编写脚本解出flag
str1 = '' str2 = 'access denieda' flag = '' for i in range(len(str2)): str1 += chr(ord(str2[i])^i) # print str1 #abafwv&cmgcnhl for i in range(len(str2)): if i % 3 == 0: flag+= chr(ord(str1[i])^0x1f) elif i % 3 == 1: flag+= chr(ord(str1[i])^0x20) elif i % 3 == 2: flag+= chr(ord(str1[i])^0x21) print flag #~B@yWW9CLxCOwL

总结:当没有头绪的时候,可以查看变量或字符串的引用
这道题有涉及到虚函数表的知识
参考链接:https://www.linkedbyx.com/taskinfo/443/detail

    推荐阅读