librz/bin: add iH header structure support for Menuet format (#6189)

* librz/bin: add `iH` header structure for Menuet format
* librz/bin: parse Menuet headers by version
This commit is contained in:
Cheese Cake
2026-04-10 23:17:48 +08:00
committed by GitHub
parent 5668bdaf61
commit 66ccde55dd
2 changed files with 144 additions and 2 deletions
+128
View File
@@ -81,6 +81,133 @@ static ut64 menuetEntry(const ut8 *buf, int buf_size) {
return UT64_MAX;
}
typedef struct {
ut8 magic[8];
ut8 version_char;
ut32 header_version;
ut32 program_start;
ut32 image_size;
ut32 memory_size;
ut32 field_24;
ut32 field_28;
ut32 field_32;
ut32 tls_map;
ut32 import_start;
ut32 import_end;
ut32 entry_point;
bool truncated_v2;
} MenuetHeader;
static bool menuet_parse_header(RzBuffer *buf, MenuetHeader *hdr) {
rz_return_val_if_fail(buf && hdr, false);
const ut64 sz = rz_buf_size(buf);
if (sz < 32) {
return false;
}
memset(hdr, 0, sizeof(*hdr));
ut64 off = 0;
if (!rz_buf_read_offset(buf, &off, hdr->magic, sizeof(hdr->magic)) ||
memcmp(hdr->magic, "MENUET0", 7) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->header_version) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->program_start) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->image_size) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->memory_size) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->field_24)) {
return false;
}
hdr->version_char = MENUET_VERSION(hdr->magic);
if (hdr->version_char == '0') {
return true;
}
if (!rz_buf_read_le32_offset(buf, &off, &hdr->field_28) ||
!rz_buf_read_le32_offset(buf, &off, &hdr->field_32)) {
return false;
}
if (hdr->version_char == '1') {
return true;
}
if (hdr->version_char != '2') {
return false;
}
if (sz < 52) {
hdr->truncated_v2 = true;
return true;
}
return rz_buf_read_le32_offset(buf, &off, &hdr->tls_map) &&
rz_buf_read_le32_offset(buf, &off, &hdr->import_start) &&
rz_buf_read_le32_offset(buf, &off, &hdr->import_end) &&
rz_buf_read_le32_offset(buf, &off, &hdr->entry_point);
}
static RzStructuredData *menuet_structure(RzBinFile *bf) {
rz_return_val_if_fail(bf && bf->buf, NULL);
MenuetHeader hdr;
if (!menuet_parse_header(bf->buf, &hdr)) {
return NULL;
}
RzStructuredData *info = rz_structured_data_new_map();
if (!info) {
return NULL;
}
RzStructuredData *menuet = rz_structured_data_map_add_map(info, "menuet");
if (!menuet) {
rz_structured_data_free(info);
return NULL;
}
const ut8 version_char = hdr.version_char;
const ut64 version = (version_char >= '0' && version_char <= '9') ? (ut64)(version_char - '0') : UT64_MAX;
rz_structured_data_map_add_bytes(menuet, "magic", hdr.magic, sizeof(hdr.magic), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
if (version != UT64_MAX) {
rz_structured_data_map_add_unsigned(menuet, "version", version, false);
}
rz_structured_data_map_add_unsigned(menuet, "program_start", hdr.program_start, true);
rz_structured_data_map_add_unsigned(menuet, "image_size", hdr.image_size, true);
rz_structured_data_map_add_unsigned(menuet, "memory_size", hdr.memory_size, true);
switch (version_char) {
case '0':
rz_structured_data_map_add_unsigned(menuet, "required_os", hdr.header_version, false);
rz_structured_data_map_add_unsigned(menuet, "reserved", hdr.field_24, true);
break;
case '1':
rz_structured_data_map_add_unsigned(menuet, "header_version", hdr.header_version, false);
rz_structured_data_map_add_unsigned(menuet, "stack_pointer", hdr.field_24, true);
rz_structured_data_map_add_unsigned(menuet, "parameters", hdr.field_28, true);
rz_structured_data_map_add_unsigned(menuet, "path", hdr.field_32, true);
break;
case '2':
if (hdr.truncated_v2) {
rz_structured_data_map_add_boolean(menuet, "truncated", true);
break;
}
rz_structured_data_map_add_unsigned(menuet, "header_version", hdr.header_version, false);
rz_structured_data_map_add_unsigned(menuet, "stack_pointer", hdr.field_24, true);
rz_structured_data_map_add_unsigned(menuet, "cmdline", hdr.field_28, true);
rz_structured_data_map_add_unsigned(menuet, "path", hdr.field_32, true);
rz_structured_data_map_add_unsigned(menuet, "tls_map", hdr.tls_map, true);
rz_structured_data_map_add_unsigned(menuet, "import_start", hdr.import_start, true);
rz_structured_data_map_add_unsigned(menuet, "import_end", hdr.import_end, true);
rz_structured_data_map_add_unsigned(menuet, "entry_point", hdr.entry_point, true);
break;
default:
rz_structured_data_map_add_boolean(menuet, "unknown_version", true);
break;
}
return info;
}
static RzPVector /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
RzPVector *ret;
ut8 buf[64] = { 0 };
@@ -209,6 +336,7 @@ RzBinPlugin rz_bin_plugin_menuet = {
.maps = &rz_bin_maps_of_file_sections,
.sections = &sections,
.info = &info,
.bin_structure = &menuet_structure,
.create = &create,
};
+16 -2
View File
@@ -1,8 +1,22 @@
NAME=Menuet: Open/iI
NAME=Menuet: Open/iI/iH
FILE=bins/menuet/dosbox
CMDS=iI~?MenuetOS
CMDS=<<EOF
iI~?MenuetOS
iH
EOF
EXPECT=<<EOF
1
menuet:
magic: "4d 45 4e 55 45 54 30 31 |MENUET01 |"
version: 1
program_start: 0x24
image_size: 0x11b000
memory_size: 0x1526000
header_version: 1
stack_pointer: 0x11f000
parameters: 0x11f000
path: 0x0
EOF
RUN