📄 ntfs_dent.c
字号:
/*** ntfs_dent** The Sleuth Kit**** name layer support for the NTFS file system**** Brian Carrier [carrier <at> sleuthkit [dot] org]** Copyright (c) 2006-2008 Brian Carrier, Basis Technology. All Rights reserved** Copyright (c) 2003-2005 Brian Carrier. All rights reserved**** TASK** Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved****** This software is distributed under the Common Public License 1.0**** Unicode added with support from I.D.E.A.L. Technology Corp (Aug '05)***/#include "tsk_fs_i.h"#include "tsk_ntfs.h"/** * \file ntfs_dent.c * NTFS file name processing internal functions. *//******************************************************************************** Find an unallocated NTFS MFT entry based on its parent directory*/typedef struct { TSK_FS_NAME *fs_name; TSK_INUM_T parinode; TSK_FS_DIR *fs_dir;} NTFS_PAR_DATA;/* dent call back for tsk_fs_ifind_par to find unallocated files * based on parent directory*/static TSK_WALK_RET_ENUMntfs_par_act(TSK_FS_FILE * fs_file, void *ptr){ NTFS_PAR_DATA *par_data = (NTFS_PAR_DATA *) ptr; TSK_FS_META_NAME_LIST *fs_name_list; /* go through each file name structure */ fs_name_list = fs_file->meta->name2; while (fs_name_list) { // we got our target if (fs_name_list->par_inode == par_data->parinode) { /* Fill in the basics of the fs_name entry * so we can print in the fls formats */ par_data->fs_name->meta_addr = fs_file->meta->addr; par_data->fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; strncpy(par_data->fs_name->name, fs_name_list->name, par_data->fs_name->name_size); if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) par_data->fs_name->type = TSK_FS_NAME_TYPE_DIR; else par_data->fs_name->type = TSK_FS_NAME_TYPE_REG; tsk_fs_dir_add(par_data->fs_dir, par_data->fs_name); } fs_name_list = fs_name_list->next; } return TSK_WALK_CONT;}static uint8_tntfs_dent_copy(NTFS_INFO * ntfs, ntfs_idxentry * idxe, TSK_FS_NAME * fs_name){ ntfs_attr_fname *fname = (ntfs_attr_fname *) & idxe->stream; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info; UTF16 *name16; UTF8 *name8; int retVal; int i; fs_name->meta_addr = tsk_getu48(fs->endian, idxe->file_ref); fs_name->meta_seq = tsk_getu16(fs->endian, idxe->seq_num); name16 = (UTF16 *) & fname->name; name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) ((uintptr_t) name16 + fname->nlen * 2), &name8, (UTF8 *) ((uintptr_t) name8 + fs_name->name_size), TSKlenientConversion); if (retVal != TSKconversionOK) { *name8 = '\0'; if (tsk_verbose) tsk_fprintf(stderr, "Error converting NTFS name to UTF8: %d %" PRIuINUM, retVal, fs_name->meta_addr); } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + fs_name->name_size) fs_name->name[fs_name->name_size] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } if (tsk_getu64(fs->endian, fname->flags) & NTFS_FNAME_FLAGS_DIR) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; fs_name->flags = 0; return 0;}/* This is a sanity check to see if the time is valid * it is divided by 100 to keep it in a 32-bit integer */static uint8_tis_time(uint64_t t){#define SEC_BTWN_1601_1970_DIV100 ((369*365 + 89) * 24 * 36)#define SEC_BTWN_1601_2010_DIV100 (SEC_BTWN_1601_1970_DIV100 + (40*365 + 6) * 24 * 36) t /= 1000000000; /* put the time in seconds div by additional 100 */ if (!t) return 0; if (t < SEC_BTWN_1601_1970_DIV100) return 0; if (t > SEC_BTWN_1601_2010_DIV100) return 0; return 1;}/** * Process a lsit of index entries and add to FS_DIR * * @param a_is_del Set to 1 if these entries are for a deleted directory * @param idxe Buffer with index entries to process * @param idxe_len Length of idxe buffer (in bytes) * @param used_len Length of data as reported by idexlist header (everything * after which and less then idxe_len is considered deleted) * * @returns 1 to stop, 0 on success, and -1 on error */// @@@ Should make a_idxe const and use internal pointer in function loopstatic TSK_RETVAL_ENUMntfs_proc_idxentry(NTFS_INFO * a_ntfs, TSK_FS_DIR * a_fs_dir, uint8_t a_is_del, ntfs_idxentry * a_idxe, uint32_t a_idxe_len, uint32_t a_used_len){ uintptr_t endaddr, endaddr_alloc; TSK_FS_NAME *fs_name; TSK_FS_INFO *fs = (TSK_FS_INFO *) & a_ntfs->fs_info; if ((fs_name = tsk_fs_name_alloc(NTFS_MAXNAMLEN_UTF8, 0)) == NULL) { return TSK_ERR; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Processing index entry: %" PRIu64 " Size: %" PRIu32 " Len: %" PRIu32 "\n", (uint64_t) ((uintptr_t) a_idxe), a_idxe_len, a_used_len); /* Sanity check */ if (a_idxe_len < a_used_len) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_proc_idxentry: Allocated length of index entries is larger than buffer length"); return TSK_ERR; } /* where is the end of the buffer */ endaddr = ((uintptr_t) a_idxe + a_idxe_len); /* where is the end of the allocated data */ endaddr_alloc = ((uintptr_t) a_idxe + a_used_len); /* cycle through the index entries, based on provided size */ while (((uintptr_t) & (a_idxe->stream) + sizeof(ntfs_attr_fname)) < endaddr) { ntfs_attr_fname *fname = (ntfs_attr_fname *) & a_idxe->stream; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: New IdxEnt: %" PRIu64 " $FILE_NAME Entry: %" PRIu64 " File Ref: %" PRIu64 " IdxEnt Len: %" PRIu16 " StrLen: %" PRIu16 "\n", (uint64_t) ((uintptr_t) a_idxe), (uint64_t) ((uintptr_t) fname), (uint64_t) tsk_getu48(fs->endian, a_idxe->file_ref), tsk_getu16(fs->endian, a_idxe->idxlen), tsk_getu16(fs->endian, a_idxe->strlen)); /* perform some sanity checks on index buffer head * and advance by 4-bytes if invalid */ if ((tsk_getu48(fs->endian, a_idxe->file_ref) > fs->last_inum) || (tsk_getu48(fs->endian, a_idxe->file_ref) < fs->first_inum) || (tsk_getu16(fs->endian, a_idxe->idxlen) <= tsk_getu16(fs->endian, a_idxe->strlen)) || (tsk_getu16(fs->endian, a_idxe->idxlen) % 4) || (tsk_getu16(fs->endian, a_idxe->idxlen) > a_idxe_len)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); continue; } /* do some sanity checks on the deleted entries */ if ((tsk_getu16(fs->endian, a_idxe->strlen) == 0) || (((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)) > endaddr_alloc)) { /* name space checks */ if ((fname->nspace != NTFS_FNAME_POSIX) && (fname->nspace != NTFS_FNAME_WIN32) && (fname->nspace != NTFS_FNAME_DOS) && (fname->nspace != NTFS_FNAME_WINDOS)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of invalid name space\n"); continue; } if ((tsk_getu64(fs->endian, fname->alloc_fsize) < tsk_getu64(fs->endian, fname->real_fsize)) || (fname->nlen == 0) || (*(uint8_t *) & fname->name == 0)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of reported file sizes, name length, or NULL name\n"); continue; } if ((is_time(tsk_getu64(fs->endian, fname->crtime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->atime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->mtime)) == 0)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of invalid times\n"); continue; } } /* For all fname entries, there will exist a DOS style 8.3 * entry. We don't process those because we already processed * them before in their full version. If the type is * full POSIX or WIN32 that does not satisfy DOS, then a * type NTFS_FNAME_DOS will exist. If the name is WIN32, * but already satisfies DOS, then a type NTFS_FNAME_WINDOS * will exist * * Note that we could be missing some info from deleted files * if the windows version was deleted and the DOS wasn't... * * @@@ This should be added to the shrt_name entry of TSK_FS_NAME. The short * name entry typically comes after the long name */ if (fname->nspace == NTFS_FNAME_DOS) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of name space: %d\n", fname->nspace); goto incr_entry; } /* Copy it into the generic form */ if (ntfs_dent_copy(a_ntfs, a_idxe, fs_name)) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because error copying dent_entry\n"); goto incr_entry; } /* * Check if this entry is deleted * * The final check is to see if the end of this entry is * within the space that the idxallocbuf claimed was valid OR * if the parent directory is deleted */ if ((a_is_del == 1) || (tsk_getu16(fs->endian, a_idxe->strlen) == 0) || (((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)) > endaddr_alloc)) { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Entry Details of %s: Str Len: %" PRIu16 " Len to end after current: %" PRIu64 " flags: %x\n", fs_name->name, tsk_getu16(fs->endian, a_idxe->strlen), (uint64_t) (endaddr_alloc - (uintptr_t) a_idxe - tsk_getu16(fs->endian, a_idxe->idxlen)), fs_name->flags); if (tsk_fs_dir_add(a_fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } incr_entry: /* the theory here is that deleted entries have strlen == 0 and * have been found to have idxlen == 16 * * if the strlen is 0, then guess how much the indexlen was * before it was deleted */ /* 16: size of idxentry before stream * 66: size of fname before name * 2*nlen: size of name (in unicode) */ if (tsk_getu16(fs->endian, a_idxe->strlen) == 0) { a_idxe = (ntfs_idxentry *) ((((uintptr_t) a_idxe + 16 + 66 + 2 * fname->nlen + 3) / 4) * 4); } else { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)); } } /* end of loop of index entries */ tsk_fs_name_free(fs_name); return TSK_OK;}/* * remove the update sequence values that are changed in the last two * bytes of each sector * * return 1 on error and 0 on success */static uint8_tntfs_fix_idxrec(NTFS_INFO * ntfs, ntfs_idxrec * idxrec, uint32_t len){ int i; uint16_t orig_seq; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info; ntfs_upd *upd; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_fix_idxrec: Fixing idxrec: %" PRIu64 " Len: %" PRIu32 "\n", (uint64_t) ((uintptr_t) idxrec), len); /* sanity check so we don't run over in the next loop */ if ((unsigned int) ((tsk_getu16(fs->endian, idxrec->upd_cnt) - 1) * ntfs->ssize_b) > len) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "fix_idxrec: More Update Sequence Entries than idx record size"); return 1; } /* Apply the update sequence structure template */ upd = (ntfs_upd *) ((uintptr_t) idxrec + tsk_getu16(fs->endian, idxrec->upd_off)); /* Get the sequence value that each 16-bit value should be */ orig_seq = tsk_getu16(fs->endian, upd->upd_val); /* cycle through each sector */ for (i = 1; i < tsk_getu16(fs->endian, idxrec->upd_cnt); i++) { /* The offset into the buffer of the value to analyze */ int offset = i * ntfs->ssize_b - 2; uint8_t *new_val, *old_val; /* get the current sequence value */ uint16_t cur_seq =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -