Correct error message
[binmatch.git] / binmatch.c
1 /*
2  * Find occurances of one binary file within another
3  * Copyright (C) 2010 TJ
4  * Author: TJ <linux@tjworld.net>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15 */
16
17 #include <sys/mman.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26
27 void
28 usage(const char *name) {
29  printf("Usage: %s:  [-d] -n <needle> -h <haystack>\n", name);
30  printf("\t-d\tprint matching addresses in decimal not hexadecimal\n"
31         "\t-n\tpath to the file containing the needle\n"
32         "\t-h\tpath to the file containing the haystack\n"
33       "\n\tInformation messages are written to stderr and only matches are written to stdout.\n"
34         "\tThis allows the output to be piped through other filters.\n"
35  );
36 }
37
38 int
39 main(int argc, char *argv[], char *env[]) {
40  int ret = 0;
41  int c, use_decimal, needle_fd, haystack_fd;
42  char *needle_name, *haystack_name;
43  void *needle_mmap, *haystack_mmap;
44  struct stat needle_stat, haystack_stat;
45
46  needle_name = haystack_name = needle_mmap = haystack_mmap = NULL;
47  use_decimal = 0;
48
49  if (argc > 1) { // must have some parameters
50   opterr = 0;
51
52   while ((c = getopt(argc, argv, "n:h:d")) != -1 ) { // iterate the options
53    switch(c) {
54     case 'n':
55      needle_name = optarg;
56      break;
57     case 'h':
58      haystack_name = optarg;
59      break;
60     case 'd':
61      use_decimal = 1;
62      break;
63     default:
64      abort();
65    }
66   }
67
68   if ((needle_fd = open(needle_name, O_RDONLY)) == -1) {
69    perror("Unable to open needle");
70    ret |= 1;
71   }
72
73   if ((haystack_fd = open(haystack_name, O_RDONLY)) == -1) {
74    perror("Unable to open haystack");
75    ret |= 2;
76   }
77   
78   if (!ret) {
79    fstat(needle_fd, &needle_stat);
80    fstat(haystack_fd, &haystack_stat);
81    fprintf(stderr, "Base:\t%s\n", use_decimal == 1 ? "decimal" : "hexadecimal");
82    fprintf(stderr, "Needle:\t\t%12ld\t%s\n", needle_stat.st_size, needle_name);
83    fprintf(stderr, "HayStack:\t%12ld\t%s\n", haystack_stat.st_size, haystack_name);
84
85    if(MAP_FAILED == (needle_mmap = mmap(needle_mmap, needle_stat.st_size, PROT_READ, MAP_SHARED, needle_fd, 0))) {
86     perror("Unable to memory-map needle");
87     exit(4);
88    }
89    if(MAP_FAILED == (haystack_mmap = mmap(haystack_mmap, haystack_stat.st_size, PROT_READ, MAP_SHARED, haystack_fd, 0))) {
90     perror("Unable to memory-map haystack");
91     exit(8);
92    }
93    {
94     void *n = needle_mmap; // convenient short names
95     void *h = haystack_mmap;
96     unsigned long end = haystack_stat.st_size - needle_stat.st_size;
97     unsigned long offset;
98
99     fprintf(stderr, "Searching...\n");
100     for (offset = 0; offset <= end; offset++) {
101      if (memcmp(n, h+offset, needle_stat.st_size) == 0) { // match ?
102       if (use_decimal) printf("%10ld matches\n", offset);
103       else printf("0x%08lX matches\n", offset);
104      }
105     }
106     fprintf(stderr, "Done.\n");
107    }
108   }
109  }
110  else
111   usage(argv[0]);
112
113  if (needle_mmap > 0) munmap(needle_mmap, needle_stat.st_size);
114  if (haystack_mmap > 0) munmap(haystack_mmap, haystack_stat.st_size);
115  if (needle_fd > 0) close(needle_fd);
116  if (haystack_fd > 0) close(haystack_fd);
117
118  return ret;
119 }