Showing posts with label compile. Show all posts
Showing posts with label compile. Show all posts

Tuesday, April 14, 2009

Compiling Perl Into Binary Code On Linux And Unix. Cool, But...

Hey there,

Since as long back as I can remember, the Perl compiler has always been a vague, yet distant objective. Something that, when I was really into it, wasn't fully supported and didn't work unless you rewrote it yourself (which kind of ran contrary to the reason you were using Perl in the first place: To get complicated tasks taken care of quickly!)

Over the years, I've seen different front-ends come and go (a few of them which looked pretty slick), but I never bothered to check any of them out to a great degree. If I absolutely "had" to write something in "C," then I would. Otherwise, I'd go with Perl. Actually, my coding philosophy is a bit more pliable. Basically, given that I've been monkeying around with Unix and Linux (for pay) for 13 years or so, I tend to go with whatever is easiest, most reliable and most portable depending upon the task at hand. If it can be written in a "find" statement, that's good enough for me. Shell script, Sed and Awk (which usually end up in a Shell script), tcl, tk, expect, Perl, Python, C; whatever is the simplest way to resolve a problem and not kill my machines or compromise security to a great degree; that's what I go with. I see no point in writing a Perl script to open up a file descriptor to read STDIN, parse that and spit out lines containing the word "hi," like in this example:

#!/usr/bin/perl

# perl.pl - A complete waste of time ;)

open(FILE, "<myfile.txt");
@file=<FILE>;
close(FILE);

foreach $x (@file) {
print $x if ( $x =~ /hi/ );
}


host # ./perl.pl
hi there how are you?
Say hi to the mrs. for me


When simply typing (or making this into a one-line shell script):

host # grep hi myfile.txt
hi there how are you?
Say hi to the mrs. for me


will get me the exact same results. Admittedly, my Perl script above was a bit bloated, but the excess goes toward the point I'm making. At least I hope it does ;)

I came across an interesting product (Read: Not Free) called perl2exe that caught my attention since it can compile code for different OS's (derived from your original Perl script) and (after testing), actually works quite well. You can check it out for a free 30 day trial, although you should be aware that all of your generated code will have an advertisement tacked on the end and a 2 second delay. It'll also help you to know (if you want to check it out) that you need to download all the different OS packages (not just the one for the OS on which you're going to install) if you want to use the cross-platform code generation feature. It will compile code for Linux on a Unix box, but you have to download both the Linux and Unix distro gzipp'ed tarballs in order to do this. I'm not sure why. It may be just be another pain-in-the-arse designed to convince you to buy; but I am by no means, and in no way, shape or form, suggesting that you do so. And I'll tell you why...

Although this is one of the nicest packages, for compiling Perl scripts into executable binary code, that I've come across in a while (ease of use, etc) it still fails to address the one "major" flaw of all Perl-To-Binary conversion tools on the market. When you compile your Perl Script, you've lost all the flexibility you began using Perl for in the first place! No more inline editing for you ;)

For instance, a while back, we did a post on getting the year from Solaris' wtmpx file. Taking that Perl script and converting it to binary was a snap, like so:

host # time perl2exe -o rip_wtmpx rip_wtmpx.pl
Perl2Exe V9.100 Copyright (c) 1997-2008 IndigoSTAR Software

This is an evaluation version of Perl2Exe, which may be used for 30 days.
For more information see the attached pxman.htm file,
or visit http://www.indigostar.com

Converting 'rip_wtmpx.pl' to rip_wtmpx

real 0m0.506s
user 0m0.382s
sys 0m0.102s


Done in about a half a second. And, much to my amazement, it worked perfectly:

host # ./rip_wtmpx
PROCESSING WTMPX FILE FOR CROSS-CHECKING: .....
PROCESSED 2393 ENTRIES

root Thu Nov 6 13:42:07 2008
root Thu Nov 6 13:48:00 2008
root Thu Nov 6 13:51:58 2008
root Thu Nov 6 13:54:12 2008
root Thu Nov 6 14:38:20 2008
root Thu Nov 6 14:39:52 2008
root Thu Nov 6 14:39:54 2008
...


Which is the same result I get from running the Perl script directly (The whole point of it was to get the "year" from wtmpx, since the "last" command, and others like it, don't seem to want to give out that information, even though it's in the wtmp/utmp struct and proves very useful if you don't rotate your logs every year like I obviously don't ;)

