; Name:		dePE-PROT
; Version:	1.0
; Author:	Unknown One/[TMG]
; Target:	PE-PROT 0.9 beta encrypted files
; Music:	Shots from AK-47
; Cheers to:	CHRiS ;)

; Description:
; This is pure ungeneric decryptor for files protected with PE-PROT 0.9 beta by
; CHRiSTOPH GABLER (hiho, Kriz! :). There is another decryptor written by Lorian/uCF
; but it is not compatible with WinNT/2k so I wrote that to help me analize one more
; protector while I am too far away from real life. Full win32 assembler source code
; is included.

        .586p
        .model  flat,stdcall
        locals
        jumps


UNICODE =       0
        include w32.inc                 ; Very usefull include file

.data

ofn_struc       OPENFILENAME    <>
ofn_filter      db      'Executable file',00h,'*.exe',00h,00h
ofn_title       db      'Select file to unpack',00h
f_name          db      200h dup(?)
f_handle        dd      ?
f_size          dd      ?
read_len        dd      ?
write_len       dd      ?

outfname        db      'out.exe',00h

buffer          dd      ?

pe_header_ptr   dd      ?
sections_start  dd      ?
entry_addr      dd      ?
image_base      dd      ?
section_size    dd      ?


; Messages
error_caption   db      'Error!',00h
cant_open_err   db      'Cannot open input file!',00h
no_mem_err      db      'Cannot allocate memory!',00h
not_mz_err      db      'Not valid EXE file (''MZ'' signature does not present)!',00h
not_pe_err      db      'Not valid PE file (''PE'' signature does not present)!',00h
import_err      db      'Cannot rebuild import section (not found)!',00h
success_msg     db      'File successfully unpacked!',00h


magic_1		dw	?		; Used by PE-PROT decryptor

.code

start   proc
; Prepare the OpenFileName structure and get file name
        mov     ofn_struc.on_lStructSize,OPENFILENAME_
        mov     ofn_struc.on_lpstrFilter,offset ofn_filter
        mov     ofn_struc.on_lpstrFile,offset f_name
        mov     ofn_struc.on_lpstrTitle,offset ofn_title
        mov     ofn_struc.on_nMaxFile,0200h
        mov     ofn_struc.on_Flags,OFN_FILEMUSTEXIST or \
                                   OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                                   OFN_EXPLORER or OFN_HIDEREADONLY
        call    GetOpenFileNameA, offset ofn_struc
        or      eax,eax                 ; Nothing selected?
        jz      exit                    ; If so - exit

        call    CreateFileA, offset f_name, GENERIC_READ+GENERIC_WRITE,\
                             NULL,NULL,\
                             OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
        cmp     eax,INVALID_HANDLE_VALUE
        jne     open_ok

        call    MessageBoxA, NULL, offset cant_open_err, offset error_caption, NULL
        jmp     exit

;------ File is opened OK
open_ok:
        mov     f_handle,eax

;------ Load file in memory
        call    GetFileSize, f_handle, 00h
        mov     f_size,eax

        call    GlobalAlloc, GMEM_FIXED, f_size ; Allocate memory
        or      eax,eax
        jnz     mem_alloc_ok

	call	CloseHandle, f_handle
        call    MessageBoxA, NULL, offset no_mem_err, offset error_caption, NULL
        jmp     exit

;------ Memory allocated OK
mem_alloc_ok:
        mov     buffer,eax

        call    ReadFile, f_handle, buffer, f_size, offset read_len, NULL

	call	CloseHandle, f_handle

;------ Check for valid EXE file
check_valid_exe:
        mov     edx,buffer              ; EDI points to read buffer
        cmp     word ptr [edx],'MZ'
        jz      exe_ok
        cmp     word ptr [edx],'ZM'
        jz      exe_ok

        call    MessageBoxA, NULL, offset not_mz_err, offset error_caption, NULL
        jmp     free_mem_exit

exe_ok:
;------ Check for valid PE file
        add     edx,dword ptr [edx+003ch]       ; EDX -> PE header
        cmp     word ptr [edx],'EP'             ; PE file?
        jz      pe_ok

        call    MessageBoxA, NULL, offset not_pe_err, offset error_caption, NULL
        jmp     free_mem_exit

