source: trunk/src/samhain_stealth.c@ 467

Last change on this file since 467 was 396, checked in by katerina, 13 years ago

Fix for ticket #294 (minor issues with stealth mode).

File size: 10.4 KB
Line 
1#include "config_xor.h"
2
3#ifdef HAVE_BROKEN_INCLUDES
4#define _ANSI_C_SOURCE
5#define _POSIX_SOURCE
6#endif
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <string.h>
12#include <ctype.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <errno.h>
17
18
19#ifndef SH_BUFSIZE
20#define SH_BUFSIZE 1024
21#endif
22
23#ifdef SH_STEALTH
24char * globber(const char * string);
25#define _(string) globber(string)
26#define N_(string) string
27#else
28#define _(string) string
29#define N_(string) string
30#endif
31
32#ifdef SH_STEALTH
33
34#ifndef SH_MAX_GLOBS
35#define SH_MAX_GLOBS 32
36#endif
37
38#ifndef GLOB_LEN
39#define GLOB_LEN 511
40#endif
41
42char * globber(const char * str)
43{
44 register int i, j;
45 static int count = -1;
46 static char glob[SH_MAX_GLOBS][GLOB_LEN+1];
47
48 ++count; if (count > (SH_MAX_GLOBS-1) ) count = 0;
49 j = strlen(str);
50 if (j > GLOB_LEN) j = GLOB_LEN;
51
52 for (i = 0; i < j; ++i)
53 {
54 if (str[i] != '\n' && str[i] != '\t')
55 glob[count][i] = str[i] ^ XOR_CODE;
56 else
57 glob[count][i] = str[i];
58 }
59 glob[count][j] = '\0';
60 return glob[count];
61}
62#endif
63
64static unsigned long off_data;
65
66char sh_util_charhex( int c )
67{
68 if ( c >= 0 && c <= 9 )
69 return '0' + c;
70 else if ( c >= 10 && c <= 15 )
71 return 'a' + (c - 10);
72 else
73 {
74 fprintf(stderr, _("Out of range: %d\n"), c);
75 return 'X';
76 }
77}
78
79int sh_util_hexchar( char c )
80{
81 if ( c >= '0' && c <= '9' )
82 return c - '0';
83 else if ( c >= 'a' && c <= 'f' )
84 return c - 'a' + 10;
85 else if ( c >= 'A' && c <= 'F' )
86 return c - 'A' + 10;
87 else return -1;
88}
89
90/* --------- third step -----------
91 *
92 * get data from a block of hex data
93 */
94int hideout_hex_block(int fd, unsigned char * str, int len)
95{
96 register int i, j, k;
97 unsigned char c, e;
98 register int num;
99 unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
100 unsigned long here = 0;
101 unsigned long retval = 0;
102
103 i = 0;
104 while (i < len)
105 {
106 for (j = 0; j < 8; ++j)
107 {
108
109 /* get a low byte, modify, read back */
110 for (k = 0; k < 2; ++k)
111 {
112 c = ' ';
113 do {
114 do {
115 num = read (fd, &c, 1);
116 } while (num == 0 && errno == EINTR);
117 if (num == 0) return -1;
118 ++here;
119 } while (c == '\n' || c == '\t' || c == '\r' ||
120 c == ' ');
121 }
122
123
124 /* e is the value of the low byte
125 */
126 e = (unsigned char) sh_util_hexchar( c );
127 if ((e & mask[7]) != 0) /* bit is set */
128 str[i] |= mask[j];
129 else /* bit is not set */
130 str[i] &= ~mask[j];
131
132 }
133 if (str[i] == '\n') break;
134 ++i;
135 }
136 str[i+1] = '\0';
137 retval += here;
138 return retval;
139}
140
141/* --------- second step -----------
142 *
143 * hide data in a block of hex data
144 */
145int hidein_hex_block(int fd, char * str, int len)
146{
147 register int i, j, k;
148 unsigned char c, d, e;
149 register int num;
150 unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
151 unsigned long here = 0;
152 unsigned long retval = 0;
153
154 for (i = 0; i < len; ++i)
155 {
156 d = str[i];
157 for (j = 0; j < 8; ++j)
158 {
159
160 /* get a low byte, modify, read back */
161 for (k = 0; k < 2; ++k)
162 {
163 c = ' ';
164 do {
165 do {
166 num = read (fd, &c, 1);
167 } while (num == 0 && errno == EINTR);
168 if (num == 0) return -1;
169 ++here;
170 } while (c == '\n' || c == '\t' || c == '\r' ||
171 c == ' ');
172 }
173
174 /* e is the value of the low byte
175 */
176 e = (unsigned char) sh_util_hexchar( c );
177 if ((d & mask[j]) != 0) /* bit is set */
178 e |= mask[7];
179 else /* bit is not set */
180 e &= ~mask[7];
181
182 e = sh_util_charhex ( e );
183 lseek(fd, -1, SEEK_CUR);
184 do {
185 num = write(fd, &e, 1);
186 } while (num == 0 && errno == EINTR);
187 }
188 }
189 retval += here;
190 return retval;
191}
192
193/* --------- first step -----------
194 *
195 * find first block of hex data
196 */
197unsigned long first_hex_block(int fd, unsigned long * max)
198{
199 int i;
200 register int num = 1;
201 char c;
202 int nothex = 0;
203 unsigned long retval = 0;
204 int this_line = 0;
205 char theline[SH_BUFSIZE];
206
207 *max = 0;
208
209 while (1)
210 {
211 theline[0] = '\0';
212 this_line = 0;
213 c = '\0';
214 while (c != '\n' && num > 0)
215 {
216 do {
217 num = read (fd, &c, 1);
218 } while (num == 0 && errno == EINTR);
219 if (num > 0) theline[this_line] = c;
220 else return 0;
221 this_line += num;
222 }
223 theline[this_line] = '\0';
224
225 /* not only 'newline' */
226 if (this_line > 60)
227 {
228 nothex = 0;
229 i = 0;
230 while (nothex == 0 && i < (this_line-1))
231 {
232 if (! isxdigit((int)theline[i])) nothex = 1;
233 ++i;
234 }
235 if (nothex == 1) retval += this_line;
236 }
237 else
238 {
239 nothex = 1;
240 retval += this_line;
241 }
242
243 if (nothex == 0)
244 {
245 *max = 0;
246 do {
247 do {
248 num = read (fd, theline, SH_BUFSIZE);
249 } while (num == 0 && errno == EINTR);
250 for (i = 0; i < num; ++i)
251 {
252 c = theline[i];
253 if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
254 ;
255 else if (!isxdigit((int)c))
256 break;
257 else
258 *max += 1;
259 }
260 } while (num > 0);
261
262 *max /= 16;
263 return retval;
264 }
265
266 }
267 /* return 0; *//* unreachable */
268}
269
270static void usage ()
271{
272 fprintf(stdout, "%s", _("\nUsage: samhain_stealth -i|s|g|o <where> "\
273 "[what]\n\n"));
274
275 fprintf(stdout, "%s", _(" -i info on PS image 'where'\n"));
276 fprintf(stdout, "%s", _(" (how much bytes can be hidden in it).\n"));
277 fprintf(stdout, "%s", _(" -s hide file 'what' in PS image 'where'\n"));
278 fprintf(stdout, "%s", _(" -g get hidden data from PS image 'where'\n"));
279 fprintf(stdout, "%s", _(" (output to stdout)\n"));
280 fprintf(stdout, "%s", _(" -o size of file 'where' = offset to "\
281 "end-of-file\n"));
282 fprintf(stdout, "%s", _(" (same as wc -c).\n\n"));
283 fprintf(stdout, "%s", _(" Example: let bar.ps be the ps file, and"\
284 "foo the config file\n"));
285 fprintf(stdout, "%s", _(" 1) extract with: samhain_stealth "\
286 "-g bar.ps >foo\n"));
287 fprintf(stdout, "%s", _(" 2) hide with: samhain_stealth "\
288 "-s bar.ps foo\n\n"));
289
290 fprintf(stdout, "%s", _(" This program hides a file in an UNCOMPRESSED "\
291 "postscript\n"));
292 fprintf(stdout, "%s", _(" image. To generate such an image, you may " \
293 "use e.g.:\n"));
294 fprintf(stdout, "%s", _(" 'convert +compress foo.jpg bar.ps'.\n"));
295 fprintf(stdout, "%s", _(" 'gimp' apparently saves postscript "\
296 "uncompressed by default\n"));
297 fprintf(stdout, "%s", _(" (V 1.06 of the postscript plugin).\n"));
298 fprintf(stdout, "%s", _(" 'xv' seems to save with run-length "\
299 "compression, which is unsuitable.\n"));
300 fprintf(stdout, "%s", _(" The program does not check the "\
301 "compression type of the PS file.\n"));
302 fprintf(stdout, "%s", _(" Just have a look at the result to check.\n"));
303 return;
304}
305
306int main (int argc, char * argv[])
307{
308 int fd;
309 int add_off;
310 unsigned long max;
311 char buf[1024];
312 FILE * infil;
313 int pgp_flag = 0;
314
315 if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h')
316 {
317 usage();
318 return (0);
319 }
320 if (argc == 2 && 0 == strcmp(argv[1], _("--help")))
321 {
322 usage();
323 return (0);
324 }
325
326 if (argc < 3 || argv[1][0] != '-' ||
327 (argv[1][1] != 'o' && argv[1][1] != 'i' &&
328 argv[1][1] != 's' && argv[1][1] != 'g'))
329 {
330 usage ();
331 return (1);
332 }
333
334
335
336 /* offset to end
337 */
338 if (argv[1][1] == 'o')
339 {
340 fd = open(argv[2], O_RDONLY);
341 if (fd == -1)
342 {
343 fprintf(stderr, _("Error: could not open() %s for reading\n"),
344 argv[2]);
345 return (1);
346 }
347
348 off_data = lseek (fd, 0, SEEK_END);
349 fprintf(stdout, _("%ld %s\n"),
350 off_data, argv[2]);
351 close (fd);
352 return (0);
353 }
354
355 fd = open(argv[2], O_RDWR);
356 if (fd == -1)
357 {
358 fprintf(stderr, _("Error: could not open() %s for read/write\n"),
359 argv[2]);
360 return (1);
361 }
362
363 /* find the first block of hex data
364 */
365 if (argv[1][1] == 'i')
366 {
367 off_data = first_hex_block(fd, &max);
368 fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
369 off_data, max);
370 if (max > 0)
371 return (0);
372 else
373 {
374 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
375 return (1);
376 }
377 }
378
379 /* seek to the first block of fresh hex data and hide data
380 */
381 if (argv[1][1] == 's')
382 {
383 infil = fopen(argv[3], "r");
384 if (infil == NULL)
385 {
386 fprintf(stderr, _("Error: could not open() %s\n"), argv[3]);
387 return (8);
388 }
389 off_data = first_hex_block(fd, &max);
390 fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
391 off_data, max);
392 if (max == 0)
393 {
394 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
395 return (1);
396 }
397
398 fprintf(stdout, _(" .. hide %s in %s .. \n"), argv[3], argv[2]);
399 while (fgets(buf, sizeof(buf), infil))
400 {
401 lseek(fd, off_data, SEEK_SET);
402 add_off = hidein_hex_block(fd, buf, strlen(buf));
403 if (add_off == -1)
404 {
405 fprintf(stderr, _("Error: %s has insufficient capacity\n"),
406 argv[2]);
407 return (1);
408 }
409 off_data += add_off;
410 }
411 fclose(infil);
412 /*
413 * make sure there is a terminator
414 */
415 lseek(fd, off_data, SEEK_SET);
416 add_off = hidein_hex_block(fd, _("\n[EOF]\n"), 7);
417 if (add_off == -1)
418 {
419 fprintf(stderr, _("Error: %s has insufficient capacity\n"),
420 argv[2]);
421 return (1);
422 }
423 fprintf(stdout, "%s", _(" .. finished\n"));
424 return (0);
425 }
426
427 if (argv[1][1] == 'g')
428 {
429 off_data = first_hex_block(fd, &max);
430 if (max == 0)
431 {
432 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
433 return (1);
434 }
435 lseek(fd, off_data, SEEK_SET);
436
437 while (1 == 1)
438 {
439 add_off = hideout_hex_block(fd, (unsigned char *) buf, 1023);
440 if (add_off == -1)
441 {
442 fprintf(stderr, _("Error: premature end of data in %s\n"),
443 argv[2]);
444 return (1);
445 }
446 if (0 == strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n")))
447 pgp_flag = 1;
448 fprintf(stdout, "%s", buf);
449 if (0 == strncmp(buf, _("[EOF]"), 5) && pgp_flag == 0)
450 break;
451 if (0 == strcmp(buf, _("-----END PGP SIGNATURE-----\n")) &&
452 pgp_flag == 1)
453 break;
454
455 off_data += add_off;
456 lseek(fd, off_data, SEEK_SET);
457 }
458 return (0);
459 }
460
461 fprintf(stderr, _("Invalid mode of operation: %s"), argv[1]);
462 return (1);
463}
464
Note: See TracBrowser for help on using the repository browser.