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
24 char * 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 
globber(const char * str)42 char * 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 
64 static unsigned long off_data;
65 
sh_util_charhex(int c)66 char 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 
sh_util_hexchar(char c)79 int 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  */
hideout_hex_block(int fd,unsigned char * str,int len)94 int 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  */
hidein_hex_block(int fd,char * str,int len)145 int 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  */
first_hex_block(int fd,unsigned long * max)197 unsigned 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 
usage()270 static 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 
main(int argc,char * argv[])306 int 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 
465