1 /*
2 * The Sleuth Kit
3 *
4 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5 * Copyright (c) 2012-2014 Brian Carrier. All rights reserved
6 *
7 *
8 * This software is distributed under the Common Public License 1.0
9 */
10
11 /**
12 * \file encase.c
13 * Contains the Encase hash database specific extraction and printing routines.
14 */
15
16 #include "tsk_hashdb_i.h"
17
18 /**
19 * Test the file to see if it is an Encase database
20 *
21 * @param hFile File handle to hash database
22 *
23 * @return 1 if encase and 0 if not
24 */
25 uint8_t
encase_test(FILE * hFile)26 encase_test(FILE * hFile)
27 {
28 char buf[8];
29
30 fseeko(hFile, 0, SEEK_SET);
31 if (8 != fread(buf, sizeof(char), 8, hFile))
32 return 0;
33
34 if (memcmp(buf, "HASH\x0d\x0a\xff\x00", 8))
35 return 0;
36
37 return 1;
38 }
39
40 /**
41 * Set db_name using information from this database type
42 *
43 * @param hdb_info the hash database object
44 */
45 static void
encase_name(TSK_HDB_BINSRCH_INFO * hdb_info)46 encase_name(TSK_HDB_BINSRCH_INFO * hdb_info)
47 {
48 FILE * hFile = hdb_info->hDb;
49 wchar_t buf[40];
50 UTF16 *utf16;
51 UTF8 *utf8;
52 size_t ilen;
53 memset(hdb_info->base.db_name, '\0', TSK_HDB_NAME_MAXLEN);
54 if(!hFile) {
55 if (tsk_verbose)
56 fprintf(stderr,
57 "Error getting name from Encase hash db; using file name instead");
58 hdb_base_db_name_from_path(&hdb_info->base);
59 return;
60 }
61
62 memset(buf, '\0', 40);
63
64 fseeko(hFile, 1032, SEEK_SET);
65 if (39 != fread(buf, sizeof(wchar_t), 39, hFile)) {
66 if (tsk_verbose)
67 fprintf(stderr,
68 "Error getting name from Encase hash db; using file name instead");
69 hdb_base_db_name_from_path(&hdb_info->base);
70 return;
71 }
72
73 // do some arithmetic on type sizes to be platform independent
74 ilen = wcslen(buf) * (sizeof(wchar_t) / sizeof(UTF16));
75
76 utf8 = (UTF8 *) hdb_info->base.db_name;
77 utf16 = (UTF16 *) buf;
78
79 tsk_UTF16toUTF8(TSK_LIT_ENDIAN,
80 (const UTF16 **) &utf16,
81 &utf16[ilen], &utf8, &utf8[78],
82 TSKlenientConversion);
83 }
84
85
encase_open(FILE * hDb,const TSK_TCHAR * db_path)86 TSK_HDB_INFO *encase_open(FILE *hDb, const TSK_TCHAR *db_path)
87 {
88 TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = NULL;
89
90 // get the basic binary-search info struct
91 hdb_binsrch_info = hdb_binsrch_open(hDb, db_path);
92 if (NULL == hdb_binsrch_info) {
93 return NULL;
94 }
95
96 // overwrite the database-specific ones
97 hdb_binsrch_info->base.db_type = TSK_HDB_DBTYPE_ENCASE_ID;
98 encase_name(hdb_binsrch_info);
99 hdb_binsrch_info->base.make_index = encase_make_index;
100 hdb_binsrch_info->get_entry = encase_get_entry;
101
102 return (TSK_HDB_INFO*)hdb_binsrch_info;
103 }
104
105 /**
106 * Process the database to create a sorted index of it. Consecutive
107 * entries with the same hash value are not added to the index, but
108 * will be found during lookup.
109 *
110 * @param hdb_info_base Hash database to make index of.
111 * @param dbtype Type of hash database (should always be TSK_HDB_DBTYPE_ENCASE_STR)
112 *
113 * @return 1 on error and 0 on success.
114 */
115 uint8_t
encase_make_index(TSK_HDB_INFO * hdb_info_base,TSK_TCHAR * dbtype)116 encase_make_index(TSK_HDB_INFO * hdb_info_base, TSK_TCHAR * dbtype)
117 {
118 TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = (TSK_HDB_BINSRCH_INFO*)hdb_info_base;
119 unsigned char buf[19];
120 char phash[19];
121 TSK_OFF_T offset = 0;
122 int db_cnt = 0, idx_cnt = 0;
123
124 /* Initialize the TSK index file */
125 if (hdb_binsrch_idx_initialize(hdb_binsrch_info, dbtype)) {
126 tsk_error_set_errstr2( "encase_makeindex");
127 return 1;
128 }
129
130 /* Status */
131 if (tsk_verbose)
132 TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
133 hdb_binsrch_info->base.db_fname);
134
135 memset(phash, '0', sizeof(phash));
136 memset(buf, '0', sizeof(buf));
137
138 /* read the file and add to the index */
139 fseek(hdb_binsrch_info->hDb, 1152, SEEK_SET);
140 while (18 == fread(buf,sizeof(char),18,hdb_binsrch_info->hDb)) {
141 db_cnt++;
142
143 /* We only want to add one of each hash to the index */
144 if (memcmp(buf, phash, 18) == 0) {
145 continue;
146 }
147
148 /* Add the entry to the index */
149 if (hdb_binsrch_idx_add_entry_bin(hdb_binsrch_info, buf, 16, offset)) {
150 tsk_error_set_errstr2( "encase_make_index");
151 return 1;
152 }
153
154 idx_cnt++;
155
156 /* Set the previous has value */
157 memcpy(phash, buf, 18);
158 offset += 18;
159 }
160
161 if (idx_cnt > 0) {
162 if (tsk_verbose) {
163 fprintf(stderr, " Valid Database Entries: %d\n", db_cnt);
164 fprintf(stderr, " Index File Entries %s: %d\n",
165 (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
166 }
167
168 /* Close and sort the index */
169 if (hdb_binsrch_idx_finalize(hdb_binsrch_info)) {
170 tsk_error_set_errstr2( "encase_makeindex");
171 return 1;
172 }
173 }
174 else {
175 tsk_error_reset();
176 tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
177 tsk_error_set_errstr(
178 "encase_makeindex: No valid entries found in database");
179 return 1;
180 }
181
182 return 0;
183 }
184
185 /**
186 * Find the entry at a
187 * given offset. The offset was likely determined from the index.
188 * The callback is called for each entry. EnCase does not store names,
189 * so the callback is called with just the hash value.
190 *
191 * @param hdb_info Hash database to get data from
192 * @param hash MD5 hash value that was searched for
193 * @param offset Byte offset where hash value should be located in db_file
194 * @param flags (not used)
195 * @param action Callback used for each entry found in lookup
196 * @param cb_ptr Pointer to data passed to callback
197 *
198 * @return 1 on error and 0 on succuss
199 */
200 uint8_t
encase_get_entry(TSK_HDB_INFO * hdb_info,const char * hash,TSK_OFF_T offset,TSK_HDB_FLAG_ENUM flags,TSK_HDB_LOOKUP_FN action,void * cb_ptr)201 encase_get_entry(TSK_HDB_INFO * hdb_info, const char *hash,
202 TSK_OFF_T offset, TSK_HDB_FLAG_ENUM flags,
203 TSK_HDB_LOOKUP_FN action, void *cb_ptr)
204 {
205 TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = (TSK_HDB_BINSRCH_INFO*)hdb_info;
206 int found = 0;
207 char buf[19];
208
209 if (tsk_verbose)
210 fprintf(stderr,
211 "encase_getentry: Lookup up hash %s at offset %" PRIdOFF
212 "\n", hash, offset);
213
214 if (strlen(hash) != TSK_HDB_HTYPE_MD5_LEN) {
215 tsk_error_reset();
216 tsk_error_set_errno(TSK_ERR_HDB_ARG);
217 tsk_error_set_errstr(
218 "encase_getentry: Invalid hash value: %s", hash);
219 return 1;
220 }
221
222 memset(buf, 0, sizeof(buf));
223
224 /* Loop so that we can find multiple occurrences of the same hash */
225 fseeko(hdb_binsrch_info->hDb, offset, SEEK_SET);
226 while (1) {
227 int retval;
228 char hash_str[TSK_HDB_HTYPE_MD5_LEN+1];
229
230 if (18 != fread(buf,sizeof(char),18,hdb_binsrch_info->hDb)) {
231 if (feof(hdb_binsrch_info->hDb)) {
232 break;
233 }
234 tsk_error_reset();
235 tsk_error_set_errno(TSK_ERR_HDB_READDB);
236 tsk_error_set_errstr(
237 "encase_getentry: Error reading database");
238 return 1;
239 }
240
241 snprintf(hash_str, TSK_HDB_HTYPE_MD5_LEN+1, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
242 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
243 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
244
245 /* Is this the one that we want? */
246 if (0 != strcasecmp(hash_str, hash)) {
247 break;
248 }
249
250 retval = action(hdb_info, hash, "", cb_ptr);
251 if (retval == TSK_WALK_ERROR) {
252 return 1;
253 }
254 else if (retval == TSK_WALK_STOP) {
255 return 0;
256 }
257 found = 1;
258
259 /* Advance to the next row */
260 offset += 18;
261 }
262
263 if (found == 0) {
264 tsk_error_reset();
265 tsk_error_set_errno(TSK_ERR_HDB_ARG);
266 tsk_error_set_errstr(
267 "encase_getentry: Hash not found in file at offset: %lu",
268 (unsigned long) offset);
269 return 1;
270 }
271
272 return 0;
273 }
274