But, then, you may recall that we followed up that post with a post on how to get the year from lastlog on Linux since Linux's implementation of the wtmp(x) struct had a totally different "pack" template than the one used on Solaris. I was getting around this by coding a mixture of both scripts and having it evaluate the host OS and act accordingly. Even so, for the odd machine (or new OS implementation we rolled out) I'd have to make slight tweaks. And that (although it's a pitiful example, I know ;) is where the whole "convenience" of binary Perl falls apart. Now, everytime I want to make a simple change (in this extremely simple example) I have to update my Perl script, regenerate binary code from it, for all the OS's required, and then redistributed all of that. The alternative, using just Perl, would be to modify the Perl script and redistribute the one version everywhere.

True, in this instance, there doesn't seem to be that much difference (just multiply it by a larger number of machines on your server farm and it gets worse ;), but the "convenience" really makes a difference when you find yourself on a machine that's got some weird kink in it. If you're using a straight-up Perl script, you can just edit it slightly to adjust for however fugged-up that particular box is. You don't have to maintain a separate binary. Odds are, the goof you're compensating for will be fixed the next time you patch or upgrade the OS.

And if security is a concern, you can still avoid this by either implementing effective external security mechanisms (extended facls, role access databases, etc) or figuring out a way to achieve your desired end that doesn't pose a security risk. I don't know if Perl (to this day) actually "recommends" that you ever write any "suid" code (generally speaking, creating a script or binary that will be run as a different user - Set User ID - usually one with elevated system privileges) in Perl script unless you're protecting it by taking additional measures. Generally, if I "have" to write an "suid" program, I'll write it in "C" (like the one in our post on securing suid programs with a simple C wrapper, which doesn't even come close to the protection provided by the one-and-only Wietse Zweitze Venema's mother of all SUID C Wrappers.

Bottom line: It's up to you if you want to implement this sort of functionality. To my way of thinking, short of ensuring you don't get screwed on a work-for-hire at an institution in which you have no trust, there's really no reason to encrypt (I mean convert into binary ;) your Perl script. It's a pretty cool idea, but...

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Tuesday, April 8, 2008

Usage And Compile Help For Linux/Unix Network Port Shell Program

Hey there,

Today's post is a follow up to yesterday's post on running a shell on a network socket. There are a few notes we'd like to add regarding compilation and usage, once you've got the program up and running on your Linux or Unix server.

First, the compile time note. Additional testing on other flavors of Linux showed that neither:

#include <sys/byteorder.h>

nor

#include <sys/endian.h>

worked on all systems :( We did find that this Linux "include" seems to work as a handy substitute for either:

#include <linux/byteorder/generic.h>

Of course, if none of these options work for you, we put comments in the code that name the functions and/or declarations that we're trying to grab from each of the includes. So, if you still find yourself in a pickle after trying all 3 of these include statements, you can probably find the correct include (.h header file) by typing the following at your command prompt:

host # find /usr/include |xargs egrep 'htons|htonl' /dev/null

It may be a bit tricky trying to find the correct include file, but it will probably have a name very similar to the 3 noted above.

Now, on to the fun stuff: Usage :)

To get this out of the way, if you've compiled and used the program to run a Linux or Unix shell on a network socket, you've probably noticed that the input and output don't behave exactly as you would expect in a regular shell.

Note that this line in the code:

execl("/bin/sh","sh",(char *)0);

was originally attempted in the following two manners (to try and force an interactive shell):

execl("/bin/sh","sh","-i",NULL); <--- Socket would connect, but then it would disconnect you immediately
execl("/bin/sh","sh","-i",(char *)0); <--- Socket would connect, and it wouldn't look ugly, but it wouldn't do anything else either (and we made sure it wasn't just an issue with echo by touching some files and verifying that they never got "touched" ;)

When all was said and done, this was the quickest, and dirtiest, way we could get the shell to answer on the network socket and be truly interactive. However, as mentioned above, it doesn't quite behave the way you might assume. Even shell built-in's don't work correctly for the most part, like in this mini-run-through:

host # ls
. .. netsock netsock.c
host # ./netsock
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
: command not found
pwd
: command not found
id
: command not found
echo
: command not found


Yet, strangely enough, "echo," with arguments, works (???):

echo hi
hi


although "eval" doesn't work, straight up:

eval ls
: command not found


Now, we can start to have some fun :) Using the backtick operators to execute an "eval" statement and echoing that, we can actually do something, and get confirmation back on our terminal!:

echo `eval ls`
netsock netsock.c
<--- This will always pump the output out on one line, so if you have a lot of files in your directory, you'll get back a long long line.
echo `eval pwd`
/export/user/bin
echo `eval id`
uid=0(root) gid=0(root) groups=0(root)
<--- This will be your PID if you started the program, which may be good enough if you just need to get in and do something that doesn't require privilege. Note that this program runs the shell on the socket under the UID and GID of the user that invokes it (or their effective UID and GID at that time)
echo `eval touch TOUCHY`
<--- We'll touch something, just to see if it works. Of course, we get no terminal response to indicate success, but that's normal since we don't have a prompt to return to.

Now, if we disconnect from the Telnet connection and do an ls, we should have an extra file waiting for us:

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY


Good deal :) Now we'll write a simple script and see if we can execute it from the shell attached to the network port. If this works, it'll be much easier to stage work for the future:

host # vi test.sh
host # chmod 700 test.sh
host # cat test.sh
mkdir a
cd a
touch file
echo "ALL SET"
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
echo `eval ./test.sh`
ALL SET


And we get the output we expected! Just need to disconnect from Telnet again and check to make sure it actually did everything it was supposed to, and not just run the echo statement.

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY
a
host # ls a
. .. file


Success! Here's hoping this "how to" and compilation-assistance post helps you get more out of this program. If you haven't got the code already, please check out our post on running a shell on a network socket and have a blast!

Just, please, be considerate of others :)

Best wishes,

, Mike