source: trunk/src/samhain_stealth.c@ 96

Last change on this file since 96 was 34, checked in by rainer, 18 years ago

Code cleanup and minor fixes

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