Skip to content

Commit

Permalink
Add draft parsing of codesign structs
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Nov 12, 2020
1 parent ecb4bd3 commit 64f0a0d
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 9 deletions.
112 changes: 105 additions & 7 deletions src/ZachO.zig
Expand Up @@ -280,7 +280,7 @@ fn formatData(self: ZachO, seg: SegmentCommand, writer: anytype) !void {
try writer.print(" {},{}\n", .{ sect.segname, sect.sectname });
try writer.print(" file = {{ {}, {} }}\n", .{ file_start, file_end });
try writer.print(" address = {{ 0x{x:0<16}, 0x{x:0<16} }}\n\n", .{ addr_start, addr_end });
try formatBinaryBlob(self.data.items[file_start..file_end], writer);
try formatBinaryBlob(self.data.items[file_start..file_end], " ", writer);
try writer.print("\n", .{});
}
}
Expand All @@ -293,22 +293,120 @@ fn formatCodeSignatureData(self: ZachO, csig: CodeSignatureCommand, writer: anyt

try writer.print("Code signature data:\n", .{});
try writer.print("file = {{ {}, {} }}\n\n", .{ start_pos, end_pos });
try formatBinaryBlob(self.data.items[start_pos..end_pos], writer);
try writer.print("\n", .{});

var data = self.data.items[start_pos..end_pos];
const magic = mem.readIntBig(u32, data[0..4]);
const length = mem.readIntBig(u32, data[4..8]);
const count = mem.readIntBig(u32, data[8..12]);
data = data[12..];

try writer.print("{{\n", .{});
try writer.print(" Magic = 0x{x}\n", .{magic});
try writer.print(" Length = {}\n", .{length});
try writer.print(" Count = {}\n", .{count});
try writer.print("}}\n", .{});

if (magic != machoext.CSMAGIC_EMBEDDED_SIGNATURE) {
try writer.print("unknown signature type: 0x{x}\n", .{magic});
try formatBinaryBlob(self.data.items[start_pos..end_pos], null, writer);
return;
}

var i: usize = 0;
while (i < count) : (i += 1) {
const tt = mem.readIntBig(u32, data[0..4]); // ignored for some reason?
const offset = mem.readIntBig(u32, data[4..8]);

try writer.print("{{\n", .{});

const tt_fmt = switch (tt) {
machoext.CSSLOT_CODEDIRECTORY => "CSSLOT_CODEDIRECTORY",
machoext.CSSLOT_REQUIREMENTS => "CSSLOT_REQUIREMENTS",
machoext.CSSLOT_ALTERNATE_CODEDIRECTORIES => "CSSLOT_ALTERNATE_CODEDIRECTORIES",
machoext.CSSLOT_SIGNATURESLOT => "CSSLOT_SIGNATURESLOT",
else => "Unknown",
};
try writer.print(" Type: {}(0x{x})\n", .{ tt_fmt, tt });
try writer.print(" Offset: {}\n", .{offset});

var inner = data[offset - 12 - i * 8 ..];
const magic2 = mem.readIntBig(u32, inner[0..4]);
const length2 = mem.readIntBig(u32, inner[4..8]);
const magic2_fmt = switch (magic2) {
machoext.CSMAGIC_REQUIREMENTS => "CSMAGIC_REQUIREMENTS",
machoext.CSMAGIC_CODEDIRECTORY => "CSMAGIC_CODEDIRECTORY",
machoext.CSMAGIC_BLOBWRAPPER => "CSMAGIC_BLOBWRAPPER",
else => "Unknown",
};

try writer.print(" Magic: {}(0x{x})\n", .{ magic2_fmt, magic2 });
try writer.print(" Length: {}\n", .{length2});

switch (magic2) {
machoext.CSMAGIC_CODEDIRECTORY => {
const version = mem.readIntBig(u32, inner[8..12]);
try writer.print(" Version: 0x{x}\n", .{version});
try writer.print(" Flags: 0x{x}\n", .{mem.readIntBig(u32, inner[12..16])});
try writer.print(" Hash offset: {}\n", .{mem.readIntBig(u32, inner[16..20])});
try writer.print(" Ident offset: {}\n", .{mem.readIntBig(u32, inner[20..24])});
try writer.print(" Number of special slots: {}\n", .{mem.readIntBig(u32, inner[24..28])});
try writer.print(" Number of code slots: {}\n", .{mem.readIntBig(u32, inner[32..36])});
try writer.print(" Code limit: {}\n", .{mem.readIntBig(u32, inner[40..44])});
try writer.print(" Hash size: {}\n", .{mem.readIntBig(u8, inner[44..45])});
try writer.print(" Hash type: {}\n", .{mem.readIntBig(u8, inner[45..46])});
try writer.print(" Platform: {}\n", .{mem.readIntBig(u8, inner[46..47])});
try writer.print(" Page size: {}\n", .{mem.readIntBig(u8, inner[47..48])});
try writer.print(" Reserved: {}\n", .{mem.readIntBig(u32, inner[48..52])});

const len = blk: {
switch (version) {
0x20400 => {
try writer.print(" Offset of executable segment: {}\n", .{mem.readIntBig(u64, inner[52..60])});
try writer.print(" Limit of executable segment: {}\n", .{mem.readIntBig(u64, inner[60..68])});
try writer.print(" Executable segment flags: 0x{x}\n", .{mem.readIntBig(u64, inner[68..76])});
inner = inner[76..];
break :blk length2 - 76;
},
0x20100 => {
try writer.print(" Offset of optional scatter vector: {}\n", .{mem.readIntBig(u32, inner[52..56])});
inner = inner[56..];
break :blk length2 - 56;
},
else => {
inner = inner[52..];
break :blk length2 - 52;
}
}
};
try writer.print(" Data still to parse:\n", .{});
try formatBinaryBlob(inner[0..len], " ", writer);
},
else => {
try writer.print(" Data:\n", .{});
try formatBinaryBlob(inner[8..length2], " ", writer);
},
}

try writer.print("}}\n", .{});

data = data[8..];
}
}

