Unpacking PKLITE executables

Recently I came across program that was packed (according to PEiD) by PKLITE32 1.1 (PKWARE Inc.). It is an old version of Keil uVision linker. I have been forced to use Keil 3.60 to manage some code for 8051 CPU. The problem was that the evaluation version of Keil restrict us to create up to 2kB machine code. I needed much more.

Reading the output generated by IDE during compilation I realized that the linker is the problem:

BL51 BANKED LINKER/LOCATER V6.11 - SN: Eval Version
(...)
******************************************************************************
* RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 0CDBH BYTE (160%) *
******************************************************************************

Our linker is BL51.exe. We can open it by some PE editor (e.g. by CFF Explorer Suite) we can see some mysterious sections like .pklstb or .relo2. PEiD claims that it is PKWARE32 packer. I couldn’t find any automatic unpacker for that so we have to do it manually.

We can also determine that sections .text and .data are writeable and sections data is not included into exe file. Probably this sections are packed and stored into another section (.pklstb?). Also entrypoint points into .pklstab code. Let’s try disassembling it by IDA.

.pklstb:0048E000 ; =============== S U B R O U T I N E ===============
.pklstb:0048E000
.pklstb:0048E000
.pklstb:0048E000                 public start
.pklstb:0048E000 start           proc near
.pklstb:0048E000                 push    offset dword_48E080
.pklstb:0048E005                 push    offset sub_49E01E
.pklstb:0048E00A                 push    0
.pklstb:0048E00F                 call    sub_49E01E
.pklstb:0048E014                 jmp     near ptr byte_410AA3
.pklstb:0048E014 start           endp
.pklstb:0048E014
.pklstb:0048E014 ; ---------------------------------------------------

Label dword_48E080 points to some incomprehensible data, byte_410AA3 lays into uninitialized .text section. In sub_49E01E there is some code – consisted with loops and many conditional branches. It must be our unpacking routine.

We can also try to search for string (RESTRICTED VERSION WITH) using strings window (Shift + F12). As we can see – there is no such string.

In this point we have 2 options: we can analyse unpacking function to understand how does it work, or we can just run it and let it unpack itself. I choose option 2 – it is much easier and faster choice.

We have to put breakpoint on jmp instruction (this must be entrypoint into unpacked code). Then we just run debugger and wait. When the breakpoint breaks, all data will be unpacked automagically. If we double click on label byte_410AA3, we can see that there is something in .text section now. If we press c key – assembler code shows up. Now we have to dump unpacked sections (I prefer WinHex – it could edit files already loaded into memory), alter it in original file (you can delete .pklstb) and set entrypoint to point into 10AA3 address (its RVA – address in memory subtracted by base address 0x400000).

Now we can find “RESTRICTED VERSION…” string, change one conditional branch and finally – we can compile code greater than 2kB.

Build target 'Target 1'
linking...
Program Size: data=43.0 xdata=0 code=3688
"bf" - 0 Error(s), 0 Warning(s).

No, I won’t tell you how to crack Keil 🙂