Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
feature: allow macOS code signing by including payload in str table
Browse files Browse the repository at this point in the history
Bug: #66, #128, #1023
  • Loading branch information
jesec committed May 10, 2021
1 parent 551d07d commit be5c2ae
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 6 deletions.
42 changes: 36 additions & 6 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
/* eslint-disable require-atomic-updates */

import { existsSync, mkdirp, readFile, remove, stat, readFileSync } from 'fs-extra';
import { execSync } from 'child_process';
import {
existsSync,
mkdirp,
readFile,
remove,
stat,
readFileSync,
writeFileSync,
} from 'fs-extra';
import { need, system } from 'pkg-fetch';
import assert from 'assert';
import minimist from 'minimist';
Expand All @@ -17,6 +26,7 @@ import { shutdown } from './fabricator';
import walk, { Marker, WalkerParams } from './walker';
import { Target, NodeTarget, SymLinks } from './types';
import { CompressType } from './compress_type';
import { patchMachOExecutable } from './mach-o';

const { version } = JSON.parse(
readFileSync(path.join(__dirname, '../package.json'), 'utf-8')
Expand Down Expand Up @@ -269,7 +279,6 @@ export async function exec(argv2: string[]) {
// doCompress
const algo = argv.C || argv.compress || 'None';


let doCompress: CompressType = CompressType.None;
switch (algo.toLowerCase()) {
case 'brotli':
Expand All @@ -284,8 +293,9 @@ export async function exec(argv2: string[]) {
break;
default:
// eslint-disable-next-line no-console
throw wasReported(`Invalid compression algorithm ${algo} ( should be None, Brotli or Gzip)`);

throw wasReported(
`Invalid compression algorithm ${algo} ( should be None, Brotli or Gzip)`
);
}
if (doCompress !== CompressType.None) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -350,7 +360,7 @@ export async function exec(argv2: string[]) {
if (!existsSync(inputBin)) {
throw wasReported(
'Bin file does not exist (taken from package.json ' +
"'bin' property)",
"'bin' property)",
[inputBin]
);
}
Expand Down Expand Up @@ -632,8 +642,28 @@ export async function exec(argv2: string[]) {
}

const slash = target.platform === 'win' ? '\\' : '/';
await producer({ backpack, bakes, slash, target: target as Target, symLinks, doCompress });
await producer({
backpack,
bakes,
slash,
target: target as Target,
symLinks,
doCompress,
});

if (target.platform !== 'win' && target.output) {
if (target.platform === 'macos') {
// patch executable to allow code signing
const buf = patchMachOExecutable(readFileSync(target.output));
writeFileSync(target.output, buf);

if (hostPlatform === 'macos') {
// sign executable ad-hoc to workaround the new mandatory signing requirement
// users can always replace the signature if necessary
execSync(`codesign --sign - ${target.output}`);
}
}

await plusx(target.output);
}
}
Expand Down
58 changes: 58 additions & 0 deletions lib/mach-o.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
function parseCStr(buf: Buffer) {
for (let i = 0; i < buf.length; i += 1) {
if (buf[i] === 0) {
return buf.slice(0, i).toString();
}
}
}

function patchCommand(type: number, buf: Buffer, file: Buffer) {
// segment_64
if (type === 0x19) {
const name = parseCStr(buf.slice(0, 16));

if (name === '__LINKEDIT') {
const fileoff = buf.readBigUInt64LE(32);
const vmsize_patched = BigInt(file.length) - fileoff;
const filesize_patched = vmsize_patched;

buf.writeBigUInt64LE(vmsize_patched, 24);
buf.writeBigUInt64LE(filesize_patched, 40);
}
}

// symtab
if (type === 0x2) {
const stroff = buf.readUInt32LE(8);
const strsize_patched = file.length - stroff;

buf.writeUInt32LE(strsize_patched, 12);
}
}

function patchMachOExecutable(file: Buffer) {
const align = 8;
const hsize = 32;

const ncmds = file.readUInt32LE(16);
const buf = file.slice(hsize);

for (let offset = 0, i = 0; i < ncmds; i += 1) {
const type = buf.readUInt32LE(offset);

offset += 4;
const size = buf.readUInt32LE(offset) - 8;

offset += 4;
patchCommand(type, buf.slice(offset, offset + size), file);

offset += size;
if (offset & align) {
offset += align - (offset & align);
}
}

return file;
}

export { patchMachOExecutable };

0 comments on commit be5c2ae

Please sign in to comment.