【问题标题】:How can I edit a binary file under windows by scripting如何通过脚本在windows下编辑二进制文件
【发布时间】:2015-08-27 11:41:56
【问题描述】:

我通常是一个读者,但这次我找不到答案。 我有一些由科学设备生成的技术文件。 有时,记录的文件会损坏,我们必须手动进行一些十六进制修改。 我想知道如何实现自动化。 我在考虑 Perl,因为我对此有所了解,但即使我设法读取了感兴趣的偏移量,我也不知道如何编写新值。

我有两件事要做:

  1. 在偏移量 4 处写入文件大小减 8
  2. 计算“TRCKfmt”模式的数量,即 5452434B666D74 十六进制值,然后在偏移量 5C (92) 处记下十六进制值。

我尝试在文件句柄上使用sysreadsyswrite,但我无法完成不同的步骤。

也许Perl不是一个好选择,我不知道如何解决。

这是我的实际脚本:

use warnings;
use strict;
use diagnostics;

use Fcntl qw(:seek);

my($fh, $filename, $byte_position, $byte_value);

$filename      = "MYFILE.tac";
$byte_position = 4;
my $filesize = -s $filename;
    print "Size: $filesize\n";


open($fh, "<", $filename)
  || die "can't open $filename: $!";

binmode($fh)
  || die "can't binmode $filename";

sysseek($fh, $byte_position, SEEK_CUR)  # NB: 0-based
  || die "couldn't see to byte $byte_position in $filename: $!";

sysread($fh, $byte_value, 1) == 1
  || die "couldn't read byte from $filename: $!";

printf "read byte with ordinal value %#02x at position %d\n",
     ord($byte_value), $byte_position;

感谢您的帮助。

【问题讨论】:

  • 重新“在偏移量 4 处写入”,为了清楚起见,您想覆盖已经存在的内容吗?
  • @Sinan Ünür,这不是真的。如果他试图覆盖文件的某些部分,他可以在他试图做的时候寻找并打印需要更改的字节。这样做只需要多做一点工作。
  • 是的,&lt; 必须更改为 &lt;+
  • 谢谢大家的回答。确实,我想覆盖实际值。

标签: windows perl scripting hex scientific-software


【解决方案1】:

让自己轻松一点,只需将整个文件加载到内存中。

my $qfn = "MYFILE.tac";

my $file;
{
   open(my $fh, '<:raw', $qfn)
      or die("Can't open \"$qfn\": $!\n");

   local $/;
   $file = <$fh>;
}

{
   my $packed_length = pack('N', length($file) - 8);
   substr($file, 0x0004, length($packed_length), $packed_length);
}

{
   my $num_blocks;
   ++$num_blocks while $file =~ /TRCKfmt/g;
   my $packed_num_blocks = pack('N', $num_blocks);
   substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}

{
   open(my $fh, '>:raw', $qfn)
      or die("Can't create \"$qfn\": $!\n");

   print($fh $file);
}

你没有说数字应该以什么格式存储。我假设它们是大端字节序的 32 位无符号整数。

【讨论】:

  • 所以,我试了一下,它没有按应有的方式工作。该脚本给出了很好的答案,但方向错误。我会截屏来解释hpics.li/e69f97f@ikegami 你对这一点有什么想法吗?
  • 嘿嘿,看来包应该是V而不是N,我会做一些试验,但似乎没关系
【解决方案2】:

让我们创建一个全为 0 字节的文件:

C:\...\> perl -E "binmode STDOUT; say qq{\0} x 32 for 1 .. 4" > test
C:\...\> xxd 测试
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000020: 0a00 0000 0000 0000 0000 0000 0000 0000 ......
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000040: 000a 0000 0000 0000 0000 0000 0000 0000 ......
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ......
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000080: 0000 000a ....

下面的程序从DATA 部分读取偏移量和替换字节。您可能希望将它们放在外部文件中:

#!/usr/bin/env perl

use strict;
use warnings;

use Fcntl qw(:seek);

@ARGV or die "Need filename\n";
my ($file) = @ARGV;

open my $fh, '+<:raw', $file
    or die "Cannot open '$file': $!";

while (my $edit = <DATA>) {
    next unless $edit =~ /\S/;
    my ($offset, $value) = map hex, split ' ', $edit;
    seek $fh, $offset, SEEK_SET
        or die "Failed to seek to '$offset': $!";
    print $fh chr($value)
        or die "Failed to write new byte '$value' at offset '$offset': $!";
}

close $fh
    or die "Failed to close '$file': $!";

__DATA__
0 64
8 65
10 61
18 64
20 62
28 65
30 65
38 66
40 20

运行程序后:

C:\...\> xxd 测试
00000000: 6400 0000 0000 0000 6500 0000 0000 0000 d.......e......
00000010: 6100 0000 0000 0000 6400 0000 0000 0000 a.......d.......
00000020: 6200 0000 0000 0000 6500 0000 0000 0000 b.......e......
00000030: 6500 0000 0000 0000 6600 0000 0000 0000 e.......f......
00000040: 200a 0000 0000 0000 0000 0000 0000 0000 ......
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ......
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ......
00000080: 0000 000a ....

【讨论】:

  • 谢谢,但数据不是恒定的,因此,我需要每次定义值,通过测量文件的大小和模式的出现次数
【解决方案3】:

好的,感谢@ikegami,这是这个答案的回复!

#!c:/Perl64/bin/perl.exe
use warnings;
use strict;
use diagnostics;


my $dir = 'MYDIRECTORY';

opendir DIR, $dir or die "cannot open dir $dir: $!";
my @files = glob "$dir/*.tac";
closedir(DIR);

foreach(@files){
  my $qfn = $_;

my $file;
{
   open(my $fh, '<:raw', $qfn)
      or die("Can't open \"$qfn\": $!\n");

   local $/;
   $file = <$fh>;
}

{
   my $packed_length = pack('V', length($file) - 8);

   substr($file, 0x0004, length($packed_length), $packed_length);
}

{
   my $num_blocks;
   ++$num_blocks while $file =~ /TRCKfmt/g;
   my $packed_num_blocks = pack('V', $num_blocks);
   substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}

{
   open(my $fh, '>:raw', $qfn)
      or die("Can't create \"$qfn\": $!\n");

   print($fh $file);
}
}

谢谢你 Stackoverflow 的家伙,这真的很有帮助

【讨论】:

    猜你喜欢
    • 2011-05-09
    • 2010-12-27
    • 2014-01-22
    • 1970-01-01
    • 2011-01-16
    • 2019-10-22
    • 1970-01-01
    • 2020-03-21
    • 1970-01-01
    相关资源
    最近更新 更多