#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
int main(int argc,char**argv){ setbuf(stdout,NULL);
  const char*path=argv[1];
  int fd=open(path,O_RDONLY); struct stat st; fstat(fd,&st);
  unsigned char *file=malloc(st.st_size); read(fd,file,st.st_size);
  struct mach_header_64 *hdr=(void*)file;
  unsigned char *lc=(unsigned char*)(hdr+1);
  unsigned long long total=0; for(unsigned int c=0;c<hdr->ncmds;c++){struct load_command*cc=(void*)lc; if(cc->cmd==LC_SEGMENT_64){struct segment_command_64*s=(void*)lc; unsigned long long end=s->vmaddr+s->vmsize; if(end>total)total=end;} lc+=cc->cmdsize;}
  total=(total+16383)&~16383ULL;
  unsigned char *base=mmap(NULL,total,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0);
  lc=(unsigned char*)(hdr+1);
  for(unsigned int c=0;c<hdr->ncmds;c++){struct load_command*cc=(void*)lc; if(cc->cmd==LC_SEGMENT_64){struct segment_command_64*s=(void*)lc; if(strcmp(s->segname,"__LINKEDIT")) memcpy(base+s->vmaddr,file+s->fileoff,s->filesize); if(!strcmp(s->segname,"__TEXT")){int r=mprotect(base+s->vmaddr,s->vmsize,PROT_READ|PROT_EXEC);printf("mprotect text r=%d errno=%d\n",r,errno);}} lc+=cc->cmdsize;}
  /* find symtab + answer */
  unsigned long long symoff=0,stroff=0; unsigned int nsyms=0;
  lc=(unsigned char*)(hdr+1);
  for(unsigned int c=0;c<hdr->ncmds;c++){struct load_command*cc=(void*)lc; if(cc->cmd==LC_SYMTAB){struct symtab_command*s=(void*)lc;symoff=s->symoff;nsyms=s->nsyms;stroff=s->stroff;} lc+=cc->cmdsize;}
  struct nlist_64 *sym=(void*)(file+symoff); void*ans=0;
  for(unsigned int i=0;i<nsyms;i++){const char*n=(char*)file+stroff+sym[i].n_un.n_strx; if(!strcmp(n,"_answer"))ans=base+sym[i].n_value;}
  printf("ans=%p\n",ans); int(*f)(void)=ans; printf("call -> %d\n",f()); return 0;
}
