Perl2Exe back to Perl – 64-bit (with x64_dbg)

Categories Code, Malware

After posting information on my website about the Perl2Exe reversing article I published before, I got a comment with a question on how to perform the same “trick” on 64-bit Perl2Exe executables. Sadly enough at that time there was no free and easy to use 64-bit debugger available to create a similar approach for 64-bit Perl2Exe executables. However, that has changed with the release of x64_dbg. While I am still looking forward to the 64-bit version of OllyDbg, this new debugger looks very promising and with it I was able to create a fairly simple way of recovering the Perl sourcecode of 64-bit Perl2Exe executables. I decided to create this fairly short write-up about how to do this, which can also be used as a first hands-on with x64_dbg.

For reference, the approach for 32-bit Perl2Exe executables (using OllyDbg) can be found here, which also describes how Perl2Exe works and what the idea is behind the approach that we also follow in this article. These details have been left out of this current article.

Update 15-02-2017: User Julian commented on this article below that the instructions did not work on binaries created with Perl2Exe version 24. Updated instructions for this version can be found at the end of the article.

Test programs / code

I created a short test program to test the approach described in the article. The code of this test program is shown below.

#!/usr/bin/perl

print "\n[*] Perl2exe Perl sourcecode revealer test code - 64bit\n".
      "    by Thijs (Thice) Bosschert\n".
      "    v1.0 04-01-2015\n\n";

# Comment: This is a test comment

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

You can download the 64-bit Perl2Exe test-file here: Example_code_Perl2Exe_v16-x64.exe

This file was created with Perl2Exe v16.00 and Strawberry Perl 5.16.3 for Windows on Windows 7 64-bit.

64 bit approach

Open the Perl2Exe executable in x64_dbg with File –> Open (or press F3).

Go to the Memory Map by clicking the Memory Map tab (or press Alt-M)

Select the .text part of Perl2Exe executable and Right Click + Follow in Disassembler (or press Enter)

Perl2Exe64_follow

Right Click the main window and Search for –> String references (or Right Click, S, S)

Perl2Exe64_StringRef

Search for “RunPerl” string:

Perl2Exe64_Search1

Set breakpoint on the result (press F2)

Perl2Exe64_Search2

Execute the program till it hits the RunPerl breakpoint (Debug –> Run or press F9). You might need to press F9 more than once before it hits our breakpoint.

Perl2Exe64_breakpoint

Go to the Memory Map by clicking the Memory Map tab (or press Alt-M)

Select the .text part of the Perl2Exe dll file (p2x5NNN.dll) and Right Click + Follow in Disassembler (or press Enter)

Perl2Exe64_p2xdll

Right Click the main window and Search for –> String references (or Right Click, S, S)

Search for “P2XDLL” string, Right Click + Follow in Disassembler  (or double click it). We now end up in the follow part of the code, this is the part of the code we will be adjusting.

000000002800E77E | 48 8D 15 63 D1 1B 00     | lea rdx,qword ptr ds:[281CB8E8]         | ;281CB8E8:"P2XDLL/"
000000002800E785 | 48 8B CB                 | mov rcx,rbx                             |
000000002800E788 | FF 15 D2 2E 1A 00        | call qword ptr ds:[<&strstr>]           |
000000002800E78E | 48 3B C3                 | cmp rax,rbx                             |
000000002800E791 | 0F 84 61 02 00 00        | je p2x5163.2800E9F8                     |
000000002800E797 | 48 8D 15 42 D1 1B 00     | lea rdx,qword ptr ds:[281CB8E0]         | ;281CB8E0:"DLL/"
000000002800E79E | 48 8B CB                 | mov rcx,rbx                             |
000000002800E7A1 | FF 15 B9 2E 1A 00        | call qword ptr ds:[<&strstr>]           |
000000002800E7A7 | 48 3B C3                 | cmp rax,rbx                             |
000000002800E7AA | 75 27                    | jnz p2x5163.2800E7D3                    |
000000002800E7AC | 8B 44 24 30              | mov eax,dword ptr ss:[rsp+30]           |
000000002800E7B0 | 44 8B 4C 24 38           | mov r9d,dword ptr ss:[rsp+38]           |
000000002800E7B5 | 44 8B 44 24 34           | mov r8d,dword ptr ss:[rsp+34]           |
000000002800E7BA | 48 8B 15 87 93 1E 00     | mov rdx,qword ptr ds:[281F7B48]         |
000000002800E7C1 | 48 8D 4B 04              | lea rcx,qword ptr ds:[rbx+4]            |
000000002800E7C5 | 89 44 24 20              | mov dword ptr ss:[rsp+20],eax           |
000000002800E7C9 | E8 E2 F7 FF FF           | call p2x5163.2800DFB0                   |
000000002800E7CE | E9 25 02 00 00           | jmp p2x5163.2800E9F8                    |
000000002800E7D3 | 48 8D 15 FE D0 1B 00     | lea rdx,qword ptr ds:[281CB8D8]         | ;281CB8D8:"BUNDLE/"

Same code seen in x64_dbg:

Perl2Exe64_Adjust1

Select the JNZ jump instruction beneath the line containing DLL/ (line 10 in the overview above), this is the jump instruction we are going to remove so that all the files will be dumped to the local disk. Remove the jump instruction by double clicking it and typing NOP (or press Ctrl+9 to NOP it out automatically).

A couple of lines beneath the adjusted JNZ (line 15 in the overview above)we need to remove the “+4” from the LEA command to recover full filenames (else all filenames will be missing the first characters). To adjust this line, double click it, remove the +4 and select Fill with NOP’s:

Perl2Exe64_+4

To make sure the program does not end and remove the files again we will set a breakpoint. Set the breakpoint against removal of the files on the line before the line containing “BUNDLE” (line 18 in the overview above).

The code and screenshot below show the changed lines as well as the Breakpoint.

000000002800E77E | 48 8D 15 63 D1 1B 00     | lea rdx,qword ptr ds:[281CB8E8]         | ;281CB8E8:"P2XDLL/"
000000002800E785 | 48 8B CB                 | mov rcx,rbx                             |
000000002800E788 | FF 15 D2 2E 1A 00        | call qword ptr ds:[<&strstr>]           |
000000002800E78E | 48 3B C3                 | cmp rax,rbx                             |
000000002800E791 | 0F 84 61 02 00 00        | je p2x5163.2800E9F8                     |
000000002800E797 | 48 8D 15 42 D1 1B 00     | lea rdx,qword ptr ds:[281CB8E0]         | ;281CB8E0:"DLL/"
000000002800E79E | 48 8B CB                 | mov rcx,rbx                             |
000000002800E7A1 | FF 15 B9 2E 1A 00        | call qword ptr ds:[<&strstr>]           |
000000002800E7A7 | 48 3B C3                 | cmp rax,rbx                             |
000000002800E7AA | 90                       | nop                                     |
000000002800E7AB | 90                       | nop                                     |
000000002800E7AC | 8B 44 24 30              | mov eax,dword ptr ss:[rsp+30]           |
000000002800E7B0 | 44 8B 4C 24 38           | mov r9d,dword ptr ss:[rsp+38]           |
000000002800E7B5 | 44 8B 44 24 34           | mov r8d,dword ptr ss:[rsp+34]           |
000000002800E7BA | 48 8B 15 87 93 1E 00     | mov rdx,qword ptr ds:[281F7B48]         |
000000002800E7C1 | 48 8D 0B                 | lea rcx,qword ptr ds:[rbx]              |
000000002800E7C4 | 90                       | nop                                     |
000000002800E7C5 | 89 44 24 20              | mov dword ptr ss:[rsp+20],eax           |
000000002800E7C9 | E8 E2 F7 FF FF           | call p2x5163.2800DFB0                   |
000000002800E7CE | E9 25 02 00 00           | jmp p2x5163.2800E9F8                    |
000000002800E7D3 | 48 8D 15 FE D0 1B 00     | lea rdx,qword ptr ds:[281CB8D8]         | ;281CB8D8:"BUNDLE/"

Perl2Exe64_Adjust2

After we adjusted the program we can continue running it. Every time it dumps a file it will hit the breakpoint and halt. At that moment you can see the file it has just droppen in the register values on the right side of the mains screen in x64_dbg:

Perl2Exe64_registers

After we dumped the files we can retrieve the Perl source-code from the temp directory. To find the temp directory we can look at the Log tab in x64_dbg (Alt-L)

Perl2Exe64_Log

The temp directory will in general be present in the temp directory of the current user. When we open the directory we will find the files that were dumped:

Perl2Exe64_dir

And when we open the _main.pl file we got our source code back again:

Perl2Exe64_main
 

Perl2Exe v24

Binaries created with Perl2Exe version 24 seem to differ slightly from the instructions provided on this page.

After searching for the “P2XDLL” string, we end up in a slightly different code. The code to adjust for the v24 version of Perl2Exe is:

The JE-instruction (jump if equal) at location 0x6F2C7597 needs to be NOPped out, as shown below:

All other steps stay the same except in this version there seems to be no need to use the full filename fix, so that part of the tutorial can be skipped.

 

Quick action list

This is a short reminder list to recover the Perl source code of a 64-bit Perl2Exe Executable:

  • Open Perl2Exe executable in x64_dbg (F3)
  • Go to Memory Map (Alt+M)
  • Click on .text part of Perl2Exe executable and press Enter
  • Go to String References window (Right-click, S, S)
  • Search for “RunPerl” string, set breakpoint (F2)
  • Execute till it hits RunPerl breakpoint (F9)
  • Go to Memory Map (Alt+M)
  • Click on .text part of Perl2Exe DLL file and press Enter
  • Go to String References window (Right-click, S, S)
  • Search for “P2XDLL” string, double click it
  • NOP involved JNZ jump (Ctrl+9)
  • Remove the “+4” to recover full file-names
  • Set breakpoint against removal of the files (F2)
  • Continue program (F9)
  • Retrieve Perl source code from temp directory

 

 

3 Comments

  • Nobody
    14/02/2017

    Hi Thijs,

    Thank you for this great tutorial. Although I was able to re-create the file dumps for the example binary you gave, when I tried to do the same with V24 of Per2exe I didn’t get the files. It seems there’s a much smaller series of instructions and I think another call to a dll file, but as I’m not a reverse engineer I was wondering if you could give me some pointers.

    Many thanks in advance.

  • Thice
    14/02/2017

    @Nobody
    Hi, I dropped you an email. If you can send me the file I can take a look at it.

  • Yaric
    09/08/2022

    I have binary for perl2exe v30 and have lost source. Would you like to help to recover it for some $ please?

Leave a Reply

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