fn formatBinaryBlob(blob: []const u8, writer: anytype) !void {
fn formatBinaryBlob(blob: []const u8, prefix: ?[]const u8, writer: anytype) !void {
// Format as 16-by-16-by-8 with two left column in hex, and right in ascii:
// xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxx
var i: usize = 0;
const step = 16;
while (i <= blob.len) : (i += step) {
const pp = prefix orelse "";
while (i < blob.len) : (i += step) {
if (blob[i..].len < step / 2) {
try writer.print("{x:<033} {e}\n", .{ blob[i..], blob[i..] });
try writer.print("{}{x:<033} {}\n", .{ pp, blob[i..], blob[i..] });
continue;
}
const rem = std.math.min(blob[i..].len, step);
try writer.print("{x:<016} {x:<016} {e}\n", .{
try writer.print("{}{x:<016} {x:<016} {}\n", .{
pp,
blob[i .. i + rem / 2],
blob[i + rem / 2 .. i + rem],
blob[i .. i + rem],
Expand Down
82 changes: 80 additions & 2 deletions src/machoext.zig
Expand Up @@ -7,16 +7,94 @@ pub const code_signature = extern struct {
datasize: u32,
};

pub const CSMAGIC_EMBEDDED_SIGNATURE: u32 = 0xFADE0CC0;
/// single Requirement blob
pub const CSMAGIC_REQUIREMENT: u32 = 0xfade0c00;
/// Requirements vector (internal requirements)
pub const CSMAGIC_REQUIREMENTS: u32 = 0xfade0c01;
/// CodeDirectory blob
pub const CSMAGIC_CODEDIRECTORY: u32 = 0xfade0c02;
/// embedded form of signature data
pub const CSMAGIC_EMBEDDED_SIGNATURE: u32 = 0xfade0cc0;
/// XXX
pub const CSMAGIC_EMBEDDED_SIGNATURE_OLD: u32 = 0xfade0b02;
/// embedded entitlements
pub const CSMAGIC_EMBEDDED_ENTITLEMENTS: u32 = 0xfade7171;
/// multi-arch collection of embedded signatures
pub const CSMAGIC_DETACHED_SIGNATURE: u32 = 0xfade0cc1;
/// CMS Signature, among other things
pub const CSMAGIC_BLOBWRAPPER: u32 = 0xfade0b01;

pub const CS_SUPPORTSSCATTER: u32 = 0x20100;
pub const CS_SUPPORTSTEAMID: u32 = 0x20200;
pub const CS_SUPPORTSCODELIMIT64: u32 = 0x20300;
pub const CS_SUPPORTSEXECSEG: u32 = 0x20400;

/// slot index for CodeDirectory
pub const CSSLOT_CODEDIRECTORY: u32 = 0;
pub const CSSLOT_INFOSLOT: u32 = 1;
pub const CSSLOT_REQUIREMENTS: u32 = 2;
pub const CSSLOT_RESOURCEDIR: u32 = 3;
pub const CSSLOT_APPLICATION: u32 = 4;
pub const CSSLOT_ENTITLEMENTS: u32 = 5;

/// first alternate CodeDirectory, if any
pub const CSSLOT_ALTERNATE_CODEDIRECTORIES: u32 = 0x1000;
/// max number of alternate CD slots */
pub const CSSLOT_ALTERNATE_CODEDIRECTORY_MAX: u32 = 5;
/// one past the last
pub const CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT: u32 = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX;

/// CMS Signature
pub const CSSLOT_SIGNATURESLOT: u32 = 0x10000;
pub const CSSLOT_IDENTIFICATIONSLOT: u32 = 0x10001;
pub const CSSLOT_TICKETSLOT: u32 = 0x10002;

/// compat with amfi
pub const CSTYPE_INDEX_REQUIREMENTS: u32 = 0x00000002;
/// compat with amfi
pub const CSTYPE_INDEX_ENTITLEMENTS: u32 = 0x00000005;

pub const CS_HASHTYPE_SHA1: u32 = 1;
pub const CS_HASHTYPE_SHA256: u32 = 2;
pub const CS_HASHTYPE_SHA256_TRUNCATED: u32 = 3;
pub const CS_HASHTYPE_SHA384: u32 = 4;

pub const CS_SHA1_LEN: u32 = 20;
pub const CS_SHA256_LEN: u32 = 32;
pub const CS_SHA256_TRUNCATED_LEN: u32 = 20;

/// always - larger hashes are truncated
pub const CS_CDHASH_LEN: u32 = 20;
/// max size of the hash we'll support
pub const CS_HASH_MAX_SIZE: u32 = 48;

pub const SuperBlob = extern struct {
magic: u32,
length: u32,
count: u32,
index: ?*BlobIndex,
};

pub const BlobIndex = extern struct {
@"type": u32,
offset: u32,
};

pub const CodeDirectory = extern struct {
magic: u32,
length: u32,
version: u32,
flags: u32,
hashOffset: u32,
identOffset: u32,
nSpecialSlots: u32,
nCodeSlots: u32,
codeLimit: u32,
hashSize: u8,
hashType: u8,
platform: u8,
pageSize: u8,
spare2: u32,
execSegBase: u64,
execSegLimit: u64,
execSegFlags: u64,
};

0 comments on commit 64f0a0d

Please sign in to comment.