Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Turn your script into binary without a compiler! :-P

by gmpassos (Priest)
on Jul 24, 2002 at 04:34 UTC ( #184697=snippet: print w/ replies, xml ) Need Help??

Description: Yes! This is what you think! Turn your script in to a binary (.exe) without a compiler! The source was for Win32, but the idea works in any OS, since it's simple K.I.S.S. But don't thinks that this will hide (encrypt) your code, we still can see it inside the binary. Still OPEN SOURCE! ;-P ,see the text below:
When I was modifying my Perl release (named HWXperl), I 
made some changes inside perlmain.c to can use my Perl 
binary (perl.exe), after compile Perl, to create a binary 
for my script without a compiler.

How this works (some C):

Inside perlmain.c i set 2 char:
    char  HWXsize[] = "##[HWXZ]##";
    char  HWXsize2[] = "##[HWXS]##";
And put some perl code inside another char: char HWXrunA[] = 'see the source onde the end...' And tell the perlmain.c to check if the varialbe HWXsize start with '#', if start the perlmain (perl.exe) will run in the normal way (like the standart perl.exe). If not (changed to a number) it will get the number inside the char, open the binary, put the buffer in the point of the char, read from this point and run, with a eval, what was readed. After compile the binary, to add my script the only thing that I have to do is open the binary file (on binmode!), change ##[HWXZ]## to the real size of the binary, and ##[HWXS]## to the size of the script to add:
   $binary =~ s/##\[HWXZ\]##/0000004096/gi ;
   $binary =~ s/##\[HWXS\]##/0000002011/gi ;
NOTE: the sctring with the size need to have the same length of ##[HWXZ]## and ##[HWXS]## (10)! or binary will crash! And after change ##[HWX*]## add my script in the END of the binary! And save the binary data to another .exe, like hello.exe I put 2 variable for the size, 1 for the original size of the binary and the other for the size of the script, to allow extra data. Let's say that you want to add your script and some .pm modules. The 2 vars allow to first read only your main script by the perlmain and the rest can be made by your won script. Please, send your feedback! Graciliano M. P. NOW ABOUT THE SOURCE ;-p perlmain.c This version was for Win32, but you can use the idea for any OS. To use, first make a clean (make clean|dmake clean) on your Perl source, and save it on 'runperl.c', because perlmain.c comes from it, don't forget to check if 'perlmain.c' was deleted! After this compile Perl (make|dmake)
/*
 * perlmain.c [HWX version] - Changed by By Graciliano M. P.
 *
 * This is not the original perlmain.c. This was changed to allow the 
+end
 * user to add their won script in the end of the binary and run it. T
+his is
 * like make a binary without a compiler. Original source at perlmain.
+c.orig
 *
 * See the HWX Tools for use....
 */

#include "EXTERN.h"
#include "perl.h"

#include <string.h>

#ifdef __GNUC__

int _CRT_glob = 0;

#endif

int
main(int argc, char **argv, char **env)
{
    char  HWXmain[300] ;
    char  HWXopt[] = "-e";
    char  HWXsize[] = "##[HWXZ]##";
    char  HWXsize2[] = "##[HWXS]##";
    int   HWXrun=1 ;
    char  *arg0=NULL ;
    char  *arg1=NULL ;
    int   n, i, j ;
    char  HWXrunA[] = "my%HWX_BIN;eval{my%HWX=(z=>'" ;
    char  HWXrunB[] = "',s=>'" ;
    char  HWXrunC[] = "',x=>$^X);if((!-s$HWX{x})||-d$HWX{x}){if($^O=~/
+(msw|win|dos)/i){$HWX{x}.='.exe'}}open(HWX,$HWX{x});binmode(HWX);seek
+(HWX,$HWX{z},0);read(HWX,$_,$HWX{s});close(HWX);%HWX_BIN=%HWX};eval($
+_);if($@){print STDERR$@}" ;

    arg1 = malloc(sizeof(char) * strlen(HWXsize) + 1) ;
    strcpy (arg1, HWXsize);
    if ( arg1[0] == '#' ) { HWXrun = 0 ;}
  
    if (argc > 1 && HWXrun == 1) {
       arg1 = malloc(sizeof(char) * strlen(argv[1]) + 1) ;
       strcpy (arg1, argv[1]);
       if ( arg1[0] == '-' && arg1[1] != '-' ) { HWXrun = 0 ;}
    }
  
    if ( HWXrun == 1 ) {
      sprintf(HWXmain,"%s%s%s%s%s\0",HWXrunA,HWXsize,HWXrunB,HWXsize2,
+HWXrunC);
      
      arg0 = malloc(sizeof(char) * strlen(argv[0]) + 1) ;
      strcpy (arg0, argv[0]);
  
      n = argc ;
      argc = argc + 2 ;
      i = n - 1 ;
      j = 1 ;
    
      while (i > 0) {
        j = i + 2 ;
        argv[j] = argv[i] ;
        i-- ;
      }

      argv[0] = arg0 ;
      argv[1] = HWXopt ;
      argv[2] = HWXmain ;
    }

    return RunPerl(argc, argv, env);
}

