Fwd: Updating PAR executables

[email protected] (Roderich Schupp)
Newsgroups perl.par
Message-ID <CAC9r9zYfoRKxMy4TTpBUoET52Avf8j+MHSpufLAsT9eDKqdjsQ@mail.gmail.com>
On Tue, Mar 14, 2017 at 12:49 PM, Johan Vromans <[email protected]>
wrote:

> I have a perl application that consists of pure perl modules only.


Are you sure that your pure perl modules don't require (directly or
transitively) something platform dependent, e.g. IO.pm (which is an XS
module)?
Check by pp'ing it into foo.exe and look at its contents with "unzip -l
foo.exe".

If that's the case, the following might work (haven't actually tried this).
For reference, see "man par.pl", "Stand-alone executable format".


   1. Get any packed executable (e.g. pp a hello-world one liner) from your
   target platform.
   2. Run the attached script on it (repurposed from
   contrib/extract-embedded/extract-embedded.pl). This will print something
   like

   embedded FILEs start at offset 2119320
   zip starts at offset 3143323
   size of FILEs section is 1024003

   3. Chop off the executable after the start of the zip.
   4. Pack your application into a .par file ("pp -p -o my.par ...")
   5. Append my.par to the executable stub.
   6. Compute the SHA1 of the file so far and append it in hex (40 bytes)
   7. Append "\0CACHE"
   8. Append pack('N', size of FILEs section + size of my.par)
   9. Append "\012PAR.pm\012"
   10. Ta-da, new executable for the target platform

Cheers, Roderich
analyze-pp.pl (application/x-perl, 1.6 KB)
#!/usr/bin/perl 

use File::Spec;
use File::Basename;
use File::Path;
use strict;
use warnings;

@ARGV == 1 || die "usage: $0 executable\n";

{
    my ($exe) = @ARGV;
    open my $fh, '<', $exe or die qq[failed to open "$exe": $!];
    binmode $fh;

    # search for the "\nPAR.pm\n signature backward from the end of the file
    my $buf;
    my $size = -s $exe;
    my $offset = 512;
    my $idx = -1;
    while (1)
    {
        $offset = $size if $offset > $size;
        seek $fh, -$offset, 2 or die qq[seek failed on "$exe": $!];
        my $nread = read $fh, $buf, $offset;
        die qq[read failed on "$exe": $!] unless $nread == $offset;
        $idx = rindex($buf, "\nPAR.pm\n");
        last if $idx >= 0 || $offset == $size || $offset > 128 * 1024;
        $offset *= 2;
    }
    die qq[no PAR signature found in "$exe"] unless $idx >= 0;

    # seek 4 bytes backward from the signature to get the offset of the 
    # first embedded FILE, then seek to it
    $offset -= $idx - 4;
    seek $fh, -$offset, 2;
    read $fh, $buf, 4;
    seek $fh, -$offset - unpack("N", $buf), 2;

    my $FILES_offset = tell $fh;
    printf qq[embedded FILEs start at offset %d\n], $FILES_offset;

    read $fh, $buf, 4;
    while ($buf eq "FILE") 
    {
        read $fh, $buf, 4;
        seek $fh, unpack("N", $buf), 1;

        read $fh, $buf, 4;
        seek $fh, unpack("N", $buf), 1;

        read $fh, $buf, 4;
    }
    die qq[no zip found after FILEs in "$exe"] unless $buf eq "PK\003\004";

    my $ZIP_offset = tell($fh) - 4;
    printf qq[zip starts at offset %d\n], $ZIP_offset;
    printf qq[size of FILEs section is %d\n], $ZIP_offset - $FILES_offset;

    close $fh;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.