#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.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);
  size_t n=(st.st_size+16383)&~16383UL;
  void*p=mmap(NULL,n,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
  struct mach_header_64 *hdr=p;
  unsigned char *lc=(unsigned char*)(hdr+1);
  unsigned long long symoff=0,stroff=0; unsigned int nsyms=0;
  for(unsigned int i=0,cnt=0;cnt<hdr->ncmds;cnt++){
    struct load_command *c=(void*)lc;
    if(c->cmd==LC_SEGMENT_64){ struct segment_command_64 *s=(void*)lc; if(!strcmp(s->segname,"__TEXT")){ int r=mprotect((char*)p+s->vmaddr,s->vmsize,PROT_READ|PROT_EXEC); printf("mprotect %s %llx+%llx r=%d\n",s->segname,s->vmaddr,s->vmsize,r);} }
    if(c->cmd==LC_SYMTAB){ struct symtab_command *s=(void*)lc; symoff=s->symoff;stroff=s->stroff;nsyms=s->nsyms; }
    lc+=c->cmdsize;i+=c->cmdsize;
  }
  struct nlist_64 *sym=(void*)((char*)p+symoff); void *ans=0;
  for(unsigned int i=0;i<nsyms;i++){
    const char*name=(char*)p+stroff+sym[i].n_un.n_strx;
    if(strstr(name,"answer")) printf("sym %s type=%x sect=%d value=%llx\n",name,sym[i].n_type,sym[i].n_sect,sym[i].n_value);
    if(!strcmp(name,"_answer")) ans=(char*)p+sym[i].n_value;
  }
  printf("symoff=%llu stroff=%llu nsyms=%u ans=%p\n",symoff,stroff,nsyms,ans); int(*f)(void)=ans; printf("call -> %d\n",f()); return 0;
}
