Skip to content

Commit

Permalink
object: Add implicit swap for MZ + MINIMUM_SIZE checks
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Sep 6, 2023
1 parent 84cfe41 commit 667f071
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 39 deletions.
31 changes: 21 additions & 10 deletions app/dump/mz.d
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ void dump_mz_hdr(adbg_object_t *o) {
dprint_x16("e_cs", e_cs);
dprint_x16("e_lfarlc", e_lfarlc);
dprint_u16("e_ovno", e_ovno);
dprint_x16("e_res[0]", e_res[0]); // lazy
dprint_x16("e_res[1]", e_res[1]); // lazy
dprint_x16("e_res[2]", e_res[2]); // lazy
dprint_x16("e_res[3]", e_res[3]); // lazy
dprint_x16("e_res[4]", e_res[4]); // lazy
dprint_x16("e_res[5]", e_res[5]); // lazy
dprint_x16("e_res[6]", e_res[6]); // lazy
dprint_x16("e_res[7]", e_res[7]); // lazy
dprint_x16("e_res[8]", e_res[8]); // lazy
dprint_x16("e_res[9]", e_res[9]); // lazy
dprint_x16("e_res[10]", e_res[10]); // lazy
dprint_x16("e_res[11]", e_res[11]); // lazy
dprint_x16("e_res[12]", e_res[12]); // lazy
dprint_x16("e_res[13]", e_res[13]); // lazy
dprint_x16("e_res[14]", e_res[14]); // lazy
dprint_x16("e_res[15]", e_res[15]); // lazy
dprint_x32("e_lfanew", e_lfanew);
}
}
Expand All @@ -58,15 +74,10 @@ void dump_mz_relocs(adbg_object_t *o) {

dprint_header("Relocations");

ushort count = o.i.mz.header.e_crlc;
mz_reloc *reloc = o.i.mz.relocs;

if (count == 0 || reloc == null)
return;

for (ushort i; i < count; ++i)
printf("%u. segment=%04X offset=%04X\n",
i, reloc[i].segment, reloc[i].offset);
mz_reloc *reloc = void;
size_t i;
while ((reloc = adbg_object_mz_reloc(o, i++)) != null) with (reloc)
printf("%u. segment=%04X offset=%04X\n", cast(uint)i, segment, offset);
}

