从二进制文件中读取十六进制

时间:2014-05-24 13:57:56

标签: c hex extract fread seek

我一直在寻找一个合适的答案,这些答案会给我带来很好的帮助。那一刻,但还找不到一个,但我有一个二进制文件,其中有许多其他文件,这些文件有十六进制引用文件所在的位置。
例如,如果我打开一个十六进制编辑器并在偏移量0x500处查看此二进制文件,则从0x500到0x507将是二进制文件中该特定文件的邮件。然后从0x508到0x50F将是实际的文件大小(或块大小,或块大小或任何你想要调用的大小)然后接下来的32个字节是实际的文件名。
这是C脚本,我知道它的错误,这就是为什么我在这里寻求帮助让我去:p

int main (){

FILE* in = fopen("file", "rb");

        int location[0x08];
        int size[0x08];
        int name[0x20];
        int fileLocation;
        int fileSize;
        int fileName;

        int buffer[0x08];
        int entryCount;

        fseek(in, 0x08, SEEK_SET);
        entryCount = fread(buffer, sizeof(buffer), 1, in);


        for ( int x = 0; x < 25; ++x) {

            fileLocation = fread(location, sizeof(location), 1, in);
            fileSize = fread(size, sizeof(size), 1, in);
            fileName = fread(name, sizeof(name), 1, in);
            // extract data based on references//


    }
}

我在perl中创建了一个很好的脚本,但尝试将其迁移到C并且对我来说有点混乱; 0
任何有关我如何将其迁移到C的帮助将非常有帮助,谢谢你的期待 这是perl中的脚本:

my $fileLocation = '';
my $fileSize     = '';
my $fileName     = '';
my $file         = '';
my $chunk        = '';
my $exit         = '';

seek( $infile, 0x10, 0 ) or die "cannot seek $infile: $!";



until ($exit) {
    read( $infile, $fileLocation, 0x08 );
    read( $infile, $fileSize,     0x08 );
    read( $infile, $fileName,     0x20 );

    if ( $fileLocation =~ 'terminating reference' ) {
        last;
    }

    $fileLocation =~    s/(.)/sprintf("%02x",ord($1))/egs;
    $fileSize =~        s/(.)/sprintf("%02x",ord($1))/egs;
    $fileName =~        s/\0+$//;

    if ( $fileLocation =~ 'terminating reference' ) {
        last;
    }

    open( $file, '>', "extracted/$fileName" ) or die "Cannot open $fileName $!";
    binmode($file);
    sysseek( $infile, hex($fileLocation), 0 );
    sysread( $infile, $chunk, hex($fileSize) );
    syswrite( $file, $chunk );

    $fileLocation = '';
    $fileSize     = '';
};

这将读取8个字节,然后是8个字节,然后是32个字节,然后它将根据变量$ fileLocation,$ fileSize和$ filename一遍又一遍地提取数据,直到我来到终止引用,然后将退出< / p>

2 个答案:

答案 0 :(得分:2)

由于数据以十六进制字符存储在文件中,您(1)需要阅读char s,而不是int s(感谢@ user3121023),( 2)将十六进制转换为整数,然后(3)使用结果值。

此外,fread的返回结果您认为它是什么!它返回读取的字节数,因此您可以检查操作是否成功。

对于终止0,

read_buffer需要是您的最大读取长度(32字节)加上 1.(当然:只有在您想要printf读取数据时才需要但是打印数据是明智的,以确保你做的一切正确。)

char read_buffer[0x21];

for ( int x = 0; x < 25; ++x)
{
     if (fread (read_buffer, 1,8, in) < 8) break;
     read_buffer[8] = 0;
     fileLocation = strtol(read_buffer, NULL, 16);
     printf ("location: %s -> %08Xh\n", read_buffer, fileLocation);

     if (fread (read_buffer, 1,8, in) < 8) break;
     read_buffer[8] = 0;
     fileSize = strtol(read_buffer, NULL, 16);
     printf ("size: %s -> %08Xh\n", read_buffer, fileSize);

     if (fread (read_buffer, 1,0x20, in) < 0x20) break;
     read_buffer[0x20] = 0;
     printf ("name: %s\n", read_buffer);
     // extract data based on references//
}

我省略了将read_buffer复制到name的步骤,因为为此你的name声明太小了。由于您希望name作为C字符串(无论它如何保存在原始文件中),您需要将其声明为至少

char name[21];

答案 1 :(得分:1)

我认为你可以在32位系统上声明你的变量

unsigned long location;
unsigned long size;
unsigned long entry;
char name[0x20];

在64位系统上,您可以使用unsigned int代替unsigned long

然后读取数据

fseek(in, 0x08, SEEK_SET);
entryCount = fread(entry, sizeof(entry), 1, in);
printf ( "entry %lu\n", entry);

for ( int x = 0; x < 25; ++x) {

    fileLocation = fread(&location, sizeof(location), 1, in);
    printf ( "location %lu\n", location);
    fileSize = fread(&size, sizeof(size), 1, in);
    printf ( "size %lu\n", size);
    fileName = fread(name, sizeof(name), 1, in);
    printf ( "name %s\n", name);
    // extract data based on references//
}