mirror of
https://github.com/upx/upx.git
synced 2024-11-27 14:40:25 +00:00
WIP: smallest executable on Apple M1 (aarch64 or arm64)
Requirements for success after snipping a loader_command: "codesign -s - my_app" must succeed. "lldb my_app; process launch -s; continue" must succeed. Optional loader_commands (macho-snip can remove these successfully): LC_UUID, LC_BUILD_VERSION, LC_SOURCE_VERISON, LC_DATA_IN_CODE (when 0==datasize) Apple "strip -N" clears out LC_SYMTAB and LC_DYSYMTAB, but leaves LC_DYLD_INFO_ONLY.export_size. Perhaps this could be zero if constructed that way; snipping seems tedious because codesign requires that __LINKEDIT must have no gaps. LC_FUNCTION_STARTS seems to be required by codesign. codesign wants offsets that point into __LINKEDIT to be in order: LC_DYLD_INFO_ONLY, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_SYMTAB MacOS seesm to require LC_LOAD_DYLINKER (else "zsh: Kiled"), which seems to require LD_LOAD_DYLIB (else SIGABRT). https://github.com/upx/upx/issues/446 ---- modified: macho-snip.c modified: udf.s
This commit is contained in:
parent
480ab51650
commit
252143d0bb
@ -247,10 +247,11 @@ main(int argc, char const * /*const*/ *const argv, char const *const *const envp
|
||||
unsigned ncmds = mhdr->ncmds;
|
||||
unsigned headway = mhdr->sizeofcmds;
|
||||
struct load_command *cmd = (struct load_command *)(1+ mhdr);
|
||||
for (; ncmds; --ncmds) {
|
||||
struct load_command *cmd_next;
|
||||
unsigned delta_dataoff = 0;
|
||||
for (; ncmds; --ncmds, cmd = cmd_next) {
|
||||
unsigned end_dataoff = 0;
|
||||
unsigned end_datasize = 0;
|
||||
struct load_command *cmd_next;
|
||||
again: ;
|
||||
fprintf(stderr, "cmd@%p %s %d(%#x)\n",
|
||||
cmd, cmd_names[cmd->cmd&0xFF].name, cmd->cmd&0xFF, cmd->cmd);
|
||||
@ -271,15 +272,7 @@ again: ;
|
||||
}
|
||||
} break;
|
||||
case LC_CODE_SIGNATURE: {
|
||||
fprintf(stderr, "macho-snip: LC_CODE_SIGNATURE not implemented\n");
|
||||
continue;
|
||||
struct linkedit_data_command *cmd_LED = (struct linkedit_data_command *)cmd;
|
||||
if (( cmd_LED->dataoff + cmd_LED->datasize )
|
||||
== (linkedit->fileoff + linkedit->filesize)) {
|
||||
linkedit->filesize -= cmd_LED->datasize;
|
||||
}
|
||||
memset(addr + linkedit->fileoff, 0, cmdsize);
|
||||
goto snip;
|
||||
fprintf(stderr, "macho-snip: use 'codesign --remove-signature' to remove LC_CODE_SIGNATURE\n");
|
||||
} break;
|
||||
|
||||
//struct nlist_64 {
|
||||
@ -305,6 +298,8 @@ again: ;
|
||||
// value per 4KB page) has offset (4 mod 16) instead of (0 mod 16).]
|
||||
|
||||
case LC_SYMTAB: {
|
||||
fprintf(stderr, "macho-snip: LC_SYMTAB skipped\n");
|
||||
continue;
|
||||
struct symtab_command *symcmd = (struct symtab_command *)cmd;
|
||||
if (( symcmd->strsize + symcmd->stroff)
|
||||
!= (linkedit->filesize + linkedit->fileoff)) {
|
||||
@ -328,6 +323,8 @@ again: ;
|
||||
symcmd->nsyms -= 1; // lop last symbol FIXME: generalize
|
||||
} break;
|
||||
case LC_DYSYMTAB: {
|
||||
fprintf(stderr, "macho-snip: LD_DYSYMTAB skipped\n");
|
||||
continue;
|
||||
struct dysymtab_command *dysym = (struct dysymtab_command *)cmd;
|
||||
if (0==(dysym->nundefsym -= 1)) { // FIXME: generalize
|
||||
dysym->iundefsym = 0;
|
||||
@ -335,15 +332,25 @@ again: ;
|
||||
} break;
|
||||
|
||||
case LC_BUILD_VERSION:
|
||||
case LC_DYLD_INFO: // also LC_DYLD_INFO_ONLY because low 8 bits
|
||||
case LC_LOAD_DYLIB:
|
||||
case LC_LOAD_DYLINKER:
|
||||
case LC_MAIN:
|
||||
case LC_SOURCE_VERSION: {
|
||||
case LC_SOURCE_VERSION:
|
||||
case LC_UUID:
|
||||
{
|
||||
for (jargv = 2; jargv < argc; ++jargv) {
|
||||
if (argv[jargv] && !strcmp(cmd_names[cmd->cmd & 0xFF].name, argv[jargv])) {
|
||||
argv_done |= 1uL << jargv;
|
||||
fprintf(stderr, "macho-snip: %#x, %s\n",
|
||||
cmd_names[cmd->cmd & 0xFF].val, cmd_names[cmd->cmd & 0xFF].name);
|
||||
// EXPERIMENT:
|
||||
if (cmd->cmd == LC_DYLD_INFO_ONLY) { // the "must process" case
|
||||
struct dyld_info_command *dyldcmd = (struct dyld_info_command *)cmd;
|
||||
dyldcmd->export_off = 0;
|
||||
dyldcmd->export_size = 0;
|
||||
goto next; // EXPERIMENT
|
||||
}
|
||||
goto snip;
|
||||
}
|
||||
}
|
||||
@ -366,8 +373,7 @@ again: ;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
cmd = (struct load_command *)(cmdsize + (void *)cmd);
|
||||
continue;
|
||||
continue; // no changes ==> advance
|
||||
snip_linkedit_data_command: ;
|
||||
struct linkedit_data_command *ldc = (struct linkedit_data_command *)cmd;
|
||||
end_datasize = ldc->datasize;
|
||||
@ -379,12 +385,12 @@ snip_linkedit_data_command: ;
|
||||
snip: ;
|
||||
memmove(cmd, cmd_next, headway);
|
||||
memset(headway + (char *)cmd, 0, cmdsize); // space that was vacated
|
||||
cmd_next = cmd; // we moved *cmd_next to *cmd
|
||||
cmd_next = cmd; // we moved tail at *cmd_next to *cmd
|
||||
mhdr->sizeofcmds -= cmdsize;
|
||||
mhdr->ncmds -= 1;
|
||||
argv[jargv] = 0; // snip only once per argv[]
|
||||
} // switch
|
||||
cmd = cmd_next;
|
||||
next: ;
|
||||
} // ncmds
|
||||
argv_done |= (1<<1) | (1<<0); // argv[0,1] do not name linker_commands
|
||||
if (~(~0uL << argc) != argv_done) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
.align 4
|
||||
// start: .globl start # for standalone
|
||||
_main: .globl _main # for -lc
|
||||
// start: .globl start /* for standalone */
|
||||
_main: .globl _main /* for -lc */
|
||||
#ifdef __x86_64__
|
||||
ud2
|
||||
#endif
|
||||
#ifdef __AARCH64EL__
|
||||
.int 0x7b # udf 123
|
||||
.int 0x7b /* udf 123 */
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user