有时候,缘份是件很奇怪的东西。话说,半月前,在看雪上发现一作者写的《x64dbg插件编写基础》,觉得很好。因为我不写插件,所以也没有想法,当时时只是看了看,但印象很深。
今天搜索资料时,发现我的硬盘里静静地躺着个x64dbg的插件源码,看文件生成时间是2021年,是不是很巧了?既然碰上了,就顺便打开对照着学习一番吧。
结合作者给出的内容,作简单的笔记,梳理如下:
1、x64dbg提供的sdk包在x64dbg的pluginsdk文件夹中,要将整个pluginsdk文件夹拷贝到工程目录之下;
2、配置头文件目录和lib文件的目录以及引入lib文件:
在工程属性->vc++目录->外部包含目录加入pluginsdk路径
在工程属性->vc++目录->库目录加入pluginsdk路径
在工程属性->链接器->输入->附加依赖项中添加 x32bridge.lib和x32dbg.lib,这也是pluginsdk下唯二的两个lib。
3、涉及到的函数:
(1)主函数
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
)
{
return TRUE;
}
(2)pluginit
pluginit函数是x64dbg插件必须导出的一个函数
在整个函数中,要做的事件就是填充参数initStruct:
PLUG_EXPORT bool pluginit(PLUG_INITSTRUCT* initStruct)
{
initStruct->pluginVersion = PLUGIN_VERSION;
initStruct->sdkVersion = PLUG_SDKVERSION;
strncpy_s(initStruct->pluginName, PLUGIN_NAME, _TRUNCATE);
pluginHandle = initStruct->pluginHandle;
return pluginInit(initStruct);
}
(3)plugstop和plugsetup
这两个导出函数不是必须的,但是可以在里面做一些事情:
plugstop:插件被移除的时候被调用,可以用来清除注册的回调和命令,清理资源
plugsetup:当插件初始化成功的时候调用,可以在这里添加菜单、做其他的界面相关的事情。
本例在plugsetup中添加了两个子菜单,代码如下:
PLUG_EXPORT bool plugstop()
{
return pluginStop();
}
//Deinitialize your plugin data here (clearing menus optional).
bool pluginStop() //插件卸载时要干的事,一般是卸载回调,也就是x32dbg调用
{
return true;
}
================
PLUG_EXPORT void plugsetup(PLUG_SETUPSTRUCT* setupStruct)
{
hwndDlg = setupStruct->hwndDlg;
hMenu = setupStruct->hMenu;
hMenuDisasm = setupStruct->hMenuDisasm;
hMenuDump = setupStruct->hMenuDump;
hMenuStack = setupStruct->hMenuStack;
int TopHandle=_plugin_menuadd(hMenu, PLUGIN_NAME);
//一级菜单,就是插件名,没有这句代码无法显示设置的PLUGIN_NAME,返回顶层菜单句柄,二级菜单需要这个句柄
_plugin_menuaddentry(hMenu, 0, "插件菜单中的二级菜单");
//插件菜单二级菜单名
int DismTopHandle=_plugin_menuadd(hMenuDisasm, PLUGIN_NAME);
//反汇编窗口的右键菜单,没有这句无法显示PLUGIN_NAME,返回顶层菜单句柄,二级菜单需要这个句柄
_plugin_menuaddentry(hMenuDisasm, 1, "反汇编窗口中的二级菜单");
//反汇编窗口右键二级菜单名
//_plugin_registercallback(pluginHandle, PLUG_CB_MENUENTRY, MyEntry) 注册事件的回调,第二个参数是类型,当出现第二个参数的类型事件的时候就调用MyEntry函数
pluginSetup();
}
//Do GUI/Menu related things here.
void pluginSetup()
//初始化完成以后要干的事,一般是注册插件菜单以及二级菜单
{
}
===========
void MyEntry(CBTYPE CbType, void* callbackInfo)
//我自己的注册事件的回调
{
}
PLUG_EXPORT void CBMENUENTRY(CBTYPE cbType, PLUG_CB_MENUENTRY* info)
//插件回调函数,就是你点了插件上面的哪个二级菜单就会调用此处,info是菜单号,由_plugin_menuaddentry的第二个参数控制
{
//比如上面我注册的插件号是1,那么info为1的话就说明我点击了反汇编窗口的二级菜单这个功能
int eip = Script::Register::GetEIP();
//获得EIP
int esp = Script::Register::GetESP();
//获得ESP
if (eip!=0 && esp!=0 )
{
}
}
(4)事件回调函数
当我们添加了插件的子菜单之后,要如何响应菜单的点击呢?
导出以CB开头的函数就可以去接收到对应的事件,比如
PLUG_EXPORT void CBINITDEBUG(CBTYPE cbType, PLUG_CB_INITDEBUG* info)
{
}
PLUG_EXPORT void CBTRACEEXECUTE(CBTYPE cbType, PLUG_CB_TRACEEXECUTE* info)
{
}
参数中所用到的结构体可以在这里找到:https://help.x64dbg.com/en/latest/developers/plugins/Callbacks/index.html,只要是满足CB*的导出函数,且属于这里面的类型https://help.x64dbg.com/en/latest/developers/plugins/API/registercallback.html,应该都可以注册成功,注意函数名中不要有下划线。
4、以上举例的代码,放在如下:
链接:https://pan.baidu.com/s/1zl6JUW2eK0YNN1c7k388Ag
提取码:z6k4
5、给一个github上非常好的插件源码例子
链接:https://pan.baidu.com/s/1nP7myiOPWhnRZGUGA-H6rA
提取码:9yhp