Target:样品为VC 6.0 MFC CHello 基础编程样例
0x01 60s内攻破的碰撞成分
0x02 动态分析与静态分析之争
0x03 MFC的启动过程
0x01 60s内攻破的碰撞成分
贞:从拿到样品开始算,如何在60s内得到验证的passKey?
(1)样品的图标折射出MFC的特征;
(2)拖进已经打开的IDA开始自动分析,同时双击启动样品实例;
(3)打开IDA->View->Open subviews->Strings查阅字符信息,如下;
Address Length Type String
.rdata:0040333E 00000006 C (16 bits) @7
.rdata:00403558 00000008 C (&A)...
.rdata:00403560 00000006 C pass!
.rdata:00403580 00000017 C WelcomeToKanXueCtf2017
.rdata:0040359E 00000006 C pass!
.rdata:0040392C 0000000A C MFC42.DLL
.rdata:00403976 0000000B C MSVCRT.dll
.rdata:00403A8A 0000000D C KERNEL32.dll
.rdata:00403B2C 0000000B C USER32.dll
(4)若不怀疑CTF存在简单性的可能,直接复制WelcomeToKanXueCtf2017到提交框就能恰好碰撞成功。
(5)若有所怀疑,且觉得WelcomeToKanXueCtf2017更可能是欢迎标题,敏感点落在pass!字符串身上。
搁置验证尝试,IDA交叉引用pass!(快捷键X)到函数 Hi_msg_pass_success_401770 的如下代码段
.text:0040177B push offset Caption ;
.text:0040177B ; 恭喜!
.text:00401780 push offset Text ; "pass!"
.text:00401785 push 0 ; hWnd
.text:00401787 call ds:MessageBoxA
(6)继续追溯Hi_msg_pass_success_401770的交叉引用到Hi_CDialogPassCheck__Check_sub_4017F0函数体内,如下;
在调用提示通过的函数Hi_msg_pass_success_401770上下文发现了strcmp 和 "WelcomeToKanXueCtf2017",
这时可以足够的信任,"WelcomeToKanXueCtf2017"至少作为passKey最终比对明文的一部分,
再多看一眼局部变量loc_passKeyPtr在上文的来源,其直接就是CEdit的内容,
中间没有任何变换处理,与"WelcomeToKanXueCtf2017"比对后也没有更多的比对操作,
基本可以肯定"WelcomeToKanXueCtf2017"就是该CTF的签到暗语,直接复制提交。
.text:004017F0 Hi_CDialogPassCheck__Check_sub_4017F0 proc near
.text:004017F0 loc_passKeyPtr = dword ptr -8
.text:004017F0 loc_thisptrCDialogPassCheck= dword ptr -4
.text:004017F0 push ebp
.text:004017F1 mov ebp, esp
.text:004017F3 sub esp, 48h
.text:004017F6 push ebx
.text:004017F7 push esi
.text:004017F8 push edi
.text:004017F9 mov [ebp+loc_thisptrCDialogPassCheck], ecx
.text:004017FC mov eax, [ebp+loc_thisptrCDialogPassCheck]
.text:004017FF add eax, 64h
.text:00401802 push eax ; struct CString *
.text:00401803 push 3EAh ; int //CEdit 控件ID
.text:00401808 mov ecx, [ebp+loc_thisptrCDialogPassCheck] ; this
.text:0040180B call CWnd::GetDlgItem(int) //获取CEdit空间对象
.text:00401810 mov ecx, eax ; this
.text:00401812 call CWnd::GetWindowTextA(CString &)
//将CEdit的字符值赋予验证对话框对象位于偏移0x64处的passKey成员
//loc_thisptrCDialogPassCheck.m_64h_CString_passKey = input_pass_key
.text:00401817 mov ecx, [ebp+loc_thisptrCDialogPassCheck]
.text:0040181A add ecx, 64h
.text:0040181D call Hi_CString_GetLength_4018D0 //passKey 长度
.text:00401822 push eax ; int
.text:00401823 mov ecx, [ebp+loc_thisptrCDialogPassCheck]
.text:00401826 add ecx, 64h ; this
.text:00401829 call CString::GetBuffer(int) //passKey Ptr
.text:0040182E mov [ebp+loc_passKeyPtr], eax
.text:00401831 mov ecx, [ebp+loc_passKeyPtr]
.text:00401834 push ecx ; loc_passKeyPtr
.text:00401835 call strlen
.text:0040183A add esp, 4
.text:0040183D test eax, eax
.text:0040183F jnz short loc_401854
.text:00401841 push 0 ; unsigned int
.text:00401843 push 0 ; char *
.text:00401845 push offset byte_403598 ;
.text:00401845 ; 请输入pass!
.text:0040184A mov ecx, [ebp+loc_thisptrCDialogPassCheck] ; this
.text:0040184D call CWnd::MessageBoxA(char const *,char const *,uint)
.text:00401852 jmp short loc_401875
.text:00401854 ; ---------------------------------------------------------------------------
.text:00401854 loc_401854:
.text:00401854 push offset Str2 ; "WelcomeToKanXueCtf2017"
.text:00401859 mov edx, [ebp+loc_passKeyPtr]
.text:0040185C push edx ; Str1
.text:0040185D call strcmp
.text:00401862 add esp, 8
.text:00401865 test eax, eax
.text:00401867 jnz short loc_401870
.text:00401869 call Hi_msg_pass_success_401770 ;
.text:00401869 ; MessageBoxA(0,"pass!","恭喜!")
.text:0040186E jmp short loc_401875
.text:00401870 ; ---------------------------------------------------------------------------
.text:00401870 loc_401870:
.text:00401870 call Hi_msg_ComeOn_fail_4017B0 ;
.text:00401870 ; MessageBoxA(0,"加油!","错了!")
.text:00401875
.text:00401875 loc_401875:
.text:00401875
.text:00401875 pop edi
.text:00401876 pop esi
.text:00401877 pop ebx
.text:00401878 mov esp, ebp
.text:0040187A pop ebp
.text:0040187B retn
.text:0040187B Hi_CDialogPassCheck__Check_sub_4017F0 endp
0x02 动态分析与静态分析之争
贞:在从外表看出来是MFC,体积较小的印象之初,是选择动态调试还是静态分析先?
(1)因为这是小体积的独立样例,核心的逻辑或数据一般都会在里面,
且若无法避免需要动态调试分析时,动态调试分析的针对性需要静态分析辅助,
即先上静态,一窥全貌,再做应对安排。
(2)实际上在应对确定MFC消息响应函数这块,静态分析可能比动态来得更直接快速。
包括直接从MFC类对象的虚表函数中找到其定义的消息映射表,
或如上述通过敏感字符提示信息的交叉引用逆向追溯。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!