Files
radaree2/test/unit/test_kernelcache_cmdsize.c

138 lines
5.7 KiB
C

#include <r_util.h>
#include <r_bin.h>
#include "minunit.h"
#include "../../libr/bin/format/mach0/mach0_defines.h"
static void write_le32(RBuffer *buf, ut64 off, ut32 value) {
ut8 tmp[4];
r_write_le32 (tmp, value);
r_buf_write_at (buf, off, tmp, sizeof (tmp));
}
static void write_le64(RBuffer *buf, ut64 off, ut64 value) {
ut8 tmp[8];
r_write_le64 (tmp, value);
r_buf_write_at (buf, off, tmp, sizeof (tmp));
}
static void write_padded(RBuffer *buf, ut64 off, const char *str, size_t len) {
ut8 tmp[16];
memset (tmp, 0, sizeof (tmp));
r_str_ncpy ((char *)tmp, str, len);
r_buf_write_at (buf, off, tmp, len);
}
static void write_mach0_header(RBuffer *buf, ut64 off, ut32 filetype, ut32 ncmds, ut32 sizeofcmds) {
write_le32 (buf, off + offsetof (struct mach_header_64, magic), MH_MAGIC_64);
write_le32 (buf, off + offsetof (struct mach_header_64, cputype), CPU_TYPE_ARM64);
write_le32 (buf, off + offsetof (struct mach_header_64, cpusubtype), 0);
write_le32 (buf, off + offsetof (struct mach_header_64, filetype), filetype);
write_le32 (buf, off + offsetof (struct mach_header_64, ncmds), ncmds);
write_le32 (buf, off + offsetof (struct mach_header_64, sizeofcmds), sizeofcmds);
write_le32 (buf, off + offsetof (struct mach_header_64, flags), MH_PIE);
write_le32 (buf, off + offsetof (struct mach_header_64, reserved), 0);
}
static void write_segsect64(RBuffer *buf, ut64 off, const char *segname, const char *sectname, ut64 vaddr, ut64 paddr) {
const ut32 cmdsize = sizeof (struct segment_command_64) + sizeof (struct section_64);
ut64 sec_off = off + sizeof (struct segment_command_64);
write_le32 (buf, off + offsetof (struct segment_command_64, cmd), LC_SEGMENT_64);
write_le32 (buf, off + offsetof (struct segment_command_64, cmdsize), cmdsize);
write_padded (buf, off + offsetof (struct segment_command_64, segname), segname, 16);
write_le64 (buf, off + offsetof (struct segment_command_64, vmaddr), vaddr);
write_le64 (buf, off + offsetof (struct segment_command_64, vmsize), 0x1000);
write_le64 (buf, off + offsetof (struct segment_command_64, fileoff), paddr);
write_le64 (buf, off + offsetof (struct segment_command_64, filesize), 0x1000);
write_le32 (buf, off + offsetof (struct segment_command_64, maxprot), 5);
write_le32 (buf, off + offsetof (struct segment_command_64, initprot), 5);
write_le32 (buf, off + offsetof (struct segment_command_64, nsects), 1);
write_le32 (buf, off + offsetof (struct segment_command_64, flags), 0);
write_padded (buf, sec_off + offsetof (struct section_64, sectname), sectname, 16);
write_padded (buf, sec_off + offsetof (struct section_64, segname), segname, 16);
write_le64 (buf, sec_off + offsetof (struct section_64, addr), vaddr);
write_le64 (buf, sec_off + offsetof (struct section_64, size), 0x10);
write_le32 (buf, sec_off + offsetof (struct section_64, offset), (ut32)paddr);
write_le32 (buf, sec_off + offsetof (struct section_64, align), 2);
write_le32 (buf, sec_off + offsetof (struct section_64, reloff), 0);
write_le32 (buf, sec_off + offsetof (struct section_64, nreloc), 0);
write_le32 (buf, sec_off + offsetof (struct section_64, flags), 0);
write_le32 (buf, sec_off + offsetof (struct section_64, reserved1), 0);
write_le32 (buf, sec_off + offsetof (struct section_64, reserved2), 0);
write_le32 (buf, sec_off + offsetof (struct section_64, reserved3), 0);
}
static bool has_kext_section(RList *sections) {
RListIter *it;
RBinSection *section;
r_list_foreach (sections, it, section) {
if (section && section->name && strstr (section->name, "testkext.")) {
return true;
}
}
return false;
}
bool test_kernelcache_cmdsize(void) {
RBuffer *buf = r_buf_new_sparse (0);
const ut64 big_size = 0x100000400ULL;
const ut64 header_size = sizeof (struct mach_header_64);
const ut64 cmd1_off = header_size;
const ut32 cmd1_size = 0xfffffff0U;
const ut64 cmd2_off = cmd1_off + (ut64)cmd1_size;
const ut32 cmd2_size = 48;
const ut64 seg_cmd_size = sizeof (struct segment_command_64) + sizeof (struct section_64);
const ut64 cmd3_off = cmd2_off + cmd2_size;
const ut64 cmd4_off = cmd3_off + seg_cmd_size;
const ut64 cmd5_off = cmd4_off + seg_cmd_size;
const ut64 kext_off = 0x2000;
const ut64 kext_cmd_off = kext_off + header_size;
r_buf_resize (buf, big_size);
write_mach0_header (buf, 0, MH_FILESET, 5, 0);
write_le32 (buf, cmd1_off + offsetof (struct load_command, cmd), LC_SEGMENT_64);
write_le32 (buf, cmd1_off + offsetof (struct load_command, cmdsize), cmd1_size);
write_le32 (buf, cmd2_off + offsetof (struct load_command, cmd), LC_KEXT);
write_le32 (buf, cmd2_off + offsetof (struct load_command, cmdsize), cmd2_size);
write_le64 (buf, cmd2_off + 8, kext_off);
write_le64 (buf, cmd2_off + 16, kext_off);
write_padded (buf, cmd2_off + 32, "testkext", 16);
write_segsect64 (buf, cmd3_off, "__PRELINK_INFO", "__info", 0x3000, 0x3000);
write_segsect64 (buf, cmd4_off, "__PRELINK_TEXT", "__text", 0x4000, 0x4000);
write_segsect64 (buf, cmd5_off, "__PRELINK_DATA", "__data", 0x5000, 0x5000);
write_mach0_header (buf, kext_off, MH_EXECUTE, 1, seg_cmd_size);
write_segsect64 (buf, kext_cmd_off, "__TEXT_EXEC", "__text", 0x1000, 0x1000);
RBin *bin = r_bin_new ();
RIO *io = r_io_new ();
r_io_bind (io, &bin->iob);
RBinFileOptions opt = {0};
r_bin_file_options_init (&opt, -1, 0, 0, 0);
opt.pluginname = "kernelcache";
bool res = r_bin_open_buf (bin, buf, &opt);
mu_assert ("kernelcache buffer could not be opened", res);
RList *sections = r_bin_get_sections (bin);
mu_assert ("kernelcache sections missing kext data", sections && has_kext_section (sections));
r_bin_free (bin);
r_io_free (io);
r_unref (buf);
mu_end;
}
bool all_tests(void) {
mu_run_test (test_kernelcache_cmdsize);
return tests_passed != tests_run;
}
int main(int argc, char **argv) {
return all_tests ();
}