rendered paste body; Program name: yoda's Crypter
; Version: 1.2
; Author: C-ripper
; Target: Yoda's Crypter v.1.2
; Greetings: yoda, r!sc, bane, Uknown One/TMG, everyone :)
.586p
.model flat,stdcall
locals
jumps
include win32.inc
EXTRN GetOpenFileNameA:PROC
EXTRN MessageBoxA:PROC
EXTRN GlobalAlloc:PROC
EXTRN GlobalFree:PROC
EXTRN VirtualAlloc:PROC
EXTRN VirtualFree:PROC
EXTRN ExitProcess:PROC
EXTRN ReadFile:PROC
EXTRN WriteFile:PROC
EXTRN GetFileSize:PROC
EXTRN CloseHandle:PROC
EXTRN CreateFileA:PROC
.data
NULL equ 00h
GMEM_FIXED equ 0000h
ofn_struc OPENFILENAME <>
ofn_struc_size equ 04ch
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 ?
out_fhandle dd ?
outfname db 'unpacked.exe',00h
buffer dd ?
temp_buf dd ?
tls_table dd 0,0,0,0
pe_header_ptr dd ?
section_start dd ?
sections_num dd ?
image_base dd ?
import_start dd ?
import_rva dd ?
far_proc db ?
min_size dd ?
imp_align db ?
correct_imp_loc dd ?
garbage dd ?
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
success_caption db 'Success',00h
.code
start proc
; Prepare the OpenFileName structure and get file name
mov ofn_struc.lStructSize,ofn_struc_size
mov ofn_struc.lpstrFilter,offset ofn_filter
mov ofn_struc.lpstrFile,offset f_name
mov ofn_struc.lpstrTitle,offset ofn_title
mov ofn_struc.nMaxFile,0200h
mov ofn_struc.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,-1 ; ////Invalid_File_Handle?
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 ;buffer points to the beginning of the
;file in memory
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 ; edx points to offset of the file_start
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] ; PE header==>EDX
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 ;
movzx eax,word ptr [edx+0006h] ;number of sections
mov sections_num,eax
;###### UNPACKING START ##############################################
mov eax,dword ptr [edx+0028h] ; EAX points to entry point of program
call rva2fo
or eax,eax
jz free_mem_exit
mov ebp,eax ; EBP is entry point offset
;--------------------Detect Yoda's v1.2 layer
cmp dword ptr [ebp],0000e860h ; pushad
jne free_mem_exit
cmp dword ptr [ebp+0dh],00097bb9h ;mov ecx,97Bh
jne free_mem_exit
mov esi,pe_header_ptr
mov edi,dword ptr [esi+10ch] ;get phys_offset of first section
mov edx,dword ptr [esi+108h] ;phys_size
mov esi,buffer
add esi,edi
mov edi,esi ;esi points to start of CODE section
add edi,edx
Call VirtualAlloc,NULL,37h,1000h,0004h ;alloc some memory for 1st
;decrypt routine
mov temp_buf,eax
mov esi,pe_header_ptr
mov edx,sections_num
imul edx,edx,28h
sub edx,14h ;edx=(edx-28h)+14h -->Phys_Offset
add edx,esi
add edx,0f8h
mov ebx,dword ptr [edx]
mov edx,buffer
add ebx,edx
mov section_start,ebx ;fix the beginning off yC section
mov edi,ebx
add edi,0078h
mov byte ptr [eax+36h],0c3h ;to return after it's done
mov ecx,00000036h
copy_:
mov dl,byte ptr [edi]
mov byte ptr [eax],dl
inc edi
inc eax
loopnz copy_
mov edi,section_start
cmp dword ptr [edi+0a29h],00 ;get first for bytes of needed .rdata(?) section
jz no_tls_table
mov ecx,dword ptr [edi+0a29h]
mov dword ptr tls_table,ecx
mov ecx,dword ptr [edi+0a2dh]
mov dword ptr tls_table+4,ecx
mov ecx,dword ptr [edi+0a31h]
mov dword ptr tls_table+8,ecx
mov ecx,dword ptr [edi+0a35h]
mov dword ptr tls_table+0ch,ecx
no_tls_table:
add edi,0aeh
mov ecx,97bh
mov edx,temp_buf
call edx
Call VirtualFree,temp_buf,0000h,8000h
mov edi,section_start
add edi,3d2h ;2nd decrypt proc, reading it from
Call VirtualAlloc,NULL,37h,1000h,0004h ;the decrypted part of the file
mov temp_buf,eax
mov edi,section_start
add edi,03cfh
mov byte ptr [eax+36h],0c3h
mov ecx,00000036h
copy__:
mov dl,byte ptr [edi] ;again copy 3eh bytes to buffer
mov byte ptr [eax],dl ;to run decrypt_sections proc
inc edi
inc eax
loopnz copy__
mov eax,pe_header_ptr
mov edi,eax
mov esi,edi
add esi,0f8h
xor edx,edx
decrypt_sections:
cmp dword ptr [esi],63727372h
jnz loc_1
jmp next_section
loc_1:
cmp dword ptr [esi],7273722eh
jnz loc_2
jmp next_section
loc_2:
cmp dword ptr [esi],6f6c6572h
jnz loc_3
jmp next_section
loc_3:
cmp dword ptr [esi],6c65722eh
jnz loc_4
jmp next_section
loc_4:
cmp dword ptr [esi],00004379h
jnz loc_5
jmp next_section
loc_5:
cmp dword ptr [esi],6164652eh
jnz loc_6
jmp next_section
loc_6:
cmp dword ptr [esi+14h],00h
jz next_section
cmp dword ptr [esi+10h],00h
jz next_section
pushad
mov ecx,[esi+10h]
mov edi,[esi+14h]
mov esi,buffer
add esi,edi
mov edx,temp_buf
call edx
popad
next_section:
add esi,28h
inc edx
cmp dx,[edi+06]
jnz decrypt_sections
Call VirtualFree,temp_buf,0000h,8000h
;^^^^^^^^^^^^^^^^^^^^^^Decrypt import table^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
mov eax,section_start ;pointer to reserved import
add eax,07efh ;info for later use
xor edi,edi
mov imp_align,00000001
cmp dword ptr [eax+08],00
jz pre_calc
mov imp_align,00000002
pre_calc:
mov edx,dword ptr [eax+10h] ;we may take this thunk for comparison
calc_pointers: ;we'll better calc them
cmp dword ptr [eax],00 ;to define later their place ;in original .exe
jnz continue_
cmp dword ptr [eax+04],00
jz find_data_section
continue_:
add eax,04
inc edi
jmp calc_pointers
imul edi,edi,04
mov far_proc,00
find_data_section:
mov ecx,sections_num ;looking for section were to put
mov bl,01 ;important part of import
mov esi,pe_header_ptr
add esi,0f8h
find_idata:
cmp bl,cl
jz proceed_ ;if yes then it's last section
cmp edx,dword ptr [esi+0ch]
jg move_on
jmp chk_next_rva
move_on:
cmp edx,dword ptr [esi+0ch+28h]
jg chk_next_rva
cmp edx,[esi+34h]
jnz proceed_
inc bl
jmp proceed_ ;if (thunk>rva[i]) && (thunk<rva[i+1]) then
chk_next_rva: ;we found it and bl equ it's index
add esi,00000028h
inc bl
cmp cl,bl
jnz find_idata
proceed_:
mov min_size,edi
sub bl,01
movzx ebx,bl
imul ebx,ebx,00000028h
add ebx,0000000ch
mov edi,pe_header_ptr
add edi,0f8h
add edi,ebx
mov esi, dword ptr [edi] ;esi holds pointer to data section
mov import_rva,esi ;save Virtual Offset for later use
mov esi, dword ptr [edi+8] ;esi is physical offset of .(i)data now
add esi,buffer
mov import_start,esi
cmp far_proc,01
jz _end_ ;return to the is_in_this_section call
stay_here:
mov edi,section_start
add edi,7efh
xor edi,edi
not_found:
push esi
xor edx,edx
find_space:
cmp dword ptr [esi],00
jz chk_farther
inc edx
cmp edx,min_size
jz chk_values
add esi,04
jmp find_space
look_again:
pop esi
add esi,04
jmp not_found
chk_farther:
add esi,04
jmp not_found
chk_values:
mov edi,min_size
imul edi,edi,04
sub esi,edi
add esi,04
mov eax,dword ptr [esi]
mov garbage,eax
xor ecx,ecx
chk_the_rest:
add esi,04
inc ecx
cmp dword ptr [esi],eax
jnz look_again
cmp ecx,min_size
jz restore_import
jmp chk_the_rest
restore_import:
inc ecx ;there are usually 2 methods of
imul ecx,ecx,04 ;locating the grabbed import
sub esi,ecx ;info
add esi,04
mov correct_imp_loc,esi
mov edi,section_start
add edi,07efh ;here we'll copy the needed data
cmp imp_align,1 ;and rva of this place should be present
jnz locate_method2 ;in pe_header at [pe_header_ptr+80h]
mov dword ptr [esi],00
mov dword ptr [esi+04],00
mov dword ptr [esi+08],00
add esi,0ch
mov_imp:
mov eax,dword ptr [edi]
cmp eax,00
jz decrypt_import
mov dword ptr [esi],eax
add edi,04
add esi,04
mov eax,dword ptr [edi]
cmp eax,00
jz decrypt_import
mov dword ptr [esi],eax
cmp dword ptr [edi+08],00
jz decrypt_import
mov dword ptr [esi+04],00
mov dword ptr [esi+08],00
mov dword ptr [esi+0ch],00
add edi,08h
add esi,10h
jmp mov_imp
locate_method2:
push esi
push edi
add edi,8
c1_: cmp dword ptr [edi],00
jz c2_
mov eax,dword ptr [edi]
mov dword ptr [esi],eax
mov dword ptr [esi+04],00
mov dword ptr [esi+08],00
add esi,14h
add edi,0ch
jmp c1_
c2_:
mov dword ptr [esi],00
mov dword ptr [esi+04],00
mov dword ptr [esi+08],00
mov dword ptr [esi+0ch],00
mov dword ptr [esi+10h],00
pop edi
pop esi
add esi,0ch
c3_:
mov eax,dword ptr [edi]
mov dword ptr [esi],eax
mov eax, dword ptr [edi+04]
mov dword ptr [esi+04],eax
add esi,14h
add edi,0ch
cmp dword ptr [edi],00
jnz c3_
decrypt_import:
cmp imp_align,00000001
jnz decrypt2_import
;simply perform a "ror al,04" operation over each character of library\WinApi name
;in case 1 we have the pointer to library and the pointer to thunk pointing to WinApis
;from this library; in case two there are 1 lib_name and 2! thunks
mov ebx,correct_imp_loc ;ajust pointer to thunk pointing to first library
sub ebx,04
reverse:
add ebx,10h
mov edi,dword ptr [ebx]
cmp edi,00
jz decr_done
sub edi,import_rva
add edi,import_start
mov esi,edi
call imports_back
add ebx,04
mov edi,dword ptr [ebx]
sub edi,import_rva
add edi,import_start
pr_thunks:
mov ecx,dword ptr [edi]
cmp ecx,00
jz reverse
sub ecx,import_rva
add ecx,import_start
add ecx,00000002
push edi
mov edi,ecx
mov esi,edi
call imports_back
pop edi
add edi,04
jmp pr_thunks
decrypt2_import:
Call VirtualAlloc,NULL,temp_buf,1000h,0004h
mov temp_buf,eax
mov dword ptr [eax],00000000h ;initialize allocated space
mov ebx,correct_imp_loc
reverse_:
add ebx,0ch
mov edi,dword ptr [ebx]
cmp edi,00
jz decr_done
mov ecx,edi
call is_in_this_section
mov edi,eax
mov esi,edi
call imports_back
add ebx,04
mov edi,dword ptr [ebx]
sub edi,import_rva
add edi,import_start
pr1_thunks:
mov ecx,dword ptr [edi]
cmp ecx,00
jz reverse__
test ecx,80000000h
jnz rev1_
call repeat_check
cmp al,00
jnz reverse__
call is_in_this_section
mov ecx,eax
add ecx,00000002
push edi
mov edi,ecx
mov esi,edi
call imports_back
pop edi
rev1_:
add edi,04
jmp pr1_thunks
reverse__:
add ebx,04
cmp dword ptr [ebx],00
jz decr_done
mov edi,dword ptr [ebx]
sub edi,import_rva
add edi,import_start
pr2_thunks:
mov ecx,dword ptr [edi]
cmp ecx,00
jz reverse_
test ecx,80000000h
jnz rev2_
call repeat_check
cmp al,00
jnz reverse_
call is_in_this_section
mov ecx,eax
add ecx,00000002
push edi
mov edi,ecx
mov esi,edi
call imports_back
pop edi
rev2_:
add edi,04
jmp pr2_thunks
;decrypt apis pointed by thunk at offset correct_imp_loc+00h
mov edi,correct_imp_loc
jmp pr2_thunks
;###################simple procedure that rotates the bytes##################
imports_back proc
lp1_:
lodsb
ror al,04
stosb
cmp byte ptr [edi],00
jnz lp1_
ret
imports_back endp
;############################################################################
;############################################################################
repeat_check proc
uses ebx,ecx
xor al,al
mov ebx,temp_buf
chk_val:
cmp dword ptr [ebx],00
jz end__
cmp dword ptr [ebx],ecx
jz set_flag
add ebx,04
jmp chk_val
set_flag:
mov al,01
add ebx,04
jmp chk_val
end__:
mov dword ptr [ebx],ecx
ret
repeat_check endp
;############################################################################
;############################################################################
is_in_this_section proc
uses ecx,ebx,edx,edi,esi,import_rva,import_start
mov far_proc,00
sub ecx,import_rva
cmp ecx,00
jg dont_change
mov far_proc,01
add ecx,import_rva
mov edx,ecx
jmp find_data_section
_end_:
mov eax,edx
sub eax,import_rva
add eax,import_start
jmp _end
dont_change:
add ecx,import_start
mov eax,ecx
_end:
ret
is_in_this_section endp
;############################################################################
;here we'll define the pointer to "new" import table
decr_done:
call VirtualFree,NULL,temp_buf,0000h,8000h
mov eax,correct_imp_loc
sub eax,import_start
add eax,import_rva
mov import_rva,eax
;^^^^^^^^^^^^^^^^^^^^^^^^^Final part: correction of pe header^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cmp dword ptr tls_table,00
jz fix_oep
mov ecx,sections_num
mov esi,pe_header_ptr
add esi,0f8h
xor eax,eax
local_:
mov eax,dword ptr [esi+14h] ;get file offset of each section
add eax,buffer ;until we find the proper one
mov ebx,dword ptr tls_table
cmp [eax],ebx
jnz tls_chk
mov ebx,dword ptr tls_table+04
cmp [eax+04],ebx
jnz tls_chk
mov ebx,dword ptr tls_table+08
cmp [eax+08],ebx
jnz tls_chk
mov ebx,dword ptr tls_table+0ch
cmp [eax+0ch],ebx
jz found_it
tls_chk:
dec ecx
add esi,28h
loopnz local_
found_it:
mov edi,pe_header_ptr
chk_4_origin: ;this check is done cause sometimes .tls and
cmp dword ptr [esi+10h],00 ;.rdata have the same physical offset, but
jnz write_it ;in such case raw size of .tls equals to 0000h
add esi,28h ;so we'll need to write down the correct
loopnz chk_4_origin ;tls table rva
write_it:
mov ebx,dword ptr [esi+0ch]
mov dword ptr [edi+0c0h],ebx
fix_oep:
mov eax,section_start
add eax,07dbh ;grab new (real) entry point and fix it
mov edi,dword ptr [eax]
mov eax,edi
mov edi,pe_header_ptr
mov dword ptr [edi+28h],eax
mov edx,dword ptr [edi+50h] ;fix image_size:=image_size-2000h
sub edx,2000h
mov dword ptr [edi+50h],edx
mov edx,import_rva
mov dword ptr [edi+80h],edx ;set rva to import table we've restored
;delete some shit from pe header
mov eax,pe_header_ptr
mov edx,sections_num
mov ebx,buffer
add eax,0f8h
dec edx
imul edx,edx,28h
add eax,edx ;eax points to .yC
xor ebx,ebx
rem_shit:
mov dword ptr [eax+ebx],00000000h
add ebx,4
cmp ebx,28h
jnz rem_shit
mov eax,pe_header_ptr ;correct pe_header
mov edx,sections_num ;fix number of objects
dec edx
mov word ptr [eax+0006h],dx
add eax,11ch
mov dword ptr [eax],0e0000060h ;make 1st section
;loadable(for win32dasm)
;*******when finished save file to delamed.exe*****************
mov ebx,f_size
sub ebx,0a46h ;subtract phys_size of yC section
mov f_size,ebx
;###### 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
call MessageBoxA,NULL,offset success_msg,offset success_caption,NULL
;----- Free used memory buffer
free_mem_exit:
call GlobalFree,buffer
exit:
call ExitProcess, NULL ; Exit program
start endp
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 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