articles icon indicating copy to clipboard operation
articles copied to clipboard

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

Open xinali opened this issue 6 years ago • 0 comments

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 avatar Feb 27 '18 12:02 xinali