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

Hi, I need to have swap 2 strings in .dll file Can anyone tell me what is wrong with the following code?
#!/usr/local/bin/perl use strict; my $string; my $string_1="This program cannot be run in DOS mode."; my $string_2="somethingelse in the file"; open(ORIG,"<old.dll") || die "Cannot open file! $!"; open(NEW,">new.dll") || die "Cannot creat new file! $!"; binmode ORIG; while(<ORIG>){ $string.= $_; } $string=~s/(.*)($string_1)(.*)($string_2)(.*)/$1$4$3$2$5/g; binmode NEW; print NEW $string; close(ORIG); close(NEW); exit();
[Edited 2001-05-08, ar0n - Moved to SOPW ]

Replies are listed 'Best First'.
(tye)Re: how do I swap 2 strings in a file?
by tye (Sage) on May 08, 2001 at 20:48 UTC

    Executable files are generally not position-independent which means you need to pad your replacement string to be the same length as the original string.

            - tye (but my friends call me "Tye")
Re: how do I swap 2 strings in a file?
by TGI (Parson) on May 08, 2001 at 20:46 UTC

    Definitely check out Death to Dot Star!.

    Since I haven't really worked with binmode, I don't know what gotchas it introduces. You might want to try using the multiline (m) option on your regex.

    Also, a better way to read in your file at one go is:

    #Slurp up ORIG { local $/; $string= <ORIG> }

    This works by undefing the input record separator, which causes any read from the filehandle to get the whole file. BTW, setting $/="" blank lines are the delimiter.


    TGI says moo

(Boo)Re: how do I swap 2 strings in a file?
by boo_radley (Parson) on May 08, 2001 at 20:41 UTC
    This may be a total red herring, but it worked when I debugged command.com to say goofy things, so it's probably got some grain of truth to it.

    In some executables under dos, before a string, will come a byte which describes the length of the string. e.g. before "hello" will be 0x05. If you swap out "this program doesn't do DOS, baby!" for "hello", the dll may think the string is only 5 chars wide -- "this " -- and take "p" to mean 0x70, for a string 112 chars wide, allowing the DLL to mistranslate the remnant of the string, and possibly various other strings, code and whatnot as part of a string that shouldn't exist.

      If I remember correctly, most executables compiled with Pascal will have this length byte at the head of each string.
Re: how do I swap 2 strings in a file?
by cLive ;-) (Prior) on May 08, 2001 at 21:08 UTC
    Add an s modifier (treat as single line) and amend regex to become:
    $string =~s /($string_1)(.*?)($string_2)/$3$2$1/gs;

    Should work, as far as I can see...

    cLive ;-)

Re: how do I swap 2 strings in a file?
by converter (Priest) on May 08, 2001 at 23:03 UTC
    I don't know if this will help or not, but I've noticed that in some segments of some executable binaries, strings are stored in arrays of integers, so that in a hex browser, the string IBM PC-DOS would look like:
    I.B.M.P.C.-.D.O. 49 00 42 00 4d 00 20 00 50 00 43 00 2d 00 44 00 4f 0 +0 S. 53 00
    Your best bet, when you're after replacing text in a file with 8-bit characters, is to use a hex browser to look at the text you want to replace and find out how it's actually stored, not how it's displayed when printed by the program.

    In the above example, you could match "IBM" with:

    /I\x00B\x00M\x00/
    Or match and replace with "BAR" using:
    s[I\x00B\x00M\x00]{B\x00A\x00R\x00};

    P.S. I could have the byte order wrong in the example above, but if your text is stored this way, you'll understand what I'm referring to.

Re: how do I swap 2 strings in a file?
by srawls (Friar) on May 08, 2001 at 21:58 UTC
    Why don't you try this to switch the strings. It doesn't involve a regex, and is easier to follow:
    while(<ORIG>){ if ($_ eq $string_1) {$string .= $string_2; next;} elsif ($_ eq $string_2) {$string .= $string_1; next;} $string.= $_; }


    The 15 year old, freshman programmer,
    Stephen Rawls

      I don't think this will work. This assumes that the string to replace takes up a whole line (or chunk based on whatever you've got $/ set to).

      If the file looks like this:

      1221323asdl;lerTHIS IS
      THE STRING I WANTasdlf
      asdajla;sdfasdfasdfass
      

      nothing will happen.

      That being said, the above technique is a clever way to change (or slightly modified, insert) whole lines in a file.


      TGI says moo

        Ok, agreed. But I'd still like to clean up that regex, so here it goes:
        $string=~s/($string_1)(.*)($string_2)/$3$2$1/msg;
        That should be a bit better than matching the whole string, also I added the /m modifier. I put the /s modifier in too because I thought /msg just looked cool : )

        The 15 year old, freshman programmer,
        Stephen Rawls