Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

看雪腾讯ctf第五题(待完善) #14

Open
xinali opened this issue Feb 27, 2018 · 0 comments
Open

看雪腾讯ctf第五题(待完善) #14

xinali opened this issue Feb 27, 2018 · 0 comments
Labels

Comments

@xinali
Copy link
Owner

xinali commented Feb 27, 2018

writeup大纲

  1. GetMessageMap函数寻找
  2. int 2d处理 seh exception handler
  3. 大整数结构体
  4. 大整数之间的进制转换
  5. 矩阵转换 相乘 魔方转化 矩阵是不是也可以使用结构体 看到了有使用结构体解决
  6. ecc椭圆曲线加密算法
  7. 得到答案

GetMessageMap处理函数寻找

通过MessageBox寻找

通过od2 设置MessageBox断点,断下来后,我们来看调用栈(这里比较了od1,od2,x32dbg,最终还是od2显示的效果最好!)

之后跟进每一个函数查看函数大致功能,因为真正的处理函数距离MessageBox不会太远

函数40B1A2

可以看到该函数中MessageBox所有的参数都已经确定了,再往前翻
函数40B71C

可以发现失败这一状态,在这个函数前已经确认了,再往前翻:
函数4071FD

可以发现,真正的确认状态的函数就是4071FD,成功找到MessageMap处理函数

通过od1 字符串智能搜索

直接搜到处理函数

通过查找GetMessageMap函数

介绍该方法时,首先要了解两方面的知识:

  1. c++的虚函数表相关知识
  2. MFC消息处理机制

c++ 虚函数表相关知识

c++普遍使用类,虚拟类派生的类都会维护一个虚函数表vtable,并且编译器在编译时会将虚函数表插入到生成的二进制文件中,而且一般存在rodata区块中。该类的每一个实例(对象)会维护一个vptr,即指向虚函数表的指针。大概的空间布局是这样的

类中数据布局
vptr虚表指针
基类数据
类成员

MFC消息处理机制

首先,我们先对MFC的消息映射做一个简单介绍。MFC为了实现消息映射在响应消息的类内部自动做了如下两方面的处理:

a、消息映射声明和实现
在类的定义(头文件)里,添加声明消息映射的宏DECLARE_MESSAGE_MAP,在类的实现(源文件)里,通过BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()实现消息映射。
b、消息响应函数的声明和实现

当通过ClassWizard添加消息响应函数时就会自动添加函数的声明和实现,代码如下:
声明:

//{{AFX_MSG  
afx_msg void OnTimer(UINT nIDEvent);  
afx_msg void OnPaint();  
//}}AFX_MSG  
DECLARE_MESSAGE_MAP()

映射:

BEGIN_MESSAGE_MAP(CTestDialog, CDialog)  
//{{AFX_MSG_MAP(CTestDialog)  
ON_WM_TIMER()  
ON_WM_PAINT()  
//}}AFX_MSG_MAP  
END_MESSAGE_MAP()

实现:

void CTestDialog::OnPaint()   
{  
}    
void CTestDialog::OnTimer(UINT nIDEvent)   
{     
    CDialog::OnTimer(nIDEvent);  
}
void CTestDialog::OnPaint()   
{  
}    
void CTestDialog::OnTimer(UINT nIDEvent)   
{     
    CDialog::OnTimer(nIDEvent);  
}

简单点说就是MFC的类在声明时会调用DECLARE_MESSAGE_MAP()声明消息映射,在生成对象后会映射AFX_MSG_MAP

MFC源码大概是这样的

class CreverseApp : public CWinApp
{
public:
	CreverseApp();
// Overrides
public:
	virtual BOOL InitInstance();
// Implementation
	DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CreverseApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

// CreverseApp construction
CreverseApp::CreverseApp()
{
	// support Restart Manager
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

// The one and only CreverseApp object

CreverseApp theApp;

MFC就是靠这样的机制来处理程序的整个消息的,现在需要理清的就是消息和消息处理函数的映射,其中涉及到主要的两个结构体:

struct AFX_MSGMAP  
{  
    const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); // 基类消息映射入口地址  
    const AFX_MSGMAP_ENTRY* lpEntries;           // 当前类消息映射入口地址  
};

struct AFX_MSGMAP_ENTRY  
{  
    UINT nMessage;   // windows message  
    UINT nCode;      // control code or WM_NOTIFY code  
    UINT nID;        // control ID (or 0 for windows messages)  
    UINT nLastID;    // used for entries specifying a range of control id's  
    UINT_PTR nSig;   // signature type (action) or pointer to message #  
    AFX_PMSG pfn;    // routine to call (or special value)  
};

其中AFX_MSGMAPGetMessageMap函数获取,其最后一个成员直接指向映射关系数组。GetMessagemap函数是个虚函数,每个实现的类的虚函数表都有该函数,我们需要找到对应的窗口类或是对话框类的GetMessageMap函数。而最终的目标就是找到这个映射关系数组,好方便找到对应的消息处理函数

ida中实践寻找映射关系

首先找到MFC开始函数,大概是这样的

.text:00401CBB                 public start
.text:00401CBB                 call    ___security_init_cookie
.text:00401CC0                 jmp     ___tmainCRTStartup

.text:004019FB ___tmainCRTStartup proc near            ; CODE XREF: start+5j
.text:004019FB
.text:004019FB                 push    5Ch
.text:004019FD                 push    offset unk_403DD8
.text:00401A02                 call    __SEH_prolog4
;... other initialization code
.text:00401B3E                 push    ecx             ; nShowCmd
.text:00401B3F                 push    eax             ; lpCmdLine
.text:00401B40                 push    ebx             ; hPrevInstance
.text:00401B41                 push    400000h         ; hInstance
.text:00401B46                 call    _wWinMain@16    ; wWinMain(x,x,x,x)

; int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
_wWinMain@16 proc near
        jmp     ?AfxWinMain@@YGHPAUHINSTANCE__@@0PA_WH@Z ; AfxWinMain(HINSTANCE__ *,HINSTANCE__ *,wchar_t *,int)
_wWinMain@16 endp

再来看看AfxWinMain的源代码

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        _In_ LPTSTR lpCmdLine, int nCmdShow)
{
        ASSERT(hPrevInstance == NULL);

        int nReturnCode = -1;
        CWinThread* pThread = AfxGetThread();
        CWinApp* pApp = AfxGetApp();

        // AFX internal initialization
        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
                goto InitFailure;

        // App global initializations (rare)
        if (pApp != NULL && !pApp->InitApplication())
                goto InitFailure;

        // Perform specific initializations
        if (!pThread->InitInstance())
        {
                if (pThread->m_pMainWnd != NULL)
                {
                        TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
                        pThread->m_pMainWnd->DestroyWindow();
                }
                nReturnCode = pThread->ExitInstance();
                goto InitFailure;
        }
        nReturnCode = pThread->Run();

InitFailure:
        AfxWinTerm();
        return nReturnCode;
}

不同版本的MFC可能会有所区别,但是整体的结构基本不会变,再来对比一下第五题的反汇编代码

