📄 ntfs.c
字号:
a_mft->upd_cnt) - 1) * a_ntfs->ssize_b) > a_ntfs->mft_rsize_b)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "dinode_lookup: More Update Sequence Entries than MFT size"); return TSK_COR; } if (tsk_getu16(fs->endian, a_mft->upd_off) > a_ntfs->mft_rsize_b) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "dinode_lookup: Update sequence offset larger than MFT size"); return TSK_COR; } /* Apply the update sequence structure template */ upd = (ntfs_upd *) ((uintptr_t) a_mft + tsk_getu16(fs->endian, a_mft->upd_off)); /* Get the sequence value that each 16-bit value should be */ sig_seq = tsk_getu16(fs->endian, upd->upd_val); /* cycle through each sector */ for (i = 1; i < tsk_getu16(fs->endian, a_mft->upd_cnt); i++) { uint8_t *new_val, *old_val; /* The offset into the buffer of the value to analyze */ size_t offset = i * a_ntfs->ssize_b - 2; /* get the current sequence value */ uint16_t cur_seq = tsk_getu16(fs->endian, (uintptr_t) a_mft + offset); if (cur_seq != sig_seq) { /* get the replacement value */ uint16_t cur_repl = tsk_getu16(fs->endian, &upd->upd_seq + (i - 1) * 2); tsk_error_reset(); tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, "Incorrect update sequence value in MFT entry\nSignature Value: 0x%" PRIx16 " Actual Value: 0x%" PRIx16 " Replacement Value: 0x%" PRIx16 "\nThis is typically because of a corrupted entry", sig_seq, cur_seq, cur_repl); return TSK_COR; } new_val = &upd->upd_seq + (i - 1) * 2; old_val = (uint8_t *) ((uintptr_t) a_mft + offset); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dinode_lookup: upd_seq %i Replacing: %.4" PRIx16 " With: %.4" PRIx16 "\n", i, tsk_getu16(fs->endian, old_val), tsk_getu16(fs->endian, new_val)); *old_val++ = *new_val++; *old_val = *new_val; } return TSK_OK;}/* * given a cluster, return the allocation status or * -1 if an error occurs */static intis_clustalloc(NTFS_INFO * ntfs, TSK_DADDR_T addr){ int bits_p_clust, b; TSK_DADDR_T base; bits_p_clust = 8 * ntfs->fs_info.block_size; /* While we are loading the MFT, assume that everything * is allocated. This should only be needed when we are * dealing with an attribute list ... */ if (ntfs->loading_the_MFT == 1) { return 1; } else if (ntfs->bmap == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "is_clustalloc: Bitmap pointer is null: %" PRIuDADDR "\n", addr); return -1; } /* Is the cluster too big? */ if (addr > ntfs->fs_info.last_block) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "is_clustalloc: cluster too large"); return -1; } /* identify the base cluster in the bitmap file */ base = addr / bits_p_clust; b = (int) (addr % bits_p_clust); /* is this the same as in the cached buffer? */ if (base != ntfs->bmap_buf_off) { TSK_DADDR_T c = base; TSK_FS_ATTR_RUN *run; TSK_DADDR_T fsaddr = 0; ssize_t cnt; /* get the file system address of the bitmap cluster */ for (run = ntfs->bmap; run; run = run->next) { if (run->len <= c) { c -= run->len; } else { fsaddr = run->addr + c; break; } } if (fsaddr == 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "is_clustalloc: cluster not found in bitmap: %" PRIuDADDR "", c); return -1; } if (fsaddr > ntfs->fs_info.last_block) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "is_clustalloc: Cluster in bitmap too large for image: %" PRIuDADDR, fsaddr); return -1; } ntfs->bmap_buf_off = base; cnt = tsk_fs_read_block (&ntfs->fs_info, fsaddr, ntfs->bmap_buf, ntfs->fs_info.block_size); if (cnt != ntfs->fs_info.block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, "is_clustalloc: Error reading bitmap at %" PRIuDADDR, fsaddr); return -1; } } /* identify if the cluster is allocated or not */ return (isset(ntfs->bmap_buf, b)) ? 1 : 0;}/********************************************************************** * * TSK_FS_ATTR functions * **********************************************************************//** * Process a non-resident runlist and convert its contents into the generic fs_attr_run * structure. * @param ntfs File system that attribute is located in. * @param start_vcn The starting VCN for this run. * @param runlist The raw runlist data from the MFT entry. * @param a_data_run_head [out] Pointer to pointer of run that is created. (NULL on error and for $BadClust - special case because it is a sparse file for the entire FS). * @param totlen [out] Pointer to location where total length of run (in bytes) can be returned (or NULL) * * @returns Return status of error, corrupt, or OK (note a_data_run can be NULL even when OK is returned if $BadClust is encountered) */static TSK_RETVAL_ENUMntfs_make_data_run(NTFS_INFO * ntfs, TSK_OFF_T start_vcn, ntfs_runlist * runlist_head, TSK_FS_ATTR_RUN ** a_data_run_head, TSK_OFF_T * totlen){ TSK_FS_INFO *fs = (TSK_FS_INFO *) ntfs; ntfs_runlist *run; TSK_FS_ATTR_RUN *data_run, *data_run_prev = NULL; unsigned int i, idx; TSK_DADDR_T prev_addr = 0; TSK_OFF_T file_offset = start_vcn; run = runlist_head; *a_data_run_head = NULL; /* initialize if non-NULL */ if (totlen) *totlen = 0; /* Cycle through each run in the runlist * We go until we find an entry with no length * An entry with offset of 0 is for a sparse run */ while (NTFS_RUNL_LENSZ(run) != 0) { int64_t addr_offset = 0; /* allocate a new tsk_fs_attr_run */ if ((data_run = tsk_fs_attr_run_alloc()) == NULL) { tsk_fs_attr_run_free(*a_data_run_head); *a_data_run_head = NULL; return TSK_ERR; } /* make the list, unless its the first pass & then we set the head */ if (data_run_prev) data_run_prev->next = data_run; else *a_data_run_head = data_run; data_run_prev = data_run; /* These fields are a variable number of bytes long * these for loops are the equivalent of the getuX macros */ idx = 0; /* Get the length of this run */ for (i = 0, data_run->len = 0; i < NTFS_RUNL_LENSZ(run); i++) { data_run->len |= (run->buf[idx++] << (i * 8)); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_make_data_run: Len idx: %i cur: %" PRIu8 " (%" PRIx8 ") tot: %" PRIuDADDR " (%" PRIxDADDR ")\n", i, run->buf[idx - 1], run->buf[idx - 1], data_run->len, data_run->len); } /* Sanity check on length */ if (data_run->len > fs->block_count) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_make_run: Run length is larger than file system"); tsk_fs_attr_run_free(*a_data_run_head); *a_data_run_head = NULL; return TSK_COR; } data_run->offset = file_offset; file_offset += data_run->len; /* Update the length if we were passed a value */ if (totlen) *totlen += (data_run->len * ntfs->csize_b); /* Get the address of this run */ for (i = 0, data_run->addr = 0; i < NTFS_RUNL_OFFSZ(run); i++) { //data_run->addr |= (run->buf[idx++] << (i * 8)); addr_offset |= (run->buf[idx++] << (i * 8)); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_make_data_run: Off idx: %i cur: %" PRIu8 " (%" PRIx8 ") tot: %" PRIuDADDR " (%" PRIxDADDR ")\n", i, run->buf[idx - 1], run->buf[idx - 1], addr_offset, addr_offset); } /* addr_offset value is signed so extend it to 64-bits */ if ((int8_t) run->buf[idx - 1] < 0) { for (; i < sizeof(addr_offset); i++) addr_offset |= (int64_t) ((int64_t) 0xff << (i * 8)); } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_make_data_run: Signed addr_offset: %" PRIdDADDR " Previous address: %" PRIdDADDR "\n", addr_offset, prev_addr); /* The NT 4.0 version of NTFS uses an offset of -1 to represent * a hole, so add the sparse flag and make it look like the 2K * version with a offset of 0 * * A user reported an issue where the $Bad file started with * its offset as -1 and it was not NT (maybe a conversion) * Change the check now to not limit to NT, but make sure * that it is the first run */ if (((addr_offset == -1) && (prev_addr == 0)) || ((addr_offset == -1) && (ntfs->ver == NTFS_VINFO_NT))) { data_run->flags |= TSK_FS_ATTR_RUN_FLAG_SPARSE; data_run->addr = 0; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_make_data_run: Sparse Run\n"); } /* A Sparse file has a run with an offset of 0 * there is a special case though of the BOOT MFT entry which * is the super block and has a legit offset of 0. * * The value given is a delta of the previous offset, so add * them for non-sparse files * * For sparse files the next run will have its offset relative * to the current "prev_addr" so skip that code */ else if ((addr_offset) || (ntfs->mnum == NTFS_MFT_BOOT)) { data_run->addr = prev_addr + addr_offset; prev_addr = data_run->addr; /* Sanity check on length and offset */ if (data_run->addr + data_run->len > fs->block_count) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_make_run: Run offset and length is larger than file system"); tsk_fs_attr_run_free(*a_data_run_head); *a_data_run_head = NULL; return TSK_COR; } } else { data_run->flags |= TSK_FS_ATTR_RUN_FLAG_SPARSE; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_make_data_run: Sparse Run\n"); } /* Advance run */ run = (ntfs_runlist *) ((uintptr_t) run + (1 + NTFS_RUNL_LENSZ(run) + NTFS_RUNL_OFFSZ(run))); } /* special case for $BADCLUST, which is a sparse file whose size is * the entire file system. * * If there is only one run entry and it is sparse, then there are no * bad blocks, so get rid of it. */ if ((*a_data_run_head != NULL) && ((*a_data_run_head)->next == NULL) && ((*a_data_run_head)->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) && ((*a_data_run_head)->len == fs->last_block + 1)) { tsk_fs_attr_run_free(*a_data_run_head); *a_data_run_head = NULL; } return TSK_OK;}/*********** UNCOMPRESSION CODE *************//* * NTFS Breaks compressed data into compression units, which are * typically 16 clusters in size. If the data in the comp unit * compresses to something smaller than 16 clusters then the * compresed data is stored and the rest of the compression unit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -