/*
 * Empilhador de strings - Copyright 2004 by Narcotic <narcotic@motdlabs.org>
 *
 *
 * Esse programa cria codigo p/ empilhar strings na pilha e ser usada num shellcode
 *   Uso: empilha [-o] [-s sintaxe] [-r registrador] string\n");
 *	-o               imprime os opcode\n");
 *	-s sintaxe       sintaxe usada [att/intel]\n");
 *	-r registrador   registrador q vai receber o end da string\n");
 *                   	 (eax, ebx, ecx ou edx\n\n");
 *    
 * Ex de uso: empilha -s intel -o -r edx ABCDEF
 *
 *
 * Por padrao o programa assume o uso do registrador eax e da sintaxe INTEL
 *
 */
 
 
#include <stdio.h>
#include <string.h>

#ifndef false
#define false 0
#define true  1
#endif

enum 
{
	ATT,
	INTEL
};


#define PUSHA	"pushl $"
#define PUSHI	"push "

char *registers[] = { 
	"eax", "ebx", "ecx", "edx" 
};

/****     construcao dos opcodes p/ o shellcode            ****/
/* Esse codigo cuida apenas de alguns opcodes, limitados aos  */
/* q o programa gera p/ empilhar a string, sao eles:          */
/*  mov, xor, push e shr                                      */

/* cada registrador eh representado por 3 bits */
enum 
{
	EAX,      /* 000 */
	ECX,	  /* 001 */
	EDX,	  /* 010 */
	EBX,	  /* 011 */
	ESP	  /* 100 */
};

typedef union _instruction {
	unsigned char bytes[4];
	unsigned int  opcode;
} instruction;

typedef struct _command {
	instruction inst;
	unsigned char *data;
	unsigned char *dissasm;
	struct _command *next;
} command;


/* 0011 0011 11 reg reg */
#define XOR_REGISTER 0x33C0

/* move valor imediato p/ registrador */
/* 1011 w reg : dados */
#define MOV_REGISTER_DATA 0xB0
/* 1000 1011 11 reg reg */
#define MOV_REGISTER_REGISTER 0x8BC0

/* tamanho dos operadores - 1 byte sig 16 bits */
#define OPERAND_SIZE 0x66

/* 0101 0 reg */
#define PUSH_REGISTER 0x50
/* 0110 1000 : dados */
#define PUSH_IMMEDIATE 0x68

/* 1100 0001 1110 1 reg : dados */
#define SHR_REGISTER_IMM 0xC1E8


/* macros */
#define XOR_RR(reg1,reg2)	(XOR_REGISTER | (reg1 << 3) | reg2)
#define SHR_RI(reg)		(SHR_REGISTER_IMM | reg)

#define MOV_RI32(reg)		(MOV_REGISTER_DATA | 0x08 | reg)
#define MOV_RI16(reg)		((OPERAND_SIZE << 8) | (MOV_REGISTER_DATA | 0x08 | reg))
#define MOV_RI8(reg)		(MOV_REGISTER_DATA | reg)
#define MOV_RR(reg1,reg2)	(MOV_REGISTER_REGISTER | (reg1 << 3) | reg2)