pe_ok:
        mov     pe_header_ptr,edx

        mov     eax,dword ptr [edx+0034h]       ; Get image base and save it for later use
        mov     image_base,eax                  ;

;###### UNPACKING START ##############################################

        .radix  16d                             ; Too many hex values

unpack_one_layer:
        mov     eax,dword ptr [edx+0028h]       ; EAX points to entry point of program
        call    rva2fo
	or	eax,eax
	jz	write_file

;------ Layer 1
	mov	ebp,eax
	
; Check for PE-PROT 0.9 beta layer
	cmp	byte ptr [ebp],0e9h		; Is it JMP xxxx ?
	jne	free_mem_exit			; If not - exit		
	
	mov	ebx,000000d3h			; Get JMP offset and correct it
	sub	ebx,[ebp+0001h]			; by using offsets from version regged to CHRiS
						; (the one used on the protector itself)

	sub	ebp,ebx				; Correct pointer to PE-PROT layer
	
	cmp	dword ptr [ebp+00d8h],57555152h	; Additional checks for PE-PROT 0.9 beta
	jne	free_mem_exit
	cmp	dword ptr [ebp+00dch],30a16764h
	jne	free_mem_exit

	lea	ebx,[ebp+013bh]

	mov	ecx, 0000031Dh
	mov	dl,[ebp+010dh]
	xor	eax, eax

u1:
	add	al, byte ptr [ebx]
	ror	byte ptr [ebx], cl
	sub	byte ptr [ebx], dl
	xor	byte ptr [ebx], 0c3h
	inc	ebx
	add	dl, [ebp+012bh]
	dec	ecx
	jnz	u1


;------ Layer 2
	lea	ebx, dword ptr [ebp+023ch]		; 40A23C
	mov	ecx, 00000182h
	mov	dx, [ebp+0212h]

u2:
	mov	al, 0ebh
	
	xor	byte ptr [ebx], al
	mov	ax, dx
	sub	byte ptr [ebx], al
	sub	byte ptr [ebx], ah
	
	mov	al, [ebp+0231h]
	xor	byte ptr [ebx], al
	
	add	dx, 0010h
	inc	ebx
	loop	u2

;------ Layer 3
	lea	ebx,[ebp+0289h]		; 40A289
	mov	ecx,0135h
	mov	edx,[ebp+03e2h]		; 40A3E2 Add the checksum

u3:
	push	ecx
	mov	cl,0ebh
	rol	byte ptr [ebx],cl
	pop	ecx
	
	sub	[ebx],dl
	xor	[ebx],dh
	inc	ebx
	add	edx,[ebp+03e6]		; 40A3E6
	loop	u3

;------ Layer 4
	mov	[ebp+03fch],edx		; 40A3FC - Image base
	add	[ebp+03eah],edx		; 40A3EA
	add	[ebp+03eeh],edx		; 40A3EE

	lea	ebx,[ebp+02d6h]		; 40A2D6
	mov	ecx,00E2h
	mov	edx,[ebp+03b8h]		; 40A3B8

u4:
	xor	[ebx],dh
	sub	[ebx],dl
	
	add	edx,[ebp+02c8h]
	
	inc	ebx
	loop	u4

;------ Decrypt sections
	mov	magic_1,0feebh

	cmp	byte ptr [ebp+03f2h], 00	; 40A3F2 (00h) Check if sections are encrypted
	jne	ds_5
	   	
	mov	byte ptr [ebp+03f2h],01		; 40A3F2
	lea	esi,[ebp+03fbh]			; 40A3FB
	movzx	esi,byte ptr [esi]		; Get number of sections
	mov	edi,ebp

ds_4:
	lea	ebx,[ebp+03fch]			; 40A3FC - Image base
	mov	ebx,[ebx]			; EBX=image base (calculated)
	   	
	lea	eax,[edi+0400h]			; 40A400 - Sections info (RVA/len)
	mov	eax,[eax]
	
	call	rva2fo
	xchg	eax,ebx

	lea	ecx,[edi+0404h]			; 40A404
	mov	ecx,[ecx]			; Length

; Possible check for resources/imports decryption????????????????????????????????
ds_2:
	cmp	ebx,[ebp+03eeh]			; 40A3EE
	jg	ds_1
	cmp	ebx,[ebp+03eah]			; 40A3EA
	jl	ds_1
	jmp	ds_3

