source: trunk/src/samhain_stealth.c@ 211

Last change on this file since 211 was 205, checked in by katerina, 16 years ago

New option LooseDirCheck (ticket #132). Also, replace _exit() with raise(SIGKILL).

File size: 10.2 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, _("\nUsage: samhain_stealth -i|s|g|o <where> "\
273 "[what]\n\n"));
274
275 fprintf(stdout, _(" -i info on PS image 'where'\n"));
276 fprintf(stdout, _(" (how much bytes can be hidden in it).\n"));
277 fprintf(stdout, _(" -s hide file 'what' in PS image 'where'\n"));
278 fprintf(stdout, _(" -g get hidden data from PS image 'where'\n"));
279 fprintf(stdout, _(" (output to stdout)\n"));
280 fprintf(stdout, _(" -o size of file 'where' = offset to "\
281 "end-of-file\n"));
282 fprintf(stdout, _(" (same as wc -c).\n\n"));
283 fprintf(stdout, _(" Example: let bar.ps be the ps file, and foo the config file\n"));
284 fprintf(stdout, _(" 1) extract with: samhain_stealth -g bar.ps >foo\n"));
285 fprintf(stdout, _(" 2) hide with: samhain_stealth -s bar.ps foo\n\n"));
286
287 fprintf(stdout, _(" This program hides a file in an UNCOMPRESSED "\
288 "postscript\n"));
289 fprintf(stdout, _(" image. To generate such an image, you may "\
290 "use e.g.:\n"));
291 fprintf(stdout, _(" 'convert +compress foo.jpg bar.ps'.\n"));
292 fprintf(stdout, _(" 'gimp' apparently saves postscript uncompressed "\
293 "by default\n"));
294 fprintf(stdout, _(" (V 1.06 of the postscript plugin).\n"));
295 fprintf(stdout, _(" 'xv' seems to save with run-length compression, "\
296 "which is unsuitable.\n"));
297 fprintf(stdout, _(" The program does not check the compression type of "\
298 "the PS file.\n"));
299 fprintf(stdout, _(" Just have a look at the result to check.\n"));
300 return;
301}
302
303int main (int argc, char * argv[])
304{
305 int fd;
306 int add_off;
307 unsigned long max;
308 char buf[1024];
309 FILE * infil;
310 int pgp_flag = 0;
311
312 if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h')
313 {
314 usage();
315 return (0);
316 }
317 if (argc == 2 && 0 == strcmp(argv[1], _("--help")))
318 {
319 usage();
320 return (0);
321 }
322
323 if (argc < 3 || argv[1][0] != '-' ||
324 (argv[1][1] != 'o' && argv[1][1] != 'i' &&
325 argv[1][1] != 's' && argv[1][1] != 'g'))
326 {
327 usage ();
328 return (1);
329 }
330
331
332
333 /* offset to end
334 */
335 if (argv[1][1] == 'o')
336 {
337 fd = open(argv[2], O_RDONLY);
338 if (fd == -1)
339 {
340 fprintf(stderr, _("Error: could not open() %s for reading\n"), argv[2]);
341 return (1);
342 }
343
344 off_data = lseek (fd, 0, SEEK_END);
345 fprintf(stdout, _("%ld %s\n"),
346 off_data, argv[2]);
347 close (fd);
348 return (0);
349 }
350
351 fd = open(argv[2], O_RDWR);
352 if (fd == -1)
353 {
354 fprintf(stderr, _("Error: could not open() %s for read/write\n"),
355 argv[2]);
356 return (1);
357 }
358
359 /* find the first block of hex data
360 */
361 if (argv[1][1] == 'i')
362 {
363 off_data = first_hex_block(fd, &max);
364 fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
365 off_data, max);
366 if (max > 0)
367 return (0);
368 else
369 {
370 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
371 return (1);
372 }
373 }
374
375 /* seek to the first block of fresh hex data and hide data
376 */
377 if (argv[1][1] == 's')
378 {
379 infil = fopen(argv[3], "r");
380 if (infil == NULL)
381 {
382 fprintf(stderr, _("Error: could not open() %s\n"), argv[3]);
383 return (8);
384 }
385 off_data = first_hex_block(fd, &max);
386 fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
387 off_data, max);
388 if (max == 0)
389 {
390 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
391 return (1);
392 }
393
394 fprintf(stdout, _(" .. hide %s in %s .. \n"), argv[3], argv[2]);
395 while (fgets(buf, sizeof(buf), infil))
396 {
397 lseek(fd, off_data, SEEK_SET);
398 add_off = hidein_hex_block(fd, buf, strlen(buf));
399 if (add_off == -1)
400 {
401 fprintf(stderr, _("Error: %s has insufficient capacity\n"),
402 argv[2]);
403 return (1);
404 }
405 off_data += add_off;
406 }
407 fclose(infil);
408 /*
409 * make sure there is a terminator
410 */
411 lseek(fd, off_data, SEEK_SET);
412 add_off = hidein_hex_block(fd, _("[EOF]\n"), 6);
413 if (add_off == -1)
414 {
415 fprintf(stderr, _("Error: %s has insufficient capacity\n"),
416 argv[2]);
417 return (1);
418 }
419 fprintf(stdout, _(" .. finished\n"));
420 return (0);
421 }
422
423 if (argv[1][1] == 'g')
424 {
425 off_data = first_hex_block(fd, &max);
426 if (max == 0)
427 {
428 fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
429 return (1);
430 }
431 lseek(fd, off_data, SEEK_SET);
432
433 while (1 == 1)
434 {
435 add_off = hideout_hex_block(fd, (unsigned char *) buf, 1023);
436 if (add_off == -1)
437 {
438 fprintf(stderr, _("Error: premature end of data in %s\n"),
439 argv[2]);
440 return (1);
441 }
442 if (0 == strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n")))
443 pgp_flag = 1;
444 fprintf(stdout, "%s", buf);
445 if (0 == strncmp(buf, _("[EOF]"), 5) && pgp_flag == 0)
446 break;
447 if (0 == strcmp(buf, _("-----END PGP SIGNATURE-----\n")) &&
448 pgp_flag == 1)
449 break;
450
451 off_data += add_off;
452 lseek(fd, off_data, SEEK_SET);
453 }
454 return (0);
455 }
456
457 fprintf(stderr, _("Invalid mode of operation: %s"), argv[1]);
458 return (1);
459}
460
461
Note: See TracBrowser for help on using the repository browser.