void dump_mz_disasm(adbg_object_t *o, uint flags) {
Expand All @@ -82,7 +93,7 @@ void dump_mz_disasm(adbg_object_t *o, uint flags) {
uint len = void;
with (o.i.mz.header) {
blks = e_cblp ? e_cp - 1 : e_cp;
len = (blks * 16) + e_cblp;
len = (blks * PARAGRAPH) + e_cblp;
}
if (len == 0)
return;
Expand Down
11 changes: 6 additions & 5 deletions src/adbg/error.d
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,13 @@ enum AdbgError {
//
objectUnknownFormat = 301,
objectUnsupportedFormat = 302,
objectTooSmall = 303,
objectInvalidVersion = 310,
objectInvalidMachine = 310,
objectInvalidClass = 310,
objectInvalidEndian = 310,
objectInvalidType = 310,
objectInvalidABI = 310,
objectInvalidMachine = 311,
objectInvalidClass = 312,
objectInvalidEndian = 313,
objectInvalidType = 314,
objectInvalidABI = 315,
// Old meanings
unknownObjFormat = objectUnknownFormat,
unsupportedObjFormat = objectUnsupportedFormat,
Expand Down
3 changes: 0 additions & 3 deletions src/adbg/utils/bit.d
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,6 @@ ushort adbg_bswap16(ushort v) pure {
return cast(ushort)(v >> 8 | v << 8);
}

// Old name
public alias adbg_util_bswap16 = adbg_bswap16;

/// Byte-swap an 32-bit value.
/// Params: v = 32-bit value
/// Returns: Byte-swapped value
Expand Down
8 changes: 7 additions & 1 deletion src/adbg/v2/object/format/elf.d
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import adbg.include.c.stdlib : calloc, free;
/// Signature magic for ELF.
enum MAGIC_ELF = CHAR32!"\x7FELF";

/// Minimum file size for ELF.
// https://stackoverflow.com/a/53383541
private enum MINIMUM_SIZE = 130;

// ELF32
private alias uint Elf32_Addr;
private alias ushort Elf32_Half;
Expand Down Expand Up @@ -656,8 +660,10 @@ else
private enum PLATFORM_DATA = ELF_DATA_LSB;

int adbg_object_elf_load(adbg_object_t *o) {
if (o.file_size < MINIMUM_SIZE)
return adbg_oops(AdbgError.objectTooSmall);

o.format = AdbgObject.elf;
o.i.elf32.ehdr = cast(Elf32_Ehdr*)o.buffer;

o.p.reversed = o.i.elf32.ehdr.e_ident[ELF_EI_DATA] != PLATFORM_DATA;
version (Trace) trace("reversed=%d", o.p.reversed);
Expand Down
7 changes: 7 additions & 0 deletions src/adbg/v2/object/format/macho.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import core.stdc.stdlib : calloc;
// - https://github.com/opensource-apple/cctools/blob/master/include/mach-o/loader.h

// Self-imposed limits

/// Smallest Mach-O size.
// https://codegolf.stackexchange.com/a/154685
private enum MINIMUM_SIZE = 0x1000; // Due to paging
//TODO: Apply limits (with logging?)
private enum LIMIT_FAT_ARCH = 200;
private enum LIMIT_COMMANDS = 2000;
Expand Down Expand Up @@ -385,6 +389,9 @@ enum {
}

int adbg_object_macho_load(adbg_object_t *o) {
if (o.file_size < MINIMUM_SIZE)
return adbg_oops(AdbgError.objectTooSmall);

o.format = AdbgObject.macho;

o.i.macho.header = cast(macho_header*)o.buffer;
Expand Down
76 changes: 67 additions & 9 deletions src/adbg/v2/object/format/mz.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,27 @@
/// License: BSD-3-Clause
module adbg.v2.object.format.mz;

import adbg.error;
import adbg.v2.object.server : adbg_object_t, AdbgObject;
import adbg.utils.bit : CHAR16;
import adbg.utils.bit;

//TODO: Support compressed MZ files?

/// Minimum file size for an MZ EXE.
// NOTE: Borland EXE about 6K (includes a CRT?).
private enum MINIMUM_SIZE = mz_hdr.sizeof + 0x200;

/// Magic number for MZ objects.
enum MAGIC_MZ = CHAR16!"MZ";
/// Swappged magic for MZ objects.
enum MAGIC_ZM = CHAR16!"ZM";

private enum ERESWDS = 16;
private enum PAGE = 512;
/// Number of reserved words for e_res.
enum ERESWDS = 16;
/// Size of a MZ paragraph.
enum PARAGRAPH = 16;
/// Size of a MZ page.
enum PAGE = 512;

/// MZ header structure
struct mz_hdr {
Expand All @@ -31,7 +44,7 @@ struct mz_hdr {
ushort e_lfarlc; /// File address of relocation table
ushort e_ovno; /// Overlay number
ushort[ERESWDS] e_res; /// Reserved words
uint e_lfanew; /// File address of new exe header (usually at 3Ch)
uint e_lfanew; /// File address of new exe header
}
static assert(mz_hdr.e_lfanew.offsetof == 0x3c);

Expand All @@ -41,10 +54,55 @@ struct mz_reloc {
ushort segment;
}

int adbg_object_mz_load(adbg_object_t *obj) {
obj.format = AdbgObject.mz;
obj.i.mz.header = cast(mz_hdr*)obj.buffer;
with (obj.i.mz) if (header.e_lfarlc && header.e_crlc && header.e_lfarlc < obj.file_size)
relocs = cast(mz_reloc*)(obj.buffer + header.e_lfarlc);
int adbg_object_mz_load(adbg_object_t *o) {
import core.stdc.stdlib : calloc;

if (o.file_size < MINIMUM_SIZE)
return adbg_oops(AdbgError.objectTooSmall);

if (o.p.reversed) with (o.i.mz.header) {
e_magic = adbg_bswap16(e_magic);
e_cblp = adbg_bswap16(e_cblp);
e_cp = adbg_bswap16(e_cp);
e_crlc = adbg_bswap16(e_crlc);
e_cparh = adbg_bswap16(e_cparh);
e_minalloc = adbg_bswap16(e_minalloc);
e_maxalloc = adbg_bswap16(e_maxalloc);
e_ss = adbg_bswap16(e_ss);
e_sp = adbg_bswap16(e_sp);
e_csum = adbg_bswap16(e_csum);
e_ip = adbg_bswap16(e_ip);
e_cs = adbg_bswap16(e_cs);
e_lfarlc = adbg_bswap16(e_lfarlc);
e_ovno = adbg_bswap16(e_ovno);
for (size_t i; i < ERESWDS; ++i)
e_res[i] = adbg_bswap16(e_res[i]);
}

o.format = AdbgObject.mz;
with (o.i.mz) if (header.e_lfarlc && header.e_crlc && header.e_lfarlc < o.file_size) {
relocs = cast(mz_reloc*)(o.buffer + header.e_lfarlc);
if (o.p.reversed)
o.i.mz.reversed_relocs = cast(bool*)calloc(header.e_crlc, bool.sizeof);
}
return 0;
}

mz_hdr* adbg_object_mz_header(adbg_object_t *o) {
if (o == null) return null;
return o.i.mz.header;
}

mz_reloc* adbg_object_mz_reloc(adbg_object_t *o, size_t index) {
if (o == null) return null;
if (o.i.mz.relocs == null) return null; // no relocations available
if (index >= o.i.mz.header.e_crlc) return null;

mz_reloc *reloc = &o.i.mz.relocs[index];
if (o.p.reversed && o.i.mz.reversed_relocs[index] == false) {
reloc.offset = adbg_bswap16(reloc.offset);
reloc.segment = adbg_bswap16(reloc.segment);
o.i.mz.reversed_relocs[index] = true;
}
return reloc;
}
7 changes: 7 additions & 0 deletions src/adbg/v2/object/format/pe.d
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ extern (C):
/// Magic number for PE32 object files.
enum MAGIC_PE32 = CHAR32!"PE\0\0";

/// Minimum file size for PE32.
// https://stackoverflow.com/a/47311684
private enum MINIMUM_SIZE = 97;

enum : ushort { // PE_HEADER.Machine, likely all little-endian
PE_MACHINE_UNKNOWN = 0, /// Any machine
PE_MACHINE_ALPHAOLD = 0x183, /// Alpha (old value), unused
Expand Down Expand Up @@ -540,6 +544,9 @@ struct PE_SECTION_ENTRY { align(1):
/// Params: obj = Object
/// Returns: Status code
int adbg_object_pe_load(adbg_object_t *obj) {
if (obj.file_size < MINIMUM_SIZE)
return adbg_oops(AdbgError.objectTooSmall);

obj.format = AdbgObject.pe;

void *base = obj.buffer + obj.i.mz.header.e_lfanew;
Expand Down
49 changes: 38 additions & 11 deletions src/adbg/v2/object/server.d
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ struct adbg_object_t {
struct mz_t {
mz_hdr *header;
mz_reloc *relocs;

bool *reversed_relocs;
}
mz_t mz;

Expand Down Expand Up @@ -198,6 +200,9 @@ void adbg_object_close(adbg_object_t *o) {
if (o == null)
return;
switch (o.format) with (AdbgObject) {
case mz:
with (o.i.mz) if (reversed_relocs) free(reversed_relocs);
break;
//case pe:
case macho:
with (o.i.macho) {
Expand All @@ -206,6 +211,23 @@ void adbg_object_close(adbg_object_t *o) {
}
break;
case elf:
import adbg.v2.object.format.elf :
ELF_EI_CLASS, ELF_CLASS_32, ELF_CLASS_64;
switch (o.i.elf32.ehdr.e_ident[ELF_EI_CLASS]) {
case ELF_CLASS_32:
with (o.i.elf32) {
if (reversed_phdr) free(reversed_phdr);
if (reversed_shdr) free(reversed_shdr);
}
break;
case ELF_CLASS_64:
with (o.i.elf64) {
if (reversed_phdr) free(reversed_phdr);
if (reversed_shdr) free(reversed_shdr);
}
break;
default:
}
break;
default:
}
Expand Down Expand Up @@ -265,35 +287,33 @@ L_ARG:

// Auto-detection
//TODO: Consider moving auto-detection as separate function?
// Especially if debugger can return process' base address for image headers
switch (*o.buffer32) {
case MAGIC_ELF:
case MAGIC_ELF: // "\x7fELF" is text and MAGIC is automatically swapped on target
return adbg_object_elf_load(o);
case MACHO_MAGIC: // 32-bit LE
case MACHO_MAGIC_64: // 64-bit LE
case MACHO_CIGAM: // 32-bit BE
case MACHO_CIGAM_64: // 64-bit BE
case MACHO_FAT_MAGIC: // Fat LE
case MACHO_FAT_CIGAM: // Fat BE
case MACHO_MAGIC: // 32-bit
case MACHO_MAGIC_64: // 64-bit
case MACHO_CIGAM: // 32-bit reversed
case MACHO_CIGAM_64: // 64-bit reversed
case MACHO_FAT_MAGIC: // Fat
case MACHO_FAT_CIGAM: // Fat reversed
return adbg_object_macho_load(o);
default:
}

//TODO: Support compressed MZ files?
switch (*o.buffer16) {
case MAGIC_MZ:
if (o.file_size < mz_hdr.sizeof)
return adbg_oops(AdbgError.unknownObjFormat);

uint offset = o.i.mz.header.e_lfanew;

if (offset == 0)
return adbg_object_mz_load(o);
if (offset >= o.file_size - PE_HEADER.sizeof)
return adbg_oops(AdbgError.assertion);

uint sig = *cast(uint*)(o.buffer + offset);

if (sig == MAGIC_PE32)
if (sig == MAGIC_PE32) // text
return adbg_object_pe_load(o);

switch (cast(ushort)sig) {
Expand All @@ -302,6 +322,13 @@ L_ARG:
default: // Assume MZ?
return adbg_object_mz_load(o);
}
case MAGIC_ZM:
if (o.file_size < mz_hdr.sizeof)
return adbg_oops(AdbgError.unknownObjFormat);

o.p.reversed = true;
with (o.i.mz.header) e_lfanew = adbg_bswap32(e_lfanew);
goto case MAGIC_MZ;
default:
return adbg_oops(AdbgError.unknownObjFormat);
}
Expand Down

0 comments on commit 667f071

Please sign in to comment.