DuiLib逆向分析の按钮事件定位

0x00 前言

记录自己学习Duilib逆向分析的笔记。

DuiLib介绍

DuiLib官方介绍,Duilib是一个Windows下免费开源的DirectUI界面库,由于简约易扩展的设计以及稳定高效的实现被各大互联网公司普遍接受,广泛应用于包括IM、视频客户端、股票行情软件、导航软件、手机辅助软件、安全软件等多个行业的众多pc客户端软件。Duilib还在不断的发展中,在文档、例子、动画、渲染引擎等多个方面将持续改进。

DirectUI介绍,直接在父窗口上绘图,构建易于扩展的界面。(DirectUI意为直接在父窗口上绘图(Paint on parent dc directly)。即子窗口不以窗口句柄 的形式创建(windowless),只是逻辑上的窗口,绘制在父窗口之上。)

Duilib是一个自绘控件界面库,可以很方便的构建高效,绚丽的,非常易于扩展的界面。

国外如微软,国内如腾讯百度等公司的客户端产品多采用这种方式来组织界面,从而很好的将界面和逻辑分离,同时易于实现各种超炫的界面效果如换色,换肤,透明等。

DuiLib安装

安装DuiLib推荐用C++库管理器vcpkg来安装,这东西我感觉类似Python的pip。可以很方便的安装管理第三方库

vcpkg官方安装教程,安装vcpkg非常简单,就如下几条命令就搞定:

1
2
3
4
5
6
7
git clone https://github.com/microsoft/vcpkg
#将vcpkg目录添加到环境变量
RefreshEnv.cmd #更新环境变量
bootstarp-vcpkg.bat #vcpkg初始化相关文件
vcpkg integrate install #配置到VS相关环境中
vcpkg search [库名] #搜索相关第三方库
vcpkg install [库名] #安装第三方库

安装DuiLib库:

1
vcpkg install DuiLib #安装DuiLib库

DuiLib Hello,World!

装好了库后,我们来写第一个DuiLib程序,经典的Hello,World!

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
42
43
44
45
46
47
//DuiLib库头文件
#include <DuiLib/UILib.h>
//命名空间
using namespace DuiLib;

//重写Windows窗口类,继承自->CWindow -> INotifyUI
class CDuilibWnd : public CWindowWnd,public INotifyUI
{

public:
//虚函数
virtual LPCTSTR GetWindowClassName() const {return _T("DuiWnd");}//窗口类
//重写响应消息
virtual void Notify(TNotifyUI& msg)
{
if(msg.sType == _T("click"))
{
if(msg.pSender->GetName() == _T("Hello_btn"))
{
MessageBoxA(NULL,"Hello,World!","Dui逆向の按钮事件定位",MB_OK);
}
}
}
//重写消息处理
virtual LRESULT HandleMessage(UINT uMsg,WPARAM wParam,LPARAM lParam)//回调函数
{
LRESULT lRes = 0;
if(uMsg == WM_CREATE)
{
m_PaintManager.Init(m_hWnd);
//利用XML布局生成界面
CDialogBuilder builder;
CControlUI* pRoot = builder.Create(_T("duilib.xml"),0,NULL,&m_PaintManager);
ASSERT(pRoot && "Failed to parse XML");
m_PaintManager.AttachDialog(pRoot);
//用于处理消息
m_PaintManager.AddNotifier(this);
return lRes;
}
if(m_PaintManager.MessageHandler(uMsg,wParam,lParam,lRes)) return lRes;
return __super::HandleMessage(uMsg,wParam,lParam);
}

protected:
CPaintManagerUI m_PaintManager;
}

1
2
3
4
5
6
7
8
9
10
int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
CPaintManagerUI::SetInstance(hInstance);//绑定窗口句柄
CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());//加载XML
//创建并显示窗口
CDuilibWnd duilibWnd;
duilibWnd.Create(NULL,_T("Dui逆向の按钮事件定位"),UI_WNDSTYLE_FRAME,WS_EX_WINDOWEDGE);
duilibWnd.ShowModal();//监听消息
return 0;
}

duilib.xml 界面布局文件

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<Window size="320,100">
<HorizontalLayout bkcolor="#FFFFFFFF">
<Button name="Hello_btn" text="按钮" height="40" width="80" bordersize="1,1,1,1" bordercolor="#0079DE" padding="111,10,0,0"/>
</HorizontalLayout>
</Window>

编译生成后的界面如下,并且点击按钮后触发了事件:

image-20211210141430317

Duilib逆向分析之定位按钮事件

碎碎念

所以我觉得做逆向开发,不能盲目的一开始就去看OD,去IDA F5反编译,而是应该擅长利用搜索引擎去学习了解相关:框架、库、模型、开发等知识,有了这些知识后逆向就如鱼得水。

第一步:获取xml布局文件

首先切入点是从duilib.xml文件开始,所以我们在逆向Duilib相关程序时候应该先拿到他的布局文件。

而在我们的demo中duilib.xml是在本地的,而在源码中可以看到builder.Create来加载使用duilib.xml

image-20211210142047876

如果xml在本地的话则很简单直接找到路径即可,但是常规逆向分析中基本都是在内存中的,那这种要如何获取到他的xml布局文件呢?

思路还是一样,先定位到这个builder.Create函数,然后跟进去一步步调试,看堆栈信息,看经过哪一句汇编代码或Call后出现xml内容。

image-20211210150307646

第二步:按钮事件分金点穴

当我们拿到布局后,找到对应按钮的名称,例子中的按钮对应的名称是Hello_btn,然后去调试软件中搜索相关字符串Hello_btn

image-20211210150422786

并且下上断点。

image-20211210150543271

当我们点击按钮后,成功的断到如下位置:

image-20211210150711936

111

断点断到后,查看上下文中的汇编就已经很明显了,在je下面 (je那一句是判断当前btn按钮事件是否是Hello_btn的按钮事件),对应的源码就是:

1
2
3
4
if(msg.pSender->GetName() == _T("Hello_btn"))
{
MessageBoxA(NULL,"Hello,World!","Dui逆向の按钮事件定位",MB_OK);
}

感谢观看我的笔记,如有问题请指出谢谢。

逆向、PWN学习交流

Pwn菜鸡学习小分队群聊二维码