RE—攻防世界—流浪者
看文件图标就知道这和MFC有关,没有加壳和反调试混淆。
MFC
微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class libraries),以C++类的形式封装了[Windows API](https://baike.baidu.com/item/Windows API/6088382),并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
其实MFC就是一个对C++语言的封装,用来减小开发人员工作量。
分析
那到手是一个exe文件,试运行一下,就是一个输入密码的题,MFC编写的程序比单纯的控制台程序更难分析。
由于不知道exe的入口函数是什么,我们可以去找到判断密码正确与否的函数,最简单的办法便是字符串的交叉引用。Shift+F12可以查看程序的字符串。
其中pass!在我们输入的时候没有出现。
交叉引用后反编译查看源代码
发现是程序通过会出现的界面。
于是跳转到call了该函数的函数那里:
可以发现该函数对传入的数字加上4*v4然后在一个aAbcdef这个数组里面找到对应的值并赋值给str1,最后比较字符串“KanXueCTF2019JustForhappy”和str1。
所以我们需要找到传入的al是什么,继续交叉引用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| int __thiscall sub_401890(CWnd *this) { CWnd *DlgItem; int v2; struct CString *v4; int v5[26]; int i; char *Str; CWnd *v8;
v8 = this; v4 = (CWnd *)((char *)this + 100); DlgItem = CWnd::GetDlgItem(this, 1002); CWnd::GetWindowTextA(DlgItem, v4); v2 = sub_401A30((char *)v8 + 100); Str = CString::GetBuffer((CWnd *)((char *)v8 + 100), v2); if ( !strlen(Str) ) return CWnd::MessageBoxA(v8, aPass, 0, 0); for ( i = 0; Str[i]; ++i ) { if ( Str[i] > '9' || Str[i] < '0' ) { if ( Str[i] > 'z' || Str[i] < 'a' ) { if ( Str[i] > 'Z' || Str[i] < 'A' ) sub_4017B0(); else v5[i] = Str[i] - 29; } else { v5[i] = Str[i] - 87; } } else { v5[i] = Str[i] - 48; } } return sub_4017F0((int)v5); }
|
于是便可以对上面的程序来反解出flag;
逆算法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| KanXue = "KanXueCTF2019JustForhappy" abcdef = "abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ" SomeDwordArray = [] Key = ""
for i in range(len(KanXue)): SomeDwordArray.append(abcdef.find(KanXue[i]))
print("SomeDwordArray =", SomeDwordArray)
for dw in SomeDwordArray: if dw <= 9 and dw >= 0: Key += chr(dw + ord('0')) elif dw + ord('W') >= ord('a') and dw + ord('W') <= ord('z'): Key += chr(dw + ord('W')) else: Key += chr(dw + 0x1D)
print(Key)
|
解出来的key加上flag{}。