📄 ntfs.c
字号:
// figure out the needed offsets cu_blkoffset = a_offset / fs->block_size; if (cu_blkoffset) { cu_blkoffset /= a_fs_attr->nrd.compsize; cu_blkoffset *= a_fs_attr->nrd.compsize; } byteoffset = (size_t) (a_offset - cu_blkoffset * fs->block_size); // cycle through the run until we find where we can start to process the clusters for (data_run_cur = a_fs_attr->nrd.run; (data_run_cur) && (buf_idx < a_len); data_run_cur = data_run_cur->next) { TSK_DADDR_T addr; size_t a; // See if this run contains the starting offset they requested if (data_run_cur->offset + data_run_cur->len < (TSK_DADDR_T) cu_blkoffset) continue; // seek to the start of where we want to read (we may need to read several runs) if (data_run_cur->offset > (TSK_DADDR_T) cu_blkoffset) a = 0; else a = (size_t) (cu_blkoffset - data_run_cur->offset); addr = data_run_cur->addr; // don't increment addr if it is 0 -- sparse if (addr) addr += a; /* cycle through the relevant in the run */ for (; a < data_run_cur->len && buf_idx < a_len; a++) { // queue up the addresses until we get a full unit comp_unit[comp_unit_idx++] = addr; // time to decompress (if queue is full or this is the last block) if ((comp_unit_idx == a_fs_attr->nrd.compsize) || ((a == data_run_cur->len - 1) && (data_run_cur->next == NULL))) { size_t cpylen; // decompress the unit if (ntfs_proc_compunit(ntfs, &comp, comp_unit, comp_unit_idx)) { free(comp_unit); ntfs_uncompress_done(&comp); return -1; } // copy uncompressed data to the output buffer if (comp.uncomp_idx < byteoffset) { // @@ ERROR free(comp_unit); ntfs_uncompress_done(&comp); return -1; } else if (comp.uncomp_idx - byteoffset < a_len - buf_idx) { cpylen = comp.uncomp_idx - byteoffset; } else { cpylen = a_len - buf_idx; } memcpy(&a_buf[buf_idx], &comp.uncomp_buf[byteoffset], cpylen); // reset this in case we need to also read from the next run byteoffset = 0; buf_idx += cpylen; comp_unit_idx = 0; } /* If it is a sparse run, don't increment the addr so that * it remains 0 */ if (((data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) == 0) && ((data_run_cur-> flags & TSK_FS_ATTR_RUN_FLAG_FILLER) == 0)) addr++; } } free(comp_unit); ntfs_uncompress_done(&comp); return (ssize_t) buf_idx; } else { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_file_read_special: called with non-special attribute: %x", a_fs_attr->flags); return -1; }}/* * Process an NTFS attribute sequence and load the data into data * structures. * An attribute sequence is a linked list of the attributes in an MFT entry. * This is called by copy_inode and proc_attrlist. * * @param ntfs File system to analyze * @param fs_file Generic metadata structure to add the attribute info to * @param attrseq Start of the attribute sequence to analyze * @param len Length of the attribute sequence buffer * @returns Error code */static TSK_RETVAL_ENUMntfs_proc_attrseq(NTFS_INFO * ntfs, TSK_FS_FILE * fs_file, ntfs_attr * attrseq, size_t len){ ntfs_attr *attr = attrseq; const TSK_FS_ATTR *fs_attr_attrl = NULL; char name[NTFS_MAXNAMLEN_UTF8 + 1]; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_attrseq: Processing entry %" PRIuINUM "\n", fs_file->meta->addr); if (fs_file->meta->attr == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "Null attribute list in ntfs_proc_attrseq"); return TSK_ERR; } /* Cycle through the list of attributes */ for (; ((uintptr_t) attr >= (uintptr_t) attrseq) && ((uintptr_t) attr <= ((uintptr_t) attrseq + len)) && (tsk_getu32(fs->endian, attr->len) > 0 && (tsk_getu32(fs->endian, attr->type) != 0xffffffff)); attr = (ntfs_attr *) ((uintptr_t) attr + tsk_getu32(fs->endian, attr->len))) { UTF16 *name16; UTF8 *name8; int retVal; uint8_t isDefaultData = 0; /* Get the type of this attribute */ uint32_t type = tsk_getu32(fs->endian, attr->type); /* Copy the name and convert it to UTF8 */ if (attr->nlen) { int i; name8 = (UTF8 *) name; name16 = (UTF16 *) ((uintptr_t) attr + tsk_getu16(fs->endian, attr->name_off)); retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) ((uintptr_t) name16 + attr->nlen * 2), &name8, (UTF8 *) ((uintptr_t) name8 + sizeof(name)), TSKlenientConversion); if (retVal != TSKconversionOK) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_attrseq: Error converting NTFS attribute name to UTF8: %d %" PRIuINUM, retVal, fs_file->meta->addr); *name = '\0'; } /* Make sure it is NULL Terminated */ else if ((uintptr_t) name8 > (uintptr_t) name + sizeof(name)) name[sizeof(name)] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (name[i] != '\0') { if (TSK_IS_CNTRL(name[i])) name[i] = '^'; i++; } } /* Call the unnamed $Data attribute, $Data */ else if (type == NTFS_ATYPE_DATA) { name[0] = '$'; name[1] = 'D'; name[2] = 'a'; name[3] = 't'; name[4] = 'a'; name[5] = '\0'; isDefaultData = 1; // save this so we know later in the loop } else { name[0] = 'N'; name[1] = '/'; name[2] = 'A'; name[3] = '\0'; } /* For resident attributes, we will copy the buffer into * a TSK_FS_ATTR buffer, which is stored in the TSK_FS_META * structure */ if (attr->res == NTFS_MFT_RES) { TSK_FS_ATTR *fs_attr; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_attrseq: Resident Attribute in %" PRIuINUM " Type: %" PRIu32 " Id: %" PRIu16 " Name: %s\n", ntfs->mnum, type, tsk_getu16(fs->endian, attr->id), name); /* Validate the offset lengths */ if (((tsk_getu16(fs->endian, attr->c.r.soff) + (uintptr_t) attr) > ((uintptr_t) attrseq + len)) || ((tsk_getu16(fs->endian, attr->c.r.soff) + tsk_getu32(fs->endian, attr->c.r.ssize) + (uintptr_t) attr) > ((uintptr_t) attrseq + len))) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_CORRUPT; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_attr_walk: Resident attribute %" PRIuINUM "-%" PRIu32 " starting offset and length too large", fs_file->meta->addr, type); return TSK_COR; } // Get a free fs_attr structure if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_RES)) == NULL) { strncat(tsk_errstr2, " - proc_attrseq", TSK_ERRSTR_L - strlen(tsk_errstr2)); return TSK_ERR; } // set the details in the fs_attr structure if (tsk_fs_attr_set_str(fs_file, fs_attr, name, type, tsk_getu16(fs->endian, attr->id), (void *) ((uintptr_t) attr + tsk_getu16(fs->endian, attr->c.r.soff)), tsk_getu32(fs->endian, attr->c.r.ssize))) { strncat(tsk_errstr2, " - proc_attrseq", TSK_ERRSTR_L - strlen(tsk_errstr2)); return TSK_ERR; } // set the meta size if we find the relevant attribute if ((fs_file->meta->type == TSK_FS_META_TYPE_DIR) && (type == NTFS_ATYPE_IDXROOT)) { fs_file->meta->size = tsk_getu32(fs->endian, attr->c.r.ssize); } else if ((fs_file->meta->type == TSK_FS_META_TYPE_REG) && (type == NTFS_ATYPE_DATA) && (isDefaultData)) { fs_file->meta->size = tsk_getu32(fs->endian, attr->c.r.ssize); } } /* For non-resident attributes, we will copy the runlist * to the generic form and then save it in the TSK_FS_META->attr * list */ else { TSK_FS_ATTR *fs_attr; TSK_FS_ATTR_RUN *fs_attr_run; uint8_t data_flag = 0; uint16_t id = tsk_getu16(fs->endian, attr->id); uint32_t compsize = 0; TSK_RETVAL_ENUM retval; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_attrseq: Non-Resident Attribute in %" PRIuINUM " Type: %" PRIu32 " Id: %" PRIu16 " Name: %s Start VCN: %" PRIu64 "\n", ntfs->mnum, type, id, name, tsk_getu64(fs->endian, attr->c.nr.start_vcn)); /* convert the run to generic form */ retval = ntfs_make_data_run(ntfs, tsk_getu64(fs->endian, attr->c.nr.start_vcn), (ntfs_runlist *) ((uintptr_t) attr + tsk_getu16(fs->endian, attr->c.nr.run_off)), &fs_attr_run, NULL); if (retval != TSK_OK) { strncat(tsk_errstr2, " - proc_attrseq", TSK_ERRSTR_L - strlen(tsk_errstr2)); return retval; } /* Determine the flags based on compression and stuff */ data_flag = 0; if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_COMP) { data_flag |= TSK_FS_ATTR_COMP; fs_file->meta->flags |= TSK_FS_META_FLAG_COMP; } if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_ENC) data_flag |= TSK_FS_ATTR_ENC; if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_SPAR) data_flag |= TSK_FS_ATTR_SPARSE; /* SPECIAL CASE * We are in non-res section, so we know this * isn't $STD_INFO and $FNAME * * When we are processing a non-base entry, we may * find an attribute with an id of 0 and it is an * extention of a previous run (i.e. non-zero start VCN) * * We will lookup if we already have such an attribute * and get its ID * * We could also check for a start_vcn if this does * not fix the problem */ if (id == 0) { int cnt, i; // cycle through the attributes cnt = tsk_fs_file_attr_getsize(fs_file); for (i = 0; i < cnt; i++) { const TSK_FS_ATTR *fs_attr2 = tsk_fs_file_attr_get_idx(fs_file, i); if (!fs_attr2) continue; /* We found an attribute with the same name and type */ if ((fs_attr2->type == type) && (strcmp(fs_attr2->name, name) == 0)) { id = fs_attr2->id; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_attrseq: Updating id from 0 to %" PRIu16 "\n", id); break; } } } /* the compression unit size is stored in the header * it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -