summaryrefslogtreecommitdiff
path: root/other/shellkit/mips.c
blob: dda3f92b19cc0ef4c3030390c63b50458e0f1d96 (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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* mips.c - generic mips functions
 *
 * by team teso
 */

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

static unsigned long int mips_nop_rwreg (void);
static unsigned long int mips_nop_roreg (void);
static unsigned long int mips_nop_xfer (char *xferstr);

/* mips generic isa "nop" space generator
 */

/* get random read write register (i.e. not sp, everything else allowed)
 */
static unsigned long int
mips_nop_rwreg (void)
{
	unsigned long int	reg;

	do {
		reg = random_get (0, 31);
	} while (reg == 29);	/* 29 = $sp */

	return (reg);
}


static unsigned long int
mips_nop_roreg (void)
{
	return (random_get (0, 31));
}


static unsigned long int
mips_nop_xfer (char *xferstr)
{
	int			bw = 0;	/* bitfield walker */
	unsigned long int	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, 5, mips_nop_roreg (), bw);
			break;
		case ('w'):
			BSET (tgt, 5, mips_nop_rwreg (), bw);
			break;
		case ('c'):
			BSET (tgt, 16, random_get (0, 0xffff), bw);
			break;
		case ('.'):
			break;	/* ignore */
		default:
			fprintf (stderr, "on steroids, huh?\n");
			exit (EXIT_FAILURE);
			break;
		}
	}

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

	return (tgt);
}


unsigned int
mips_nop (unsigned char *dest, unsigned int dest_len,
	unsigned char *bad, int bad_len)
{
	int	walk;
	int	bcount;	/* bad counter */
	char *	xs;
	char *	xferstr[] = {
		"000000.r.r.w.00000.000100",	/* sllv rs rt rd */
		"000000.r.r.w.00000.000110",	/* srlv rs rt rd */
		"000000.r.r.w.00000.000111",	/* srav rs rt rd */
		"000000.r.r.w.00000.100001",	/* addu rs rt rd */
		"000000.r.r.w.00000.100011",	/* subu rs rt rd */
		"000000.r.r.w.00000.100100",	/* and rs rt rd */
		"000000.r.r.w.00000.100101",	/* or rs rt rd */
		"000000.r.r.w.00000.100110",	/* xor rs rt rd */
		"000000.r.r.w.00000.100111",	/* nor rs rt rd */
		"000000.r.r.w.00000.101010",	/* slt rs rt rd */
		"000000.r.r.w.00000.101011",	/* sltu rs rt rd */
		"001001.r.w.c",			/* addiu rs rd const */
		"001010.r.w.c",			/* slti rs rd const */
		"001011.r.w.c",			/* sltiu rs rd const */
		"001100.r.w.c",			/* andi rs rd const */
		"001101.r.w.c",			/* ori rs rd const */
		"001110.r.w.c",			/* xori rs rd const */
		"001111.00000.w.c",		/* lui rd const */
		NULL,
	};
	unsigned long int	tgt;

	if (dest_len % 4) {
		fprintf (stderr, "off by %d padding of dest_len (= %u), rounding down\n",
			dest_len % 4, dest_len);
		dest_len -= (dest_len % 4);
	}

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

			dest[walk + 0] = (tgt >> 24) & 0xff;
			dest[walk + 1] = (tgt >> 16) & 0xff;
			dest[walk + 2] = (tgt >> 8) & 0xff;
			dest[walk + 3] = tgt & 0xff;
			if (badstr (&dest[walk], 4, bad, bad_len) == 0)
				break;
		}

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

	return (walk);
}