Perl2Exe back to Perl – 2014

Categories Code, Malware

Two years ago I published my Perl2Exe back to Perl article in Digital Forensics Magazine, more information can be found in my post here. Since I published this article in a magazine I was not allowed to post it on my own website as well, but since enough time has passed I am now allowed to publish the full article which can be found below.

Reverse engineering Perl2Exe back to Perl

 

Perl2Exe is a program which converts Perl source code to standalone Windows executable files which hide the Perl code. When a forensic investigator encounters a Perl2Exe program (for example malware) it can take a lot of effort to analyse these files. This article describes a new and easy to follow approach to recover the full Perl source code from these Perl2Exe executable files, making the analysis of these files much easier.

Perl2Exe

 

The Perl2Exe program is published by IndigoStar which can be found online at http://www.indigostar.com/. The best way to describe Perl2Exe is the following quote from the IndigoStar website:

Perl2Exe is a command line program for converting Perl scripts to executable files.

This allows you to create stand alone programs in Perl that do not require the Perl interpreter. You can ship the executable files without having to ship your Perl source code.

Source: http://www.indigostar.com/perl2exe.php (17-06-2012)

Perl2Exe converts the source code of the Perl script by packing it inside a single executable together with a Perl interpreter. The Perl source code is included inside the executable in encrypted form and thus it cannot easily be recovered from the executable.

In the past there have been a couple of other projects to retrieve the Perl source code from Perl2Exe executable files (see list at the end of this article). However, none of these projects work with the current versions of Perl and Perl2Exe. In the past couple of years there have been a number of Perl2Exe versions released (see list at the end of this article) and each new version seems to break the previously found solutions to recover the Perl source code.

The two approaches to recover the Perl source code described in this article have been tested successfully against Perl2Exe version v8.82 and higher, up till the latest version at this moment (v11.00). More details on the compatibility with the Perl and Perl2Exe versions can be found further on in this article.

Setup

 

The different Perl versions and Perl2Exe program versions have been tested on multiple Microsoft Windows versions including Windows XP (32-bit) and Microsoft Windows 7 (64-bit) virtual machines as well as live machines. The small and simple test Perl code used for this project is shown below:

#!/usr/bin/perl

print "\n[*] Perl2exe Perl sourcecode revealer test code\n".
"    by Thijs (Thice) Bosschert\n".
"    v1.0 17-06-2012\n\n";

# Comment: This is a test comment

print "\n[*] This is just a test line.\n\n";

 

Creating Perl2Exe executable files is as simple as running the program with the Perl source code file as an argument, for example:

perl2exe.exe Example_code.pl

After running the Perl2Exe program an executable is created from the Perl source code, in this example that executable would be Example_code.exe, and the output of this executable is shown below:

[*] Perl2exe Perl sourcecode revealer test code 
    by Thijs (Thice) Bosschert 
    v1.0 17-06-2012 
[*] This is just a test line.

How a Perl2Exe generated program works

 

The newly created Perl2Exe executable contains the encrypted Perl source code as well as a Perl interpreter. To be able to run the Perl script the Perl2Exe executable needs to launch the Perl interpreter first. A simplified schematic overview of the involved steps is shown in figure 1.

ThB_Perl2Exe_Figure_1

Figure 1 – Overview of Perl2Exe components

To launch the Perl interpreter it is unpacked and stored on the local hard drive by the Perl2Exe executable. The file locations where the Perl interpreter file is stored are shown below:

Windows XP / 2000 / 2003:

%HOMEPATH%\Local Settings\Temp\p2xtmp-####
(C:\Documents and Settings\<username>\Local Settings\Temp\p2xtmp-####)

Windows Vista / 7:

%HOMEPATH%\AppData\Local\Temp\p2xtmp-####\
(C:\Users\<username>\AppData\Local\Temp\p2xtmp-####\)

 

In both file locations the #### part of the directory name is the process ID number the program is running under, which changes each time the Perl2Exe executable is executed. As soon as the Perl2Exe executable finishes running, the temporary directory will be removed again from the system.

The file that the Perl2Exe executable will write to the temporary directory is named p2x####.dll, the #### part of the filename consists out of three or four digits which refer to the Perl version the Perl interpreter uses. For example the file p2x5142.dll is the Perl interpreter for Perl version 5.14.2 and the file p2x588.dll is the Perl interpreter for Perl version 5.8.8.

The Perl interpreter DLLs written to the temporary directory are packed with the UPX packer, however they can easily be unpacked with UPX as well as can be seen below:

C:\UPX\upx307w>upx.exe -d -o c:\p2x5142_u.dll c:\p2x5142.dll 
Ultimate Packer for eXecutables 
Copyright (C) 1996 - 2010 
UPX 3.07w Markus Oberhumer, Laszlo Molnar & John Reiser Sep 08th 2010 
 
File size Ratio Format Name 
-------------------- ------ ----------- ----------- 
937984 <- 437248 46.62% win32/pe p2x5142_u.dll 
 
Unpacked 1 file.

 

After unpacking the DLL file it can be easier analysed with tools such as IDA (http://www.hex-rays.com/products/ida/index.shtml). However that is not the approach we will follow in this article because these DLL files only contain the Perl interpreter and in this case we are interested in the Perl source code.

After storing the Perl interpreter DLL file in the temporary directory the Perl2Exe executable will load it so it can run the Perl script. The Perl script is included in the Perl2Exe executable, but not within the Perl interpreter, the Perl source code is only loaded in to the memory and not written to the local hard drive.

 

Recovering the Perl script source code

Since the Perl script source code is not written to the hard drive we need to find a way to recover it in a different way. Luckily the Perl interpreter contains code to store certain kinds of other files to the local hard drive in the same temporary directory as the Perl interpreter is stored in. We are going to use this feature to our own benefit and let Perl2Exe do the hard work for us. We can adjust the program code of the Perl interpreter with some small changes so that it will also write the Perl source code to the temporary directory. The Perl interpreter checks which kind of files it reads from memory and if these kind of files need to be stored in the temporary directory. We will adjust the flow of this piece of program code so that it will also write the Perl source code to the temporary directory. A very basic schematic overview of the theory behind the changes to the Perl interpreter is shown in figures 2 and 3.

The original flow of a small part of the Perl interpreter:

 

ThB_Perl2Exe_Figure_2

Figure 2 – Original flow of a small part of the Perl interpreter

 

The adjusted flow of a small part of the Perl interpreter:

 

ThB_Perl2Exe_Figure_3

Figure 3 – adjusted flow of a small part of the Perl interpreter

 

In the schematics above the Perl script source code would originally not be written to the temporary directory, but after changing the flow of the program it will be.

The adjustments we are going to make to the code are only meant to retrieve the Perl script source code and not to have the program continue in a normal way. Since we adjust some of the program code it can easily become unstable or give an error later on. However, since we are making changes to a temporary file the changes will be gone as soon as the program ends and the temporary directory is removed again. Note: the approach described in this article executes the Perl program, which in case the executable is malware means that this malware is executed on the local system. Be careful and always analyse unknown files in a controlled lab environment such as a Virtual Machine.

To make the proposed adjustment to the program code of the Perl interpreter we will make use of the debugger OllyDbg (http://www.ollydbg.de/). The first step is to load the Perl2Exe executable in OllyDbg, to do so we start OllyDbg and then use the following menu option to load the Perl2Exe executable file:

File → Open → Choose the Perl2Exe executable you want to analyse

 

 

After the file is loaded we will scroll to the top of the page and then scroll down till we find the string RunPerl, after clicking on this line we will press F2 to set a breakpoint, after doing so the address in front of this line will turn red as can be seen in the screenshot in figure 4.

 ThB_Perl2Exe_Figure_4

Figure 4 – OllyDbg screenshot of RunPerl location

 

The breakpoint we have just set will pause the execution of the Perl2Exe executable at the moment it already has extracted the Perl interpreter to the temporary directory but before this interpreter is started. This allows us to make the adjustment to the Perl interpreter as described earlier. To start the program we are analysing we need to press the play button in the shortcut bar or press the F9 button, both will start the program which will then run and pause at our newly created breakpoint.

After we hit our breakpoint it is time to switch from the Perl2Exe executable to the Perl interpreter. We can easily do this switch within OllyDbg by using the following steps. We need to launch the Executable modules window which we can do by clicking on the light blue square with the E in it on the shortcut bar or by pressing the key combination Alt+E. Within the newly opened window we will see the .exe and .dll files which are loaded by the running program. We will quickly notice that one of these files is the Perl interpreter DLL file which is stored in the temporary directory. This is the file we want to open and we can do this by double clicking it. As soon as this is done we will be looking at the assembly code of the Perl interpreter.

Finding the specific location of the code we want to change can be quite a lot of work, but since this work already has been done by me we will use a simple trick to find this location instead. The trick we will use is to search for a specific unique string which will bring us right to the location where we need to make a small adjustment.

To be able to search for strings in OllyDbg we need to bring up the Text strings window which can easily be done by clicking the right mouse button somewhere inside the main OllyDbg window and select Search for and then select All referenced strings. The screenshot of this action is shown in figure 5.

 ThB_Perl2Exe_Figure_5

Figure 5 – Overview of ‘All referenced strings’ command location

 

The window that is opened shows a lot of text strings in the Perl interpreter file, don’t be alarmed by this, we are only interested in a specific string which we will search for. To open the search window we need to click the right mouse button and select Search for text or press the key combination Ctrl+F.

The string we are going to look for and the code we are going to adjust is different for the Perl2Exe versions 8/9 and 10/11. We will first discuss versions 10 and 11 and then show the difference for versions 8 and 9.

 

Perl2Exe versions 10 and 11

 

When analyzing a Perl2Exe executable which is created with Perl2Exe version 10 or 11 we will use the following steps. In the search window we will search for the string P2XDLL, if the string is not found it is quite likely that the Perl2Exe version used by the executable is version 9 or older and the approach for those versions should be followed. If the string is found the Perl2Exe version is version 10 or higher and when double clicking the P2XDLL string it will return us to the Perl interpreter program code at the location that we are interested in. The part of the code we are interested in is shown in the overview below.

  Address   Hex dump          Command              Comments
  280B29B3    68 9CF80C28     PUSH 280CF89C        ; ASCII "P2XDLL/"
  280B29B8    56              PUSH ESI
  280B29B9    FFD7            CALL EDI
  280B29BB    59              POP ECX
  280B29BC    3BC6            CMP EAX,ESI
  280B29BE    59              POP ECX
  280B29BF    0F84 05010000   JE 280B2ACA
  280B29C5    68 94F80C28     PUSH 280CF894        ; ASCII "DLL/"
  280B29CA    56              PUSH ESI
  280B29CB    FFD7            CALL EDI
  280B29CD    59              POP ECX
  280B29CE    3BC6            CMP EAX,ESI
  280B29D0    59              POP ECX
>>280B29D1    75 29           JNE SHORT 280B29FC
  280B29D3    68 94F80C28     PUSH 280CF894        ; ASCII "DLL/"

The part in the code overview that we want to change is pointed out by the two arrows in front of it, it is the last line before the second line with ASCII “DLL/”. The line contains a jump instruction and this specific jump (JNE, Jump Not Equal) is the location we can change to make sure the Perl source code is going to be saved in the temporary directory. We will remove this jump completely from the code by changing it to NOP (No Operation) instructions, which will do nothing and make sure the code continues after it. To make this change will just need to double click the line with the JNE in it and then change the text in the small pop-up window to NOP, after clicking Assemble we can Close the pop-up. The resulting code after doing this is shown below.

  Address   Hex dump          Command              Comments
  280B29B3    68 9CF80C28     PUSH 280CF89C        ; ASCII "P2XDLL/"
  280B29B8    56              PUSH ESI
  280B29B9    FFD7            CALL EDI
  280B29BB    59              POP ECX
  280B29BC    3BC6            CMP EAX,ESI
  280B29BE    59              POP ECX
  280B29BF    0F84 05010000   JE 280B2ACA
  280B29C5    68 94F80C28     PUSH 280CF894        ; ASCII "DLL/"
  280B29CA    56              PUSH ESI
  280B29CB    FFD7            CALL EDI
  280B29CD    59              POP ECX
  280B29CE    3BC6            CMP EAX,ESI
  280B29D0    59              POP ECX
>>280B29D1    90              NOP
>>280B29D2    90              NOP
  280B29D3    68 94F80C28     PUSH 280CF894        ; ASCII "DLL/"

 

At this moment the program will write all the files it comes across to the temporary directory including the Perl source code we are after. However, after the program finishes the whole temporary directory will be removed again from the system which means we lose all the files again including the Perl source code. To avoid this we will need to set a breakpoint in the program to make sure we can recover the files before the program finishes. We will set the breakpoint in the program right after the creation of the temporary files, the location to do this is shown in the code overview below. To set the breakpoint we need to select this line (the one with ADD ESP, 18) and press the F2 button.

  Address   Hex dump          Command              Comments
>>280B29D1    90              NOP
>>280B29D2    90              NOP
  280B29D3    68 94F80C28     PUSH 280CF894        ; ASCII "DLL/"
  280B29D8    E8 D9520000     CALL      
  280B29DD    FF75 EC         PUSH DWORD PTR SS:[EBP-14]
  280B29E0    03F0            ADD ESI,EAX
  280B29E2    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
  280B29E5    FF75 F4         PUSH DWORD PTR SS:[EBP-0C]
  280B29E8    FF35 04DE0D28   PUSH DWORD PTR DS:[280DDE04]
  280B29EE    56              PUSH ESI
  280B29EF    E8 73FAFFFF     CALL 280B2467
>>280B29F4    83C4 18         ADD ESP,18
  280B29F7    E9 CE000000     JMP 280B2ACA

With this breakpoint set we are now ready to start dumping our files to the temporary directory. To start doing this we will need to continue the program which we still got on pause, this can be done by pressing F9 (or using the play button in the shortcut bar). Because of our breakpoint the program will pause after each file creation, but every time we press the F9 button a new file will be created in the temporary directory. After a couple of F9s we will see that a file with the name n.pl is created, which is the main.pl file which contains the full Perl source code that we are after. Make sure you copy this file from the temporary directory to another location because when the program finishes this directory will be removed again.

Now you got the full Perl source code which should make the analysis of this executable file a lot easier and you probably saved you a lot of time with this quick reverse engineering trick.

 

Perl2Exe versions 8 and 9

When the P2XDLL string from the previous approach cannot be found it is quite likely that the executable was created with an older Perl2Exe version, for example version 8 or 9. In that case we need to follow a couple of different steps to recover the Perl source code. In the search window we will search for the string .pll which we will then double click to return to the program code of the Perl interpreter, this will land us close to the line we need to adjust. The part of the code we are interested in is shown in the overview below, the line we need to adjust is pointed out with the arrows in front of it.

  Address   Hex dump           Command               Comments
  28091A97    68 8C4B0A28      PUSH 280A4B8C         ; ASCII "p2x"
  28091A9C    56               PUSH ESI
  28091A9D    FFD7             CALL EDI
  28091A9F    59               POP ECX
  28091AA0    3BC6             CMP EAX,ESI
  28091AA2    59               POP ECX
>>28091AA3    75 1E            JNE SHORT 28091AC3
  28091AA5    56               PUSH ESI
  28091AA6    E8 674F0000      CALL    
  28091AAB    C70424 844B0A28  MOV DWORD PTR SS      ; ASCII ".dll"
  28091AB2    56               PUSH ESI
  28091AB3    8D5C30 FC        LEA EBX,[ESI+EAX-4]
  28091AB7    FFD7             CALL EDI
  28091AB9    59               POP ECX
  28091ABA    3BC3             CMP EAX,EBX
  28091ABC    59               POP ECX
  28091ABD    0F84 BA010000    JE 28091C7D
  28091AC3    68 844B0A28      PUSH 280A4B84         ; ASCII ".dll"

Because of the flow of the program of this Perl2Exe version we cannot simply remove this jump instruction but we need to change it so that the jump is going to a different destination. The jump destination that we need can be found in the last jump instruction (JNE) before the line containing the ASCII “.pll” string we saw before. The exact location can be found in the program code below.

  Address   Hex dump           Command               Comments
  28091AC3    68 844B0A28      PUSH 280A4B84         ; ASCII ".dll"
  28091AC8    56               PUSH ESI
  28091AC9    FFD7             CALL EDI
  28091ACB    59               POP ECX
  28091ACC    85C0             TEST EAX,EAX
  28091ACE    59               POP ECX
>>28091ACF    0F85 09010000    JNE 28091BDE
  28091AD5    68 7C4B0A28      PUSH 280A4B7C         ; ASCII ".pll"

To change the previous jump to this new destination, we need to double click the JNE jump instruction beneath the ASCII “p2x” string and adjust the jump instruction so that it points to the new location we just identified (the one above theASCII “.pll”line). We will change the jump from a JNE (Jump Not Equal) to a normal JMP (Jump) so that all the files will be dropped by the program including the Perl source code that we are after. Because the assembly instruction for this jump is a different size as the instruction we are changing we need to make sure that the option Keep size in OllyDbg is not selected as can be seen in figure 6.

 ThB_Perl2Exe_Figure_6

Figure 6 – OllyDbg jump adjustment screen

 

After changing the jump we need to set a breakpoint to make sure our dumped Perl source code does not get removed when the whole temporary directory gets removed by the program. The breakpoint for this version is quite simple since it will suffice to put the breakpoint on the instruction we just changed (press F2 to set this breakpoint). The changed code and breakpoint location are shown in the code overview below.

  Address   Hex dump           Command               Comments
  28091A97    68 8C4B0A28      PUSH 280A4B8C         ; ASCII "p2x"
  28091A9C    56               PUSH ESI
  28091A9D    FFD7             CALL EDI
  28091A9F    59               POP ECX
  28091AA0    3BC6             CMP EAX,ESI
  28091AA2    59               POP ECX
>>28091AA3    E9 36010000      JMP 28091BDE
  28091AA8    90               NOP
  28091AA9    90               NOP
  28091AAA    90               NOP
  28091AAB    C70424 844B0A28  MOV DWORD PTR SS      ; ASCII ".dll"

After continuing the program (press F9) the program will start writing the different files to the temporary directory and return to the breakpoint every time it has done so. After a couple of F9 presses the file _main.pl will appear which will contain the full Perl source code that we are after. Once again, make sure to copy this file to a different directory so that you do not lose it when the temporary directory is removed.

 

Conclusion

With a little bit of hands-on reverse engineering we were able to recover the full Perl source code out of a Perl2Exe executable. This Perl source code will make it a lot easier to analyze the file. What is even better is that the Perl source code also includes any comments that might have been included by the author. Before having to use this approach in a running investigation it might make sense to practice a bit in performing the different steps. Executable files which can be used for this can be found on the website in the links section, all of these executable files will be harmless for the system they are used on.

Quick action list

This is a short reminder list to recover the Perl source code:

  • Open Perl2Exe executable in OllyDbg
  • Set breakpoint on RunPerl
  • Run Perl2Exe executable within in OllyDbg
  • Switch to Perl interpreter DLL file
  • Go to Text strings window
  • Search for PX2DLL or .pll depending on the version and double click it
  • Change jump for specific Perl interpreter version
  • Set breakpoints against removal of the files
  • Continue program
  • Retrieve Perl source code from temp directory

Links

Test files

Online test files for different Perl2Exe versions can be found at:

Software

Links to software mentioned in this article:

Past projects

The following projects have been published in the past with the same goals as this article. However none of them work with the current Perl and Perl2Exe versions:

 

Versions

The approaches described in this article have been successfully tested against multiple different Perl2Exe versions, Perl versions and platforms including:

  • Windows 2000, 2003, XP, Vista and 7 (32-bit and 64-bit)
  • Perl2Exe versions 8, 9, 10 and 11
  • Strawberry Perl versions v5.8.8.4 till v5.14.2
  • ActivePerl version 5.12.4.1205
  • IndigoPerl version V9.02

The following Perl2Exe versions have been released over the years:

  • Perl2Exe V11.00, released Mar 10, 2012
  • Perl2Exe V10.40, released Jun 25, 2011
  • Perl2Exe V10.10, released Feb 3, 2011
  • Perl2Exe V9.110, released Dec 7, 2009
  • Perl2Exe V8.82, release Aug 21, 2007

Source: http://www.indigostar.com/perl2exe.php

15 Comments

  • Thice.nl » Post overview
    02/09/2014

    […] rid of the Buma Stemra ransomware malware – Windows 7 Reverse Engineering Perl2Exe back to Perl Perl2Exe back to Perl – 2014 Soon: Perl2Exe back to Perl – […]

  • aedahh
    29/10/2015

    Hello,
    Thanks for posting this very interesting article.
    I was looking for way to decompile a perl exe that I have compiled with IndigoStar Perl2Exe (version unknown) in 2007 and end up here.
    I am stuck at finding the break point: search for P2XDLL or .pll both returned item not found.
    Appreciate if you could provide some additional guidance or I can post my perl exe if needed.

    Thanks in advanced

  • Thice
    18/11/2015

    Please send me the EXE file to check.

  • aedahh
    22/02/2016

    Hello, I was hoping that I will not need to continue with that project, but looks like I will need to do some update for newer OS with this test script.
    I have upload file to Dropbox, url here https://www.dropbox.com/s/d8psz4rel2kof4j/xpPrint3.zip?dl=0
    Thanks

  • Carlos
    21/03/2016

    Hello,

    I tried to follow your instructions which seem fairly straight forward, but I am visually impaired and unfortunately OllyDbg is not fully accessible with my screen reading software. I was wondering if you wouldn’t mind looking at this executable
    http://homeserver.pcanywhere.net:8080/Public/drums.exe
    and extracting the source for me. I would greatly appreciate your assistance.

    Thanks and regards.

  • Carlos
    11/04/2016

    For the record, as you can see here on Softpedia,
    http://www.softpedia.com/get/Multimedia/Audio/Other-AUDIO-Tools/Beats-Me.shtml#download
    the gentleman who wrote this program intended for it to be open source. Unfortunately, he passed away a few years ago
    http://www.webbie.org.uk/Veli-Pekka/accessibility.html
    so the source code is not available. He was a blind programmer and he wrote this MIDI drum machine to be accessible with screen readers for the blind. I thought I would teach myself Perl and take a shot at adding some improvements, but I always learn better from examples than manuals or text books alone.

  • Thice
    11/04/2016

    @Carlos
    Hi Carlos, I will look a bit further in to this file. I quickly recovered the main.pl file, however that did not include the real code of the program as can be seen below:
    —————————————-
    package main; # just the main program instanciating the Windows GUI.
    use strict; use warnings;
    use SeqGUI;
    my $ui = SeqGUI ->new();
    $ui->addTracks();
    $ui->addSteps();
    $ui->addPatternButtons();
    $ui->addSong();
    $ui->addSongButtons();
    $ui->addSlider();
    $ui->addMenus();
    $ui->addHotkeys();
    $ui->run();
    —————————————-

    I will look in to recovering the SeqGUI code.

  • Thice
    11/04/2016

    @aedahh
    The Perl2Exe DLL file in the executable you supplied is p2x586.dll, and in this version the search for .pll will work. I was able to recover the source code of the project by changing the following code:

    CPU Disasm
    Address Hex dump Command Comments
    280935E4 |. 75 1E |JNE SHORT 28093604

    To:

    CPU Disasm
    Address Hex dump Command Comments
    280935E4 /E9 36010000 JMP 2809371F
    280935E9 |90 NOP
    280935EA |90 NOP
    280935EB |90 NOP

    If you follow the tutorial carefully you will be able to do the same.

  • Caarlos
    11/04/2016

    Thanks Thice. I appreciate the assistance.

  • Thice
    12/04/2016

    @Caarlos
    Hi Carlos, check your email 🙂

  • Ben
    11/01/2017

    Thank you! This tutorial has been a lifesaver. I took over a project at work where I have about 150 compiled perl exe’s that need updating. The person that wrote them was let go, but he stored the original source on his laptop that IT has already repurposed. I have recovered the source on about half of them. It appears that somewhere along the way, he switched from perl2exe to perlapp. I have been combing through a disassembler on those exe’s and perl516.dll, assuming that it has the same check to write to a file or be placed in memory, but can’t seem to identify the logic flow. Do you have any tips or by chance know a way to dump the source from an exe compiled in perlapp?

  • Jaime
    09/04/2018

    difficult to find that RunPerl… stuck at that point….

  • Thice
    10/04/2018

    Feel free to send me the file to check it.

  • Arunkumar A
    02/07/2018

    Hi,

    I followed the steps and I was Stuck at finding the “JNE”. I cannot find the “jne” in my exe. What am I missing?. I dont know the perltoexe version. But the dll name is p2x588.dll.

    Awaiting your reply.

  • Thice
    19/07/2018

    Feel free to send me the file to check it.

Leave a Reply

Your email address will not be published. Required fields are marked *