【问题标题】:Can you use sed or perl -pe to remove a part from a binary file?您可以使用 sed 或 perl -pe 从二进制文件中删除一部分吗?
【发布时间】:2011-09-23 01:05:27
【问题描述】:

我正在尝试从二进制文件中删除 ANSI 字符串“stringstart”和“stringend”之间的部分。是否可以使用 sed 或 perl -pe 来做到这一点?

我正在考虑一些正则表达式解决方案,但我不知道如何编写它,也不知道正则表达式如何与二进制文件配合使用。

【问题讨论】:

    标签: regex perl sed replace


    【解决方案1】:

    您可以执行一个正则表达式来删除 [] 内的 ^ 之后未定义的所有字符。例如

    cp /bin/ls ./binfile
    file binfile
    binfile: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
    

    在上面做 perl 馅饼:

    perl -pi -e 's/[^[a-zA-Z0-9_+\n]//g' binfile
    

    然后再看二进制文件:

    file binfile
    binfile: ASCII text, with very long lines
    

    您显然必须在该命令中添加更多内容,因为它会删除其他几个可能是有效的字符。但这应该可以帮助您入门。

    【讨论】:

    • 我认为它会杀死很多东西。我希望文件的内容保持不变,除了两个 ANSI 字符串之间的那部分。
    【解决方案2】:

    sed 是为处理文本文件而不是二进制文件而设计的,尽管这些天来,这种区别通常不如以前那么重要。最大的问题是文本文件不包含零字节(值为 0 的字节)而二进制文件包含,并且许多 C 字符串处理函数在第一个零字节处停止。 sed 还读取由换行符标记的“行”。结果,二进制文件可能会以长行结束。最后,不能保证字符串开始和结束标记相对于换行符的相对位置。所有这些特征使得sed 不如 Perl 更适合这项工作。

    在 Perl 中,我非常想将文件放入内存中,使用适当的正则表达式从内存映像中删除数据,然后将结果写回适当的位置。

    perl -e 'local($/); $data = <>; $data =~ s/stringstart(.*?)stringend//gms; print $data'
    

    现已测试 - 使用以下方法创建的测试数据:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    sub full_set
    {
        foreach my $i (0..255) { printf "%c", $i; }
    }
    sub random_set
    {
        my($n) = @_;
        foreach my $i (0..$n) { printf "%c", int(rand(255)); }
    }
    
    full_set;
    random_set(1024);
    printf("stringstart");
    full_set;
    random_set(512);
    full_set;
    printf("stringend");
    random_set(256);
    

    脚本从输入中删除 1045 个字符 - 对应于 'stringstart', 'stringend' (20) + 2 * 256 + 513(因为 random_set(512) 打印 513 个字符)。

    请注意,主脚本会一次将所有文件读入内存。如果您希望它一次处理一个文件,则必须更加努力;它可能不再是单线了。

    【讨论】:

    • @Jonathan,我想你可能想在你的正则表达式中使用惰性版本.*?。否则它只会执行一次替换,从第一个 stringstart 到最后一个 stringend。如果只有一对 start/end 预期,那么正则表达式当然没问题——那么你可以删除 g 修饰符。
    • zero bytes 是指空字节吗?
    • @vol7ron;是的 - 我的意思是值为 0 的字节,又名 NUL,又名 U+0000,可能又名空字节。
    • 那么这段代码是否适用于多个起始端对?在我的代码中,会有不止一个开始-结束对。
    • @Jonathan:明白了,让我想起了过去的 CGI 时代,在 \0 上解析参数 :)
    【解决方案3】:

    另一种方法:

    perl -pi -we'BEGIN{$/="stringend"} chomp and s/stringstart.*//s' your_binary_file
    

    【讨论】:

    • 完美;为什么让它变得比必须的更困难? :) 在开始块中设置输入记录分隔符。对带有隐式打印 $_ 的隐式循环使用 -p 开关。去掉输入记录分隔符。用“stringend”输入记录分隔符终止记录中的开始标记以及它之后的任何内容。完毕。我一直在考虑触发器运算符,但你的更重要。
    猜你喜欢
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 2021-12-12
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 2023-03-21
    相关资源
    最近更新 更多