static int test_ntfs_fe() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "fe_test_1-NTFS"; char fname[512]; snprintf(fname, 512, "%s/fe_test_1.img", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } if ((fs = tsk_fs_open_img(img, 32256, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } if (test_dir_open_apis(fs, "/allocated", 30)) { fprintf(stderr, "%s failure\n", tname); return 1; } if (test_walk_apis(fs, 30)) { fprintf(stderr, "%s failure\n", tname); return 1; } tsk_fs_close(fs); tsk_img_close(img); return 0; }
/** * Analyze the volume starting at byte offset 'start' * and walk each file that can be found. * * @param img Disk image to be analyzed. * @param start Byte offset of volume starting location. * * @return 1 on error and 0 on success */ static uint8_t procFs(TskImgInfo * img_info, TSK_OFF_T start) { TskFsInfo *fs_info = new TskFsInfo(); /* Try it as a file system */ if (fs_info->open(img_info, start, TSK_FS_TYPE_DETECT)) { delete fs_info; tsk_error_print(stderr); /* We could do some carving on the volume data at this point */ return 1; } /* Walk the files, starting at the root directory */ if (fs_info->dirWalk(fs_info->getRootINum(), (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE), dirAct, NULL)) { delete fs_info; tsk_error_print(stderr); fs_info->close(); return 1; } /* We could do some analysis of unallocated blocks at this point... */ fs_info->close(); delete fs_info; return 0; }
int test_ntfs_comp() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; char *tname = "ntfs-comp-1"; char fname[512]; snprintf(fname, 512, "%s/ntfs-comp-1.img", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } if ((fs = tsk_fs_open_img(img, 0, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } if (testfile(fs, 34)) { fprintf(stderr, "%s error (both)\n", tname); return 1; } if (testfile(fs, 32)) { fprintf(stderr, "%s error (sparse)\n", tname); return 1; } tsk_fs_close(fs); tsk_img_close(img); return 0; }
int test_fat12() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "fat12.dd"; char fname[512]; snprintf(fname, 512, "%s/fat12.dd", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if ((fs = tsk_fs_open_img(img, 0, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (testfile(fs, 33)) { fprintf(stderr, "%s failure\n", tname); return 1; } tsk_fs_close(fs); tsk_img_close(img); return 0; }
/* Verify that a specific attribute can be read from the file * @param a_addr The metadata address of the file to analyze * @param a_type Type that is known to be in file * @returns 1 if a test failed */ static int test_get_type(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, TSK_FS_ATTR_TYPE_ENUM a_type) { TSK_FS_FILE *fs_file; // open the file fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr); if (!fs_file) { fprintf(stderr, "Error opening file %" PRIuINUM " via meta\n", a_addr); tsk_error_print(stderr); return 1; } // verify the specified type can be opened const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_type(fs_file, a_type, 0, 0); if (!fs_attr) { fprintf(stderr, "Error getting specified attribute %d-X (no id) from %" PRIuINUM "\n", a_type, a_addr); tsk_error_print(stderr); return 1; } tsk_fs_file_close(fs_file); return 0; }
/** * Analyze the volume starting at byte offset 'start' * and walk each file that can be found. * * @param img Disk image to be analyzed. * @param start Byte offset of volume starting location. * * @return 1 on error and 0 on success */ static uint8_t proc_fs(TSK_IMG_INFO * img_info, TSK_OFF_T start) { TSK_FS_INFO *fs_info; /* Try it as a file system */ if ((fs_info = tsk_fs_open_img(img_info, start, TSK_FS_TYPE_DETECT)) == NULL) { tsk_error_print(stderr); /* We could do some carving on the volume data at this point */ return 1; } /* Walk the files, starting at the root directory */ if (tsk_fs_dir_walk(fs_info, fs_info->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE), dir_act, NULL)) { tsk_error_print(stderr); tsk_fs_close(fs_info); return 1; } /* We could do some analysis of unallocated blocks at this point... */ tsk_fs_close(fs_info); return 0; }
int main(int argc, char **argv1) { TSK_IMG_INFO *img_info; TSK_TCHAR **argv; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif if (argc != 2) { fprintf(stderr, "Missing image name\n"); exit(1); } #if DO_HASHLOOKUP /* Setup hash infrastructure */ if ((hdb_info = tsk_hdb_open(_TSK_T("/XXX/NSRLFile.txt"), TSK_HDB_OPEN_NONE)) == NULL) { tsk_error_print(stderr); exit(1); } if (tsk_hdb_hasindex(hdb_info, TSK_HDB_HTYPE_MD5_ID) == 0) { fprintf(stderr, "Hash database does not have an index (create one using hfind -i nsrl-md5 HASHFILE\n"); exit(1); } #else hdb_info = NULL; #endif img_info = tsk_img_open_sing(argv[1], TSK_IMG_TYPE_DETECT, 0); if (img_info == NULL) { fprintf(stderr, "Error opening file\n"); tsk_error_print(stderr); exit(1); } if (proc_vs(img_info, 0)) { tsk_error_print(stderr); tsk_img_close(img_info); exit(1); } tsk_img_close(img_info); return 0; }
int mft_image(_TCHAR *image) { int argc = 1; //_TCHAR *argv1[2] = {0,}; //argv1[0] = L"test"; //argv1[1] = imaTge; //printf("%s, %s\n\n", argv1[0], argv1[1]); TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT; // Use autodetection methods. TSK_TCHAR *argv[1] = {0, }; unsigned int ssize = 0; //TSK_TCHAR *cp; int32_t sec_skew = 0; bool do_hash = false; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) //argv = CommandLineToArgvW(GetCommandLineW(), &argc); argv[0] = image; if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); // 경로명에 한글이 포함되면 안되는 문제를 해결함 TskGetTimes tskGetTimes(sec_skew, do_hash); if (tskGetTimes.openImage(argc, &argv[0], imgtype, ssize)) { tsk_error_print(stderr); exit(1); } /* http://www.sleuthkit.org/sleuthkit/docs/api-docs/classTskAuto.html#a6b8742f6c15472e822b2226c4cfb2187 uint8_t TskAuto::openImage ( int a_numImg, const TSK_TCHAR *const a_images[], TSK_IMG_TYPE_ENUM a_imgType, unsigned int a_sSize ) a_numImg The number of images to open (will be > 1 for split images). a_images The path to the image files (the number of files must be equal to num_img and they must be in a sorted order) a_imgType The disk image type (can be autodetection) a_sSize Size of device sector in bytes (or 0 for default) */ if (tskGetTimes.findFilesInImg()) { // we already logged the errors exit(1); } }
int main(int argc, char **argv) { IMG_INFO *img; char *imgtype = NULL; int ch; uint8_t type = 0; progname = argv[0]; while ((ch = getopt(argc, argv, "i:tvV")) > 0) { switch (ch) { case '?': default: fprintf(stderr, "Invalid argument: %s\n", argv[optind]); usage(); case 'i': imgtype = optarg; break; case 't': type = 1; break; case 'v': verbose++; break; case 'V': print_version(stdout); exit(0); } } /* We need at least one more argument */ if (optind >= argc) { fprintf(stderr, "Missing image name\n"); usage(); } if ((img = img_open(imgtype, argc - optind, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } if (type) { char *str = img_get_type(img->itype); printf("%s\n", str); } else { img->imgstat(img, stdout); } img->close(img); exit(0); }
static void proc_fs(TSK_FS_INFO* fs, FILE* log) { // Walk starting at $OrphanFiles to provoke recursive call to tsk_fs_dir_load_inum_named. if (tsk_fs_dir_walk(fs, TSK_FS_ORPHANDIR_INUM(fs), TSK_FS_DIR_WALK_FLAG_RECURSE, proc_dir, log)) { fprintf(stderr, "dir walk from $OrphanFiles failed\n"); tsk_error_print(stderr); } // Walk starting at the root. Note that we walk the root tree // -after- the $OrphanFile because if we use the other order, // things are already cached. if (tsk_fs_dir_walk(fs, fs->root_inum, TSK_FS_DIR_WALK_FLAG_RECURSE, proc_dir, log)) { fprintf(stderr, "dir walk from root failed\n"); tsk_error_print(stderr); } }
/** \ingroup fslib * Return a specific file or subdirectory from an open directory. * @param a_fs_dir Directory to analyze * @param a_idx Index of file in directory to open (0-based) * @returns NULL on error */ TSK_FS_FILE * tsk_fs_dir_get(const TSK_FS_DIR * a_fs_dir, size_t a_idx) { TSK_FS_NAME *fs_name; TSK_FS_FILE *fs_file; if ((a_fs_dir == NULL) || (a_fs_dir->tag != TSK_FS_DIR_TAG) || (a_fs_dir->fs_info == NULL)) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("tsk_fs_dir_get: called with NULL or unallocated structures"); return NULL; } if (a_fs_dir->names_used <= a_idx) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("tsk_fs_dir_get: Index (%" PRIuSIZE ") too large (%" PRIuSIZE ")", a_idx, a_fs_dir->names_used); return NULL; } // allocate a structure to return if ((fs_file = tsk_fs_file_alloc(a_fs_dir->fs_info)) == NULL) return NULL; fs_name = &(a_fs_dir->names[a_idx]); // copy the name into another structure that we can return and later free if ((fs_file->name = tsk_fs_name_alloc(fs_name->name ? strlen(fs_name->name) + 1 : 0, fs_name->shrt_name ? strlen(fs_name->shrt_name) + 1 : 0)) == NULL) { return NULL; } if (tsk_fs_name_copy(fs_file->name, fs_name)) return NULL; /* load the fs_meta structure if possible. * Must have non-zero inode addr or have allocated name (if inode is 0) */ if (((fs_name->meta_addr) || (fs_name->flags & TSK_FS_NAME_FLAG_ALLOC))) { if (a_fs_dir->fs_info->file_add_meta(a_fs_dir->fs_info, fs_file, fs_name->meta_addr)) { if (tsk_verbose) tsk_error_print(stderr); tsk_error_reset(); } // if the sequence numbers don't match, then don't load the meta // should ideally have sequence in previous lookup, but it isn't // in all APIs yet if (fs_file->meta->seq != fs_name->meta_seq) { tsk_fs_meta_close(fs_file->meta); fs_file->meta = NULL; } } return fs_file; }
int main(int argc, char **argv1) { TSK_IMG_INFO *img_info; TSK_TCHAR **argv; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif if (argc != 2) { fprintf(stderr, "Missing image name\n"); exit(1); } // open the disk image img_info = tsk_img_open_sing((const TSK_TCHAR *) argv[1], TSK_IMG_TYPE_DETECT, 0); if (img_info == NULL) { fprintf(stderr, "Error opening file\n"); tsk_error_print(stderr); exit(1); } // process the volume starting at sector 0 if (proc_vs(img_info, 0)) { tsk_error_print(stderr); tsk_img_close(img_info); exit(1); } // close the image tsk_img_close(img_info); return 0; }
int test_ntfs_fe() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "fe_test_1-NTFS"; char fname[512]; snprintf(fname, 512, "%s/fe_test_1.img", s_root); if ((img = tsk_img_open_sing(fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if ((fs = tsk_fs_open_img(img, 32256, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); tsk_error_reset(); return 1; } if (testfile(fs, 31)) { fprintf(stderr, "%s error (non-resident)\n", tname); return 1; } if (testfile(fs, 32)) { fprintf(stderr, "%s error (resident)\n", tname); return 1; } tsk_fs_close(fs); tsk_img_close(img); return 0; }
int test_fat12() { TSK_FS_INFO *fs; TSK_IMG_INFO *img; const char *tname = "fat12.dd"; char fname[512]; snprintf(fname, 512, "%s/fat12.dd", s_root); if ((img = tsk_img_open_sing((const TSK_TCHAR *)fname, (TSK_IMG_TYPE_ENUM) 0, 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } if ((fs = tsk_fs_open_img(img, 0, (TSK_FS_TYPE_ENUM) 0)) == NULL) { fprintf(stderr, "Error opening %s image\n", tname); tsk_error_print(stderr); return 1; } // verify the APIs get teh same for file 47 if (test_get_apis(fs, 47, 1)) { fprintf(stderr, "%s failure\n", tname); return 1; } // verify the one attribte is the expected type if (test_get_type(fs, 47, TSK_FS_ATTR_TYPE_DEFAULT)) { fprintf(stderr, "%s failure\n", tname); return 1; } tsk_fs_close(fs); tsk_img_close(img); return 0; }
int carving_hive(TCHAR * path, TSK_FS_INFO *fs, TSK_INUM_T inode) { char buf[0x2000]; memset(buf, 0, 0x2000); WideCharToMultiByte(CP_ACP, 0, path, TSTRLEN(path) , buf, TSTRLEN(path) , NULL, NULL); if(tsk_fs_path2inum(fs, buf, &inode, NULL)){ tsk_error_print(stderr); return 0; } if(hive_extract(fs, inode, TSK_FS_ATTR_TYPE_DEFAULT, NULL, NULL,NULL, (TSK_FS_FILE_WALK_FLAG_ENUM) 0)) return 0; return 1; }
/** * Analyze the volume starting at byte offset 'start' and look * for a file system. When found, the files will be analyzed. * * @param img Disk image to be analyzed. * @param start Byte offset of volume starting location. * * @return 1 on error and 0 on success */ static uint8_t proc_fs(TSK_IMG_INFO * img_info, TSK_OFF_T start) { TSK_FS_INFO *fs_info; TSK_STACK *stack; /* Try it as a file system */ if ((fs_info = tsk_fs_open_img(img_info, start, TSK_FS_TYPE_DETECT)) == NULL) { fprintf(stderr, "Error opening file system in partition at offset %" PRIuOFF "\n", start); tsk_error_print(stderr); /* We could do some carving on the volume data at this point */ return 1; } // create a stack to prevent infinite loops stack = tsk_stack_create(); // Process the directories if (proc_dir(fs_info, stack, fs_info->root_inum, "")) { fprintf(stderr, "Error processing file system in partition at offset %" PRIuOFF "\n", start); tsk_fs_close(fs_info); return 1; } tsk_stack_free(stack); /* We could do some analysis of unallocated blocks at this point... */ tsk_fs_close(fs_info); return 0; }
int testfile(TSK_FS_INFO * a_fs, TSK_INUM_T a_inum) { TSK_FS_FILE *file1 = NULL; if ((s_buf = (char *) malloc(a_fs->block_size)) == NULL) { fprintf(stderr, "Error allocating memory\n"); return 1; } file1 = tsk_fs_file_open_meta(a_fs, NULL, a_inum); if (file1 == NULL) { fprintf(stderr, "Error opening inode %" PRIuINUM "\n", a_inum); return 1; } s_file2 = tsk_fs_file_open_meta(a_fs, NULL, a_inum); if (s_file2 == NULL) { fprintf(stderr, "Error opening inode %" PRIuINUM "\n", a_inum); return 1; } s_off = 0; if (tsk_fs_file_walk(file1, (TSK_FS_FILE_WALK_FLAG_ENUM) 0, fw_action1, NULL)) { fprintf(stderr, "Error walking file inode: %" PRIuINUM "\n", a_inum); tsk_error_print(stderr); tsk_error_reset(); return 1; } free(s_buf); tsk_fs_file_close(file1); tsk_fs_file_close(s_file2); return 0; }
int main(int argc, char ** argv1) { int ch; TSK_TCHAR *idx_type = NULL; TSK_TCHAR *db_file = NULL, *lookup_file = NULL; unsigned int flags = 0; TSK_HDB_INFO *hdb_info; TSK_TCHAR **argv; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if( argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **)argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); while ((ch = GETOPT(argc, argv, _TSK_T("ef:i:qV"))) > 0) { switch (ch) { case _TSK_T('e'): flags |= TSK_HDB_FLAG_EXT; break; case _TSK_T('f'): lookup_file = OPTARG; break; case _TSK_T('i'): idx_type = OPTARG; break; case _TSK_T('q'): flags |= TSK_HDB_FLAG_QUICK; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); default: usage(); } } if (OPTIND + 1 > argc) { tsk_fprintf(stderr, "Error: You must provide the source hash database location\n"); usage(); } db_file = argv[OPTIND++]; if ((hdb_info = tsk_hdb_open(db_file, TSK_HDB_OPEN_NONE)) == NULL) { tsk_error_print(stderr); return 1; } /* What mode are we going to run in * * Are we going to make an index? */ if (idx_type != NULL) { /* Get the flags right */ if (lookup_file != NULL) { fprintf(stderr, "'-f' flag can't be used with '-i'\n"); usage(); } if (flags & TSK_HDB_FLAG_QUICK) { fprintf(stderr, "'-q' flag can't be used with '-i'\n"); usage(); } if (flags & TSK_HDB_FLAG_EXT) { fprintf(stderr, "'-e' flag can't be used with '-i'\n"); usage(); } if (tsk_hdb_makeindex(hdb_info, idx_type)) { tsk_error_print(stderr); tsk_hdb_close(hdb_info); return 1; } printf("Index Created\n"); tsk_hdb_close(hdb_info); return 0; } /* Do some hash lookups * * Check if the values were passed on the command line or via a file */ if (OPTIND < argc) { if ((OPTIND + 1 < argc) && (flags & TSK_HDB_FLAG_QUICK)) { fprintf(stderr, "Error: Only one hash can be given with quick option\n"); usage(); } if ((flags & TSK_HDB_FLAG_EXT) && (flags & TSK_HDB_FLAG_QUICK)) { fprintf(stderr, "'-e' flag can't be used with '-q'\n"); usage(); } if (lookup_file != NULL) { fprintf(stderr, "Error: -f can't be used when hashes are also given\n"); usage(); } /* Loop through all provided hash values */ while (OPTIND < argc) { char htmp[128]; int i; int retval; // convert to char -- lazy way to deal with WCHARs.. for (i = 0; i < 127 && argv[OPTIND][i] != '\0'; i++) { htmp[i] = (char) argv[OPTIND][i]; } htmp[i] = '\0'; /* Perform lookup */ retval = tsk_hdb_lookup_str(hdb_info, (const char *)htmp, (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL); if (retval == -1) { tsk_error_print(stderr); return 1; } if (flags & TSK_HDB_FLAG_QUICK) { printf("%d\n", retval); } else if (retval == 0) { print_notfound(htmp); } OPTIND++; } } /* Hash were given from stdin or a file */ else { char buf[100]; /* If the file was specified, use that - otherwise stdin */ #ifdef TSK_WIN32 HANDLE handle = NULL; if (lookup_file != NULL) { if ((handle = CreateFile(lookup_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { TFPRINTF(stderr, _TSK_T("Error opening hash file: %s\n"), lookup_file); exit(1); } } else { handle = GetStdHandle(STD_INPUT_HANDLE); } #else FILE *handle = NULL; if (lookup_file != NULL) { handle = fopen(lookup_file, "r"); if (!handle) { fprintf(stderr, "Error opening hash file: %s\n", lookup_file); exit(1); } } else { handle = stdin; } #endif while (1) { int retval; memset(buf, 0, 100); #ifdef TSK_WIN32 int done = 0; // win32 doesn't have a fgets equivalent, so we make an equivalent one for (int i = 0; i < 100; i++) { DWORD nread; if (FALSE == ReadFile(handle, &buf[i], (DWORD) 1, &nread, NULL)) { done = 1; break; } // skip the windows CR else if (buf[i] == '\r') { buf[i] = '\0'; i--; continue; } else if (buf[i] == '\n') { break; } } if (done) break; #else if (NULL == fgets(buf, 100, handle)) { break; } #endif /* Remove the newline */ buf[strlen(buf) - 1] = '\0'; retval = tsk_hdb_lookup_str(hdb_info, (const char *)buf, (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL); if (retval == -1) { tsk_error_print(stderr); return 1; } if (flags & TSK_HDB_FLAG_QUICK) { printf("%d\n", retval); break; } else if (retval == 0) { print_notfound(buf); } } #ifdef TSK_WIN32 if (lookup_file != NULL) CloseHandle(handle); #else if (lookup_file != NULL) fclose(handle); #endif } tsk_hdb_close(hdb_info); return 0; }
/** * /internal * Parse a buffer containing the contents of a directory and add TSK_FS_NAME * objects for each named file found to the TSK_FS_DIR representation of the * directory. * * @param fatfs File system information structure for file system that * contains the directory. * @param a_fs_dir Directory structure into to which parsed file metadata will * be added. * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector * size). * @param addrs Array where each element is the original address of * the corresponding sector in a_buf (size of array is number of sectors in * the directory). * @return TSK_RETVAL_ENUM */ TSK_RETVAL_ENUM fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T *addrs) { char *func_name = "fatxxfs_dent_parse_buf"; unsigned int idx = 0; unsigned int sidx = 0; int a = 0; int b = 0; TSK_INUM_T ibase = 0; FATXXFS_DENTRY *dep = NULL; TSK_FS_INFO *fs = (TSK_FS_INFO*)&fatfs->fs_info; int sectalloc = 0; TSK_FS_NAME *fs_name = NULL; FATXXFS_LFN lfninfo; int entrySeenCount = 0; int entryInvalidCount = 0; uint8_t isCorruptDir = 0; tsk_error_reset(); if (fatfs_ptr_arg_is_null(fatfs, "fatfs", func_name) || fatfs_ptr_arg_is_null(a_fs_dir, "a_fs_dir", func_name) || fatfs_ptr_arg_is_null(buf, "buf", func_name) || fatfs_ptr_arg_is_null(addrs, "addrs", func_name)) { return TSK_ERR; } assert(len > 0); if (len < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("%s: invalid buffer length", func_name); return TSK_ERR; } dep = (FATXXFS_DENTRY*)buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATXXFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; /* Loop through the sectors in the buffer. */ for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for the current sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR " for dir %" PRIuINUM "\n", addrs[sidx], a_fs_dir->addr); /* Get the allocation status of the current sector. */ if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* Loop through the putative directory entries in the current sector. */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { FATXXFS_DENTRY *dir; TSK_INUM_T inode; entrySeenCount++; /* Is the current entry a valid entry? */ if (0 == fatxxfs_is_dentry(fatfs, (FATFS_DENTRY*)dep, (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)sectalloc, ((isCorruptDir == 0) && (sectalloc)) ? 1 : 0)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); entryInvalidCount++; /* If we have seen four entries and all of them are corrupt, * then test every remaining entry in this folder -- * even if the sector is allocated. The scenario is one * where we are processing a cluster that is allocated * to a file and we happen to get some data that matches * every now and then. */ if ((entrySeenCount == 4) && (entryInvalidCount == 4)) { isCorruptDir = 1; } continue; } dir = dep; /* Compute the inode address corresponding to this directory entry. */ inode = ibase + idx; if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { /* The current entry is a long file name entry. */ FATXXFS_DENTRY_LFN *dirl = (FATXXFS_DENTRY_LFN *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence. */ if (((dirl->seq & FATXXFS_LFN_SEQ_FIRST) && (dirl->seq != FATXXFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* This is the last long file name entry in a sequence. * Reset the sequence number, check sum, and next char * address. */ lfninfo.seq = dirl->seq & FATXXFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { const char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } else { /* A short (8.3) entry */ char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo. name[lfninfo.start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNICODE); tsk_error_set_errstr ("fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0'; else *name8 = '\0'; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATXXFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATXXFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATXXFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; // make sure that only ASCII is in the short name fatfs_cleanup_ascii(name_ptr); } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* set the inode */ fs_name->meta_addr = inode; inode = 0; // so that we don't use it anymore -- use only fs_name->meta_addr /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name) && (fs_name->type == TSK_FS_NAME_TYPE_DIR) && idx < 2) { if (fs_name->name[1] == '\0') { /* Current directory - "." */ fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { /* Parent directory - ".." */ uint8_t dir_found = 0; if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Walking directory to find parent\n"); /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE), fatfs_find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return TSK_OK; } if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Finished walking directory to find parent\n"); if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, fs_name->meta_addr)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { if(FATXXFS_IS_DELETED(dep->name, fatfs)){ fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } else{ fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
int main(int argc, char **argv) { FS_INFO *fs; DADDR_T bstart = 0, blast = 0; int ch; int flags = FS_FLAG_DATA_UNALLOC | FS_FLAG_DATA_ALIGN | FS_FLAG_DATA_META | FS_FLAG_DATA_CONT; char *fstype = NULL; char lclflags = DLS_CAT, set_bounds = 1; char *imgtype = NULL, *cp, *dash; SSIZE_T imgoff = 0; IMG_INFO *img; progname = argv[0]; setlocale(LC_ALL, ""); while ((ch = getopt(argc, argv, "bef:i:lo:svV")) > 0) { switch (ch) { case '?': default: fprintf(stderr, "Invalid argument: %s\n", argv[optind]); usage(); case 'b': flags &= ~FS_FLAG_DATA_ALIGN; break; case 'e': flags |= FS_FLAG_DATA_ALLOC; break; case 'f': fstype = optarg; break; case 'i': imgtype = optarg; break; case 'l': lclflags = DLS_LIST; break; case 'o': if ((imgoff = parse_offset(optarg)) == -1) { tsk_error_print(stderr); exit(1); } break; case 's': lclflags |= DLS_SLACK; break; case 'v': verbose++; break; case 'V': print_version(stdout); exit(0); } } /* We need at least one more argument */ if (optind >= argc) { fprintf(stderr, "Missing image name\n"); usage(); } /* Slack has only the image name */ if (lclflags & DLS_SLACK) { if (lclflags & DLS_LIST) { fprintf(stderr, "Other options igroned with the slack space flag, try again\n"); exit(1); } /* There should be no other arguments */ img = img_open(imgtype, argc - optind, (const char **) &argv[optind]); if (img == NULL) { tsk_error_print(stderr); exit(1); } if ((fs = fs_open(img, imgoff, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_errno == TSK_ERR_FS_UNSUPTYPE) fs_print_types(stderr); img->close(img); exit(1); } } else { /* We need to determine if the block range was given */ if ((dash = strchr(argv[argc - 1], '-')) == NULL) { /* No dash in arg - therefore it is an image file name */ if ((img = img_open(imgtype, argc - optind, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } set_bounds = 1; } else { /* We have a dash, but it could be part of the file name */ *dash = '\0'; bstart = strtoull(argv[argc - 1], &cp, 0); if (*cp || cp == argv[argc - 1]) { /* Not a number - consider it a file name */ *dash = '-'; if ((img = img_open(imgtype, argc - optind, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } set_bounds = 1; } else { /* Check after the dash */ dash++; blast = strtoull(dash, &cp, 0); if (*cp || cp == dash) { /* Not a number - consider it a file name */ dash--; *dash = '-'; if ((img = img_open(imgtype, argc - optind, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } set_bounds = 1; } else { set_bounds = 0; /* It was a block range, so do not include it in the open */ if ((img = img_open(imgtype, argc - optind - 1, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } } } } if ((fs = fs_open(img, imgoff, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_errno == TSK_ERR_FS_UNSUPTYPE) fs_print_types(stderr); img->close(img); exit(1); } /* do we need to set the range or just check them? */ if (set_bounds) { bstart = fs->first_block; blast = fs->last_block; } else { if (bstart < fs->first_block) bstart = fs->first_block; if (blast > fs->last_block) blast = fs->last_block; } } if (fs_dls(fs, lclflags, bstart, blast, flags)) { tsk_error_print(stderr); fs->close(fs); img->close(img); exit(1); } fs->close(fs); img->close(img); exit(0); }
static uint8_t process_tsk_file(TSK_FS_FILE * fs_file, const char *path) { /* Use a flag to determine if a file is generically fit for plugins. */ bool can_run_plugin; /* Make sure that the SleuthKit structures are properly set */ if (fs_file->name == NULL) return 1; if (fs_file->meta == NULL && opt_debug) printf("File: %s %s has no meta\n", path, fs_file->name->name); /* SleuthKit meta types are defined in tsk_fs.h.*/ if (opt_debug) printf("Processing %s%s type=%s (0x%x) \n", path, fs_file->name->name, tsk_fs_name_type_str[fs_file->name->type],fs_file->name->type); /* Recover the filename from the fs_dent, if it is provided */ content ci(fs_file->fs_info->img_info); // where the content will go ci.evidence_dirname = path; ci.set_filename(fs_file->name->name); /* If we are filtering and we have a filename, see if we want this file. */ if (ci.name_filtered()) return 0; /* Looks like we are processing */ if(a) a->new_row(); // tell ARFF we are starting a new row if(x) x->push("fileobject"); // tell XML we are starting a new XML object if(opt_parent_tracking) { if(fs_file->name->par_addr) { if(x) { x->push("parent_object"); file_info("inode", fs_file->name->par_addr); if(x) x->pop(); } if((t||a) && !opt_body_file) { file_info("parent_inode", fs_file->name->par_addr); } } } if(fs_file->meta != NULL) { /* Get the content if needed */ if(ci.need_file_walk() && (opt_maxgig==0 || fs_file->meta->size/1000000000 < opt_maxgig)) { int myflags = TSK_FS_FILE_WALK_FLAG_NOID; if (opt_no_data) myflags |= TSK_FS_FILE_WALK_FLAG_AONLY; if (tsk_fs_file_walk (fs_file, (TSK_FS_FILE_WALK_FLAG_ENUM) myflags, file_act, (void *) &ci)) { // ignore errors from deleted files that were being recovered //if (tsk_errno != TSK_ERR_FS_RECOVER) { if (tsk_error_get_errno() != TSK_ERR_FS_RECOVER) { if(opt_debug) { fprintf(stderr,"Processing: %s/%s (%" PRIuINUM ")\n", path, fs_file->name->name, fs_file->meta->addr); tsk_error_print(stderr); } } tsk_error_reset(); } } } if(file_count_max && file_count>file_count_max) return TSK_WALK_STOP; file_count++; /* Send through to the plugin if we were doing that. * Currently results only go to ARFF file, not to the XML file. */ /* Finally output the informaton */ if(opt_body_file && (fs_file->meta != NULL)) { char ls[64]; tsk_fs_meta_make_ls(fs_file->meta,ls,sizeof(ls)); fprintf(t,"%s|%s|%" PRId64 "|%s|%d|%d|%" PRId64 "|%d|%d|%d|%d\n", ci.h_md5.final().hexdigest().c_str(),ci.filename().c_str(),fs_file->meta->addr, ls,fs_file->meta->uid,fs_file->meta->gid, fs_file->meta->size, (uint32_t)(fs_file->meta->atime), (uint32_t)fs_file->meta->mtime, (uint32_t)fs_file->meta->ctime, (uint32_t)fs_file->meta->crtime); return TSK_WALK_CONT; }
static TSK_WALK_RET_ENUM proc_dir(TSK_FS_FILE* fs_file, const char* path, void* stuff) { FILE* log = (FILE*)stuff; fprintf(log, "%s%s: flags: %d, addr: %d", path, fs_file->name->name, fs_file->meta->flags, (int)fs_file->meta->addr); // hmm, not sure if the ntfs sid stuff is working at all, but at // least call it to detect possible hangs if (fs_file->fs_info->fread_owner_sid) { char* sid_str = 0; if (tsk_fs_file_get_owner_sid(fs_file, &sid_str)) { if (tsk_verbose) { tsk_error_print(stderr); } } else { fprintf(log, ", sid_str: %s\n", sid_str); free(sid_str); } } fputc('\n', log); if (fs_file->meta->type == TSK_FS_META_TYPE_REG) { char buf[2048]; size_t len = 0; for (TSK_OFF_T off = 0; off < fs_file->meta->size; off += len) { if (fs_file->meta->size - off < (TSK_OFF_T)sizeof(buf)) { len = (size_t) (fs_file->meta->size - off); } else { len = sizeof(buf); } int myflags = 0; ssize_t cnt = tsk_fs_file_read(fs_file, off, buf, len, (TSK_FS_FILE_READ_FLAG_ENUM)myflags); if (cnt == -1) { if (tsk_verbose) { fprintf(stderr, "Error reading %s file: %s\n", ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); tsk_error_print(stderr); } break; } else if (cnt != (ssize_t) len) { if (tsk_verbose) { fprintf(stderr, "Warning: %" PRIuSIZE " of %" PRIuSIZE " bytes read from %s file %s\n", cnt, len, ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); } } // data is in buf[0..len); could be binary, not null terminated // might consider printing it out if all ascii or looks like text // or print hexdump, just for thread comparison } } return TSK_WALK_CONT; }
int main(int argc, char** argv1) { TSK_TCHAR **argv; TSK_TCHAR *cp; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif progname = argv[0]; TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT; TSK_OFF_T imgaddr = 0; int ch; while ((ch = GETOPT(argc, argv, _TSK_T("f:o:v"))) != -1) { switch (ch) { case _TSK_T('f'): fstype = tsk_fs_type_toid(OPTARG); if (fstype == TSK_FS_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported file system type: %s\n"), OPTARG); usage(); } break; case _TSK_T('o'): if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) { tsk_error_print(stderr); exit(1); } break; case _TSK_T('v'): tsk_verbose = 1; break; default: usage(); break; } } if (argc - OPTIND != 3) { usage(); } const TSK_TCHAR* image = argv[OPTIND]; size_t nthreads = (size_t) TSTRTOUL(argv[OPTIND + 1], &cp, 0); if (nthreads == 0) { fprintf(stderr, "invalid nthreads\n"); exit(1); } size_t niters = (size_t) TSTRTOUL(argv[OPTIND + 2], &cp, 0); if (niters == 0) { fprintf(stderr, "invalid nthreads\n"); exit(1); } TSK_IMG_INFO* img = tsk_img_open_sing(image, TSK_IMG_TYPE_DETECT, 0); if (img == 0) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } TSK_FS_INFO* fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype); if (fs == 0) { tsk_img_close(img); tsk_error_print(stderr); exit(1); } TskThread** threads = new TskThread*[nthreads]; for (size_t i = 0; i < nthreads; ++i) { threads[i] = new MyThread(i, fs, niters); } TskThread::run(threads, nthreads); for (size_t i = 0; i < nthreads; ++i) { delete threads[i]; } delete[] threads; tsk_fs_close(fs); tsk_img_close(img); exit(0); }
int main(int argc, char **argv1) { TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT; TSK_IMG_INFO *img; TSK_OFF_T imgaddr = 0; TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT; TSK_FS_INFO *fs; int ch; TSK_TCHAR *cp; uint8_t type = 0; int set = 0; TSK_DADDR_T count = 0; TSK_TCHAR **argv; unsigned int ssize = 0; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); while ((ch = GETOPT(argc, argv, _TSK_T("b:d:f:i:o:s:u:vV"))) > 0) { switch (ch) { case _TSK_T('?'): default: TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"), argv[OPTIND]); usage(); case _TSK_T('b'): ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG || ssize < 1) { TFPRINTF(stderr, _TSK_T ("invalid argument: sector size must be positive: %s\n"), OPTARG); usage(); } break; case _TSK_T('d'): type |= TSK_FS_BLKCALC_DD; count = TSTRTOULL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG) { TFPRINTF(stderr, _TSK_T("Invalid address: %s\n"), OPTARG); usage(); } set = 1; break; case _TSK_T('f'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_fs_type_print(stderr); exit(1); } fstype = tsk_fs_type_toid(OPTARG); if (fstype == TSK_FS_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported file system type: %s\n"), OPTARG); usage(); } break; case _TSK_T('i'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_img_type_print(stderr); exit(1); } imgtype = tsk_img_type_toid(OPTARG); if (imgtype == TSK_IMG_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"), OPTARG); usage(); } break; case _TSK_T('o'): if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) { tsk_error_print(stderr); exit(1); } break; case _TSK_T('s'): type |= TSK_FS_BLKCALC_SLACK; count = TSTRTOULL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG) { TFPRINTF(stderr, _TSK_T("Invalid address: %s\n"), OPTARG); usage(); } set = 1; break; case _TSK_T('u'): type |= TSK_FS_BLKCALC_BLKLS; count = TSTRTOULL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG) { TFPRINTF(stderr, _TSK_T("Invalid address: %s\n"), OPTARG); usage(); } set = 1; break; case _TSK_T('v'): tsk_verbose++; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); } } /* We need at least one more argument */ if (OPTIND == argc) { tsk_fprintf(stderr, "Missing image name\n"); usage(); } if ((!type) || (set == 0)) { tsk_fprintf(stderr, "Calculation type not given (-u, -d, -s)\n"); usage(); } if ((type & TSK_FS_BLKCALC_DD) && (type & TSK_FS_BLKCALC_BLKLS) && (type & TSK_FS_BLKCALC_SLACK)) { tsk_fprintf(stderr, "Only one block type can be given\n"); usage(); } if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_error_get_errno() == TSK_ERR_FS_UNSUPTYPE) tsk_fs_type_print(stderr); img->close(img); exit(1); } if (-1 == tsk_fs_blkcalc(fs, (TSK_FS_BLKCALC_FLAG_ENUM) type, count)) { tsk_error_print(stderr); fs->close(fs); img->close(img); exit(1); } fs->close(fs); img->close(img); exit(0); }
int main(int argc, char* argv1[]) { TSK_VS_INFO* lVsInfo = NULL; TSK_OFF_T lCnt = 0; char lBuf[32768] = { 0 }; unsigned lCntRead = 0; TSK_IMG_INFO* lImgInfo = OS_FH_INVALID; OS_FH_TYPE lOut = OS_FH_INVALID; const TSK_TCHAR *const *argv; #ifdef TSK_WIN32 argv = CommandLineToArgvW(GetCommandLineW(), &argc); #else argv = (const TSK_TCHAR *const *) argv1; #endif lOut = OS_FOPEN_WRITE(argv[2]); if (lOut == OS_FH_INVALID) { LOGGING_ERROR("Could not open export image in write mode. \n") exit(1); } lImgInfo = tsk_img_open( 1, /* number of images */ (argv + 1), /* path to images */ TSK_IMG_TYPE_DETECT, /* disk image type */ 0); /* size of device sector in bytes */ if (lImgInfo != NULL) { TSK_OFF_T lSizeSectors = lImgInfo->size / lImgInfo->sector_size + \ (lImgInfo->size % lImgInfo->sector_size ? 1 : 0); LOGGING_INFO("Image size (Bytes): %lu, Image size (sectors): %lu\n", lImgInfo->size, lSizeSectors); lVsInfo = tsk_vs_open(lImgInfo, 0, TSK_VS_TYPE_DETECT); if (lVsInfo != NULL) { if (tsk_vs_part_walk(lVsInfo, 0, /* start */ lVsInfo->part_count - 1, /* end */ TSK_VS_PART_FLAG_ALL, /* all partitions */ part_act, /* callback */ (void*) lOut /* data passed to the callback */ ) != 0) { fprintf(stderr, "Problem when walking partitions. \n"); } } else { LOGGING_DEBUG("Volume system cannot be opened.\n"); for (lCnt = 0; lCnt < lSizeSectors; lCnt++) { lCntRead = lCnt == lSizeSectors - 1 ? lImgInfo->size % lImgInfo->sector_size : lImgInfo->sector_size; LOGGING_DEBUG("Reading %u bytes\n", lCntRead); tsk_img_read( lImgInfo, /* handler */ lCnt * lImgInfo->sector_size, /* start address */ lBuf, /* buffer to store data in */ lCntRead /* amount of data to read */ ); data_act(lBuf, lCntRead, lCnt * lImgInfo->sector_size, lOut); } } } else { LOGGING_ERROR("Problem opening the image. \n"); tsk_error_print(stderr); exit(1); } if (lOut != OS_FH_INVALID) { OS_FCLOSE(lOut); } return EXIT_SUCCESS; }
/** * Open a directory and cycle through its contents. Read each file and recurse * into each directory. * * @param fs_info File system to process * @param stack Stack to prevent infinite recursion loops * @param dir_inum Metadata address of directory to open * @param path Path of directory being opened * @returns 1 on error */ static uint8_t proc_dir(TSK_FS_INFO * fs_info, TSK_STACK * stack, TSK_INUM_T dir_inum, const char *path) { TSK_FS_DIR *fs_dir; size_t i; char *path2 = NULL; char *buf = NULL; // open the directory if ((fs_dir = tsk_fs_dir_open_meta(fs_info, dir_inum)) == NULL) { fprintf(stderr, "Error opening directory: %" PRIuINUM "\n", dir_inum); tsk_error_print(stderr); return 1; } /* These should be dynamic lengths, but this is just a sample program. * Allocate heap space instead of stack to prevent overflow for deep * directories. */ if ((path2 = (char *) malloc(4096)) == NULL) { return 1; } if ((buf = (char *) malloc(2048)) == NULL) { free(path2); return 1; } // cycle through each entry for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) { TSK_FS_FILE *fs_file; TSK_OFF_T off = 0; size_t len = 0; // get the entry if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) { fprintf(stderr, "Error getting directory entry %" PRIuSIZE " in directory %" PRIuINUM "\n", i, dir_inum); tsk_error_print(stderr); free(path2); free(buf); return 1; } /* Ignore NTFS System files */ if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype)) && (fs_file->name->name[0] == '$')) { tsk_fs_file_close(fs_file); continue; } //printf("Processing %s/%s\n", path, fs_file->name->name); // make sure it's got metadata and not only a name if (fs_file->meta) { ssize_t cnt; /* Note that we could also cycle through all of the attributes in the * file by using one of the tsk_fs_attr_get() functions and reading it * with tsk_fs_attr_read(). See the File Systems section of the Library * User's Guide for more details: * http://www.sleuthkit.org/sleuthkit/docs/api-docs/ */ // read file contents if (fs_file->meta->type == TSK_FS_META_TYPE_REG) { int myflags = 0; for (off = 0; off < fs_file->meta->size; off += len) { if (fs_file->meta->size - off < 2048) len = (size_t) (fs_file->meta->size - off); else len = 2048; cnt = tsk_fs_file_read(fs_file, off, buf, len, (TSK_FS_FILE_READ_FLAG_ENUM) myflags); if (cnt == -1) { // could check tsk_errno here for a recovery error (TSK_ERR_FS_RECOVER) fprintf(stderr, "Error reading %s file: %s\n", ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); tsk_error_print(stderr); break; } else if (cnt != (ssize_t) len) { fprintf(stderr, "Warning: %" PRIuSIZE " of %" PRIuSIZE " bytes read from %s file %s\n", cnt, len, ((fs_file->name-> flags & TSK_FS_NAME_FLAG_UNALLOC) || (fs_file->meta-> flags & TSK_FS_META_FLAG_UNALLOC)) ? "unallocated" : "allocated", fs_file->name->name); } // do something with the data... } } // recurse into another directory (unless it is a '.' or '..') else if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) { if (TSK_FS_ISDOT(fs_file->name->name) == 0) { // only go in if it is not on our stack if (tsk_stack_find(stack, fs_file->meta->addr) == 0) { // add the address to the top of the stack tsk_stack_push(stack, fs_file->meta->addr); snprintf(path2, 4096, "%s/%s", path, fs_file->name->name); if (proc_dir(fs_info, stack, fs_file->meta->addr, path2)) { tsk_fs_file_close(fs_file); tsk_fs_dir_close(fs_dir); free(path2); free(buf); return 1; } // pop the address tsk_stack_pop(stack); } } } } tsk_fs_file_close(fs_file); } tsk_fs_dir_close(fs_dir); free(path2); free(buf); return 0; }
/* ** ** Read contents of directory block ** ** if entry is active call action with myflags set to TSK_FS_DENT_FLAG_ALLOC, if ** it is deleted then call action with TSK_FS_DENT_FLAG_UNALLOC. ** len is the size of buf ** ** return 1 to stop, 0 on success, and -1 on error */ static int ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo, TSK_LIST ** list_seen, char *buf, int len, int flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { TSK_FS_INFO *fs = &(ext2fs->fs_info); int dellen = 0; int idx; uint16_t reclen; uint32_t inode; char *dirPtr; TSK_FS_DENT *fs_dent; int minreclen = 4; if ((fs_dent = tsk_fs_dent_alloc(EXT2FS_MAXNAMLEN + 1, 0)) == NULL) return -1; /* update each time by the actual length instead of the ** recorded length so we can view the deleted entries */ for (idx = 0; idx <= len - EXT2FS_DIRSIZ_lcl(1); idx += minreclen) { unsigned int namelen; dirPtr = &buf[idx]; if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = tsk_getu16(fs->endian, dir->name_len); reclen = tsk_getu16(fs->endian, dir->rec_len); } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) dirPtr; inode = tsk_getu32(fs->endian, dir->inode); namelen = dir->name_len; reclen = tsk_getu16(fs->endian, dir->rec_len); } minreclen = EXT2FS_DIRSIZ_lcl(namelen); /* ** Check if we may have a valid directory entry. If we don't, ** then increment to the next word and try again. */ if ((inode > fs->last_inum) || (inode < 0) || (namelen > EXT2FS_MAXNAMLEN) || (namelen <= 0) || (reclen < minreclen) || (reclen % 4) || (idx + reclen > len)) { minreclen = 4; if (dellen > 0) dellen -= 4; continue; } /* Before we process an entry in unallocated space, make * sure that it also ends in the unalloc space */ if ((dellen) && (dellen < minreclen)) { minreclen = 4; if (dellen > 0) dellen -= 4; continue; } if (ext2fs_dent_copy(ext2fs, dinfo, dirPtr, fs_dent)) { tsk_fs_dent_free(fs_dent); return -1; } /* Do we have a deleted entry? */ if ((dellen > 0) || (inode == 0)) { fs_dent->flags = TSK_FS_DENT_FLAG_UNALLOC; if (dellen > 0) dellen -= minreclen; if (flags & TSK_FS_DENT_FLAG_UNALLOC) { int retval; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 1; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return -1; } } } /* We have a non-deleted entry */ else { fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC; if (flags & TSK_FS_DENT_FLAG_ALLOC) { int retval; retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 1; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return -1; } } } /* If the actual length is shorter then the ** recorded length, then the next entry(ies) have been ** deleted. Set dellen to the length of data that ** has been deleted ** ** Because we aren't guaranteed with Ext2FS that the next ** entry begins right after this one, we will check to ** see if the difference is less than a possible entry ** before we waste time searching it */ if ((reclen - minreclen >= EXT2FS_DIRSIZ_lcl(1)) && (dellen <= 0)) dellen = reclen - minreclen; /* we will be recursing directories */ if ((fs_dent->flags & TSK_FS_DENT_FLAG_ALLOC) && (flags & TSK_FS_DENT_FLAG_RECURSE) && (!TSK_FS_ISDOT(fs_dent->name)) && ((fs_dent->fsi->mode & TSK_FS_INODE_MODE_FMT) == TSK_FS_INODE_MODE_DIR)) { int depth_added = 0; /* Make sure we do not get into an infinite loop */ if (0 == tsk_list_find(*list_seen, fs_dent->inode)) { if (tsk_list_add(list_seen, fs_dent->inode)) { tsk_fs_dent_free(fs_dent); return -1; } if ((dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(dinfo->dirs) + strlen(fs_dent->name))) { dinfo->didx[dinfo->depth] = &dinfo->dirs[strlen(dinfo->dirs)]; strncpy(dinfo->didx[dinfo->depth], fs_dent->name, DIR_STRSZ - strlen(dinfo->dirs)); strncat(dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } dinfo->depth++; if (ext2fs_dent_walk_lcl(&(ext2fs->fs_info), dinfo, list_seen, fs_dent->inode, flags, action, ptr)) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, "ffs_dent_parse_block: error reading directory: %" PRIuINUM "\n", fs_dent->inode); tsk_error_print(stderr); } tsk_error_reset(); } dinfo->depth--; if (depth_added) *dinfo->didx[dinfo->depth] = '\0'; } } } tsk_fs_dent_free(fs_dent); return 0; } /* end ext2fs_dent_parse_block() */
/* main - open file system, list inode info */ int main(int argc, char **argv1) { TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT; TSK_IMG_INFO *img; TSK_OFF_T imgaddr = 0; TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT; TSK_FS_INFO *fs; TSK_TCHAR *cp, *dash; TSK_INUM_T istart = 0, ilast = 0; int ch; int flags = TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED; int ils_flags = 0; int set_range = 1; TSK_TCHAR *image = NULL; int32_t sec_skew = 0; TSK_TCHAR **argv; unsigned int ssize = 0; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); /* * Provide convenience options for the most commonly selected feature * combinations. */ while ((ch = GETOPT(argc, argv, _TSK_T("aAb:ef:i:lLmo:Oprs:vVzZ"))) > 0) { switch (ch) { case _TSK_T('?'): default: TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"), argv[OPTIND]); usage(); case _TSK_T('b'): ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG || ssize < 1) { TFPRINTF(stderr, _TSK_T ("invalid argument: sector size must be positive: %s\n"), OPTARG); usage(); } break; case _TSK_T('f'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_fs_type_print(stderr); exit(1); } fstype = tsk_fs_type_toid(OPTARG); if (fstype == TSK_FS_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported file system type: %s\n"), OPTARG); usage(); } break; case _TSK_T('i'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_img_type_print(stderr); exit(1); } imgtype = tsk_img_type_toid(OPTARG); if (imgtype == TSK_IMG_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"), OPTARG); usage(); } break; case _TSK_T('e'): flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC); flags &= ~TSK_FS_META_FLAG_USED; break; case _TSK_T('m'): ils_flags |= TSK_FS_ILS_MAC; break; case _TSK_T('o'): if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) { tsk_error_print(stderr); exit(1); } break; case _TSK_T('O'): flags |= TSK_FS_META_FLAG_UNALLOC; flags &= ~TSK_FS_META_FLAG_ALLOC; ils_flags |= TSK_FS_ILS_OPEN; break; case _TSK_T('p'): flags |= (TSK_FS_META_FLAG_ORPHAN | TSK_FS_META_FLAG_UNALLOC); flags &= ~TSK_FS_META_FLAG_ALLOC; break; case _TSK_T('r'): flags |= (TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED); flags &= ~TSK_FS_META_FLAG_ALLOC; break; case _TSK_T('s'): sec_skew = TATOI(OPTARG); break; case _TSK_T('v'): tsk_verbose++; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); /* * Provide fine controls to tweak one feature at a time. */ case _TSK_T('a'): flags |= TSK_FS_META_FLAG_ALLOC; flags &= ~TSK_FS_META_FLAG_UNALLOC; break; case _TSK_T('A'): flags |= TSK_FS_META_FLAG_UNALLOC; break; case _TSK_T('l'): ils_flags |= TSK_FS_ILS_LINK; break; case _TSK_T('L'): ils_flags |= TSK_FS_ILS_UNLINK; break; case _TSK_T('z'): flags |= TSK_FS_META_FLAG_UNUSED; break; case _TSK_T('Z'): flags |= TSK_FS_META_FLAG_USED; break; } } if (OPTIND >= argc) { tsk_fprintf(stderr, "Missing image name\n"); usage(); } if ((ils_flags & TSK_FS_ILS_LINK) && (ils_flags & TSK_FS_ILS_UNLINK)) { tsk_fprintf(stderr, "ERROR: Only linked or unlinked should be used\n"); usage(); } /* We need to determine if an inode or inode range was given */ if ((dash = TSTRCHR(argv[argc - 1], _TSK_T('-'))) == NULL) { /* Check if is a single number */ istart = TSTRTOULL(argv[argc - 1], &cp, 0); if (*cp || *cp == *argv[argc - 1]) { /* Not a number - consider it a file name */ image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { /* Single address set end addr to start */ ilast = istart; set_range = 0; image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND - 1, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } } else { /* We have a dash, but it could be part of the file name */ *dash = '\0'; istart = TSTRTOULL(argv[argc - 1], &cp, 0); if (*cp || *cp == *argv[argc - 1]) { /* Not a number - consider it a file name */ *dash = _TSK_T('-'); image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { dash++; ilast = TSTRTOULL(dash, &cp, 0); if (*cp || *cp == *dash) { /* Not a number - consider it a file name */ dash--; *dash = '-'; image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { set_range = 0; /* It was a block range, so do not include it in the open */ image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND - 1, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } } } if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_error_get_errno() == TSK_ERR_FS_UNSUPTYPE) tsk_fs_type_print(stderr); img->close(img); exit(1); } /* do we need to set the range or just check them? */ if (set_range) { istart = fs->first_inum; ilast = fs->last_inum; } else { if (istart < fs->first_inum) istart = fs->first_inum; if (ilast > fs->last_inum) ilast = fs->last_inum; } /* NTFS uses alloc and link different than UNIX so change * the default behavior * * The link value can be > 0 on deleted files (even when closed) */ /* NTFS and FAT have no notion of deleted but still open */ if ((ils_flags & TSK_FS_ILS_OPEN) && (TSK_FS_TYPE_ISNTFS(fs->ftype) || TSK_FS_TYPE_ISFAT(fs->ftype))) { fprintf(stderr, "Error: '-O' argument does not work with NTFS and FAT images\n"); exit(1); } if (tsk_fs_ils(fs, (TSK_FS_ILS_FLAG_ENUM) ils_flags, istart, ilast, (TSK_FS_META_FLAG_ENUM) flags, sec_skew, image)) { tsk_error_print(stderr); fs->close(fs); img->close(img); exit(1); } fs->close(fs); img->close(img); exit(0); }
/* dir_walk local function that is used for recursive calls. Callers * should initially call the non-local version. */ static TSK_WALK_RET_ENUM tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, void *a_ptr) { TSK_FS_DIR *fs_dir; TSK_FS_FILE *fs_file; size_t i; // get the list of entries in the directory if ((fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr)) == NULL) { return TSK_WALK_ERROR; } /* Allocate a file structure for the callbacks. We * will allocate fs_meta structures as needed and * point into the fs_dir structure for the names. */ if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { tsk_fs_dir_close(fs_dir); return TSK_WALK_ERROR; } for (i = 0; i < fs_dir->names_used; i++) { TSK_WALK_RET_ENUM retval; /* Point name to the buffer of names. We need to be * careful about resetting this before we free fs_file */ fs_file->name = (TSK_FS_NAME *) & fs_dir->names[i]; /* load the fs_meta structure if possible. * Must have non-zero inode addr or have allocated name (if inode is 0) */ if (((fs_file->name->meta_addr) || (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC))) { if (a_fs->file_add_meta(a_fs, fs_file, fs_file->name->meta_addr)) { if (tsk_verbose) tsk_error_print(stderr); tsk_error_reset(); } } // call the action if we have the right flags. if ((fs_file->name->flags & a_flags) == fs_file->name->flags) { retval = a_action(fs_file, a_dinfo->dirs, a_ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); /* free the list -- fs_dir_walk has no way * of knowing that we stopped early w/out error. */ if (a_dinfo->save_inum_named) { tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } return TSK_WALK_STOP; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } } // save the inode info for orphan finding - if requested if ((a_dinfo->save_inum_named) && (fs_file->meta) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) { if (tsk_list_add(&a_dinfo->list_inum_named, fs_file->meta->addr)) { // if there is an error, then clear the list tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } } /* Recurse into a directory if: * - Both dir entry and inode have DIR type (or name is undefined) * - Recurse flag is set * - dir entry is allocated OR both are unallocated * - not one of the '.' or '..' entries * - A Non-Orphan Dir or the Orphan Dir with the NOORPHAN flag not set. */ if (((fs_file->name->type == TSK_FS_NAME_TYPE_DIR) || (fs_file->name->type == TSK_FS_NAME_TYPE_UNDEF)) && (fs_file->meta) && (fs_file->meta->type == TSK_FS_META_TYPE_DIR) && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE) && ((fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) || ((fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) ) && (!TSK_FS_ISDOT(fs_file->name->name)) && ((fs_file->name->meta_addr != TSK_FS_ORPHANDIR_INUM(a_fs)) || ((a_flags & TSK_FS_DIR_WALK_FLAG_NOORPHAN) == 0)) ) { /* Make sure we do not get into an infinite loop */ if (0 == tsk_stack_find(a_dinfo->stack_seen, fs_file->name->meta_addr)) { int depth_added = 0; uint8_t save_bak = 0; if (tsk_stack_push(a_dinfo->stack_seen, fs_file->name->meta_addr)) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } if ((a_dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(a_dinfo->dirs) + strlen(fs_file->name->name))) { a_dinfo->didx[a_dinfo->depth] = &a_dinfo->dirs[strlen(a_dinfo->dirs)]; strncpy(a_dinfo->didx[a_dinfo->depth], fs_file->name->name, DIR_STRSZ - strlen(a_dinfo->dirs)); strncat(a_dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } a_dinfo->depth++; /* We do not want to save info about named unalloc files * when we go into the Orphan directory (because then we have * no orphans). So, disable it for this recursion. */ if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { save_bak = a_dinfo->save_inum_named; a_dinfo->save_inum_named = 0; } retval = tsk_fs_dir_walk_lcl(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, a_action, a_ptr); if (retval == TSK_WALK_ERROR) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, "tsk_fs_dir_walk_lcl: error reading directory: %" PRIuINUM "\n", fs_file->name->meta_addr); tsk_error_print(stderr); } tsk_error_reset(); } else if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_STOP; } // reset the save status if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { a_dinfo->save_inum_named = save_bak; } tsk_stack_pop(a_dinfo->stack_seen); a_dinfo->depth--; if (depth_added) *a_dinfo->didx[a_dinfo->depth] = '\0'; } else { if (tsk_verbose) fprintf(stderr, "tsk_fs_dir_walk_lcl: Loop detected with address %" PRIuINUM, fs_file->name->meta_addr); } } // remove the pointer to name buffer fs_file->name = NULL; // free the metadata if we allocated it if (fs_file->meta) { tsk_fs_meta_close(fs_file->meta); fs_file->meta = NULL; } } tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_CONT; }
int main(int argc, char **argv) { char *fstype = NULL; int ch; char *cp, type = 0; FS_INFO *fs; IMG_INFO *img; int set = 0; char *imgtype = NULL; SSIZE_T imgoff = 0; DADDR_T count = 0; progname = argv[0]; setlocale(LC_ALL, ""); while ((ch = getopt(argc, argv, "d:f:i:o:s:u:vV")) > 0) { switch (ch) { case '?': default: fprintf(stderr, "Invalid argument: %s\n", argv[optind]); usage(); case 'd': type |= DCALC_DD; count = strtoull(optarg, &cp, 0); if (*cp || cp == optarg) { fprintf(stderr, "Invalid address: %s\n", optarg); usage(); } set = 1; break; case 'f': fstype = optarg; break; case 'i': imgtype = optarg; break; case 'o': if ((imgoff = parse_offset(optarg)) == -1) { tsk_error_print(stderr); exit(1); } break; case 's': type |= DCALC_SLACK; count = strtoull(optarg, &cp, 0); if (*cp || cp == optarg) { fprintf(stderr, "Invalid address: %s\n", optarg); usage(); } set = 1; break; case 'u': type |= DCALC_DLS; count = strtoull(optarg, &cp, 0); if (*cp || cp == optarg) { fprintf(stderr, "Invalid address: %s\n", optarg); usage(); } set = 1; break; case 'v': verbose++; break; case 'V': print_version(stdout); exit(0); } } /* We need at least one more argument */ if (optind == argc) { fprintf(stderr, "Missing image name\n"); usage(); } if ((!type) || (set == 0)) { fprintf(stderr, "Calculation type not given (-u, -d, -s)\n"); usage(); } if ((type & DCALC_DD) && (type & DCALC_DLS) && (type & DCALC_SLACK)) { fprintf(stderr, "Only one block type can be given\n"); usage(); } if ((img = img_open(imgtype, argc - optind, (const char **) &argv[optind])) == NULL) { tsk_error_print(stderr); exit(1); } if ((fs = fs_open(img, imgoff, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_errno == TSK_ERR_FS_UNSUPTYPE) fs_print_types(stderr); img->close(img); exit(1); } if (-1 == fs_dcalc(fs, type, count)) { tsk_error_print(stderr); fs->close(fs); img->close(img); exit(1); } fs->close(fs); img->close(img); exit(0); }