ntfscat now works with attribute names

ntfscat now removes fixup from:
  $MFT/$DATA
  $MFTMirr/$DATA
  anydir/$INDEX_ALLOCATION
edge.strict_endians
flatcap 2005-06-20 14:24:53 +00:00
parent 09936e5c22
commit 0e364b49aa
2 changed files with 157 additions and 29 deletions

View File

@ -32,13 +32,48 @@ is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
.B \-f
.B "\-a " desc
.br
.ns
.TP
.B \-\-force
This will override some sensible defaults, such as not working with a mounted
volume. Use this option with caution.
.B "\-\-attribute " desc
Display the contents of a particular attribute. By default, the unname $DATA
attribute will be shown. The attribute can be specified by number (in decimal
or hexadecimal), or by name.
.TS
lB lB lB
l l l.
Hex Decimal Name
0x10 16 "$STANDARD_INFORMATION",
0x20 32 "$ATTRIBUTE_LIST",
0x30 48 "$FILE_NAME",
0x40 64 "$OBJECT_ID",
0x50 80 "$SECURITY_DESCRIPTOR",
0x60 96 "$VOLUME_NAME",
0x70 112 "$VOLUME_INFORMATION",
0x80 128 "$DATA",
0x90 144 "$INDEX_ROOT",
0xA0 160 "$INDEX_ALLOCATION",
0xB0 176 "$BITMAP",
0xC0 192 "$REPARSE_POINT",
0xD0 208 "$EA_INFORMATION",
0xE0 224 "$EA",
0xF0 240 "$PROPERTY_SET",
0x100 256 "$LOGGED_UTILITY_STREAM",
.TE
.br
.B Notes
.br
The attribute names may be given without the leading $ symbol.
.br
If you use the $ symbol, you must escape it from the shell.
.TP
.B "\-i " num
.br
.ns
.TP
.B "\-\-inode " num
Specify a file by its inode number instead of its name.
.TP
.B \-h
.br
@ -66,7 +101,7 @@ Show the version number, copyright and license
.br
.ns
.TP
.B \-\-vebose
.B \-\-verbose
Display more debug/warning/error messages.
.SH EXAMPLES
Display the contents of a file in the root of an NTFS volume.
@ -79,6 +114,14 @@ Display the contents of a file in a subdirectory of an NTFS volume.
.RS
.sp
.B ntfscat /dev/hda1 /winnt/system32/drivers/etc/hosts
.RE
.sp
Display the contents of the $INDEX_ROOT attribute of the root directory (inode
5).
.RS
.sp
.B ntfscat /dev/hda1 \-a INDEX_ROOT \-i 5 | hexdump \-C
.RE
.SH BUGS
.B ntfscat
was written in a short time, to get something "out there". It needs a lot more work.

View File

