summaryrefslogtreecommitdiff
path: root/other/shellkit/x86.c
blob: dd580c62a7e482f4c52d3d07930cc4f5875b5ffc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* x86.c - generic x86 functions
 *
 * by team teso
 */

#include <stdio.h>
#include <stdlib.h>
#include "shellcode.h"
#include "x86.h"


static unsigned long int x86_nop_rwreg (void);
static unsigned long int x86_nop_xfer (char *xferstr);


static unsigned long int
x86_nop_rwreg (void)
{
	unsigned long int	reg;

	do {
		reg = random_get (0, 7);
	} while (reg == 4);	/* 4 = $esp */

	return (reg);
}


static unsigned long int
x86_nop_xfer (char *xferstr)
{
	int			bw = 0;	/* bitfield walker */
	unsigned char		tgt;	/* resulting instruction */

	/* in a valid xferstr we trust */
	for (tgt = 0 ; xferstr != NULL && xferstr[0] != '\0' ; ++xferstr) {
		switch (xferstr[0]) {
		case ('0'):
			BSET (tgt, 1, 0, bw);
			break;
		case ('1'):
			BSET (tgt, 1, 1, bw);
			break;
		case ('r'):
			BSET (tgt, 3, x86_nop_rwreg (), bw);
			break;
		case ('.'):
			break;	/* ignore */
		default:
			fprintf (stderr, "on steroids, huh?\n");
			exit (EXIT_FAILURE);
			break;
		}
	}

	if (bw != 8) {
		fprintf (stderr, "invalid bitwalker: bw = %d\n", bw);
		exit (EXIT_FAILURE);
	}

	return (tgt);
}


unsigned int
x86_nop (unsigned char *dest, unsigned int dest_len,
	unsigned char *bad, int bad_len)
{
	int	walk;
	int	bcount;	/* bad counter */
	char *	xs;
	char *	xferstr[] = {
		"0011.0111",	/* aaa */
		"0011.1111",	/* aas */
		"1001.1000",	/* cbw */
		"1001.1001",	/* cdq */
		"1111.1000",	/* clc */
		"1111.1100",	/* cld */
		"1111.0101",	/* cmc */
		"0010.0111",	/* daa */
		"0010.1111",	/* das */
		"0100.1r",	/* dec <reg> */
		"0100.0r",	/* inc <reg> */
		"1001.1111",	/* lahf */
		"1001.0000",	/* nop */
		"1111.1001",	/* stc */
		"1111.1101",	/* std */
		"1001.0r",	/* xchg al, <reg> */
		NULL,
	};
	unsigned char	tgt;

/*
 * XXX: those nops are only one byte long. they could be used as byte values
 * in opcodes like mov (add, sub, or, ...) as value. that would increase the
 * randomness of the string. since the value is "nop save" we have no problem
 * if the execution starts within this nop.
 * now, having word sized nops, even larger nops are possible (again increasssing
 * the randomness of the nop string).
 * however, its a little complicated ;)
 */

	for (walk = 0 ; dest_len > 0 ; dest_len -= 1 , walk += 1) {
		/* avoid endless loops on excessive badlisting */
		for (bcount = 0 ; bcount < 16384 ; ++bcount) {
			xs = xferstr[random_get (0, 15)];
			tgt = x86_nop_xfer (xs);

			dest[walk] = tgt;
			if (badstr (&dest[walk], 1, bad, bad_len) == 0)
				break;
		}

		/* should not happen */
		if (bcount >= 16384) {
			fprintf (stderr, "too much blacklisting, giving up...\n");
			exit (EXIT_FAILURE);
		}
	}

	return (walk);
}