Kjetil's Information Center: A Blog About My Projects

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;
}
          


Topic: Scripts and Code, by Kjetil @ 05/01-2013, Article Link