Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I need change a string inside a binary file. How can I do that in perl?

Thanks in Advance.

Jes

Replies are listed 'Best First'.
Re: Change Binary File
by Joost (Canon) on Mar 23, 2007 at 15:31 UTC

      Even though binmode is indeed optional on *nix systems, it never hurts to use it anyway - on said systems it's just a no-op, but it makes your program more portable.

      On the other hand, if you're not aiming for portability, well, yeah, you don't need to bother.

Re: Change Binary File
by grinder (Bishop) on Mar 23, 2007 at 16:14 UTC

    If you're talking about a executable file, you probably don't want to change the length of file. That is, you can't replace 'abc' by 'abcde'. Because some of the bytes will be pointers to other parts of the file, and lengthening the file by those extra 'de' bytes in the middle will throw everything out of kilter.

    To be sure that you don't do this, you have two approaches. The main trick is to open the file with '+<', which opens the file for read and write (and doesn't truncate it upon opening). You can either seek to the position you want, and change the contents:

    use strict; use warnings; my $file = shift or die "no file given\n"; my $offset = 12345; open my $fh, '+<', $file or die "Cannot open $file for read/write: $!\ +n"; seek $fh, 0, $offset or die "Cannot seek to $offset in $file: $!\n"; print $fh "blah blah blah" or die "Cannot print to $file: $!\n"; close $fh;

    Or, if you don't know exactly at what offset you need to make the change, you'll have to walk through the file until you find what you are looking for. For instance, in blocks of 32 bytes:

    $/ = \32; my $pos = tell($fh); while( <$fh> ) { if ($_ =~ /something/) { my $cur = tell($fh); seek $fh, 0, $pos or die "Can't seek: $!\n"; print $fh "something else" or die "Can't print: $!\n"; seel $fh, 0, $cur; } $pos = tell($fh) or die "Can't tell: $!\n; }

    In files built up out of variable-length blocks, it may well be that you read a small fixed header, which you decode to determine how much you have to read to pull in the rest of the block. In this case you would wind up setting $/ each time through the loop. This brings back memories of decoding WordPerfect files...

    • another intruder with the mooring in the heart of the Perl

Re: Change Binary File
by ikegami (Patriarch) on Mar 23, 2007 at 16:01 UTC
    It's rarely a question of just substituting one string for another in "binary" files. There are usually offsets and/or size information that needs to be updated as well, depending on the type of file. However, it's usually possible if both strings are of the same length.
      The strings don't have the same size. My OS is WinXP. Thanks
        What kind of file are you trying to edit? If it's an executable (.exe, .dll), you're out of luck.
Re: Change Binary File
by roboticus (Chancellor) on Mar 24, 2007 at 12:43 UTC
    Anonymous Monk:

    Aside from the info you've already received from the other residents of the monastery, here's what I do.

    I used to occasionally have to ship executables with a serial number and licensee name in it. I'd never compile it in, as that would be a nuisance. Also, you never know how many (unintentional) cases of the string appear that you want to change.

    So, what I used to do is to:

    (a) precede the block of strings to patch with a preamble, and

    (b) set each string to a known value, and

    (c) provide plenty of expansion room in strings with variable length.

    So if my fellow brethren will forgive me, here's the kind of code I'd use in C to hold my strings:

    const char z_patchable_start[]="Start of patchable area"; const char serial_number[]="$$serial_number.....$$"; const char licensee[]="$$licensee..............................." "........................................." ".......................................$$"; const char z_patchable_end[]="End of patchable area";
    Then, in my patcher program (written in Perl!), I'd scan for the location of the $$variable_name.$$ strings found between the markers, and then replace them with the appropriate values (not to exceed the boundaries of the $$..$$.).

    Hope this helps...

    --roboticus

Re: Change Binary File
by GrandFather (Saint) on Mar 23, 2007 at 20:56 UTC

    Well, you got good answers to a very open ended and nebulous question. Generally however it helps if you provide a context and very often sample code. For a quick "Can Perl ..." question you will find that the Chatter Box is an excellent resource (you have to register, but PerlMonks doesn't require money to change hands).


    DWIM is Perl's answer to Gödel