#define PUSH_R(reg)		(PUSH_REGISTER | reg)
#define PUSH_I()		(PUSH_IMMEDIATE)

		
int main(int argc, char **argv)
{
	int len;
	char *str, *reg, *push;
	char reg_opcode;
	
	char buff[64] = { 0 };
	char *param;
	int sintaxe, i;
	int print_opcodes;

	command *tmp, *actual, *list = NULL;
	
	
	if(argc < 2)
	{
		printf("Empilhador de strings 32-bit para 80x86\n");
		printf("Copyright (c) by Narcotic <narcotic@motdlabs.org>\n");
		printf("   Uso: empilha [-o] [-s sintaxe] [-r registrador] string\n");
		printf("   -o               imprime os opcode\n");
		printf("   -s sintaxe       sintaxe usada [att/intel]\n");
		printf("   -r registrador   registrador q vai receber o end da string\n");
		printf("                    (eax, ebx, ecx ou edx\n\n");
		
		return -1;
	}

	/* valores assumidos por padrao */
	reg        = registers[0]; /* EAX */
	reg_opcode = EAX;
	sintaxe    = INTEL;
	print_opcodes = false;
	
	/* trata a entrada */
	for(i = 1; i < argc; i++)
	{
		if(argv[i][0] == '-')
		{
			switch(argv[i][1])
			{
				case 'o': print_opcodes = true;
				          break; 
				          
				case 's': if((i + 1) == argc)
					  {
					  	printf("argumento invalido \"-s\": falta sintaxe\n");
					  	return -1;
					  }
					  
					  param = argv[i + 1];
					  
					  if(strcmp(param,"att") == 0)
					  	sintaxe = ATT;
					  else if(strcmp(param,"intel") == 0)
					  	sintaxe = INTEL;
					  else
					  {
					  	printf("argumento invalido \"-s\": sintaxe inexistente\n");
					  	return -1;
					  }
					  
					  break;
					  	
				case 'r': if((i + 1) == argc)
					  {
					  	printf("argumento invalido \"-r\": falta registrador\n");
					  	return -1;
					  }
					  
					  param = argv[i + 1];
					  
					  if(param[0] == 'e' && param[2] == 'x')
					  {					  	
					  	int reg_num = param[1] - 'a';
					  	
					  	if(reg_num >= 0 && reg_num < 4)
					  	{
					  		reg = registers[reg_num];
					  		
					  		switch(reg_num)
					  		{
		  						case 0: reg_opcode = EAX; break;
								case 1: reg_opcode = EBX; break;
								case 2: reg_opcode = ECX; break;
								case 3: reg_opcode = EDX; break;
							}
						}
						else
						{
						  	printf("argumento invalido \"-r\": registrador desconhecido\n");
						  	return -1;
						}
					}
					else
					{
					  	printf("argumento invalido \"-r\": registrador desconhecido\n");
					  	return -1;
					}
					
					break;
					
				default: /* nao eh ultimo parametro *string* */
					if(i != argc - 1)
					{
						printf("parametro desconhecido\n");
						return -1;
					}
			}
		}
	}
	
	
	str = argv[argc - 1];
	len = strlen(str);
	
	/* aloca memoria p/ o primeiro elemento da nossa lista */
	list 	   = (command *)malloc(sizeof(command));
	list->next = NULL;
	
	actual = tmp = list;
				
	/* apenas 4 caracteres podem ser empilhados por vez */
	switch(len % 4)
	{
		/* nossa string eh multipla de 4 */
		/* nao faz nda         		 */
		case 0: break;
			
		/* esta sobrando um byte  	     */
		/* carrega ele em xl (al, bl, cl..)  */
		case 1: tmp->inst.opcode = MOV_RI8(reg_opcode);
		 	tmp->data        = (char *)malloc(2 * sizeof(char));
		 	strcpy(tmp->data,str + len - 1);
		 			
			if(sintaxe == INTEL)
				sprintf(buff,"mov %cl, 0x%02X",reg[1],str[len - 1]);
			else
				sprintf(buff,"movl $0x%02X, %%%cl",str[len - 1],reg[1]);
				
			tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
			strcpy(tmp->dissasm,buff);
			break;
			
		/* 2 bytes sobrando 	     */
		/* joga em xx (ax, bx, cx..) */
		case 2:	tmp->inst.opcode = MOV_RI16(reg_opcode);
		 	tmp->data        = (char *)malloc(3 * sizeof(char));
		 	strcpy(tmp->data,str + len - 2);
		 	
			if(sintaxe == INTEL)
				sprintf(buff,"mov %cx, 0x%02X%02X",reg[1],str[len - 1],str[len - 2]);
			else
				sprintf(buff,"movl $0x%02X%02X, %%%cx",str[len - 1],str[len - 2],reg[1]);				
			
			tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
			strcpy(tmp->dissasm,buff);
			break;
		
		/* 3 bytes sobrando -- aki a coisa complica */
		/* precisamos mover 3 bytes e nao deixar sobrar 0x00 */
		/* entao dividimos em 2 instrucoes, um mov com 3 bytes + 1 byte de lixo */
		/* e um shr, q vai tirar o lixo p/ gente e depois empilha :) */
		case 3: tmp->inst.opcode = MOV_RI32(reg_opcode);
		 	tmp->data        = (char *)malloc(5 * sizeof(char));
		 	strcpy(tmp->data,str + len - 3);
		 	strcat(tmp->data,"\xFF");
				
			if(sintaxe == INTEL)
				sprintf(buff,"mov %s, 0x%02X%02X%02XFF",reg,str[len - 1],str[len - 2],str[len - 3]);
			else
				sprintf(buff,"movl $0x%02X%02X%02XFF, %%%s",str[len - 1],str[len - 2],str[len - 3],reg);

			tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
			strcpy(tmp->dissasm,buff);

			actual    = tmp;
			
			tmp 	  = (command *)malloc(sizeof(command));
			tmp->next = NULL;
			actual->next = tmp;
			
			tmp->inst.opcode = SHR_RI(reg_opcode);
		 	tmp->data        = (char *)malloc(2 * sizeof(char));
		 	strcpy(tmp->data,"\x08");
			
			if(sintaxe == INTEL)
				sprintf(buff,"shr %s, 8",reg);
			else
				sprintf(buff,"shr  $0x8, %%%s",reg);

			tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
			strcpy(tmp->dissasm,buff);
			break;
	}


	/* push p/ intel ou p/ AT&T */
	if(sintaxe == INTEL)
		push = PUSHI;
	else
		push = PUSHA;
		
	actual = tmp;

	/* coloca o xor como o primeiro na lista */
	tmp       = (command *)malloc(sizeof(command));
	tmp->next = list;
	list      = tmp;
			
	tmp->inst.opcode = XOR_RR(reg_opcode,reg_opcode);
 	tmp->data        = NULL;
	
	if(sintaxe == INTEL)
		sprintf(buff,"xor %s, %s",reg,reg);
	else
		sprintf(buff,"xorl %%%s, %%%s",reg,reg);
	
	tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
	strcpy(tmp->dissasm,buff);
	

	if(len % 4)	
	{
		tmp = (command *)malloc(sizeof(command));
		tmp->next    = NULL;
		actual->next = tmp;	
	}
	else
		tmp = actual;
			
	tmp->inst.opcode = PUSH_R(reg_opcode);
 	tmp->data        = NULL;
	
	/* empilha o registrador contendo o final da string */	 
	if(sintaxe == INTEL)
		sprintf(buff,"push %s",reg);
	else
		sprintf(buff,"pushl %%%s",reg);
		
	tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
	strcpy(tmp->dissasm,buff);
	
	actual = tmp;
		
	/* string de cabeca p/ baixo */
	for(i = len - (len % 4) - 4; i >= 0; i -= 4)
	{
		tmp 	     = (command *)malloc(sizeof(command));
		tmp->next    = NULL;
		actual->next = tmp;
			
		tmp->inst.opcode = PUSH_I();
 		tmp->data        = (char *)malloc(sizeof(char) * 5);
 		memcpy(tmp->data,str + i,4);
 		tmp->data[4] = 0;
		
		sprintf(buff,"%s0x%02X%02X%02X%02X",push,str[i + 3],str[i + 2],str[i + 1],str[i]);
		tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
		strcpy(tmp->dissasm,buff);
		
		actual = tmp;
	}
		
	/* move o end da string p/ registrador */
	tmp 	     = (command *)malloc(sizeof(command));
	tmp->next    = NULL;
	actual->next = tmp;
			
	tmp->inst.opcode = MOV_RR(reg_opcode,ESP);
	tmp->data        = NULL;
	
	
	if(sintaxe == INTEL)
		sprintf(buff,"mov %s, esp",reg);
	else
		sprintf(buff,"movl %%esp, %%%s",reg);
		
	tmp->dissasm = (char *)malloc((strlen(buff) + 1) * sizeof(char));
	strcpy(tmp->dissasm,buff);
	
	for(tmp = list; tmp; tmp = tmp->next)
	{
		if(print_opcodes)
		{
			if(tmp->inst.bytes[1])
				sprintf(buff,"\\x%02X\\x%02X",tmp->inst.bytes[1],tmp->inst.bytes[0]);
			else
				sprintf(buff,"\\x%02X",tmp->inst.bytes[0]);
			
			if(tmp->data != NULL)
			{
				len = strlen(tmp->data);
				
				for(i = 0; i < len; i++)
					sprintf(buff,"%s%\\x%02X",buff,tmp->data[i]);
			}
				
			printf("% -24s /* ",buff);
		}
		
		printf("%s",tmp->dissasm);
		
		if(print_opcodes)
			printf(" */");
		
		printf("\n");
	}
	
	return 0;		
}

