;
;**WARNING: Encryption and Decryption code closed to public for security (as if there
; were any<g>). Everything else is here tho.
;
;
;VGCrypt PE 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 this code is still under development.
;
; Features:
; -three types of PE parasticality<g>:
; 1) install in cave - no physical size increase
; 2) append to last object
; 3) create new object
; -full win95/98/NT compliant
; -does not add new object unless you want to
; -stores correct new checksum of PE executable
; -preserves original file data/time and attributes
; -prompts u to encrypt again if file already encrypted, you can encrypt
; a file as many times as you want. Of course, eventually you will run out
; of available caves and the filesize will start increasing.
;
; Usage:
; -VGCRYPT filename
;
;
; known bugs:
; -might be problems with some encrypted DLLs.
;
;
; Note to coders:
; If you need to retrieve API RVAs in the decryptor, the best way is to
; manually import from the kernel32 export table in memory. The base of
; kernel32.dll can be obtained by using [esp] at entry and scanning down
; to the base. For more information, see my viral code at
; http://virogen.cjb.net.
;
;
; Updates:
; 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<g>.
; EBP now preserved correctly
; Minor winNT command line problem fixed
; Encrypted DLLs now load, but some have unusual problems
; Executables which are loaded at an image base other than the one
; specifid in the PE header (unusual) will now work properly.
; No longer flagged by AVP if appended to last object
; Note that when we reach v0.60 I will re-release the source
; code, with the noted exceptions of the encryption and decryption
; code.
; 11/30/98 v0.57: If no "caves" found, gives you choice of appending to last object or
; creating a new object.
; 11/30/98 v0.58: Minor bug fix in creating new object.
; 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 is at.
; 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 will remedy this.
;
;
;
; ====================================================================================
; Special thanks to Ghiribizzo who has provided more anti-debugging ideas than I can
; even hope to have time to implement<g>. http://Ghiribizzo.home.ml.org
; Greetz lapse,jp,vecna,darkman,Iczelion, and everyone else.
; ====================================================================================
;
;
;
include mywin.inc
ID_OFF equ 0ch ; offset of our marker in PE
DECRYPTOR_SIZE equ (offset decryptor_code_end-offset decryptor_code) ;
VIRTUAL_SIZE equ DECRYPTOR_SIZE
MAX_OBJS equ 6 ; maximum objects we can handle
; by increasing this you are increasing the size
; of the table in decryptor by MAX_OBJS*8.
.586p
locals
jumps
.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:PROC
extrn GetStdHandle:PROC
extrn ReadConsoleA:PROC
org 0
.data ; data object
; conditional compile
;console_app equ 1
;
cr equ 0dh
lf equ 0ah
tab equ 9
hline equ 196
marker equ 90909090h
cr_lf_tab db cr,lf,tab,tab,0
init_txt db 50 dup(hline),cr,lf
caption db 'Virogen''s PE Encryptor v0.75, (c)1998 Virogen[NOP]'
ifndef console_app
db 0
endif
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,0
success_txt:
ifdef console_app
db cr,lf
endif
db 'Successfully encrypted!'
ifdef console_app
db 0
endif
file_txt db cr,lf,' Installed on file: ',tab,0
db 400 dup (0) ; plenty of space
obj_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 increase!',0
already_txt:
ifdef console_app
db cr,lf,'File appears to already be encrypted. Encrypting again.',0
endif
db 'File appears to already be encrypted. Do you wish to encrypt again?',0
append_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.',0
error_txt:
ifdef console_app
db cr,lf,' '
endif
db 'There was an error encrypting the file!',cr,lf
ifdef console_app
db 0
endif
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.',0
doing_obj_txt db cr,lf,'Encrypting object: ',tab,0
skip_obj_txt db cr,lf,'Skipping object: ',tab,0
found_hole_obj db cr,lf,'Found hole in object: ',tab,0
done_txt db '..Done',0
creation dd 0,0 ; our file time structures
lastaccess dd 0,0
lastwrite dd 0,0
oldchksum dd 0
fsize dd 0
map_ptr dd 0
oldattrib dd 0 ; stored file attribs
fnameptr dd 0 ; ptr to file name we're inf
ptrpeheader dd 0
objPsize dd 0
maphandle dd 0
handle dd 0
objtblVA dd 0
objptr dd 0
lastobjimageoff dd 0
originalpsize dd 0
originalvsize dd 0
error db -1 ;
importtbl dd 0
exporttbl dd 0
byteswrote dd 0
hstdo dd 0
hstdi dd 0
ynbuf db 0
use_hole db 0
holeptr dd 0
bad_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 rwx
start:
ifdef console_app
call GetSHandle
lea ebx,init_txt
call WriteString
endif
call GetCommandLineA ; retrieve command line
or eax,eax
jz _exit_bad_cmd_line ; if none then abort /w msg
xchg esi,eax
sl:
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 our proggie name?
jnz not_eoc
cmp byte ptr [esi],'.'
jnz esl
not_eoc:
cmp eax,'.exe' ; .exe end of our proggie name?
jz esl
cmp eax,'.EXE' ; .EXE end of our proggie name?
jnz sl
esl:
lodsb
cmp al,' '
jz esl
cmp al,'"'
jz esl
dec esi
esl2:
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 message
endif
ifdef console_app
push esi
push offset fname_txt
call lstrcat
lea ebx,fname_txt
call WriteString
endif
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_success
no_hole_msg:
push offset nohole_txt
app_success:
push offset success_txt
call lstrcat
push 0
push offset caption
push offset success_txt
push 0
call MessageBoxA
endif
ifdef 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
endif
ifdef 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 WriteString
endif
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,eax
cmp eax,-1 ; if error then maybe 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
endif
ifdef console_app
lea ebx,already_txt
call WriteString
endif
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 key
mov dword ptr [esi+ID_OFF],marker ; save marker
;mov eax,[esi+imagebase]
;mov svd_imagebase,eax ; save the image base
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,eax
;cmp esi,edi
;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,1
no_room_in_hdr:
; Here we will traverse through the object table, encrypting objects
; which can be encrypted and also searching 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 WriteString
endif
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 eax[objflags],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 WriteString
endif
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_did
endif
next_obj:
ifdef console_app
lea ebx,skip_obj_txt
call WriteString
mov ebx,eax
call WriteString
endif
next_did:
add eax,40 ; increment to next object record
loop otbl_loop
done_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
; the user wants to. dunno if this is 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_encrypt
go_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 of object
mov [eax+objpoff],edx ; set physical offset of obj
inc word ptr [esi+numObj] ; increment number of objects
jmp after_apop
go_append:
popad
after_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_entry
in_hole_no_psize:
mov eax,originalvsize
not_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_entry
go_pe_hdr_hole:
mov eax,holeptr
sub eax,map_ptr
new_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_hole
mov edi,holeptr
jmp copy_to_hdr
not_hdr_hole:
cmp use_hole,1 ; if in hole then install at end of vsize
jz endvsize
add edi,originalpsize ; add original physical size
jmp go_copy
endvsize:
add edi,originalvsize ; add original virtual size
go_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.<g>
;
xor ecx,ecx
call create_mapping
jc unmapped
call GetPEHeader
lea eax,[esi+checksum]
push eax ; destination of checksum in hdr
push offset oldchksum
push fsize ; 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 infection
unmapped:
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+objpoff],0 ; make sure physical offset isn't 0
jz ret_stc
cmp dword ptr [eax+objpsize],0 ; make sure physical size isn't 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,[eax]
jz ret_stc
or ebx,ebx
jnz bobj_loop
clc
ret
ret_stc:
stc
ret
test_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_stc2
not_bad:
add esi,4
loop rva_loop
popad
clc
ret
ret_stc2:
popad
stc
ret
endp
GetPEHeader proc
mov esi,[eax+3Ch] ; where PE hdr pointer is
add esi,eax
mov ptrpeheader,esi ; esi->PE Hdr
ret
GetPEHeader 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:
ret
create_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
ret
api_err:
stc
ret
test_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
ret
align_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
ret
OpenFile endp
ifdef console_app
GetSHandle proc
push -11
call GetStdHandle
mov [hstdo],eax
push -10
call GetStdHandle
mov [hstdi],eax
ret
GetSHandle endp
WriteString proc
pushad
mov edi,ebx
xor eax,eax
mov ecx,0fffh
cld
sc_loop:
scasb ; find end of string
jz fnd
loop sc_loop
fnd:
mov ecx,edi
sub ecx,ebx
push 0
push offset byteswrote
push ecx
push ebx
push [hstdo]
call WriteConsoleA
popad
ret
WriteString 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
ret
exit_y:
clc
ret
GetYN endp
endif
end start
ends