x64dbg 插件开发指南:DbgDelEncodeTypeRange 删除编码类型范围
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
DbgDelEncodeTypeRange是 x64dbg 调试器向插件与 GUI 层开放的核心 Bridge API 之一,用于批量清除指定内存地址区间内的"编码类型"(EncodeType)标记。本文以 DbgDelEncodeTypeRange.md 为骨架,结合 src/bridge/bridgemain.cpp、src/dbg/encodemap.cpp 与 src/gui/Src/Utils/EncodeMap.cpp 等源码,完整讲解该 API 的声明、参数语义、返回行为、底层调用链与实战调用场景。读完本文,你将掌握如何在插件中用该 API 精确撤销一段内存上已被标记的数据类型(字节、字、双字、结构体等),并理解它与DbgSetEncodeType、DbgGetEncodeTypeAt等配套 API 的协作方式。
一、函数签名与声明位置
在 x64dbg 的 Bridge 层(GUI 与调试核心之间的通信层),该函数的导出声明位于 src/bridge/bridgemain.h:
BRIDGE_IMPEXP void DbgDelEncodeTypeRange(duint start, duint end);其实现位于 src/bridge/bridgemain.cpp:
BRIDGE_IMPEXP void DbgDelEncodeTypeRange(duint start, duint end) { _dbg_sendmessage(DBG_DELETE_ENCODE_TYPE_RANGE, (void*)start, (void*)end); }从声明可以看出两个要点:
- 返回类型为
void:该 API 不向调用方返回成功/失败标志,删除操作是"尽力而为"的广播式调用; - 参数为两个
duint地址:duint是 x64dbg 定义的无符号整数类型(duint= Debug Unsigned INT,在 32 位构建下为 32 位、64 位构建下为 64 位),因此该 API 天然同时支持 32 位与 64 位目标进程的地址空间。
duint的完整定义可查阅 src/dbg/_global.h 及 src/bridge/bridgemain.h 顶部的类型重定义,它是 x64dbg 所有 Bridge 地址类参数的标准类型。
二、参数语义:闭区间 [start, end]
start:要删除编码类型标记的起始虚拟地址;end:要删除编码类型标记的结束虚拟地址(包含该地址本身)。
即该 API 操作的地址范围是闭区间[start, end],长度len = end - start + 1。这一点在调试核心的实现中有直接佐证——src/dbg/encodemap.cpp:
void EncodeMapDelRange(duint Start, duint End) { if(End < Start) return; EncodeMapSetType(Start, End - Start + 1, enc_unknown); }注意两个行为细节:
- 参数顺序校验:若
End < Start,函数直接返回,不执行任何删除操作(安全兜底,不会产生异常行为); - 本质是"覆盖为 unknown":删除操作并非物理移除记录,而是将区间内每个地址的编码类型统一覆盖为
enc_unknown,随后由编码映射的底层存储机制进行回收与维护。
三、返回行为与调用约定
DbgDelEncodeTypeRange返回void,因此:
- 调用方无法直接判断删除是否成功;
- 调用后如需确认结果,应使用配套查询 API
DbgGetEncodeTypeAt(duint addr, duint size)(见 src/bridge/bridgemain.cpp),检查目标地址的编码类型是否已回落为enc_unknown。
该函数可以在目标进程暂停状态下安全调用(这也是 x64dbg 插件 API 的普遍约定——大多数调试状态修改类 API 需要进程处于暂停/调试会话中)。它通过_dbg_sendmessage将请求投递给调试核心线程处理,属于异步消息式的 Bridge 调用,调用线程不会阻塞等待核心端的同步完成。
四、底层调用链与核心实现
整条调用链可以概括为:
插件/GUI 调用 DbgDelEncodeTypeRange(start, end) → _dbg_sendmessage(DBG_DELETE_ENCODE_TYPE_RANGE, start, end) → 调试核心消息分发(src/dbg/_exports.cpp 中的主分发函数) → EncodeMapDelRange(start, end) → EncodeMapSetType(start, end - start + 1, enc_unknown) → 编码映射(encmaps)哈希表更新4.1 Bridge 消息分发
在调试核心的消息分发器 src/dbg/_exports.cpp 中:
case DBG_DELETE_ENCODE_TYPE_RANGE: { EncodeMapDelRange((duint)param1, (duint)param2); } break;DBG_DELETE_ENCODE_TYPE_RANGE消息将两个duint地址透传给核心实现EncodeMapDelRange。
4.2 编码映射的核心数据结构
编码映射(EncodeMap)是 x64dbg 用于记录"每个内存地址被解释为什么数据类型"的全局映射表,属于调试核心 src/dbg/encodemap.cpp 模块。其底层为一个以模块基址为键的哈希表(encmaps),每个条目对应一个内存区域,区域内的每个字节保存一个ENCODETYPE枚举值:
enc_unknown:未知/未标记(默认状态);enc_byte、enc_word、enc_dword、enc_qword、enc_fword、enc_tbyte等:整型数据类型;enc_float、enc_double、enc_longdouble、enc_mmword、enc_xmmword、enc_ymmword:浮点与 SIMD 类型;enc_ascii、enc_unicode:字符串类型;enc_code:代码;enc_junk:垃圾数据;enc_middle:指令中间字节。
ENCODETYPE枚举的完整定义见 src/dbg/encodemap.h,它是 x64dbg 数据区(dump 视图)按类型渲染的根本依据。
4.3 删除即"覆盖为 enc_unknown"
EncodeMapDelRange的实现非常简洁:校验End >= Start后,把区间长度End - Start + 1连同enc_unknown一起交给EncodeMapSetType。这意味着删除标记与设置标记走的是同一条底层写入路径,区别仅在于写入的目标类型是enc_unknown。从数据结构层面看,区间删除的复杂度与区间内地址数量相关,因为需要逐地址更新映射条目。
五、实战示例:如何在插件中调用
5.1 基础用法
在插件代码中(需#include "bridgemain.h"),清除0x401000到0x4010FF(共 256 字节)的编码类型:
#include "bridgemain.h" void ClearTypeMark(duint startAddr, duint size) { if(size == 0) return; DbgDelEncodeTypeRange(startAddr, startAddr + size - 1); } // 示例调用:清除 0x401000 起的 256 字节 ClearTypeMark(0x401000, 0x100);注意与EncodeMap::delRange(GUI 侧封装,见 src/gui/Src/Utils/EncodeMap.cpp)保持一致的换算方式——它传入的是(start, start + size - 1):
void EncodeMap::delRange(duint start, duint size) { if(size) DbgDelEncodeTypeRange(start, start + size - 1); }即:调用方负责把"起始地址 + 长度"换算成闭区间端点,API 内部不做长度换算。
5.2 配合查询 API 验证删除结果
删除后可用DbgGetEncodeTypeAt验证(返回enc_unknown即删除成功):
#include "bridgemain.h" bool VerifyRangeCleared(duint start, duint size) { for(duint i = 0; i < size; i++) { if(DbgGetEncodeTypeAt(start + i, 1) != enc_unknown) return false; } return true; }5.3 典型使用场景
- 撤销误标记:当分析过程中对一段内存错误地设置了类型标记(例如误标为结构体或字符串),可用该 API 一键还原为
enc_unknown,再重新标记; - 重新分析区域:配合
analyse/cfanalyse类分析命令,先清除旧标记、再重新执行分析,避免陈旧类型信息干扰; - 数据区(dump)刷新:GUI 侧
EncodeMap::delRange在用户"清除数据类型"操作时被调用,之后数据视图会依据更新后的编码映射重新渲染(getDataType/getDataSize读取映射结果,见 src/gui/Src/Utils/EncodeMap.cpp)。
六、与配套 API 的关系
DbgDelEncodeTypeRange属于 x64dbg 编码类型(EncodeType)API 家族,相关函数均定义在 src/bridge/bridgemain.h 中,共享相同的 Bridge 消息机制:
| API | 作用 | Bridge 消息 |
|---|---|---|
DbgSetEncodeType(addr, size, type) | 为区间设置编码类型 | _dbg_encodetypeset(见 src/bridge/bridgemain.cpp) |
DbgGetEncodeTypeAt(addr, size) | 查询某地址的编码类型 | DBG_ENCODE_TYPE_GET |
DbgGetEncodeSizeAt(addr, codesize) | 查询某地址的编码尺寸 | DBG_ENCODE_SIZE_GET |
DbgDelEncodeTypeRange(start, end) | 删除(清除)闭区间编码类型 | DBG_DELETE_ENCODE_TYPE_RANGE |
DbgDelEncodeTypeSegment(start) | 删除某段(模块段)的全部编码类型 | DBG_DELETE_ENCODE_TYPE_SEG(见 src/bridge/bridgemain.cpp) |
DbgGetEncodeTypeBuffer/DbgReleaseEncodeTypeBuffer | 获取/释放编码类型缓存缓冲区 | DBG_GET_ENCODE_TYPE_BUFFER/DBG_RELEASE_ENCODE_TYPE_BUFFER |
几点使用建议:
- 区间粒度 vs 段粒度:只清除一小段地址范围用
DbgDelEncodeTypeRange;要清空整个段(如卸载模块时)用DbgDelEncodeTypeSegment,后者更高效; - GUI 侧缓存同步:GUI 的
EncodeMap类维护了按需加载的内存缓存(mBuffer),当删除区间落在缓存范围内时(va >= mBase && va < mBase + mSize),需要调用DbgReleaseEncodeTypeBuffer释放失效缓存(参见 src/gui/Src/Utils/EncodeMap.cpp 中delSegment的处理方式)。插件若直接调用 Bridge API,则需自行保证与自身缓存的一致性; - 调试核心侧消息分发:插件开发者如要实现自定义调试核心扩展,需在核心消息分发器中处理
DBG_DELETE_ENCODE_TYPE_RANGE消息(参考 src/dbg/_exports.cpp 的 case 分支)。
七、总结
DbgDelEncodeTypeRange是 x64dbg 编码类型管理体系中用于"批量撤销标记"的原子操作,其核心语义可归纳为:
- 参数为闭区间
[start, end],end < start时安全返回; - 返回
void,删除结果需用DbgGetEncodeTypeAt验证; - 底层通过
DBG_DELETE_ENCODE_TYPE_RANGE消息到达调试核心,最终由EncodeMapDelRange将区间覆盖为enc_unknown(见 src/dbg/encodemap.cpp); - 与
DbgSetEncodeType、DbgGetEncodeTypeAt、DbgDelEncodeTypeSegment等 API 配合,可完整覆盖"标记 → 查询 → 局部清除 → 整段清除"的数据类型管理闭环。
对于编写逆向分析辅助插件的开发者而言,掌握该 API 即可精确控制数据区视图的类型渲染,是构建"可重入分析"、"动态数据类型推断"类插件的基础能力之一。
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考