@ -1,8 +1,8 @@
/**
* ntfscat - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
* Copyright (c) 2003 Anton Altaparmakov
* Copyright (c) 2003-2005 Richard Russon
* Copyright (c) 2003 Anton Altaparmakov
*
* This utility will concatenate files and print on the standard output.
*
@ -70,7 +70,7 @@ static void version (void)
static void usage (void)
{
Printf ("\nUsage: %s [options] device [file]\n\n"
" -a, --attribute num Display this attribute\n"
" -a, --attribute desc Display this attribute (name or number)\n"
" -i, --inode num Display this inode\n\n"
" -f --force Use less caution\n"
" -h --help Print this help\n"
@ -84,6 +84,60 @@ static void usage (void)
Printf ("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_attribute - Read an attribute name, or number
* @value: String to be parsed
* @attr: Resulting attribute id (on success)
*
* Read a string representing an attribute. It may be a decimal, octal or
* hexadecimal number, or the attribute name in full. The leading $ sign is
* optional.
*
* Return: 1 Success, a valid attribute name or number
* 0 Error, not an attribute name or number
*/
static int parse_attribute (const char *value, ATTR_TYPES *attr)
{
static const char *attr_name[] = {
"$STANDARD_INFORMATION",
"$ATTRIBUTE_LIST",
"$FILE_NAME",
"$OBJECT_ID",
"$SECURITY_DESCRIPTOR",
"$VOLUME_NAME",
"$VOLUME_INFORMATION",
"$DATA",
"$INDEX_ROOT",
"$INDEX_ALLOCATION",
"$BITMAP",
"$REPARSE_POINT",
"$EA_INFORMATION",
"$EA",
"$PROPERTY_SET",
"$LOGGED_UTILITY_STREAM",
NULL
};
int i;
long num;
for (i = 0; attr_name[i]; i++) {
if ((strcmp (value, attr_name[i]) == 0) ||
(strcmp (value, attr_name[i]+1) == 0)) {
*attr = (ATTR_TYPES) ((i+1)*16);
return 1;
}
}
num = strtol (value, NULL, 0);
if ((num > 0) && (num < 257)) {
*attr = (ATTR_TYPES) num;
return 1;
}
return 0;
}
/**
* parse_options - Read and validate the programs command line
*
@ -113,7 +167,7 @@ static int parse_options (int argc, char **argv)
int err = 0;
int ver = 0;
int help = 0;
s64 attr;
ATTR_TYPES attr = AT_UNUSED;
opterr = 0; /* We'll handle the errors, thank you. */
@ -133,16 +187,16 @@ static int parse_options (int argc, char **argv)
}
break;
case 'a':
if (opts.attr != (ATTR_TYPES)-1)
if (opts.attr != (ATTR_TYPES)-1) {
Eprintf("You must specify exactly one attribute.\n");
else if (utils_parse_size(optarg, &attr, FALSE)) {
opts.attr = (ATTR_TYPES)attr;
} else if (parse_attribute (optarg, &attr) > 0) {
opts.attr = attr;
break;
} else
Eprintf("Couldn't parse attribute number.\n");
} else {
Eprintf("Couldn't parse attribute.\n");
}
err++;
break;
case 'f':
opts.force++;
break;
@ -207,19 +261,42 @@ static int parse_options (int argc, char **argv)
return (!err && !help && !ver);
}
/**
* index_get_size - Find the INDX block size from the index root
* @inode: Inode of the directory to be checked
*
* Find the size of a directory's INDX block from the INDEX_ROOT attribute.
*
* Return: n Success, the INDX blocks are n bytes in size
* 0 Error, not a directory
*/
static int index_get_size (ntfs_inode *inode)
{
ATTR_RECORD *attr90;
INDEX_ROOT *iroot;
attr90 = find_first_attribute (AT_INDEX_ROOT, inode->mrec);
if (!attr90)
return 0; // not a directory
iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->value_offset));
return iroot->index_block_size;
}
/**
* cat
*/
static int cat (ntfs_volume *vol __attribute__((unused)), ntfs_inode *inode,
ATTR_TYPES type, ntfschar *name __attribute__((unused)),
static int cat (ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
ntfschar *name __attribute__((unused)),
int namelen __attribute__((unused)))
{
/* increase 1024 only if you fix partial writes below */
const int bufsize = 1024;
const int bufsize = 4096;
char *buffer;
ntfs_attr *attr;
s64 bytes_read, written;
s64 offset;
u32 block_size;
buffer = malloc (bufsize);
if (!buffer)
@ -227,14 +304,28 @@ static int cat (ntfs_volume *vol __attribute__((unused)), ntfs_inode *inode,
attr = ntfs_attr_open (inode, type, NULL, 0);
if (!attr) {
Eprintf ("Cannot cat a directory.\n");
Eprintf ("Cannot find attribute type 0x%lx.\n", (long) type);
free (buffer);
return 1;
}
if ((inode->mft_no < 2) && (attr->type == AT_DATA))
block_size = vol->mft_record_size;
else if (attr->type == AT_INDEX_ALLOCATION)
block_size = index_get_size (inode);
else
block_size = 0;
offset = 0;
for (;;) {
bytes_read = ntfs_attr_pread (attr, offset, bufsize, buffer);
if (block_size > 0) {
// These types have fixup
bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
bytes_read *= block_size;
} else {
bytes_read = ntfs_attr_pread (attr, offset, bufsize, buffer);
}
//fprintf (stderr, "read %lld bytes\n", bytes_read);
if (bytes_read == -1) {
perror ("ERROR: Couldn't read file");
break;
@ -275,8 +366,6 @@ int main (int argc, char *argv[])
utils_set_locale();
//XXX quieten errors, temporarily
vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force);
if (!vol) {
perror("ERROR: couldn't mount volume");
@ -301,12 +390,8 @@ int main (int argc, char *argv[])
ntfs_inode_close (inode);
ntfs_umount (vol, FALSE);
#if 0
if (result)
Printf ("failed\n");
else
Printf ("success\n");
#endif
return result;
}