perlbin.pl This is to turn your script in binary! Just check the vars for the path to the binary: $perl_bin $miniperl_bin
#!/usr/bin/perl
######################################################################
+#######
## Name:        perlbin.pl
## Purpose:     Add a perl script inside the perl(.exe) binary
## Author:      Graciliano M. P.
## Modified by:
## Created:     11/07/2002
## RCS-ID:      
## Copyright:   (c) 2002 Graciliano M. P.
## Licence:     This program is free software; you can redistribute it
+ and/or
##              modify it under the same terms as Perl itself
######################################################################
+#######
  
########
# HELP #
########

if ($ARGV[0] =~ /^-+h/i ) {
print qq`
______________________________________________________________

Perl to Binary 1.0 [HWX Tool]
______________________________________________________________

  This program will make a binary for your perl script.
  
  OPTIONS:
  
  -d|def*   Use perl.exe. You will need the perl lib in the
            same directory to run.
  -f|full   Use hwxmini.exe. You don't need the per lib
            (perl58.dll) to run.
  
  Use: $> perlbin.pl script.pl newbin.exe
  
  How it works:
  The HWXperl binarys was made to accept extra data to
  the end of the binary file and run it. Perlbin insert
  your script in the end and change a mark (#[HWXZ]#) to
  tell the original size of the file.
  
  * No compilers needed!
  
  * hwxmini.exe was based in the miniperl.exe! This don't have
    all the fatures of perl lib (perl58.dll).
  
  This is a simple, fast and easy solution! :-P

  Copyright (c) 2002 Graciliano M. P.
______________________________________________________________

`;
exit;
}
  
########
# VARS #
########

  my %opts = (
  type => 'def' ,
  ) ;

  $perl_bin      = './perl.exe' ;
  $miniperl_bin  = './miniperl.exe' ;
  $size_mark     = '##[HWXZ]##' ;
  $size_mark2    = '##[HWXS]##' ;
  $overwrite     = 1 ;
  
  my @ARGS = @ARGV ;
  
  foreach my $ARGS_i ( @ARGS ) {
    if ($ARGS_i =~ /^-+(\w+)/) {
      my $opt = $1 ;
      if    ($opt =~ /^(f|full)/i) { $opts{type} = 'full' ;}
      elsif ($opt =~ /^(d|def)/i)  { $opts{type} = 'def' ;}
      shift(@ARGS);
    }
  }
  
  if ($opts{type} eq 'full') { $perl_bin = $miniperl_bin ;}
  
  my ($script_file,$exe_name) = @ARGS ;
  
  print "_____________________________________________________________
+_\n\n" ;
  
  if (! -e $script_file) {
    print "** Can't find script: $script_file\n" ;
    exit;
  }
  
  if ($exe_name !~ /\w/) {
    my ($fl_name) = ( $script_file =~ /(.*)\.[^\.]*$/gs );
    $fl_name .= '.exe' ;
    my $prt = &PROMPT('   Newm binary name?',$fl_name) ;  
    print ">>$prt\n" ;
    while($prt !~ /\w/s ) { $prt = &PROMPT('   Newm binary name?') ;}
    $exe_name = $prt ;
  }
  
  if (-e $exe_name) {
    print "** New binary '$exe_name' already exist!\n\n" ;
    my $prt = &PROMPT('   Continue?','n','y','n') ;
    if ($prt =~ /^n/i) { exit ;}
  }
  
  print "\n   Converting $script_file\n" ;
  print "              to\n" ;
  print "              $exe_name...\n\n" ;
  
#  print "____________________________________________________________
+__\n\n" ;

