首页
社区
课程
招聘
[原创]x64dbg插件编写基础
发表于: 2023-2-12 02:44 16454

[原创]x64dbg插件编写基础

2023-2-12 02:44
16454

x64dbg 手册:https://help.x64dbg.com/en/latest/developers/index.html

x64dbg扩展功能的方式有三种:

在x64dbg的文档中并没有说明 "插件" 到底是一个什么东西,只是说插件的后缀名叫dp32或者dp64,通过观察其他的插件发现其实就是DLL,只不过是导出了一些指定函数的DLL

本文的目的就是说明编写x64dbg插件的步骤,然后编写一个简单的x64dbg插件

本机环境:win11 21h2、vs2022、x64dbg(snapshot_2023-01-25_11-53)

要给x64dbg编写插件肯定需要x64dbg提供的sdk包,sdk包就在x64dbg的根目录之下的pluginsdk文件夹中:

在pluginsdk中有x64dbg自己提供的头文件和lib文件,以及它使用的其他第三方库的头文件和lib文件,比如XEDParse、TitanEngine等

先创建一个VS的DLL工程,这一步不必多说

将整个pluginsdk文件夹拷贝到工程目录之下,虽然多了很多东西,但是比少拷贝了文件去找要好

然后配置头文件目录和lib文件的目录以及引入lib文件:

函数声明:

pluginit函数是x64dbg插件必须导出的一个函数

在整个函数中,要做的事件就是填充参数initStruct:

所以在pluginit中要做的事情就是填写插件的基本信息:

这两个导出函数不是必须的,但是可以在里面做一些事情:

本例在plugsetup中添加了两个子菜单,代码如下:

当我们添加了插件的子菜单之后,要如何响应菜单的点击呢?

导出以CB开头的函数就可以去接收到对应的事件,比如

参数中所用到的结构体可以在这里找到:https://help.x64dbg.com/en/latest/developers/plugins/Callbacks/index.html,只要是满足CB*的导出函数,且属于这里面的类型https://help.x64dbg.com/en/latest/developers/plugins/API/registercallback.html,应该都可以注册成功,注意函数名中不要有下划线

本例中,我们只需要简单的响应一下子菜单的点击:

在插件中,我们可以调用Dbg开头的函数来辅助功能,函数列表:https://help.x64dbg.com/en/latest/developers/functions/debug/index.html

比如读写被调试进程可以使用

其他功能就暂时还没探索,本例中用这两个就够啦

本例中的插件需要实现对UnhandledExceptionFilter打补丁的功能,实现调试器可以调试UEH回调

下面是小弟的通过测试的一点浅薄理解,没有跟踪系统的代码,如有不对的地方还请大佬们指出

应用层派发异常的流程大致如下:

根据上面的流程图,在异常从SEH中出来的时候,根据是否有调试器,要么派发给调试器,要么派发给UEH回调,二选一,所以在调试的过程中不会之下UEH回调的代码

为了能在调试器中调试UEH回调,我们需要改变一下系统异常分发的流程,使其走到另一个分支去

这个分支出现在kernelbase/kernel32!UnhandledExceptionFilter 中,所以需要对其打补丁

剩下的步骤就很简单了,首先在插件初始化时,判断系统版本,获取UnhandledExceptionFilter 的地址,通过特征码找到需要打补丁的地址

然后响应菜单事件,当点击EnableUeh时,打补丁,点击DisableUeh时,恢复补丁

一个简单的插件框架就这样完成了

 
 
├───pluginsdk
│   ├───dbghelp
│   ├───DeviceNameResolver
│   ├───jansson
│   ├───lz4
│   ├───TitanEngine
│   └───XEDParse
└───release
    ├───...
├───pluginsdk
│   ├───dbghelp
│   ├───DeviceNameResolver
│   ├───jansson
│   ├───lz4
│   ├───TitanEngine
│   └───XEDParse
└───release
    ├───...
 
 
extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct);
extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct);
 
struct PLUG_INITSTRUCT
{
    [IN] int pluginHandle; //插件的句柄
    [OUT] int sdkVersion; //填 PLUG_SDKVERSION 即可
    [OUT] int pluginVersion; // 填插件的版本
    [OUT] char pluginName[256]; // 填插件指针
};
struct PLUG_INITSTRUCT
{
    [IN] int pluginHandle; //插件的句柄
    [OUT] int sdkVersion; //填 PLUG_SDKVERSION 即可
    [OUT] int pluginVersion; // 填插件的版本
    [OUT] char pluginName[256]; // 填插件指针
};
//必需的,插件初始化函数
extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT * initStruct)
{
    _plugin_logprintf("[%s] pluginit\r\n", TAG);//打印日志
 
    memcpy_s(
        initStruct->pluginName,
        sizeof(initStruct->pluginName),
        TAG,
        strlen(TAG));
    initStruct->sdkVersion = PLUG_SDKVERSION;
    initStruct->pluginVersion = 1;
 
    if (!InitPlugin())//做一些初始化动作
    {
        _plugin_logprintf("[%s] pluginit Failed\r\n", TAG);//打印日志
        return false;
    }
    return true;
}
//必需的,插件初始化函数
extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT * initStruct)
{
    _plugin_logprintf("[%s] pluginit\r\n", TAG);//打印日志
 
    memcpy_s(
        initStruct->pluginName,
        sizeof(initStruct->pluginName),
        TAG,
        strlen(TAG));
    initStruct->sdkVersion = PLUG_SDKVERSION;
    initStruct->pluginVersion = 1;
 
    if (!InitPlugin())//做一些初始化动作
    {
        _plugin_logprintf("[%s] pluginit Failed\r\n", TAG);//打印日志
        return false;
    }
    return true;
}
//非必需,插件被移除时调用
extern "C" __declspec(dllexport) bool plugstop()
{
    _plugin_logprintf("[%s] plugstop\r\n", TAG);
    return true;
}
 
