-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearcher.c
executable file
·294 lines (254 loc) · 7.2 KB
/
searcher.c
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/**
* Purpose: Search a binary file for a specified hexadecimal pattern
* Programmer: Benjamin Bunk
* Input: File location, Hexadecimal set to search for
* Output: Beginning offset of where it is found, the filename, and a check of the data comparison.
*/
// Headers
#include <stdio.h> // printf
#include <string.h> // memcmp
#include <dirent.h> // struct dirent, type DIR
#include <stdbool.h> // bool
#include <stdlib.h> // exit
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <fts.h>
// Function Prototypes
int convert(char *, int);
int find_in_buffer(unsigned char *, size_t, unsigned char *, size_t);
int search(const char *);
int r_search();
void printHexBuffer(unsigned char *, size_t);
int g_hit_counter = 0;
void *input;
size_t input_length;
/**
* Main entry point.
*/
int main(int argc, char *argv[])
{
// Process arguments.
if(argc < 3) {
// Program heading.
printf("\n\n%s\n", "Searcher v0.2");
printf("%s\n", "Author: Ben Bunk");
printf("%s\n\n", "Purpose: Search a file for a hexadecimal pattern.");
printf("%s\n", "Format: searcher [filename] [hex data]");
printf("%s\n", "Example: searcher AllWeKnow.mp3 00 32 30 30 35 20 20 20 20 20 20 20 20 20 20");
printf("%s\n", "Example (Recursive Search from root (/)): searcher r 00 32 30 30 35 20 20 20 20 20 20 20 20 20 20");
printf("%s\n", "Recursive is restricted to the first 20 levels of directory stucture.");
}
else {
const char *filename = argv[1];
unsigned char input_buffer[argc-2];
// Convert input hex string to a hex array.
int i = 2;
while(argv[i]) {
input_buffer[i-2] = (unsigned char)convert(argv[i], 16);
i++;
}
// Set the global reference to the input.
input = input_buffer;
input_length = i - 2;
// Call the appropriate search method.
if (strcmp(filename, "r") == 0) {
// @todo pass in a path at some point.
r_search();
} else {
search(filename);
}
}
printf("\n\n\n");
return 0;
}
/**
* Convert a string hex characters into a char (hex) value.
*/
int convert(char *buffer, int cbase) {
int i;
int bin;
i = bin = 0;
while(buffer[i]) {
buffer[i] -= 48;
if(buffer[i] > 16)
buffer[i] -= 7;
if(buffer[i] >= cbase)
buffer[i] -= 32;
if(buffer[i] >= cbase || buffer[i] < 0)
break;
bin *= cbase;
bin += buffer[i];
i++;
}
return bin;
}
/**
* Find the starting position of one buffer inside of another.
*
* Partial matches are allowed if it is consecutive from it's start
* to the end of the window buffer. Meaning that if the first 3 values
* of the search buffer are found in the last 3 spaces of the window buffer
* it is considered a match because as much of the search buffer was found
* as possible.
* However if the first 3 values of the search buffer are found in the last 4
* positions of the window buffer but the 4 and final window buffer position
* doesn't match the 4th value in the search buffer then it would not be
* considered a match.
*
* Information from this function can be used to adjust the window size and
* read head position so that a faster function like @see memcmp can be used.
*
* unsigned char *search_buffer
* The buffer we are looking for.
* size_t search_len
* Size of the search_buffer.
* unsigned char *window_buffer
* The buffer we are looking in.
* size_t window_len
* Size of the window_buffer.
*
* Return int
* -1 if search buffer isn't found at all, N position in the window buffer if it is found.
*/
int find_in_buffer(unsigned char *search_buffer, size_t search_len, unsigned char *window_buffer, size_t window_len) {
int i;
int found_position = 0;
int search_position = 0;
bool found = false;
for (i = 0; i < window_len && search_position < search_len; i++) {
// If we find the match
if (window_buffer[i] == search_buffer[search_position]) {
if (found == false) {
found = true;
found_position = i;
}
search_position++;
}
else {
if (found == true) {
found = false;
search_position--;
i = found_position;
}
}
}
if (found == true) {
return found_position;
}
else {
return -1;
}
}
/**
* Search for a hex pattern in a given file.
*/
int search(const char *filename) {
unsigned char *input_buffer = (unsigned char *)input;
size_t buffer_length = input_length;
int i = 0;
int err = 0;
int ret_val = 0;
int found;
FILE *file;
size_t bytes_read;
int total_bytes_read = 0;
unsigned char buffer[buffer_length];
//printf("\nSearching: %s ", filename);
// Get the file handle.
if ((file = fopen(filename, "rb")) == NULL) {
//printf("Failed: %s\n", filename);
return ret_val = 1;
}
//Process the file for matches
do {
// Check if we have an occurence of our search embedded in the middle of this buffer.
if (total_bytes_read > 0) {
found = find_in_buffer(input_buffer, buffer_length, buffer, bytes_read);
if ( found != -1) {
total_bytes_read -= buffer_length;
total_bytes_read += found;
// Move the read head to the position we found.
// We are actually fast forwarding from the beginning, thus total bytes here.
fseek(file, total_bytes_read, SEEK_SET);
}
}
// Pull in a new buffer based on where the read head is. @see fseek().
bytes_read = fread(buffer, 1, buffer_length, file);
// Break at the end of the file.
if(bytes_read < buffer_length) {
err = 1;
break;
}
// Increment the Byte counter.
total_bytes_read += buffer_length;
}
while(memcmp(input_buffer, buffer, bytes_read) != 0);
// Close the file handle.
fclose(file);
// If Success.
if (err != 1) {
ret_val = 2;
/*printf("\nSuccess!\n Input: ");
printHexBuffer(input_buffer, buffer_length);
printf("\n Output: ");
printHexBuffer(buffer, bytes_read);
printf("\n Position: %d", total_bytes_read);*/
}
return ret_val;
}
/**
* Recursively trace a file structure specified in path.
*
* This function only contains the directory scanning logic and any
* aggreagate statistics at the file level.
* @see search() for information on byte level matching.
*
* @see fts()
*/
int r_search(char const *path) {
int ret_val = 0;
int i = 1;
char * const filepaths[] = {
"/", // Default directory.
NULL
};
FTS *ftsp;
FTSENT *p, *chp;
int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR;
int rval = 0;
if ((ftsp = fts_open(filepaths, fts_options, NULL)) == NULL) {
warn("fts_open");
return -1;
}
chp = fts_children(ftsp, 0);
if (chp == NULL) {
return 0; /* no files to traverse */
}
while ((p = fts_read(ftsp)) != NULL) {
switch (p->fts_info) {
case FTS_F:
ret_val = search(p->fts_path);
break;
default:
break;
}
if (ret_val > 1) {
g_hit_counter++;
//break; // Stop on a match.
}
}
fts_close(ftsp);
printf("\n\n\n Matches: %d", g_hit_counter);
return ret_val;
}
/**
* Print Hex Buffer helper method.
*/
void printHexBuffer (unsigned char *buffer, size_t len) {
int i;
for (i = 0; i < len; i++) {
printf("%.2X ", buffer[i]);
}
return;
}