x64dbg SizeofType 命令详解:查询类型位宽并驱动脚本自动化
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
SizeofType是 x64dbg 类型(Types)命令族中的查询类命令,用于获取当前类型数据库中任意类型(原始类型、别名、结构体、联合体、枚举、函数指针)的位宽(bit size),并将结果写入脚本变量$result,供后续脚本逻辑直接使用。本指南以 docs/commands/types/SizeofType.md 为核心,结合 types.cpp 与 cmd-types.cpp 的源码实现,说明命令的语法、结果语义、底层查找逻辑与典型应用场景。读完本文,你将能在脚本与命令行中准确获取任意自定义类型的尺寸,并理解"位宽以 bit 计"这一关键语义。
命令概览
SizeofType是类型操作命令族(见 docs/commands/types/index.rst)中的一员,与AddType、AddStruct、AddUnion、AddMember、AppendMember、AddFunction、AddArg、AppendArg、VisitType、ClearTypes、RemoveType、EnumTypes、LoadTypes、ParseTypes同组注册,在 x64dbg.cpp 中通过dbgcmdnew("SizeofType", cbInstrSizeofType, false)挂载到命令系统。
语法
SizeofType arg1参数
| 参数 | 含义 |
|---|---|
arg1 | 要查询的类型名称(type name),例如int32、duint、自定义结构体名等 |
结果
命令执行成功后会将类型尺寸写入脚本变量$result,单位是bit(位),而非字节(byte)。若类型不存在或无法解析,命令会打印SizeofType failed并返回失败,$result不会被更新。
基本用法与示例
在 x64dbg 命令行或脚本中直接执行:
SizeofType int32日志区输出:
sizeof(int32) = 32随后在脚本中即可通过$result取用该值:
SizeofType duint // x64 构建下输出 sizeof(duint) = 64,$result 被置为 64再结合类型定义命令使用,可对自定义结构体求尺寸。例如先用AddStruct/AddMember定义一个结构体:
AddStruct MY_STRUCT AddMember MY_STRUCT int32 field_a AddMember MY_STRUCT uint8 field_b SizeofType MY_STRUCT由于结构体尺寸是成员尺寸的累加(见下文实现解析),$result将得到40(即32 + 8bit)。这类查询非常适合在自动化脚本中动态计算缓冲区大小、结构体长度或做内存布局校验。
源码实现深度解析
1. 命令处理函数
SizeofType的命令处理函数位于 cmd-types.cpp:
bool cbInstrSizeofType(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 2)) return false; auto size = SizeofType(argv[1]); if(!size) { dputs(QT_TRANSLATE_NOOP("DBG", "SizeofType failed")); return false; } dprintf_untranslated("sizeof(%s) = %d\n", argv[1], size); varset("$result", size, false); return true; }关键逻辑有三点:
- 参数不足(少于 2 个参数,即缺类型名)直接失败;
- 调用全局 API
SizeofType,返回值为 0 视为"类型不存在/解析失败",打印SizeofType failed; - 成功时以
sizeof(<类型>) = <数值>格式输出,并通过varset("$result", size, false)写入$result脚本变量。
2. 全局 API 与线程安全
全局函数SizeofType定义于 types.cpp,它通过SHARED_ACQUIRE(LockTypeManager)以共享锁方式读取类型管理器,避免与并发的类型增删操作冲突:
int SizeofType(const std::string & type) { SHARED_ACQUIRE(LockTypeManager); return typeManager.Sizeof(type); }该函数在 types.h 中声明,可被插件等其他模块直接调用。内部核心实现是TypeManager::Sizeof(见 types.cpp)。
3. 核心查找逻辑TypeManager::Sizeof
TypeManager::Sizeof按以下顺序解析类型并返回位宽:
| 类型形态 | 返回值 | 说明 |
|---|---|---|
指针类型(类型名以*结尾) | primitiveSizes[Pointer] * 8 | 返回指针本身大小,即sizeof(void*)对应的位数(x64 下为 64,x86 下为 32),与指向的目标类型无关 |
| Typedef / 别名 | 递归调用Sizeof(alias) | 别名指向的类型继续解析,直到基础类型 |
| 枚举(Enum) | enum.sizeBits | 枚举自身的位宽 |
| 结构体 / 联合体(Struct/Union) | struct.sizeBits | 累加(结构体)或取最大值(联合体)后的位宽 |
| 函数(Function) | primitiveSizes[Pointer] * 8 | 函数类型按函数指针大小处理 |
| 其他 / 未找到 | 0 | 触发命令失败分支 |
需要特别注意的是:所有sizeBits均以 bit 为单位存储。原始类型在初始化时即做了换算(t.sizeBits = primitiveSizes[primitive] * 8,见 types.cpp),因此SizeofType int32返回 32 而非 4。
4. 原始类型尺寸表
类型管理器的构造函数(types.cpp)注册了全部内建原始类型及其别名,这是SizeofType能够直接查询的基础:
| 类型别名 | 尺寸(bit) |
|---|---|
int8_t, int8, char, byte, bool, signed char | 8 |
uint8_t, uint8, uchar, unsigned char, ubyte | 8 |
int16_t, int16, wchar_t, char16_t, short | 16 |
uint16_t, uint16, ushort, unsigned short | 16 |
int32_t, int32, int, long | 32 |
uint32_t, uint32, unsigned int, unsigned long | 32 |
int64_t, int64, long long | 64 |
uint64_t, uint64, unsigned long long | 64 |
dsint | sizeof(void*) * 8 |
duint, size_t | sizeof(void*) * 8 |
float | 32 |
double, long double | 64 |
ptr, void* | sizeof(void*) * 8 |
char*, const char* | sizeof(char*) * 8 |
wchar_t*, const wchar_t* | sizeof(wchar_t*) * 8 |
可见dsint/duint/size_t等与指针宽度相关的类型,其尺寸会随构建架构(x64/x86)自动变化,SizeofType因此也可以用来在脚本中探测当前调试器是 64 位还是 32 位。
5. 结构体尺寸的累积规则
SizeofType对结构体返回的位宽,来自结构体定义过程中实时维护的sizeBits字段:
- 结构体(struct):每添加一个成员,
s.sizeBits += m.sizeBits累加(types.cpp); - 联合体(union):取所有成员的最大值
if(typeSize > s.sizeBits) s.sizeBits = typeSize;(types.cpp); - 数组成员:
typeSize = Sizeof(type) * arraySize按元素个数放大(types.cpp); - 位域成员:尺寸取位域声明的
sizeBits(但不能超过成员类型位宽,见 types.cpp); - 显式偏移:当成员指定了超出当前布局的
bitOffset时,会通过AppendStructPadding自动插入填充位(types.cpp),这些填充同样计入最终位宽。
因此,SizeofType反映的是类型数据库中的逻辑布局尺寸,与 C 编译器在目标架构上的实际对齐规则可能不完全一致,使用时需结合具体场景判断。
与类型命令族的协作
SizeofType的典型工作流是"先定义、再查询":
- 手工定义:用
AddType/AddStruct/AddUnion/AddMember/AddFunction/AddArg逐个构建类型(对应文档见 AddType、AddStruct、AddMember、AddFunction 等); - 批量导入:用
ParseTypes解析 C 风格声明、或LoadTypes从文件/JSON 加载类型(见 ParseTypes、LoadTypes); - 查询校验:用
SizeofType获取位宽,配合EnumTypes(EnumTypes)枚举全部类型、VisitType/dt(VisitType)展示成员布局,形成完整的类型管理与检视闭环; - 脚本消费:把
$result用于条件分支、循环或内存操作,例如在脚本中先SizeofType再据此分配缓冲区或计算遍历步长。
边界情况与注意事项
- 类型不存在时返回 0:任何有效类型的位宽至少为 8 bit,因此 0 被安全用作"未找到"的哨兵值;命令会打印
SizeofType failed且不修改$result。 - 指针类型返回指针宽度:对以
*结尾的类型名(如MY_STRUCT*),返回的是指针大小而非所指结构体的大小(types.cpp)。若要查询结构体本身的尺寸,请去掉末尾的*。 - 单位是 bit:所有返回值均为位宽。若脚本需要字节数,应自行除以 8。
- 不依赖调试会话:
SizeofType只读取调试器内部的类型数据库,无需附加或启动被调试进程即可执行,可在任意时刻用于脚本初始化。
总结
SizeofType虽然语法简单,却是 x64dbg 类型系统中连接"类型定义"与"脚本逻辑"的关键查询入口。理解其$result返回值语义(bit 单位)、别名递归解析、指针/枚举/结构体/函数的差异化处理,以及"0 表示未找到"的失败约定,能帮助你在逆向分析与自动化脚本中更精确地利用自定义类型体系。相关实现与测试可进一步查阅 types.cpp、types.h 与 cmd-types.cpp。
【免费下载链接】x64dbgAn open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis.项目地址: https://gitcode.com/gh_mirrors/x6/x64dbg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考