用ImHex展示二进制文件的结构
用ImHex展示二进制文件的结构
我之前在010 Editor 和 Hex Editor Neo上展示过利用解析规则进行二进制文件结构的解析,这是文件格式解析的新兴工具(不过可惜的是UltraEdit并没有支持它)。
今天在试用ImHex这个编辑器中,我发现它也提供了类似的功能,于是拿来试试之前的配方文件格式(见之前博客)。
ImHex的作者定义了一种叫Pattern Language的样式规则,用于 ImHex的自定义数据处理。(参见https://github.com/WerWolv/Documentation/tree/master/pattern_language)经过研究,发现类似于010 Editor, 这套规则文件也是比较容易掌握的,但展示方面ImHex还有所改进和提升。除了对数据的背景色进行定义外,它还可以在属性中应用函数hex::visualize可以将数据按需要,展示为图像(image,可支持JPG, PNG, TGA, BMP, PSD, GIF, HDR 和 PIC格式)、3D图(3d)、散点图(scatter_plot)、线型图 (line_plot)、地图上的经纬度(coordinates)等,也可以用函数hex::inline_visualize将数据展示为color,gauge, button等不同类型。详细的语法和用法,github上提供了详细的语言规则。Pattern Language.
下面这个图中,上部为高亮后的数据,下部为各部分的结构名称,为一一对应关系。配方的内容部分,成分的名字我加密过了,因此不能直接看出来,但数值部分没有加密,解析结果中我特意用进度条形式展示了其百分含量(亦可参见解析的规则代码)

针对这个文件格式,相应的Pattern Language 规则如下

Click to view code.
import type.color;
import std.string;
import std.bit;
struct FITEM{
char cmpName[8] [[color("888800")]];
double Wt [[color("0033DD")]];
} [[hex::inline_visualize("gauge", Wt)]] ; //用进度条显示成分的百分比
fn showMD(double md) {return std::string::to_string(md) + " g/ml";};
fn showDDL(double ddl) {return std::string::to_string(ddl) + " mS/cm";};
struct Estimation{
double estMD [[format("showMD")]];
double estDDL [[format("showDDL")]];
} [[color("00FFFF")]] ;
struct FORMUCODE { //two parts, name and alias, 8 chars/each
char FormuName[8][[color("FF0000"),comment("配方的正式名称")]] ;
char FormuAlias[8][[color("00AA00"),comment("? means no value")]];
} ;
struct BGITEM{char FormuBGinfo[16];}[[color("CCCCCC"),format_write]];
struct SectionSize{
u32 szHeader [[color("aa0000")]]; //size of the hearder
u32 szBgInfo [[color("00bb00")]]; //size of the bginfo
char reserved[8][[color("000000")]];//reserved for padding
};
fn showBits(u8 flags) {return std::string::to_string(std::bit::popcount(flags)) +" flags from " +std::string::to_string(flags);}; //popcount计算当前数字有多少个1.
struct ParsedData { //整个fmd文件对应的结构名为ParsedData,变量名为pd.
char FileSign[4] ; //第一个变量为四字节的字符数组,固定为FMS(以防止文件名的后缀变化时不能正确识别)。
u8 FileFmtVer[4] ; //第二个变量为四字节的文件格式,与fmd文件的二进制格式有关。此模板对应的这个值是0x10
u8 statusBits[8] [[format("showBits")]];
FORMUCODE formucode;
Estimation estValues;
FITEM fi[16];
SectionSize sectsz;
BGITEM bgi[16]; //16 strings for background info
} ;
ParsedData parsed_data @ 0x00; //start from first byte.
类似地,再补充一下未加密的文件的解析:

对应的hexpat后缀的解析规则文本也备份一下:
点击查看代码
import type.color;
import std.string;
import std.bit;
fn showName(str n) { if (n[0]=='?') { return "";} else {return std::string::to_string(n);} }; //去除末尾的\x00等难看的结尾
fn showFItem(auto f) {if (f.Wt==0) {return "";} else {return std::string::to_string(f.cmpName)+": "+std::string::to_string(f.Wt) +"%";} };
struct FITEM{
char cmpName[8] [[color("880000"),name("组分"),format("showName")]];
double Wt [[color("0033DD"),name("百分含量")]];
} [[comment(std::string::to_string(Wt)+"%"+cmpName),format("showFItem")]] ; //用进度条显示成分的百分比 hex::inline_visualize("gauge", Wt),
fn showMD(double md) {return std::string::to_string(md) + " g/ml";};
fn showDDL(double ddl) {return std::string::to_string(ddl) + " mS/cm";};
//因为format的函数只能带一个参数,用auto类型指代这种结构体类型
fn showEstV(auto v) {return std::string::to_string(v.estMD) +"g/ml, "+std::string::to_string(v.estDDL) + " mS/cm";};
struct Estimation{
double estMD [[format("showMD"),name("估算的密度")]];
double estDDL [[format("showDDL"),name("估算的电导率")]];
} [[color("00FFFF"),format("showEstV")]] ;
struct FORMUCODE { //two parts, name and alias, 8 chars/each
char FormuName[8][[color("FF0000"),comment("配方的正式名称"),name("配方型号"),format("showName")]] ;
char FormuAlias[8][[color("00AA00"),name("别名"),format("showName")]]; } ;
fn showbgi(auto b) { if (b.FormuBGinfo!="") {return std::string::to_string(b.FormuBGinfo);} else {return "";}};
struct BGITEM{char FormuBGinfo[16];}[[color("CCCCCC"),format("showbgi")]];
struct SectionSize{
u32 szHeader [[color("aa0000")]]; //size of the hearder
u32 szBgInfo [[color("00bb00")]]; //size of the bginfo
char reserved[8][[color("000000"),format("showName")]];//reserved for padding
};
fn showBits(u8 flags) {return std::string::to_string(std::bit::popcount(flags)) +" flags from " +std::string::to_string(flags);}; //popcount计算当前数字有多少个1.
struct ParsedData { //整个fmd文件对应的结构名为ParsedData,变量名为pd.
char FileSign[4] [[format("showName")]]; //第一个变量为四字节的字符数组,固定为FMS(以防止文件名的后缀变化时不能正确识别)。
u8 FileFmtVer[4] ; //第二个变量为四字节的文件格式,与fmd文件的二进制格式有关。此模板对应的这个值是0x10
u8 statusBits[8] [[format("showBits")]];
FORMUCODE formucode;
Estimation estValues;
FITEM fi[16];
SectionSize sectsz;
BGITEM bgi[16]; //16 strings for background info
} ;
ParsedData parsed_data @ 0x00; //start from first byte.

浙公网安备 33010602011771号