;; ** Warning: Encryption and decryption code closed to public for security (as if there; "everything else is here tho. ;;; vgcrypt pee encryptor v0.75 beta; (c) 1998 Virogen; Email: vgen@hotmail.com; www: http://virogen.cjb.net; ---------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------;; this is a fairly Simple PE Encryptor i wrote up. I commented everything ; that is relavent to PE appendation or insertion, more so than I needed to;. even The most interesting feature of this encryptor is that it attempts to; find a location to insert itself between object virtual size and the next; file alignment boundary, Thus not Changing The Physical File Size .; Note That Code Is Still Under Development .; Features :; --Three Types of PE Parasticality
11/26/98 V0.40: Initial Release; 11/27/98 V0.45: Added Simple SEH Anti-Debugging Code; Fixed Command Line Problem When Running Under Winnt; DOS Box; Other Minor Changes in Decryptor; 11/28 / 98 v0.50: Fixed winNT image problems; Added better anti-debugging code, but still needs improvements ,; optimization, etc.; Closed decryptor and encryption source Sorry, but all the other; code is still open; 11/28. / 98 v0.51: reformatted decryptor a little, anti-debugging code still needs to; be improved alot .; 11/28/98 v0.54: Fixed exception when object with no physical offset / size encountered .; Temporarily disabled portion of Anti-debugging code .; 11/29/98 V0.56: Source Code Beautification by Ghiribizzo
Was missing last object while traversing thru object table, oops .; 11/31/98 v0.60: Checks to make sure there is room to add another object to; object table before allowing user to select this option .; Other minor changes here and there .; 12/05/98 v0.61: Now accounts correctly for PEs loaded at a differing image base; I had forgotten to recalculate encrypted object addresses This; was a minor bug because it is rare to have a PE loaded.. A base Other; Than the one specified in the header .; 12/09/98 v0.65: Now Avoids Encrypting Import & Export Table No Matter Where IT IT.; OOPS, SHOULD DONE THIS in The First Place.; 12 / 19/98 V0.75: Improved Security A little bit, Still Not Secure At All .. Someday; I would Remedy this .;;; =================== ============================================================================================================================================================================================================= ===============; Special Than Ghiribizzo who Has provided more anti-debugging ideas tour c; eve hope to have time to Implement
=================================================================================================================================================================== # Virtual_size equ decryptor_sizemax_objs EQU 6; Maximum Objects We can handle; by increasing this you are incseasing the size; of the table in decryptor by max_objs * 8.
.586plocalsjumps.model flat, stdcall
extrn ExitProcess: PROC extrn CreateFileA: PROC extrn CloseHandle: PROC extrn ReadFile: PROC extrn WriteFile: PROC extrn SetFilePointer: PROC extrn MapViewOfFile: PROC extrn CreateFileMappingA: PROC extrn UnmapViewOfFile: PROC extrn SetEndOfFile: PROC extrn SetFilePointer: PROC extrn GetFileAttributesA: PROC extrn SetFileAttributesA : PROC extrn GetFileSize: PROC extrn GetTickCount: PROC extrn GetFileSize: PROC extrn GetFileTime: PROC extrn SetFileTime: PROC extrn CheckSumMappedFile: PROC extrn MessageBoxA: PROC extrn GetCommandLineA: PROC extrn lstrcat: PROC extrn IsBadReadPtr: PROC extrn WriteConsoleA: PROCextrn GetStdHandle: PROCextrn ReadConsoleA : Proc
ORG 0 .DATA; Data Object
Conditional Compile; Console_App EQU 1
Cr EQU 0dhlf EQU 0AHTAB EQU 9HLINE EQU 196Marker EQU 90909090H
CR_LF_TAB DB CR, LF, Tab, Tab, 0Init_txt DB 50 DUP (Hline), Cr, LFCAPTION DB 'VIROGEN' '$ PE Encryptor V0.75, (C) 1998 Virogen [NOP]' IFNDEF Console_App DB 0ndIf IFDEF Console_App DB CR , LF, 'http://virogen.cjb.net email: vgen @ Hotmail.com', Cr, LF DB 50 DUP (HLINE), CR, LF, 0 Endif Badcmd_txt db 'Invalid Command Line!', Cr, LF , 'Usage: VGCRYPT filename', cr, lf, 0success_txt: ifdef console_app db cr, lfendif db '! Successfully encrypted' ifdef console_app db 0endif file_txt db cr, lf, 'Installed on file:', tab, 0 db 400 dup ( 0); Plenty of SpaceObj_txt DB CR, LF, 'Installed In Object:', Tab, 0 DB 9 DUP (0) EOBJ_TXT DB CR, LF, 'Encrypted Objects:', 0 dB (Max_Objs * 8) 1 DUP ( 0) Hole_Txt DB CR, LF, 'VGCrypt Installed in Alignment Hole, with no phsyical size incre ase ', 0already_txt: ifdef console_app db cr, lf,'!... File appears to already be encrypted Encrypting again ', 0endif db' File appears to already be encrypted Do you wish to encrypt again ', 0append_question db' Could not? Locate Any "Caves" To Install INTO! ', CR, LF,' Click Yes' DB 'to Create New Object', Cr, LF, 'Click NO To Append To Last Object.', 0error_txt: IFDEF Console_App DB CR, LF , '' endif db 'there is an error encrypting the file!'
, Cr, lfifdef console_app db 0endif fname_txt db 'Specified file:', 0 db 260 dup (0) nohole_txt db cr, lf, 'No available "caves" to install into, forced to increase physical size.', 0doing_obj_txt db cr, LF, 'Encrypting Object:', Tab, 0Skip_obj_txt DB CR, LF, 'Skipping Object:', Tab, 0Found_Hole_Obj DB CR, LF, 'Found Hole In Object:', Tab, 0DONE_TXT DB '..DONE', 0CREATION DD 0,0; our file time structureslastaccess dd 0,0lastwrite dd 0,0oldchksum dd 0fsize dd 0map_ptr dd 0oldattrib dd 0; stored file attribsfnameptr dd 0; ptr to file name we're infptrpeheader dd 0objPsize dd 0maphandle dd 0handle dd 0objtblVA dd 0objptr dd 0Lastobjimageoff DD MedoBjimage DD Medicalvsize DD 0ERROR DB -1; ImportTBL DD 0exportTBL DD 0BYTESWROTE DD 0HSTDO DD 0HSTDI DD 0YNBUF DB 0USE_HOLE DB 0HOLEPTR DD 0BAD_OTBL:; this is the list of bad objs - DID I MISS ANY? DD 'RSR.'; RSRC DD 'LER.'; RELO DD 'ADE'; EDATA DD 'ETE . '; ETEXT DD' ADI. '; Idata DD' ADR. '; RDATA DD' SLT. '; TLS DD 0
; --- Decryptor code installed Into file ---- ;;; *** Closed Source, for security ;;;; --- end of decryptor code ---
; --- start of VGCrypt --- code; code object - change flags to rwxstart:. Ifdef console_app call GetSHandle lea ebx, init_txt call WriteStringendif call GetCommandLineA; retrieve command line or eax, eax jz _exit_bad_cmd_line; if none then abort / w MSG Xchg ESI, ESL: CMP BYTE PTR [ESI], 0; if First byte Is Null Then Something Way Wrong JZ_EXIT_BAD_CMD_LINE SHL Eax, 8; Rotate 1 Byte in Eax, for loop .. Eax Running Load Lodsb; Get Next Byte in Al Cmp EAX, 'RYPT'; END OF OR PROGGIE NAME? JNZ NOT_EOC CMP BYTE PTR [ESI], '.' JNZ ESLNOT_EOC: CMP ESLNOT_EOC: CMP ESLN, '. EXE'; .EXE END OF OUR PROGGIE NAME? JZ ESL CMP EAX, '. EXE'; .exe End Our Proggie Name? JNZ SLESL: LODSB CMP AL, '' JZ ESL CMP AL, '"' JZ ESL DEC Esiesl2: CMP Byte Ptr [ESI], 0; IF First Char In Parameter 1 Is Null Then We fuq jz _exit_bad_cmd_line ifndef console_app push ESI Push Offset Success_txt Call Lstrcat;
append filename to success messageendif ifdef console_app push esi push offset fname_txt call lstrcat lea ebx, fname_txt call WriteStringendif mov fnameptr, esi; set fnameptr-> filename call EncryptFile; go encrypt; cmp error, -4; jz _exit cmp error, -1; error jz _exit_error;? if so go display error message ifndef console_app push offset obj_txt push offset success_txt call lstrcat; append object name we inserted or appending to push offset eobj_txt push offset success_txt call lstrcat; append objects we encrypted cmp use_hole, 1 jnz no_hole_msg push OFFSET HOLE_TXT JMP App_SuccessNo_Hole_MSG: push offset nohole_txt app_success: push offset success_txt call lstrcatpush 0 push offset caption push offset success_txt push 0 call MessageBoxA endififdef console_app lea ebx, success_txt call WriteString endif xor eax, eax jmp _exit
_EXIT_ERROR: IFNDEF Console_App Push Fnameptr Push Offset Error_txt Call Lstrcat
push MB_ICONEXCLAMATION push offset caption push offset error_txt push 0 call MessageBoxA endififdef console_app lea ebx, error_txt call WriteString endif mov eax, 2 jmp _exit _exit_bad_cmd_line: ifndef console_app push MB_ICONEXCLAMATION push offset caption push offset badcmd_txt push 0 call MessageBoxA endif ifdef console_app lea ebx, badcmd_txt Call WriteStringendif Xor Eax, Eax Inc Eax_exit: Call EXITPROCESS, EAX
; ----------------------------------------------; Encrypt File - Call with Fnameptr Set; EncryptFile Proc
Mov Eax, FNameptr Push Eax Call getFileAttributesa; Get File Attributes Mov Oldattrib, ERROR THENBE Shared Jnz Not_Shared Ret; Can't Encrypt IT
not_shared: push 20h; A mov eax, fnameptr push eax call SetFileAttributesA; clear 'da attribs mov esi, fnameptr call OpenFile call test_error jnc open_ok ret open_ok: mov handle, eax push offset creation push offset lastaccess push offset lastwrite push eax call GetFileTime Grab the file time XOR ECX, ECX; ONLY MAP SIZE OF FILE CALL CREATE_MAPPING; CREATE FILE MAPPING JC ABORT_ENCRYPT; Eax-> Mapped File Cmp Word PTR [EAX], 'ZM'; IS EXE? JNZ ABORT_ENCRYPT CALL GETPEHEADER; LOAD ESI->
PE Header push 2 push esi; test ptr for read acces call IsBadReadPtr; was ptr any good or eax, eax jnz abort_encrypt cmp word ptr [esi], 'EP';? PE jnz abort_encrypt cmp dword ptr [esi ID_OFF],? Marker; marker? jnz not_encrypted; if Yes, Already Processed IFNDEF Console_App Push MB_ICONHAND OR MB_YESNO push offset caption push offset already_txt push 0 call MessageBoxA cmp eax, IDYES jnz abort_encrypt endififdef console_app lea ebx, already_txt call WriteStringendif not_encrypted: call unmap;
unmap file mov ecx, 1000h; give us room to add to the file, if needed call create_mapping; map file again jc abort_encrypt call GetPEHeader; load esi -> pe header call GetTickCount; get tick count mov key, eax; save for encryption keyMOV DWORD PTR [ESI ID_OFF], Marker; Save Marker; Mov Eax, [ESI ImageBase]; MOV SVD_IMAGEBASE, EAX; Save The Image Mov Eax, [ESI DATADIR] MOV IMPORTTBL, EAX MOV Eax, [ESI
edatadir] mov exporttbl, eax xor eax, eax mov ax, word ptr [esi NtHeaderSize]; get header size add eax, 18h; object table is here add eax, esi mov objptr, eax; Let's check for existance of cave after object Table in Pe Header; Mov EDI, [EAX ObjPoff]; Add EDI, MAP_PTR; PUSH ESI; INT 3; Push Eax; XOR EAX, Eax; MOV AX, [ESI Numobj]; Inc EAX; MOV ECX, 40; XOR EDX, EDX; MUL ECX; POP ESI; Add ESI, EX; CMP ESI, ED i; JGE NO_ROOM_IN_HDR; XCHG EDI, ESI; MOV CX, Decryptor_Size; XOR Eax, Eax; Push EDI; RePz ScaSB; Pop Edi; OR CX, CX; JNZ NO_ROOM_IN_HDR; POP ESI; PUSH ESI; MOV Eax, Objptr; MOV ECX [ESI FileAlign]; MOV EBX, [EAX Objpoff]; Sub EBX, EDI; Sub EBX, MAP_PTR; MOV [EAX ObjPoff], EBX; MOV HOLEPTR, EDI; MOV USE_Hole, 1NO_ROOM_IN_HDR:; Here We Will Traverse THROUGH THE Object Table, Encrypting Objects;
Which can be encrypted and also search for a 'Cave' Big Enough; to hold US.; Pop ESI PUSH ESI MOV EAX, Objptr Lea Edi, Otable XOR ECX, ECX MOV CX, [ESI NUMOBJ]; Get Number of Objects; dec cx otbl_loop: cmp edi, offset otable_end-8; filled up table jz next_obj call test_obj; see if good obj name jc next_obj pushad cmp use_hole, 1; already found hole jz no_hole_here mov edx, [eax objpsize]; get?? Obj Psize Mov ECX, [EAX Objvsize]; Get Obj vsize cmp ecx, edx; any hole here jge no_hole_here sub edx, ecx;? get size of hole cmp edx, DECRYPTOR_SIZE; big enough for us jl no_hole_here mov objptr, eax;? save ptr obj rec mov use_hole, 1; set flag mov ECX, [EAX Objvsize]; Encrypt vsize MOV [EDI 4], ECX; IF vsize <
psize ifdef console_app lea ebx, found_hole_obj call WriteString mov ebx, eax call WriteStringendif no_hole_here: push offset cr_lf_tab push offset eobj_txt call lstrcat popad pushad push eax push offset eobj_txt call lstrcat popad push eax ecx mov ebx, eax [objflags]; get obj flags or EBX, OFLAG_WRITE; or in Writable Flag Mov EBX; Save New Object Flags Mov EBX, EAX [Objrva]; Get The Object's RVA MOV [EDI], EBX; Save IT MOV ECX, [EDI 4]; See IF We set Above or ECX, ECX; if So Then We Are Jnz Already_VSIZE ; Gonna use vsize mov ecx, eax [objpsize]; get the object's physical size mov [edi 4], ecx already_vsize: ifdef console_app lea ebx, doing_obj_txt call WriteString mov ebx, eax call WriteStringendif add edi, 8; increment to next table Member Push Edi Mov ESI, EAX [Objpoff]; ESI->
object physical offset add esi, map_ptr mov edi, esi call encrypt_object; encrypt the object pop edi ecx eax ifdef console_app lea ebx, done_txt call WriteString endif ifdef console_app jmp next_didendif next_obj: ifdef console_app lea ebx, skip_obj_txt call WriteString mov ebx, eax call WriteStringendif Next_did: add eax, 40; increment to next object record loop otbl_loopdone_otbl: pop esi; restore Ptr PE HDR CMP USE_HOLE, 1 JZ FOUND_HOLE SUB EAX, 40; Make Sure Nuff Room To Add ANOTHER Object Before We Ask if; THIS BEST WAY To Do IT, But I; Just Scan To Make Sure THE NEXT 40 BYTES (1 Object Record) Are;
all 0. pushad mov edi, eax add edi, 40 mov ecx, 40 xor eax, eax repz scasb or ecx, ecx jnz go_append push MB_ICONQUESTION or MB_YESNO push offset caption push offset append_question push 0 call MessageBoxA cmp eax, IDNO jz go_append; cmp eax, IDCANCEL; jnz go_create; popad; mov error, -4; jmp abort_encryptgo_create:; user selected to create new object popad mov ecx, [eax objrva]; get last object rva add ecx, [eax objvsize]; = last object virtual size push eax; save obj record ptr xchg ecx, eax; eax = last object virtual end mov ecx, [esi objalign]; ecx = object alignment call align_fix; go align da shiznit xchg ecx, eax; ecx = next object's rva pop eax; restore obj record ptr mov edx, [eax objpoff]; edx = last object physical offset add edx, [eax objpsize]; edx = last object psize = obj pend add eax, 40; goto next object In Table (New) MOV DWORD PTR [EAX], 'CGV.'; set object name to .vgc Mov DWORD PTR [EAX Objpsize], 0; Set Psize to 0, Updated Later Mov DWORD PTR [EAX Objvsize], 0; set vsize to 0, Update Later Mov [EAX Objrva], ECX; SET RVA OFFF], EDX; SET Physical Offset Of Obj Inc Word PTR [ESI Numobj];
INCREMENT NUMBER OF OBJECTS JMP AFTER_APOP Go_Append: popadafter_apop: Mov Objptr, Eax; Objptr-> Last Obj Found_hole: Mov Edi, Objptr; Objptr-> Obj / W Hole
cmp holeptr, 0 jnz go_pe_hdr_hole push edi push offset obj_txt; strcat object name call lstrcat; for display mov eax, [edi objpoff]; get object physical off mov lastobjimageoff, eax; save it mov ecx, [edi objpsize]; get Object Physical Size Mov ORIGINALPSIZE, ECX; Save IT 4 Later Mov Eax, [EDI Objvsize]; Get Object Virtual Size Mov OriginalVsize, Eax; Save IT CMP USE_HOLE, 1 jz psize_less_vsize cmp eax, ecx jge psize_less_vsize; padded space for alignment mov eax, ecx; set vsize to psize psize_less_vsize:? add eax, VIRTUAL_SIZE; add our virtual size mov dword ptr [edi objvsize], eax; save new virtual size cmp Use_hole, 1;
if using hole then add virtual size jz in_hole_no_psize mov eax, originalpsize; get physical size of object add eax, DECRYPTOR_SIZE; adjust physical size of object mov ecx, [esi filealign] call align_fix; on file alignment mov [edi objpsize], eax;. now we must cORRECTLY calculate the new image size This was the; bug under winNT appendation mov ecx, dword ptr [esi objalign];. get object alignment mov eax, dword ptr [edi objvsize]; add virtual size add Eax, DWORD PTR [EDI Objrva]; Last Object RVA CALL Align_fix ; Set on obj alignment mov dword ptr [esi imagesize], eax; save new imagesize mov eax, originalpsize jmp not_in_hole_psize_entryin_hole_no_psize: mov eax, originalvsizenot_in_hole_psize_entry:
mov [edi objflags], 0E0000060h; set object flags r / w / x / init data add eax, [edi objrva]; add last object's RVA; eax now RVA of decryptor code jmp new_entrygo_pe_hdr_hole: mov eax, holeptr sub eax, map_ptrnew_entry: mov ebx, [esi entrypointRVA]; get original entry mov [esi entrypointRVA], eax; put our RVA as entry mov newep, eax; save it for decryptor too mov [host_eip], ebx; save it push esi; Closed Source Mov Edi, Map_ptr CMP Holeptr, 0 JZ NOT_HDR_HOLELE MOV EDI, HOLEPTR JMP COPY_TO_HDRNOT_HDR_HOLELE: cmp use_hole, 1; if in hole then install at end of vsize jz endvsize add edi, originalpsize; add original physical size jmp go_copyendvsize: add edi, originalvsize; add original virtual sizego_copy: add edi, lastobjimageoff; add object physical offset copy_to_hdr: lea ESI, DECRYPTOR_CODE; ESI->
decryptor code mov ecx, DECRYPTOR_SIZE rep movsb pop esi; restore ptr pe hdr cmp use_hole, 1; did we find hole to install in jnz go_pad_fixup_size;? if no then we better pad mov ecx, fsize; else new filesize = old filesize jmp go_fixup_size GO_PAD_FIXUP_SIZE: MOV ECX, [ESI FileAlign]; Calculate AMT SUB ECX, DECRYPTOR_SIZE ; Of padding needed xor eax, eax rep stosb; pad up object to alignment mov eax, map_ptr; eax-> beginning of mapped file sub edi, eax; get difference from current ptr mov ecx, edi; save file size go_fixup_size: push ecx ECX =
REAL FILE SIZE CALL UNMAP; unmap file pop ecx push file_begin; from file begin push 0; distance high push ecx; distance low push handle call setfilepointer; move file pointer to; real Eof Push Handle call SetEndOfFile; set end of file go_checksum: ;; now we need to calculate checksum We need to remap the file to get it; right after file size change I might be wrong about this, there could; have been a bug in my.. code, but it seems resonable
new file size mov eax, map_ptr push eax call CheckSumMappedFile call unmap mov error, 0; if we made it here then no error jmp unmapped abort_encrypt: call unmap; unmap if aborted infectionunmapped:
push offset creation push offset lastaccess push offset lastwrite push handle call SetFileTime; restore orginal file time push handle call CloseHandle mov eax, oldattrib; get original attribs push eax mov eax, fnameptr push eax call SetFileAttributesA; restore the original attributes ret EncryptFile endp ;; Closed Source; Test_obj Proc Cmp DWORD PTR [EAX OB jpoff], 0; make sure physical offset is not 0 jz ret_stc cmp dword ptr [eax objpsize], 0; make sure physical size is not 0 jz ret_stc call test_rvas jc ret_stc lea esi, bad_otbl; scan thru bad obj bobj_loop :; Table Xchg EAX, EBX LODSD XCHG EAX, EBX CMP EBX, [EBX] JZ RET_STC OR EBX, EBX JNZ BOBJ_LOOP CLC Retret_STC: STC Rettest_Obj Endp
test_rvas proc pushad mov ecx, 2 lea esi, importtbl rva_loop: mov edx, dword ptr [esi] mov ebx, dword ptr [eax objrva] cmp ebx, edx jg not_bad jz ret_stc2 mov ebx, dword ptr [eax 40 objrva ] or ebx, ebx jz ret_stc cmp ebx, edx jg ret_stc2not_bad: add esi, 4 loop rva_loop popad clc retret_stc2: popad stc ret endpGetPEHeader proc mov esi, [eax 3Ch]; where PE hdr pointer is add esi, eax mov ptrpeheader, ESI; ESI-> PE HDR RETGETPEHEADER ENDP
; Create_mapping - create file mapping of [handle]; entry: ecx = adjust mapping size; create_mapping proc push ecx; save additional mapping size push 0; high fsize storage, not needed push handle; file handle call GetFileSize call test_error jc create_abort mov FSIZE, EAX POP ECX; RESTORE MAP SIZE PUSH 0; No Map Name Add Eax, ECX PUSH Eax; Low Size VS Push 0; High Size Push Page_Readwrite; Read & Write PUSH 0 push handle call CreateFileMappingA call test_error jc create_abort mov maphandle, eax push 0; # of bytes, 0 = map entire file push 0; file offset low push 0; file offset high push FILE_MAP_WRITE; access flags - read & write push eax; handle call MapViewOfFile call Test_ERROR JC CREATE_ABORT MOV MAP_PTR, EAX
create_abort: retcreate_mapping endp; test_error - test API for an error return; entry: eax = API return; returns: carry if error; test_error proc cmp eax, -1 jz api_err or eax, eax jz api_err clc retapi_err: stc rettest_error endp
; unmap file - unmap view of file; unmap proc push map_ptr call unmapviewoffile push maphandle call closehandle RET
Unmap endp
; Sets eax on alignment of ecx; align_fix proc xor edx, edx div ecx; / alignment or edx, edx; if no remainder then no next jz no_adjust inc eax; next alignment no_adjust: mul ecx; * alignment retalign_fix endp
OpenFile Proc Push 0 Push 20h; Attribute Normal Push 3; 3 = Open EXISTING FILE PUSH 0 Push 0 Push 0C0000000H; Permissions Push ESI CALL CREATEFILEA RETOPENFILE ENDP
ifdef console_appGetSHandle proc push -11 call GetStdHandle mov [hstdo], eax push -10 call GetStdHandle mov [hstdi], eax retGetSHandle endpWriteString proc pushad mov edi, ebx xor eax, eax mov ecx, 0fffh cldsc_loop: scasb; find end of string jz Fnd loop sc_loopfnd: MOV ECX, EDI SUB ECX, EBX PUSH 0 PUSH OFFSET BYTESWROTE PUSH ECX PUSH EBX PUSH [HSTDO] CALL WRITECONSOLEA POPAD RETWRITESTRING ENDP
GetYN proc pushad lea edi, ynbuf xor eax, eax stosb dec edi push 0 push offset byteswrote push 1 push edi push [hstdi] call ReadConsoleA popad cmp ynbuf, 'y' jz exit_y cmp ynbuf, 'Y' jz exit_y stc retexit_y: clc RET getyn endpendif
End StARTENDS