########
# INIT #
########

  $|=1;

  print "   Opening binary $perl_bin...\n" ;
  open (BINLOG,$perl_bin) ; binmode(BINLOG);
  my $binlog = join '',<BINLOG> ;
  close (BINLOG) ;
  
  $size_mark_re = $size_mark ;
  $size_mark_re =~ s/([^\w=#-])/\\$1/gs ;
  
  $size_mark2_re = $size_mark2 ;
  $size_mark2_re =~ s/([^\w=#-])/\\$1/gs ;
  
  if ($binlog !~ /$size_mark_re/s) {
    print "** The perl binary was not from HWXperl!\n" ;
    exit;
  }
  
  ##########
  # SCRIPT #
  ##########
  
  print "   Loading script $script_file...\n" ;
  
  open (SCRIPTLOG,$script_file) ; binmode(SCRIPTLOG) ;
  my $scriptlog = join '' , <SCRIPTLOG> ;
  close (SCRIPTLOG) ;
  
  ###################
  # INSERT BIN SIZE #
  ###################
  
  my $bin_lng = length($binlog) ;
  my $script_lng = length($scriptlog) ;
  
  print "   Binary original size: $bin_lng bytes.\n" ;
  
  my $size_var = $bin_lng ;
  while(length($size_var) < length($size_mark)) { $size_var = "0$size_
+var" ;}
  
  my $size_var2 = $script_lng ;
  while(length($size_var2) < length($size_mark2)) { $size_var2 = "0$si
+ze_var2" ;}
  
  print "   Inserting binary size...\n" ;
  
  $binlog =~ s/$size_mark_re/$size_var/s ;
  $binlog =~ s/$size_mark2_re/$size_var2/s ;
  
  #######
  # EXE #
  #######
  
  print "   Saving new binary: $exe_name ...\n" ;

  if (-s $exe_name && (! $overwrite) ) {
    print "** Can create new exe!\n" ;
    print "   The file $exe_name already exist!\n" ;
    print "   Remove it first!\n" ;
    exit;
  }
  
  open (EXELOG,">$exe_name") ; binmode(EXELOG);
  print EXELOG $binlog . $scriptlog ;
  close (EXELOG) ;
  
  my $new_size = (stat($exe_name))[7] ;
  print "   New binary size: $new_size bytes\n" ;
  
  print "\nEnjoy! :-P\n" ;
  
  print "_____________________________________________________________
+_\n\n" ;
  

##########
# PROMPT #
##########

sub PROMPT {
  my ( $msg , $def , @opt) = @_ ;
  my $msg_def = "<$def" if $def ne '' ;
  print "$msg $msg_def> " ;
  
  my $res ;
  chop($res = <STDIN>);
  
  if ($def ne '' && $res !~ /\w/s) { return( $def ) ;}
  
  my $opts = ' ' . join (" ", @opt) . ' ' ;
  
  my $res_re = $res ; $res_re =~ s/([^\w=-])/\\$1/gs ;
  
  while($opts !~ / $res_re /si && @opt) {
    print "$msg > " ;
    chop($res = <STDIN>);
    $res_re = $res ; $res_re =~ s/([^\w=-])/\\$1/gs ;
  }
  
  return( $res ) ;
}

#######
# END #
#######


This was made for HWXperl, see it at:
http://hwx.sourceforge.net

http://sourceforge.net/projects/hwx

Comment on Turn your script into binary without a compiler! :-P
Select or Download Code
Does exactly what it says on the tin... Re: Turn your script into binary without a compiler! :-P
by osfameron (Hermit) on Jul 24, 2002 at 07:54 UTC
    Nice idea! But
    After this compile Perl (make|dmake)
    I guess that working out how to compile Perl without a compiler was left as an exercise to the reader? ;->

    Cheerio!
    Osfameron
    http://osfameron.perlmonk.org/chickenman/

Re: Turn your script into binary without a compiler! :-P
by Courage (Parson) on Jul 24, 2002 at 11:15 UTC
    I like your idea. Here are my comments.

    I think recompiling a perl is overkill in your case. I had similar solution, and I suggest you can get a couple ideas from my node: perl scripts executor on Win32

    I think if we'll mix both ideas, we could get much simplier and flexible solution.

    Now improvements that I want to suggest to your idea and code.

    • No need to recalculate size and edit executable to find and replace substring in there. Do it better: append special magic string after your executable, and a script immediately after that. perlbin.pl will search for that string and, if not found, append magic string and script. If found, just replaces script.
    • I don't think you need my @ARGS = @ARGV. Just work directly with @ARGV.
    • just do something like
      open F,"<$^X"; binmode F; my $x = join '',<F>; $x=~s/^.*magicstring//s; eval $x
    • $^O=~/(msw|win|dos)/ is in trouble: Darwin will match it but that's no good. Check it for just 'MSWin32'

    Courage, the Cowardly Dog.

      I made in this way, with string to change inside the 
      binary, because if this string are not changed, starting 
      with #, the binary will work like the normal perl.exe
      
      Since this is made for HWXperl, when I delivery hwxperl I 
      can get any binary of the release and turn into a script! I 
      made this with miniperl.exe too, where you don't need the 
      perllib in the same directory.
      
      I don't understand what you means with 
      "I don't think you need my @ARGS = @ARGV. Just work 
      directly with @ARGV". Are you talking about the 'char argv' 
      on the C code? If is about this, I just made in the most 
      simple and portable way, because some compilers don't deal 
      with argv equally.
      
      about '$^O=~/(msw|win|dos)/', yes is not very pretty, but 
      here, when the binary can't find it self, I will put all 
      the options to fix this in any OS, here are only for Win32.
      I saw one time a vendor with 'MSwin' in the $^O, but I 
      think this is too old. Seeing again the table, I will 
      change this line...
      
          OS            $^O        $Config{'archname'}
          --------------------------------------------
          MS-DOS        dos
          PC-DOS        dos
          OS/2          os2
          Windows 95    MSWin32    MSWin32-x86
          Windows 98    MSWin32    MSWin32-x86
          Windows NT    MSWin32    MSWin32-x86
          Windows NT    MSWin32    MSWin32-ALPHA
          Windows NT    MSWin32    MSWin32-ppc
      
      I will see your code on 'perl scripts executor on Win32'. 
      Thanks for the link, and the reply...
      
      "The creativity is the expression of the liberty".
      

Back to Snippets Section

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: snippet [id://184697]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2014-12-28 11:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (180 votes), past polls