//非必需,启动插件时调用
//在这里执行UI操作,比如增加菜单
extern "C" __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT * setupStruct)
{
    _plugin_logprintf("[%s] plugsetup\r\n", TAG);
 
    //添加子菜单
    _plugin_menuaddentry(setupStruct->hMenu, 0, "enable UEH");
    _plugin_menuaddentry(setupStruct->hMenu, 1, "disable UEH");
}
//非必需,插件被移除时调用
extern "C" __declspec(dllexport) bool plugstop()
{
    _plugin_logprintf("[%s] plugstop\r\n", TAG);
    return true;
}
 
//非必需,启动插件时调用
//在这里执行UI操作,比如增加菜单
extern "C" __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT * setupStruct)
{
    _plugin_logprintf("[%s] plugsetup\r\n", TAG);
 
    //添加子菜单
    _plugin_menuaddentry(setupStruct->hMenu, 0, "enable UEH");
    _plugin_menuaddentry(setupStruct->hMenu, 1, "disable UEH");
}
 
extern "C" __declspec(dllexport) void CBINITDEBUG(CBTYPE cbType, PLUG_CB_INITDEBUG* info); //初始化调试
extern "C" __declspec(dllexport) void CBSTOPDEBUG(CBTYPE cbType, PLUG_CB_STOPDEBUG* info); //停止调试
extern "C" __declspec(dllexport) void CBEXCEPTION(CBTYPE cbType, PLUG_CB_EXCEPTION* info); //异常
extern "C" __declspec(dllexport) void CBDEBUGEVENT(CBTYPE cbType, PLUG_CB_DEBUGEVENT* info); //调试事件
extern "C" __declspec(dllexport) void CBMENUENTRY(CBTYPE cbType, PLUG_CB_MENUENTRY* info); //点击子菜单
extern "C" __declspec(dllexport) void CBINITDEBUG(CBTYPE cbType, PLUG_CB_INITDEBUG* info); //初始化调试
extern "C" __declspec(dllexport) void CBSTOPDEBUG(CBTYPE cbType, PLUG_CB_STOPDEBUG* info); //停止调试
extern "C" __declspec(dllexport) void CBEXCEPTION(CBTYPE cbType, PLUG_CB_EXCEPTION* info); //异常
extern "C" __declspec(dllexport) void CBDEBUGEVENT(CBTYPE cbType, PLUG_CB_DEBUGEVENT* info); //调试事件
extern "C" __declspec(dllexport) void CBMENUENTRY(CBTYPE cbType, PLUG_CB_MENUENTRY* info); //点击子菜单
 
//菜单响应回调
extern "C" __declspec(dllexport) void CBMENUENTRY(
    CBTYPE bType,
    PLUG_CB_MENUENTRY * pEntry
)
{
    switch (pEntry->hEntry)
    {
    case 0:    //注册时填的菜单ID
        EnableUeh();
        break;
    case 1:
        DisableUeh();
        break;
    default:
        break;
    }
}
//菜单响应回调
extern "C" __declspec(dllexport) void CBMENUENTRY(
    CBTYPE bType,
    PLUG_CB_MENUENTRY * pEntry
)
{
    switch (pEntry->hEntry)
    {
    case 0:    //注册时填的菜单ID
        EnableUeh();
        break;
    case 1:
        DisableUeh();
        break;
    default:
        break;
    }
}
 
bool DbgMemRead(
  duint va,
  void* dest,
  duint size
  );
 
bool DbgMemWrite(
duint va,
void* dest,
duint size
);
bool DbgMemRead(
  duint va,

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-2-12 03:37 被st0ne编辑 ,原因: 编辑错了
上传的附件:
收藏
免费 19
支持
分享
最新回复 (8)
雪    币: 3751
活跃值: (3156)
能力值: ( LV8,RANK:147 )
在线值:
发帖
回帖
粉丝
2
磊哥牛逼
2023-3-26 21:46
0
雪    币: 2161
活跃值: (4182)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
Roger哥牛逼
2023-3-26 22:45
0
雪    币: 2161
活跃值: (4182)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
Roger 磊哥牛逼[em_63]
Roger哥牛逼
2023-3-26 23:02
0
雪    币: 2161
活跃值: (4182)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
5
st0ne Roger哥牛逼[em_60]
我擦,评论好像删不掉?
2023-3-26 23:03
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
2023-3-27 16:33
0
雪    币: 10384
活跃值: (2860)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
7
卷王最近高产啊
2023-4-12 22:01
0
雪    币: 2161
活跃值: (4182)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
minorory 卷王最近高产啊
大诗人!!
2023-4-12 23:48
0
雪    币: 18
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
没用的 最好方法是下载官方提供的例子  不然抗死你  听我的 
2023-4-28 18:15
0
游客
登录 | 注册 方可回帖
返回
//