1 /*
2 *
3 * This is a sample file that shows how to use some of the basic
4 * POSIX-style library functions in The Sleuth Kit (www.sleuthkit.org).
5 * There are also callback-style functions that can be used to read
6 * the data and partitions.
7 *
8 * Copyright (c) 2008-2011, Brian Carrier <carrier <at> sleuthkit <dot> org>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * - Neither the Sleuth Kit name nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40
41 #include <tsk/libtsk.h>
42
43
44 /**
45 * Open a directory and cycle through its contents. Read each file and recurse
46 * into each directory.
47 *
48 * @param fs_info File system to process
49 * @param stack Stack to prevent infinite recursion loops
50 * @param dir_inum Metadata address of directory to open
51 * @param path Path of directory being opened
52 * @returns 1 on error
53 */
54 static uint8_t
proc_dir(TSK_FS_INFO * fs_info,TSK_STACK * stack,TSK_INUM_T dir_inum,const char * path)55 proc_dir(TSK_FS_INFO * fs_info, TSK_STACK * stack,
56 TSK_INUM_T dir_inum, const char *path)
57 {
58 TSK_FS_DIR *fs_dir;
59 size_t i;
60 char *path2 = NULL;
61 char *buf = NULL;
62
63 // open the directory
64 if ((fs_dir = tsk_fs_dir_open_meta(fs_info, dir_inum)) == NULL) {
65 fprintf(stderr, "Error opening directory: %" PRIuINUM "\n",
66 dir_inum);
67 tsk_error_print(stderr);
68 return 1;
69 }
70
71 /* These should be dynamic lengths, but this is just a sample program.
72 * Allocate heap space instead of stack to prevent overflow for deep
73 * directories. */
74 if ((path2 = (char *) malloc(4096)) == NULL) {
75 return 1;
76 }
77
78 if ((buf = (char *) malloc(2048)) == NULL) {
79 free(path2);
80 return 1;
81 }
82
83 // cycle through each entry
84 for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {
85 TSK_FS_FILE *fs_file;
86 TSK_OFF_T off = 0;
87 size_t len = 0;
88
89 // get the entry
90 if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
91 fprintf(stderr,
92 "Error getting directory entry %" PRIuSIZE
93 " in directory %" PRIuINUM "\n", i, dir_inum);
94 tsk_error_print(stderr);
95
96 free(path2);
97 free(buf);
98 return 1;
99 }
100
101 /* Ignore NTFS System files */
102 if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype)) &&
103 (fs_file->name->name[0] == '$')) {
104 tsk_fs_file_close(fs_file);
105 continue;
106 }
107
108 //printf("Processing %s/%s\n", path, fs_file->name->name);
109
110 // make sure it's got metadata and not only a name
111 if (fs_file->meta) {
112 ssize_t cnt;
113
114 /* Note that we could also cycle through all of the attributes in the
115 * file by using one of the tsk_fs_attr_get() functions and reading it
116 * with tsk_fs_attr_read(). See the File Systems section of the Library
117 * User's Guide for more details:
118 * http://www.sleuthkit.org/sleuthkit/docs/api-docs/ */
119
120 // read file contents
121 if (fs_file->meta->type == TSK_FS_META_TYPE_REG) {
122 int myflags = 0;
123
124 for (off = 0; off < fs_file->meta->size; off += len) {
125 if (fs_file->meta->size - off < 2048)
126 len = (size_t) (fs_file->meta->size - off);
127 else
128 len = 2048;
129
130 cnt = tsk_fs_file_read(fs_file, off, buf, len,
131 (TSK_FS_FILE_READ_FLAG_ENUM) myflags);
132 if (cnt == -1) {
133 // could check tsk_errno here for a recovery error (TSK_ERR_FS_RECOVER)
134 fprintf(stderr, "Error reading %s file: %s\n",
135 ((fs_file->name->
136 flags & TSK_FS_NAME_FLAG_UNALLOC)
137 || (fs_file->meta->
138 flags & TSK_FS_META_FLAG_UNALLOC)) ?
139 "unallocated" : "allocated",
140 fs_file->name->name);
141 tsk_error_print(stderr);
142 break;
143 }
144 else if (cnt != (ssize_t) len) {
145 fprintf(stderr,
146 "Warning: %" PRIuSIZE " of %" PRIuSIZE
147 " bytes read from %s file %s\n", cnt, len,
148 ((fs_file->name->
149 flags & TSK_FS_NAME_FLAG_UNALLOC)
150 || (fs_file->meta->
151 flags & TSK_FS_META_FLAG_UNALLOC)) ?
152 "unallocated" : "allocated",
153 fs_file->name->name);
154 }
155
156 // do something with the data...
157 }
158 }
159
160 // recurse into another directory (unless it is a '.' or '..')
161 else if (TSK_FS_IS_DIR_META(fs_file->meta->type)){
162 if (TSK_FS_ISDOT(fs_file->name->name) == 0) {
163
164 // only go in if it is not on our stack
165 if (tsk_stack_find(stack, fs_file->meta->addr) == 0) {
166 // add the address to the top of the stack
167 tsk_stack_push(stack, fs_file->meta->addr);
168
169 snprintf(path2, 4096, "%s/%s", path,
170 fs_file->name->name);
171 if (proc_dir(fs_info, stack, fs_file->meta->addr,
172 path2)) {
173 tsk_fs_file_close(fs_file);
174 tsk_fs_dir_close(fs_dir);
175 free(path2);
176 free(buf);
177 return 1;
178 }
179
180 // pop the address
181 tsk_stack_pop(stack);
182 }
183 }
184 }
185 }
186 tsk_fs_file_close(fs_file);
187 }
188 tsk_fs_dir_close(fs_dir);
189
190 free(path2);
191 free(buf);
192 return 0;
193 }
194
195
196
197
198
199 /**
200 * Analyze the volume starting at byte offset 'start' and look
201 * for a file system. When found, the files will be analyzed.
202 *
203 * @param img Disk image to be analyzed.
204 * @param start Byte offset of volume starting location.
205 *
206 * @return 1 on error and 0 on success
207 */
208 static uint8_t
proc_fs(TSK_IMG_INFO * img_info,TSK_OFF_T start)209 proc_fs(TSK_IMG_INFO * img_info, TSK_OFF_T start)
210 {
211 TSK_FS_INFO *fs_info;
212 TSK_STACK *stack;
213
214 /* Try it as a file system */
215 if ((fs_info =
216 tsk_fs_open_img(img_info, start, TSK_FS_TYPE_DETECT)) == NULL)
217 {
218 fprintf(stderr,
219 "Error opening file system in partition at offset %" PRIdOFF
220 "\n", start);
221 tsk_error_print(stderr);
222
223 /* We could do some carving on the volume data at this point */
224
225 return 1;
226 }
227
228 // create a stack to prevent infinite loops
229 stack = tsk_stack_create();
230
231 // Process the directories
232 if (proc_dir(fs_info, stack, fs_info->root_inum, "")) {
233 fprintf(stderr,
234 "Error processing file system in partition at offset %" PRIdOFF
235 "\n", start);
236 tsk_fs_close(fs_info);
237 return 1;
238 }
239
240 tsk_stack_free(stack);
241
242 /* We could do some analysis of unallocated blocks at this point... */
243
244
245 tsk_fs_close(fs_info);
246 return 0;
247 }
248
249
250 /**
251 * Process the data as a volume system to find the partitions
252 * and volumes.
253 * File system analysis will be performed on each partition.
254 *
255 * @param img Image file information structure for data to analyze
256 * @param start Byte offset to start analyzing from.
257 *
258 * @return 1 on error and 0 on success
259 */
260 static uint8_t
proc_vs(TSK_IMG_INFO * img_info,TSK_OFF_T start)261 proc_vs(TSK_IMG_INFO * img_info, TSK_OFF_T start)
262 {
263 TSK_VS_INFO *vs_info;
264
265 // Open the volume system
266 if ((vs_info =
267 tsk_vs_open(img_info, start, TSK_VS_TYPE_DETECT)) == NULL) {
268 if (tsk_verbose)
269 fprintf(stderr,
270 "Error determining volume system -- trying file systems\n");
271
272 /* There was no volume system, but there could be a file system */
273 tsk_error_reset();
274 if (proc_fs(img_info, start)) {
275 return 1;
276 }
277 }
278 else {
279 fprintf(stderr, "Volume system open, examining each\n");
280
281 // cycle through the partitions
282 for (TSK_PNUM_T i = 0; i < vs_info->part_count; i++) {
283 const TSK_VS_PART_INFO *vs_part;
284
285 if ((vs_part = tsk_vs_part_get(vs_info, i)) == NULL) {
286 fprintf(stderr, "Error getting volume %" PRIuPNUM "\n", i);
287 continue;
288 }
289
290 // ignore the metadata partitions
291 if (vs_part->flags & TSK_VS_PART_FLAG_META)
292 continue;
293
294 // could do something with unallocated volumes
295 else if (vs_part->flags & TSK_VS_PART_FLAG_UNALLOC) {
296
297 }
298 else {
299 if (proc_fs(img_info,
300 vs_part->start * vs_info->block_size)) {
301 // We could do more fancy error checking here to see the cause
302 // of the error or consider the allocation status of the volume...
303 tsk_error_reset();
304 }
305 }
306 }
307 tsk_vs_close(vs_info);
308 }
309 return 0;
310 }
311
312
313 int
main(int argc,char ** argv1)314 main(int argc, char **argv1)
315 {
316 TSK_IMG_INFO *img_info;
317 TSK_TCHAR **argv;
318
319 #ifdef TSK_WIN32
320 // On Windows, get the wide arguments (mingw doesn't support wmain)
321 argv = CommandLineToArgvW(GetCommandLineW(), &argc);
322 if (argv == NULL) {
323 fprintf(stderr, "Error getting wide arguments\n");
324 exit(1);
325 }
326 #else
327 argv = (TSK_TCHAR **) argv1;
328 #endif
329
330 if (argc != 2) {
331 fprintf(stderr, "Missing image name\n");
332 exit(1);
333 }
334
335 // open the disk image
336 img_info =
337 tsk_img_open_sing((const TSK_TCHAR *) argv[1],
338 TSK_IMG_TYPE_DETECT, 0);
339 if (img_info == NULL) {
340 fprintf(stderr, "Error opening file\n");
341 tsk_error_print(stderr);
342 exit(1);
343 }
344
345 // process the volume starting at sector 0
346 if (proc_vs(img_info, 0)) {
347 tsk_error_print(stderr);
348 tsk_img_close(img_info);
349 exit(1);
350 }
351
352 // close the image
353 tsk_img_close(img_info);
354 return 0;
355 }
356