1#!/usr/bin/env sh
2#
3#   honggfuzz stackhash blacklist file create script
4#   -----------------------------------------
5#
6#   Licensed under the Apache License, Version 2.0 (the "License");
7#   you may not use this file except in compliance with the License.
8#   You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12#   Unless required by applicable law or agreed to in writing, software
13#   distributed under the License is distributed on an "AS IS" BASIS,
14#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15#   See the License for the specific language governing permissions and
16#   limitations under the License.
17
18set -e # fail on unhandled error
19set -u # fail on undefined variable
20#set -x # debug
21
22readonly tmpFile=$(pwd)/.hf.bl.txt
23declare -a sysTools=("perl" "cut" "sort" "paste" "wc" "tr" "cat")
24
25usage() {
26cat <<_EOF
27
28  Usage: $(basename $0) [options]
29    OPTIONS:
30      -i|--input   : input crash(es) directory / file
31      -B|--bl-file : output file to save found hashes (merge if exists)
32      -e|--ext     : file extension of fuzzer files (e.g. fuzz)
33      -a|--arch    : arch fuzzer have run against ('MAC' or 'LINUX')
34
35    INFO:
36      * Blacklist file sort mode only requires [-B/--bl-file] argument
37      * Hashes gather mode requires all argument to be set
38_EOF
39  exit 1
40}
41
42command_exists () {
43    type "$1" &> /dev/null ;
44}
45
46# Check that system tools exist
47for i in "${sysTools[@]}"
48do
49  if ! command_exists $i; then
50    echo "[-] '$i' command not found"
51    exit 1
52  fi
53done
54
55INPUT_DIR=""
56BL_FILE=""
57FILE_EXT=""
58ARCH=""
59
60nArgs=$#
61while [[ $# > 1 ]]
62do
63  arg="$1"
64  case $arg in
65    -i|--input)
66      INPUT_DIR="$2"
67      shift
68      ;;
69    -B|--bl-file)
70      BL_FILE="$2"
71      shift
72      ;;
73    -e|--ext)
74      FILE_EXT="$2"
75      shift
76      ;;
77    -a|--arch)
78      ARCH="$2"
79      shift
80      ;;
81    *)
82      echo "[-] Invalid argument '$1'"
83      usage
84      ;;
85  esac
86  shift
87done
88
89gatherMode=false
90
91# Sort only mode
92if [[ "$BL_FILE" == "" ]]; then
93  echo "[-] Missing blacklist file"
94  usage
95fi
96
97# Hashes gather mode
98if [ $nArgs -gt 2 ]; then
99  if [[ "$INPUT_DIR" == "" || ! -e "$INPUT_DIR" ]]; then
100    echo "[-] Missing or invalid input directory"
101    usage
102  fi
103
104  if [[ "$FILE_EXT" == "" ]]; then
105    echo "[-] Missing file extension"
106    usage
107  fi
108
109  if [[ "$ARCH" != "MAC" && "$ARCH" != "LINUX" ]]; then
110    echo "[-] Invlid architecture, expecting 'MAC' or 'LINUX'"
111    usage
112  fi
113
114  if [[ "$ARCH" == "LINUX" ]]; then
115    STACKHASH_FIELD=5
116  elif [[ "$ARCH" == "MAC" ]]; then
117    STACKHASH_FIELD=6
118  else
119    echo "[-] Unsupported architecture"
120    exit 1
121  fi
122  gatherMode=true
123fi
124
125# save old data
126if [ -f $BL_FILE ]; then
127  cat $BL_FILE > $tmpFile
128  oldCount=$(cat $BL_FILE | wc -l | tr -d " ")
129else
130  oldCount=0
131fi
132
133if $gatherMode; then
134  echo "[*] Processing files from '$INPUT_DIR' ..."
135  find $INPUT_DIR -type f -iname "*.$FILE_EXT" | while read -r FILE
136  do
137    fileName=$(basename $FILE)
138    if ! echo $fileName | grep -qF ".STACK."; then
139      echo "[!] Skipping '$FILE'"
140      continue
141    fi
142    stackHash=$(echo $fileName | cut -d '.' -f$STACKHASH_FIELD)
143
144    # We don't want to lose crashes where unwinder failed
145    if [[ "$stackHash" != "0" && ! "$stackHash" =~ ^badbad.* ]]; then
146      echo $stackHash >> $tmpFile
147    fi
148  done
149fi
150
151# sort hex values
152echo "[*] Sorting blacklist file entries"
153perl -lpe '$_=hex' $tmpFile | \
154paste -d" " - $tmpFile  | sort -nu | cut -d" " -f 2- \
155> $BL_FILE
156
157entries=$(cat $BL_FILE | wc -l | tr -d " ")
158echo "[*] $BL_FILE contains $entries blacklisted stack hashes"
159
160rm $tmpFile
161