Recursive Binary String Search
This program is similar to the other one I made a while back, except this one searches for matches against a binary (string) value instead. For ease of use, the binary string is specified using a hexadecimal string.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <unistd.h>
#include <dirent.h>
static int hex_value(int c)
{
if (c >= 0x30 && c <= 0x39) /* '0' - '9' */
return c - 0x30;
else if (c >= 0x41 && c <= 0x46) /* 'A' - 'F' */
return (c - 0x41) + 10;
else if (c >= 0x61 && c <= 0x66) /* 'a' - 'f' */
return (c - 0x61) + 10;
else
return -1;
}
static int convert_from_hex(char *hex_string,
unsigned char *bin_string, int bin_string_len)
{
int n1, n2, high;
high = -1;
n1 = n2 = 0;
while (hex_string[n1] != '\0') {
if (hex_value(hex_string[n1]) >= 0) {
if (high == -1) {
high = hex_string[n1];
} else {
bin_string[n2] = hex_value(high) * 16 + hex_value(hex_string[n1]);
if (n2 >= bin_string_len)
break;
n2++;
high = -1;
}
}
n1++;
}
return n2;
}
static void search(char *path, unsigned char *bin_string, int len)
{
int c, match, name_shown, address, match_address;
FILE *fh;
fh = fopen(path, "rb");
if (fh == NULL) {
fprintf(stderr, "Warning: Unable to open file: %s\n", path);
return;
}
match = address = name_shown = match_address = 0;
while ((c = fgetc(fh)) != EOF) {
if (c == bin_string[match]) {
if (match_address == 0)
match_address = address;
match++;
if (match >= len) {
if (! name_shown) {
printf("%s\n", path);
name_shown = 1;
}
printf("0x%x\n", match_address);
match = 0;
match_address = 0;
}
} else {
match = 0;
match_address = 0;
}
address++;
}
fclose(fh);
}
static void recurse(char *path, unsigned char *bin_string, int len)
{
char full_path[PATH_MAX];
struct dirent *entry;
struct stat st;
DIR *dh;
dh = opendir(path);
if (dh == NULL) {
fprintf(stderr, "Warning: Unable to open directory: %s\n", path);
return;
}
while ((entry = readdir(dh))) {
if (entry->d_name[0] == '.')
continue; /* Ignore files with leading dot. */
#ifdef WINNT
snprintf(full_path, PATH_MAX, "%s\\%s", path, entry->d_name);
#else
snprintf(full_path, PATH_MAX, "%s/%s", path, entry->d_name);
#endif
stat(full_path, &st);
if (S_ISDIR(st.st_mode)) {
recurse(full_path, bin_string, len);
} else if (S_ISREG(st.st_mode)) {
search(full_path, bin_string, len);
}
}
closedir(dh);
return;
}
int main(int argc, char *argv[])
{
int len;
unsigned char *bin_string;
struct stat st;
if (argc != 3) {
fprintf(stderr, "Usage: %s <directory or file> <hex string>\n", argv[0]);
return 1;
}
len = strlen(argv[2]) / 2;
bin_string = malloc(sizeof(unsigned char) * len);
if (bin_string == NULL) {
fprintf(stderr, "Error: Unable to malloc().\n");
return 1;
}
len = convert_from_hex(argv[2], bin_string, len);
if (len == 0) {
fprintf(stderr, "Error: Invalid input hex string.\n");
return 1;
}
stat(argv[1], &st);
if (S_ISDIR(st.st_mode)) {
recurse(argv[1], bin_string, len);
} else if (S_ISREG(st.st_mode)) {
search(argv[1], bin_string, len);
} else {
fprintf(stderr, "Error: Not a directory or regular file.\n");
free(bin_string);
return 1;
}
free(bin_string);
return 0;
}