forked from iagox86/dnscat2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuffer.h
189 lines (153 loc) · 8.94 KB
/
buffer.h
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* buffer.h
* By Ron
* Created August, 2008
*
* (See LICENSE.md)
*
* This is a generic class for buffering (marshalling) data that in many ways
* dates back to my days as a Battle.net developers. It gives programmers an
* easy way to prepare data to be sent on the network, as well as a simplified
* way to build strings in a language where string building isn't always
* straight forward. In many ways, it's like the pack()/unpack() functions from
* Perl.
*
* I've strived to keep this implementation the same on every platform. You'll
* notice that there's no Windows-specific code here, and also that all
* calculations will work on both a little- or big-endian system. The only time
* you won't get the same results is when you create a buffer with the type
* BO_HOST, which always uses the host's byte ordering. I don't recommend that.
*/
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <stdlib.h> /* For "size_t". */
#include "types.h"
typedef enum
{
BO_HOST, /* Use the byte order of the host (bad idea -- changes on systems. */
BO_NETWORK, /* Use network byte order which, as it turns out, is big endian. */
BO_LITTLE_ENDIAN, /* Use big endian byte ordering (0x12345678 => 78 56 34 12). */
BO_BIG_ENDIAN, /* Use big endian byte ordering (0x12345678 => 12 34 56 78). */
} BYTE_ORDER_t;
/* This struct shouldn't be accessed directly */
typedef struct
{
/* Byte order to use */
BYTE_ORDER_t byte_order;
/* The current position in the string, used when reading it. */
size_t position;
/* The maximum length of the buffer that "buffer" is pointing to. When
* space in this runs out, it's expanded */
size_t max_length;
/* The current length of the buffer. */
size_t current_length;
/* The current buffer. Will always point to a string of length max_length */
uint8_t *data;
/* Set to FALSE when the packet is destroyed, to make sure I don't accidentally
* re-use it (again) */
NBBOOL valid;
} buffer_t;
/* Create a new packet buffer */
buffer_t *buffer_create(BYTE_ORDER_t byte_order);
/* Create a new packet buffer, with data. */
buffer_t *buffer_create_with_data(BYTE_ORDER_t byte_order, const void *data, const size_t length);
/* Go to the start of the buffer. */
void buffer_reset(buffer_t *buffer);
/* Destroy the buffer and free resources. If this isn't used, memory will leak. */
void buffer_destroy(buffer_t *buffer);
/* Makes a copy of the buffer. */
buffer_t *buffer_duplicate(buffer_t *base);
/* Get the length of the buffer. */
size_t buffer_get_length(buffer_t *buffer);
/* Get the current location in the buffer. */
size_t buffer_get_current_offset(buffer_t *buffer);
/* Set the current location in the buffer. */
void buffer_set_current_offset(buffer_t *buffer, size_t position);
/* Get the number of bytes between the current offset and the end of the buffer. */
size_t buffer_get_remaining_bytes(buffer_t *buffer);
/* Clear out the buffer. Memory is kept, but the contents are blanked out and the pointer is returned
* to the beginning. */
void buffer_clear(buffer_t *buffer);
/* Align the buffer to even multiples. */
void buffer_read_align(buffer_t *buffer, size_t align);
void buffer_write_align(buffer_t *buffer, size_t align);
/* Consume (discard) bytes. */
void buffer_consume(buffer_t *buffer, size_t count);
/* Return the contents of the buffer in a newly allocated string. Fill in the length, if a pointer
* is given. Note that this allocates memory that has to be freed! */
uint8_t *buffer_create_string(buffer_t *buffer, size_t *length);
/* Does the same thing as above, but also frees up the buffer (good for a function return). */
uint8_t *buffer_create_string_and_destroy(buffer_t *buffer, size_t *length);
/* Returns the contents of the buffer - starting at the current position - in a newly allocated
* string. Returns the length in the length pointer. If max_bytes is -1, all bytes are returned. */
uint8_t *buffer_read_remaining_bytes(buffer_t *buffer, size_t *length, size_t max_bytes, NBBOOL consume);
/* Add data to the end of the buffer */
buffer_t *buffer_add_int8(buffer_t *buffer, const uint8_t data);
buffer_t *buffer_add_int16(buffer_t *buffer, const uint16_t data);
buffer_t *buffer_add_int32(buffer_t *buffer, const uint32_t data);
buffer_t *buffer_add_ntstring(buffer_t *buffer, const char *data);
buffer_t *buffer_add_string(buffer_t *buffer, const char *data);
/* Note: UNICODE support is a hack -- it adds every second character as a NULL, but is otherwise ASCII. */
buffer_t *buffer_add_unicode(buffer_t *buffer, const char *data);
buffer_t *buffer_add_bytes(buffer_t *buffer, const void *data, const size_t length);
buffer_t *buffer_add_buffer(buffer_t *buffer, const buffer_t *source);
/* Add data to the middle of a buffer. These functions won't write past the end of the buffer, so it's
* up to the programmer to be careful. */
buffer_t *buffer_add_int8_at(buffer_t *buffer, const uint8_t data, size_t offset);
buffer_t *buffer_add_int16_at(buffer_t *buffer, const uint16_t data, size_t offset);
buffer_t *buffer_add_int32_at(buffer_t *buffer, const uint32_t data, size_t offset);
buffer_t *buffer_add_ntstring_at(buffer_t *buffer, const char *data, size_t offset);
buffer_t *buffer_add_string_at(buffer_t *buffer, const char *data, size_t offset);
buffer_t *buffer_add_unicode_at(buffer_t *buffer, const char *data, size_t offset);
buffer_t *buffer_add_bytes_at(buffer_t *buffer, const void *data, const size_t length, size_t offset);
buffer_t *buffer_add_buffer_at(buffer_t *buffer, const buffer_t *source, size_t offset);
/* Read the next data from the buffer. The first read will be at the beginning.
* An assertion will fail and the program will end if read off
* the end of the buffer; it's probably a good idea to verify that enough data can be removed
* before actually attempting to remove it; otherwise, a DoS condition can occur */
uint8_t buffer_read_next_int8(buffer_t *buffer);
uint16_t buffer_read_next_int16(buffer_t *buffer);
uint32_t buffer_read_next_int32(buffer_t *buffer);
char *buffer_read_next_ntstring(buffer_t *buffer, char *data_ret, size_t max_length);
char *buffer_read_next_unicode(buffer_t *buffer, char *data_ret, size_t max_length);
char *buffer_read_next_unicode_data(buffer_t *buffer, char *data_ret, size_t length);
void *buffer_read_next_bytes(buffer_t *buffer, void *data, size_t length);
/* Allocate memory to hold the result. */
char *buffer_alloc_next_ntstring(buffer_t *buffer);
/* Read the next data, without incrementing the current pointer. */
uint8_t buffer_peek_next_int8(buffer_t *buffer);
uint16_t buffer_peek_next_int16(buffer_t *buffer);
uint32_t buffer_peek_next_int32(buffer_t *buffer);
char *buffer_peek_next_ntstring(buffer_t *buffer, char *data_ret, size_t max_length);
char *buffer_peek_next_unicode(buffer_t *buffer, char *data_ret, size_t max_length);
void *buffer_peek_next_bytes(buffer_t *buffer, void *data, size_t length);
/* Read data at the specified location in the buffer (counting the first byte as 0). */
uint8_t buffer_read_int8_at(buffer_t *buffer, size_t offset);
uint16_t buffer_read_int16_at(buffer_t *buffer, size_t offset);
uint32_t buffer_read_int32_at(buffer_t *buffer, size_t offset);
char *buffer_read_ntstring_at(buffer_t *buffer, size_t offset, char *data_ret, size_t max_length);
char *buffer_read_unicode_at(buffer_t *buffer, size_t offset, char *data_ret, size_t max_length);
char *buffer_read_unicode_data_at(buffer_t *buffer, size_t offset, char *data_ret, size_t length);
void *buffer_read_bytes_at(buffer_t *buffer, size_t offset, void *data, size_t length);
/* Allocate memory to hold the result. */
char *buffer_alloc_ntstring_at(buffer_t *buffer, size_t offset);
/* These NBBOOL functions check if there are enough bytes left in the buffer to remove
* specified data. These should always be used on the server side to verify valid
* packets for a critical service. */
NBBOOL buffer_can_read_int8(buffer_t *buffer);
NBBOOL buffer_can_read_int16(buffer_t *buffer);
NBBOOL buffer_can_read_int32(buffer_t *buffer);
NBBOOL buffer_can_read_ntstring(buffer_t *buffer);
NBBOOL buffer_can_read_unicode(buffer_t *buffer);
NBBOOL buffer_can_read_bytes(buffer_t *buffer, size_t length);
/* These functions check if there are enough bytes in the buffer at the specified location. */
NBBOOL buffer_can_read_int8_at(buffer_t *buffer, size_t offset);
NBBOOL buffer_can_read_int16_at(buffer_t *buffer, size_t offset);
NBBOOL buffer_can_read_int32_at(buffer_t *buffer, size_t offset);
NBBOOL buffer_can_read_ntstring_at(buffer_t *buffer, size_t offset, size_t max_length);
NBBOOL buffer_can_read_unicode_at(buffer_t *buffer, size_t offset, size_t max_length);
NBBOOL buffer_can_read_bytes_at(buffer_t *buffer, size_t offset, size_t length);
/* Print out the buffer in a nice format -- useful for debugging. */
void buffer_print(buffer_t *buffer);
/* Returns a pointer to the actual buffer (I don't recommend using this). */
uint8_t *buffer_get(buffer_t *buffer, size_t *length);
#endif