ds_1:
	push	edx
	push	ecx
	push	eax
	lea	edx,magic_1
	add	byte ptr [edx],00
	add	byte ptr [edx+0001],0Ah
	mov	ax,[edx]
	mov	dl,[edx]
	add	dl,ah
	sub	[ebx],dl
	add	byte ptr [ebp+03b7h],0Bh	; 40A3B7
	mov	cl,[ebp+03b7h]			; 40A3B7
	sub	[ebx],cl
	rol	byte ptr [ebx],cl

	mov	al,[ebp+0363h]
	xor	byte ptr [ebx],al

	pop	eax
	pop	ecx
	pop	edx
ds_3:
	inc	ebx
	loop	ds_2
	
	add	edi,0008h
	dec	esi
	jne	ds_4

ds_5:

;------ Set entry point address
	mov	eax,[ebp+03f7h]			; 40A3F7 - Entry point
	mov	esi,pe_header_ptr
	mov	[esi+0028h],eax

;----- Kill cryptor sections
	dec	word ptr [esi+0006h]		; Decrease number of sections

;----- Find end of sections
        movzx	eax,word ptr [esi+0006h]
        mov	ebx,0028h
        mul	ebx
        movzx	ebx,word ptr [esi+0014h]
        add	esi,ebx
        add	esi,eax
	add	esi,0018h

	mov	edi,esi

	mov	eax,[esi-28h+14h]		; Get physical offset of section before PE-PROT
	add	eax,[esi-28h+10h]		; Add its size to get the total file size
	mov	f_size,eax			; Set write file size

	mov	eax,[esi-28h+0ch]		; Get section RVA
	add	eax,[esi-28h+08h]		; Add virtual size
	mov	esi,pe_header_ptr
	mov	[esi+0050h],eax			; Set image size (checked under WinNT/2k)
	
;----- Clear PE-PROT section info in PE header (no shit tags ;)
	mov	ecx,0028h
	xor	al,al
	cld
	rep	stosb

;###### Write unpacked file to disk ##################################
write_file:
        call    CreateFileA, offset outfname, GENERIC_WRITE,\
                             NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
        push    eax
        call    WriteFile, eax, buffer, f_size, offset write_len, NULL
        call    CloseHandle

free_mem_exit:
        call    GlobalFree,buffer

exit:
        call    ExitProcess, NULL       ; Exit program
start   endp


; Convert RVA in EAX to file offset in EAX. Return NULL if bad RVA!!!
; [section          ][gap][section]	<- File loaded by OS view
;        |-----------------|		<- Decrypt length
; [section          ][section]		<- File layout (as on disk/loaded by unpacker)
;
; if (rva > section_start + section length) and (rva < next_section_start) then EAX=0
rva2fo  proc
        uses    ecx,esi,edi

        mov     esi,pe_header_ptr       ; ESI points to PE header in memory
        movzx   ecx,word ptr [esi+0006h]; ECX=sections number

        movzx   edi,word ptr [esi+14h]  ; Get PE Header Size
        add     edi,18h                 ; Add offset of Flags field
        add     edi,esi                 ; Make EDI = Object Table Address
        mov     sections_start,edi      ; Save for later use

        mov     esi,edi
@@scan_section:
        cmp     eax,dword ptr [esi+000ch]; Compare RVA with section RVA
        jae     @@sect_found

@@go_scan_next_section:
        add     esi,0028h               ; ESI points to next section in memory
        loop    @@scan_section
	jmp	@@wrong_rva

@@sect_found:
	cmp	ecx,0001h
	je	@@its_last_section
	cmp	eax,dword ptr [esi+000ch+0028h]	; Compare with the start RVA of next section
	jae	@@go_scan_next_section

        mov     edi,dword ptr [esi+000ch]; EDI is section start RVA
        add     edi,dword ptr [esi+0010h]; EDI is the end RVA of the section in file
	cmp	eax,edi
	jae	@@wrong_rva


@@its_last_section:
        sub     eax,dword ptr [esi+000ch]; EAX is offset withing section
        add     eax,dword ptr [esi+0014h]; EAX=physical address of section + offset
        add     eax,buffer              ; EAX is offset in our memory buffer!
        ret

@@wrong_rva:
	xor	eax,eax
	ret
rva2fo  endp

        end     start
