用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.
------------- 新上手,记为备忘。
posted @ 2026-01-08 18:33  dingxianghuan  阅读(10)  评论(0)    收藏  举报