File: encase.c

package info (click to toggle)
sleuthkit 4.11.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 18,388 kB
  • sloc: ansic: 143,074; cpp: 33,286; java: 32,933; sh: 4,342; xml: 2,197; makefile: 436; python: 270
file content (273 lines) | stat: -rwxr-xr-x 7,729 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/*
* The Sleuth Kit
*
* Brian Carrier [carrier <at> sleuthkit [dot] org]
* Copyright (c) 2012-2014 Brian Carrier.  All rights reserved
*
*
* This software is distributed under the Common Public License 1.0
*/

/**
* \file encase.c
* Contains the Encase hash database specific extraction and printing routines.
*/

#include "tsk_hashdb_i.h"

/**
* Test the file to see if it is an Encase database
*
* @param hFile File handle to hash database
*
* @return 1 if encase and 0 if not
*/
uint8_t
    encase_test(FILE * hFile)
{
    char buf[8];

    fseeko(hFile, 0, SEEK_SET);
    if (8 != fread(buf, sizeof(char), 8, hFile))
        return 0;

    if (memcmp(buf, "HASH\x0d\x0a\xff\x00", 8)) 
        return 0;

    return 1;
}

/**
* Set db_name using information from this database type
*
* @param hdb_info the hash database object
*/
static void
    encase_name(TSK_HDB_BINSRCH_INFO * hdb_info)
{
    FILE * hFile = hdb_info->hDb;
    wchar_t buf[40];
    UTF16 *utf16;
    UTF8 *utf8;
    size_t ilen;
    memset(hdb_info->base.db_name, '\0', TSK_HDB_NAME_MAXLEN);
    if(!hFile) {
        if (tsk_verbose)
            fprintf(stderr,
            "Error getting name from Encase hash db; using file name instead");
        hdb_base_db_name_from_path(&hdb_info->base);
        return;
    }

    memset(buf, '\0', 40);

    fseeko(hFile, 1032, SEEK_SET);
    if (39 != fread(buf, sizeof(wchar_t), 39, hFile)) {
        if (tsk_verbose)
            fprintf(stderr,
            "Error getting name from Encase hash db; using file name instead");
        hdb_base_db_name_from_path(&hdb_info->base);
        return;
    }

    // do some arithmetic on type sizes to be platform independent
    ilen = wcslen(buf) * (sizeof(wchar_t) / sizeof(UTF16));

    utf8 = (UTF8 *) hdb_info->base.db_name;
    utf16 = (UTF16 *) buf;

    tsk_UTF16toUTF8(TSK_LIT_ENDIAN,
        (const UTF16 **) &utf16,
        &utf16[ilen], &utf8, &utf8[78],
        TSKlenientConversion);
}


TSK_HDB_INFO *encase_open(FILE *hDb, const TSK_TCHAR *db_path)
{
    TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = NULL;

    // get the basic binary-search info struct
    hdb_binsrch_info = hdb_binsrch_open(hDb, db_path);
    if (NULL == hdb_binsrch_info) {
        return NULL;
    }

    // overwrite the database-specific ones
    hdb_binsrch_info->base.db_type = TSK_HDB_DBTYPE_ENCASE_ID;
    encase_name(hdb_binsrch_info);
    hdb_binsrch_info->base.make_index = encase_make_index;
    hdb_binsrch_info->get_entry = encase_get_entry;

    return (TSK_HDB_INFO*)hdb_binsrch_info;    
}

/**
* Process the database to create a sorted index of it. Consecutive
* entries with the same hash value are not added to the index, but
* will be found during lookup.
*
* @param hdb_info_base Hash database to make index of.
* @param dbtype Type of hash database (should always be TSK_HDB_DBTYPE_ENCASE_STR)
*
* @return 1 on error and 0 on success.
*/
uint8_t
    encase_make_index(TSK_HDB_INFO * hdb_info_base, TSK_TCHAR * dbtype)
{
    TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = (TSK_HDB_BINSRCH_INFO*)hdb_info_base;
    unsigned char buf[19];
    char phash[19];
    TSK_OFF_T offset = 0;
    int db_cnt = 0, idx_cnt = 0;

    /* Initialize the TSK index file */
    if (hdb_binsrch_idx_initialize(hdb_binsrch_info, dbtype)) {
        tsk_error_set_errstr2( "encase_makeindex");
        return 1;
    }

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
        hdb_binsrch_info->base.db_fname);

    memset(phash, '0', sizeof(phash));
    memset(buf, '0', sizeof(buf));

    /* read the file and add to the index */
    fseek(hdb_binsrch_info->hDb, 1152, SEEK_SET);
    while (18 == fread(buf,sizeof(char),18,hdb_binsrch_info->hDb)) {
        db_cnt++;

        /* We only want to add one of each hash to the index */
        if (memcmp(buf, phash, 18) == 0) {
            continue;
        }

        /* Add the entry to the index */
        if (hdb_binsrch_idx_add_entry_bin(hdb_binsrch_info, buf, 16, offset)) {
            tsk_error_set_errstr2( "encase_make_index");
            return 1;
        }

        idx_cnt++;

        /* Set the previous has value */
        memcpy(phash, buf, 18);
        offset += 18;
    }

    if (idx_cnt > 0) {
        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Close and sort the index */
        if (hdb_binsrch_idx_finalize(hdb_binsrch_info)) {
            tsk_error_set_errstr2( "encase_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
            "encase_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}

/**
* Find the entry at a
* given offset.  The offset was likely determined from the index.
* The callback is called for each entry. EnCase does not store names,
* so the callback is called with just the hash value.
*
* @param hdb_info Hash database to get data from
* @param hash MD5 hash value that was searched for
* @param offset Byte offset where hash value should be located in db_file
* @param flags (not used)
* @param action Callback used for each entry found in lookup
* @param cb_ptr Pointer to data passed to callback
*
* @return 1 on error and 0 on succuss
*/
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)
{
    TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = (TSK_HDB_BINSRCH_INFO*)hdb_info;
    int found = 0;
    char buf[19];

    if (tsk_verbose)
        fprintf(stderr,
        "encase_getentry: Lookup up hash %s at offset %" PRIdOFF
        "\n", hash, offset);

    if (strlen(hash) != TSK_HDB_HTYPE_MD5_LEN) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
            "encase_getentry: Invalid hash value: %s", hash);
        return 1;
    }

    memset(buf, 0, sizeof(buf));

    /* Loop so that we can find multiple occurrences of the same hash */
    fseeko(hdb_binsrch_info->hDb, offset, SEEK_SET);
    while (1) {
        int retval;
        char hash_str[TSK_HDB_HTYPE_MD5_LEN+1];

        if (18 != fread(buf,sizeof(char),18,hdb_binsrch_info->hDb)) {
            if (feof(hdb_binsrch_info->hDb)) {
                break;
            }
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                "encase_getentry: Error reading database");
            return 1;
        }

        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",
            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], 
            buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);

        /* Is this the one that we want? */
        if (0 != strcasecmp(hash_str, hash)) {
            break;
        }

        retval = action(hdb_info, hash, "", cb_ptr);
        if (retval == TSK_WALK_ERROR) {
            return 1;
        }
        else if (retval == TSK_WALK_STOP) {
            return 0;
        }
        found = 1;

        /* Advance to the next row */
        offset += 18;
    }

    if (found == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
            "encase_getentry: Hash not found in file at offset: %lu",
            (unsigned long) offset);
        return 1;
    }

    return 0;
}