static int read_macho( int fd, struct mach_header *the_header, struct load_command ***the_commands, unsigned *the_commands_len ) { struct load_command command; struct load_command *buf; int i; int size; if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) { fatal_unexec("cannot read macho header"); return (0); } /* the mach header should already be in native form */ if (the_header->magic != MH_MAGIC) { fatal_unexec("wrong magic in macho header"); } for (i = 0; i < the_header->ncmds; i++) { if (read(fd, &command, sizeof(struct load_command)) != sizeof(struct load_command)) { fatal_unexec("cannot read macho load command header"); return (0); } size = command.cmdsize - sizeof(struct load_command); if (size < 0) { fatal_unexec("bogus load command size"); return (0); } buf = malloc(command.cmdsize); buf->cmd = command.cmd; buf->cmdsize = command.cmdsize; if (read(fd, ((char *)buf + sizeof(struct load_command)), size) != size) { fatal_unexec("cannot read load command data"); return (0); } save_command(buf, the_commands, the_commands_len); } /* Leave the file pointer at the beginning of the text segment */ return (1); }
static void mcopy(int ffd,int tfd, unsigned long fpos,unsigned long tpos,unsigned long len) { if ((ffd==-1)&&(tfd==-1)) { char *f,*t,*e; if (fpos>tpos) { f=(char *)fpos; t=(char *)tpos; e=(char *)(fpos+len); while(f<e) *t++=*f++; } else if (tpos>fpos) { f=(char *)(fpos+len); t=(char *)(tpos+len); e=(char *)fpos; while(f>e) *--t=*--f; } } else if (ffd==-1) { if (lseek(tfd,tpos,L_SET)<0) fatal_unexec("cannot seek target"); if (write(tfd,(void *)fpos,len)!=len) fatal_unexec("cannot write target"); } else if (tfd==-1) { if (lseek(ffd,fpos,L_SET)<0) fatal_unexec("cannot seek source"); if (read(ffd,(void *)tpos,len)!=len) fatal_unexec("cannot read source"); } else { int bread; char *buf=alloca(1<<16); if (lseek(ffd,fpos,L_SET)<0) fatal_unexec("cannot seek source"); if (lseek(tfd,tpos,L_SET)<0) fatal_unexec("cannot seek target"); while((len>0) && (bread=read(ffd,buf,MIN(1<<16,len)))>0) { if (bread<0) fatal_unexec("cannot read source"); if (write(tfd,buf,bread)!=bread) fatal_unexec("cannot write target"); len-=bread; } } }
void unexec( char *outfile, char *infile ) { int infd; int outfd; char tmpbuf[L_tmpnam]; char *tmpfile; infd = open(infile, O_RDONLY, 0); if (infd < 0) { fatal_unexec("cannot open input file `%s'", infile); exit(1); } tmpnam(tmpbuf); tmpfile = rindex(tmpbuf, '/'); if (tmpfile == NULL) { tmpfile = tmpbuf; } else { tmpfile++; } outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755); if (outfd < 0) { close(infd); fatal_unexec("cannot open tmp file `%s'", tmpfile); exit(1); } if (!unexec_doit(infd, outfd)) { close(infd); close(outfd); unlink(tmpfile); exit(1); } close(infd); close(outfd); if (rename(tmpfile, outfile) < 0) { unlink(tmpfile); fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile); exit(1); } }
static int read_macho( int fd, struct mach_header *the_header, struct load_command ***the_commands, unsigned *the_commands_len ) { struct load_command command; struct load_command *buf; int i; int size; if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) { fatal_unexec("cannot read macho header"); return (0); } for (i = 0; i < the_header->ncmds; i++) { if (read(fd, &command, sizeof(struct load_command)) != sizeof(struct load_command)) { fatal_unexec("cannot read macho load command header"); return (0); } size = command.cmdsize - sizeof(struct load_command); if (size < 0) { fatal_unexec("bogus load command size"); return (0); } buf = malloc(command.cmdsize); buf->cmd = command.cmd; buf->cmdsize = command.cmdsize; if (read(fd, ((char *)buf + sizeof(struct load_command)), size) != size) { fatal_unexec("cannot read load command data"); return (0); } save_command(buf, the_commands, the_commands_len); } return (1); }
void unexec(char *outfile,char *infile) { char tmpfile[MAXPATHLEN]; int infd,outfd; if ((infd=open(infile, O_RDONLY, 0))<0) fatal_unexec("cannot open input file `%s'", infile); strcpy(tmpfile,outfile); strcat(tmpfile,"-temp"); if ((outfd=open(tmpfile, O_RDWR|O_TRUNC|O_CREAT, 0755))<0) fatal_unexec("cannot open temporary output file `%s'",tmpfile); unexec_doit(infd,outfd); close(infd); close(outfd); if (rename(tmpfile, outfile)<0) { unlink(tmpfile); fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile); } }
static int filldatagap( vm_address_t start_address, vm_size_t *size, vm_address_t end_address ) { vm_address_t address; vm_size_t gapsize; address = (start_address + *size); gapsize = end_address - address; *size += gapsize; if (vm_allocate(task_self(), &address, gapsize, FALSE) != KERN_SUCCESS) { fatal_unexec("cannot vm_allocate"); return (0); } return (1); }
static int unexec_doit( int infd, int outfd ) { int i; struct load_command **the_commands = NULL; unsigned the_commands_len; struct mach_header the_header; int fgrowth = 0; int fdatastart; int fdatasize; int size; struct stat st; char *buf; vm_address_t data_address; vm_size_t data_size; vm_size_t vmaddr_growth = 0; vm_size_t dataseg_vmaddr, dataseg_vmend; struct segment_command *segment; #ifdef NS_TARGET unsigned long extreloff = 0; unsigned long nextrel = 0; struct dysymtab_command *dysymtab; struct relocation_info reloc_info; #endif if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) { return (0); } malloc_cookie = malloc_freezedry (); if (!get_data_region(&data_address, &data_size)) { return (0); } /* * DO NOT USE MALLOC IN THIS SECTION */ { /* * Fix offsets */ for (i = 0; i < the_commands_len; i++) { switch (the_commands[i]->cmd) { case LC_SEGMENT: segment = ((struct segment_command *) the_commands[i]); if (strcmp(segment->segname, SEG_DATA) == 0) { fdatastart = segment->fileoff; fdatasize = segment->filesize; fgrowth = (data_size - segment->filesize); segment->vmsize = data_size; segment->filesize = data_size; dataseg_vmaddr = segment->vmaddr; dataseg_vmend = segment->vmaddr + segment->vmsize; vmaddr_growth = segment->vmaddr + segment->vmsize; } else { ((struct segment_command *)the_commands[i])->fileoff += fgrowth; } if( strcmp( segment->segname, SEG_LINKEDIT ) == 0 ) { segment->vmaddr = vmaddr_growth; } break; case LC_SYMTAB: ((struct symtab_command *) the_commands[i])->symoff += fgrowth; ((struct symtab_command *) the_commands[i])->stroff += fgrowth; break; case LC_SYMSEG: ((struct symseg_command *) the_commands[i])->offset += fgrowth; break; #ifdef NS_TARGET case LC_DYSYMTAB: dysymtab = ((struct dysymtab_command *)the_commands[i]); extreloff = dysymtab->extreloff; nextrel = dysymtab->nextrel; dysymtab->indirectsymoff += fgrowth; dysymtab->extreloff += fgrowth; break; #endif default: break; } } /* * Write header */ if (write(outfd, &the_header, sizeof(the_header)) != sizeof(the_header)) { fatal_unexec("cannot write output file"); return (0); } /* * Write commands */ for (i = 0; i < the_commands_len; i++) { if (write(outfd, the_commands[i], the_commands[i]->cmdsize) != the_commands[i]->cmdsize) { fatal_unexec("cannot write output file"); return (0); } } /* * Write original text */ if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), L_SET) < 0) { fatal_unexec("cannot seek input file"); return (0); } size = fdatastart - (sizeof(the_header) + the_header.sizeofcmds); buf = my_malloc(size); if (read(infd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot read input file"); } if (write(outfd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot write output file"); return (0); } my_free(buf, size); /* * Write new data */ if (write(outfd, (char *)data_address, data_size) != data_size) { fatal_unexec("cannot write output file"); return (0); } } /* * OKAY TO USE MALLOC NOW */ /* * Write rest of file */ fstat(infd, &st); if (lseek(infd, fdatasize, L_INCR) < 0) { fatal_unexec("cannot seek input file"); return (0); } size = st.st_size - lseek(infd, 0, L_INCR); buf = malloc(size); if (read(infd, buf, size) != size) { free(buf); fatal_unexec("cannot read input file"); return (0); } if (write(outfd, buf, size) != size) { free(buf); fatal_unexec("cannot write output file"); return (0); } free(buf); #ifdef NS_TARGET /* * Fix up relocation entries in the data segment. */ if (lseek(infd, extreloff, L_SET) < 0) { fatal_unexec("cannot seek input file"); return (0); } for (i = 0; i < nextrel; i++) { long zeroval = 0; if (read(infd, &reloc_info, sizeof (reloc_info)) != sizeof (reloc_info)) { fatal_unexec("cannot read input file"); return (0); } if (reloc_info.r_address >= dataseg_vmaddr && reloc_info.r_address < dataseg_vmend) { if (lseek (outfd, fdatastart + reloc_info.r_address - dataseg_vmaddr, L_SET) < 0 ) { fatal_unexec("cannot seek input file"); return (0); } switch (reloc_info.r_length) { case 0: if (write(outfd, &zeroval, 1) != 1) { fatal_unexec("cannot write output file"); return (0); } break; case 1: if (write(outfd, &zeroval, 2) != 2) { fatal_unexec("cannot write output file"); return (0); } break; case 2: if (write(outfd, &zeroval, 4) != 4) { fatal_unexec("cannot write output file"); return (0); } break; } } } #endif return (1); }
static int unexec_doit( int infd, int outfd ) { int i; struct load_command **the_commands = NULL; unsigned the_commands_len; struct mach_header the_header; int fgrowth; int fdatastart; int fdatasize; int size; struct stat st; char *buf; vm_address_t data_address; vm_size_t data_size; struct segment_command *segment; if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) { return (0); } malloc_cookie = malloc_freezedry(); if (!get_data_region(&data_address, &data_size)) { return (0); } /* * DO NOT USE MALLOC IN THIS SECTION */ { /* * Fix offsets */ for (i = 0; i < the_commands_len; i++) { switch (the_commands[i]->cmd) { case LC_SEGMENT: segment = ((struct segment_command *) the_commands[i]); if (strcmp(segment->segname, SEG_DATA) == 0) { fdatastart = segment->fileoff; fdatasize = segment->filesize; fgrowth = (data_size - segment->filesize); segment->vmsize = data_size; segment->filesize = data_size; } break; case LC_SYMTAB: ((struct symtab_command *) the_commands[i])->symoff += fgrowth; ((struct symtab_command *) the_commands[i])->stroff += fgrowth; break; case LC_SYMSEG: ((struct symseg_command *) the_commands[i])->offset += fgrowth; break; default: break; } } /* * Write header */ if (write(outfd, &the_header, sizeof(the_header)) != sizeof(the_header)) { fatal_unexec("cannot write output file"); return (0); } /* * Write commands */ for (i = 0; i < the_commands_len; i++) { if (write(outfd, the_commands[i], the_commands[i]->cmdsize) != the_commands[i]->cmdsize) { fatal_unexec("cannot write output file"); return (0); } } /* * Write original text * We're already positioned at the beginning of the text * segment, so all we need to do is to copy the bytes. */ size = fdatastart - (sizeof(the_header) + the_header.sizeofcmds); buf = my_malloc(size); if (read(infd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot read input file"); } if (write(outfd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot write output file"); return (0); } my_free(buf, size); /* * Write new data */ if (write(outfd, (char *)data_address, data_size) != data_size) { fatal_unexec("cannot write output file"); return (0); } } /* * OKAY TO USE MALLOC NOW */ /* * Write rest of file */ fstat(infd, &st); if (lseek(infd, fdatasize, L_INCR) < 0) { fatal_unexec("cannot seek input file"); return (0); } size = st.st_size - lseek(infd, 0, L_INCR); buf = malloc(size); if (read(infd, buf, size) != size) { free(buf); fatal_unexec("cannot read input file"); return (0); } if (write(outfd, buf, size) != size) { free(buf); fatal_unexec("cannot write output file"); return (0); } free(buf); return (1); }