; int __stdcall AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
.text:00440E44 _wWinMain@16    proc near               ; CODE XREF: ___tmainCRTStartup+115↑p
.text:00440E44
.text:00440E44 hInstance       = dword ptr  8
.text:00440E44 hPrevInstance   = dword ptr  0Ch
.text:00440E44 lpCmdLine       = dword ptr  10h
.text:00440E44 nShowCmd        = dword ptr  14h
.text:00440E44
.text:00440E44 ; FUNCTION CHUNK AT .text:00417073 SIZE 00000020 BYTES
.text:00440E44
.text:00440E44                 mov     edi, edi
.text:00440E46                 push    ebp
.text:00440E47                 mov     ebp, esp
.text:00440E49                 pop     ebp
.text:00440E4A                 jmp     loc_440E62
.text:00440E4F ; ---------------------------------------------------------------------------
.text:00440E4F
.text:00440E4F ; void __cdecl loc_440E4F()
.text:00440E4F loc_440E4F:                             ; DATA XREF: sub_443CAE+5↓o
.text:00440E4F                 push    1
.text:00440E51                 push    0
.text:00440E53                 call    sub_417001
.text:00440E58                 call    sub_417806
.text:00440E5D                 jmp     loc_417073
.text:00440E62 ; ---------------------------------------------------------------------------
.text:00440E62
.text:00440E62 loc_440E62:                             ; CODE XREF: wWinMain(x,x,x,x)+6↑j
.text:00440E62                 mov     edi, edi
.text:00440E64                 push    ebp
.text:00440E65                 mov     ebp, esp
.text:00440E67                 push    ebx
.text:00440E68                 push    esi
.text:00440E69                 push    edi
.text:00440E6A                 or      ebx, 0FFFFFFFFh
.text:00440E6D                 call    AfxGetModuleThreadState
.text:00440E72                 mov     esi, eax        ; pthread
.text:00440E74                 call    AfxGetModuleState
.text:00440E79                 push    [ebp+nShowCmd]
.text:00440E7C                 mov     edi, [eax+4]
.text:00440E7F                 push    [ebp+lpCmdLine]
.text:00440E82                 push    [ebp+hPrevInstance]
.text:00440E85                 push    [ebp+hInstance]
.text:00440E88                 call    AfxWinInit
.text:00440E8D                 test    eax, eax
.text:00440E8F                 jz      short loc_440ECD
.text:00440E91                 test    edi, edi
.text:00440E93                 jz      short loc_440EA3
.text:00440E95                 mov     eax, [edi]
.text:00440E97                 mov     ecx, edi // edi存储CXXApp对象指针,this
.text:00440E99                 call    dword ptr [eax+0ACh] ; pApp->InitApplication
.text:00440E9F                 test    eax, eax
.text:00440EA1                 jz      short loc_440ECD
.text:00440EA3
.text:00440EA3 loc_440EA3:                             ; CODE XREF: wWinMain(x,x,x,x)+4F↑j
.text:00440EA3                 mov     eax, [esi]
.text:00440EA5                 mov     ecx, esi
.text:00440EA7                 call    dword ptr [eax+50h] ; pThread->InitInstance
.text:00440EAA                 test    eax, eax
.text:00440EAC                 jnz     short loc_440EC4
.text:00440EAE                 cmp     [esi+20h], eax  .text:00440EB1                 jz      short loc_440EBB
.text:00440EB3                 mov     ecx, [esi+20h]
.text:00440EB6                 mov     eax, [ecx]
.text:00440EB8                 call    dword ptr [eax+60h]
.text:00440EBB
.text:00440EBB loc_440EBB:                             ; CODE XREF: wWinMain(x,x,x,x)+6D↑j
.text:00440EBB                 mov     eax, [esi]
.text:00440EBD                 mov     ecx, esi
.text:00440EBF                 call    dword ptr [eax+68h]
.text:00440EC2                 jmp     short loc_440ECB
.text:00440EC4 ; ---------------------------------------------------------------------------
.text:00440EC4
.text:00440EC4 loc_440EC4:                             ; CODE XREF: wWinMain(x,x,x,x)+68↑j
.text:00440EC4                 mov     eax, [esi]
.text:00440EC6                 mov     ecx, esi
.text:00440EC8                 call    dword ptr [eax+54h]
.text:00440ECB
.text:00440ECB loc_440ECB:                             ; CODE XREF: wWinMain(x,x,x,x)+7E↑j
.text:00440ECB                 mov     ebx, eax
.text:00440ECD
.text:00440ECD loc_440ECD:                             ; CODE XREF: wWinMain(x,x,x,x)+4B↑j
.text:00440ECD                                         ; wWinMain(x,x,x,x)+5D↑j
.text:00440ECD                 call    sub_41776C
.text:00440ED2                 pop     edi
.text:00440ED3                 pop     esi
.text:00440ED4                 mov     eax, ebx
.text:00440ED6                 pop     ebx
.text:00440ED7                 pop     ebp
.text:00440ED8                 retn    10h
.text:00440ED8 _AfxWinMain@16    endp ;

这里的InitInstance很重要,其中有CXXDialog的指针,顺着这个指针,我们能够找到第五题中涉及到的窗口处理类的虚函数表

可以先大概看一下InitInstanceMFC中的源码

start -> winmain -> AfxWinMain -> CXXAPP -> CXXDialog

int 2d处理函数寻找

参考

逆向C++虚函数(一)
逆向C++虚函数(二)
MFC 消息映射机制详解

@xinali xinali added the crackme label Feb 27, 2018
@xinali xinali changed the title 看雪腾讯ctf第五题(太难了,有时间补充吧。。。) 看雪腾讯ctf第五题(待完善) Dec 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant