OK, here is a little summary on where we are with safedisk, here by safedisk I always mean safedisk 1. Safedisk protected games are packed into an encrypted ICD file, in my case the game executable is called EMPIRES2.ICD. Safedisk is actually made up of a little loader, empires2.exe (But this depends on the name of the game), and a kernel mode driver, Secdrv.sys. A safedisk service is installed, and in windows a kernel mode service is just a driver. The loader starts the secdrv service, so I've hacked advapi32 to call the NT function NtLoadDriver when it detects a kernel mode service. This function, after a couple of checks, passes the call to the ntoskrnl program I've written, Microsoft has ntoskrnl<->ntdll communication done by a fancy exception rising/handling system, I have just gone for a named pipe, as we don't use ntoskrnl as a real kernel (In windows everything you do causes loads of calls to ntoskrnl, in wine ntoskrnl is seldom used at all and only handles very few calls). Ntoskrnl loads the driver, and it successfully initialises. At this point the safedisk loader communicates with its driver using DeviceIoControl, it passes an input buffer, that contains some instructions for the driver, and an output buffer that is meant to receive some well defined values that are meant to tell the user mode loader if everything is OK (For example a debugger isn't loaded). The loader also tries to get device handles for well known debuggers, this isn't an issue for us. DeviceIoControl passes the call to NtDeviceIoControlFile, that passes the call on to ntoskrnl. A windows driver handles user mode IO requests via a function called DeviceDispatchControl, it's address is put in the member of the DEVICE_OBJECT struct that the driver's initialisation function fills for the system (This is the DriverEntry routine). In wine currently a device handle is a pointer to a DEVICE_OBJECT struct, guys in #reactos have confirmed this is how things work in windows, and even if AJ thinks we should have real file handles this approach makes no sense to me whatsoever. DeviceDispatchControl in safedisk 1 check the control code passed to DeviceIoControl (It must always be 0xef002407), it then reads the input buffer, if byte 0xc in the buffer is 0x3c it checks the debug registers, other values trigger other checks. It also checks the length of both input and output buffers. It should then read the debug registers, and this should rise and exception that we will somehow handle. However for some unknown reason this doesn't happen, and the status of the IO operation is STATUS_UNSUCCESSFUL, note that this value is in the IRP sturct under Irp.IoStatus.Status, DispatchDeviceControl always returns 0. At this point I would like to know if other safedisk 1 protected games yield different results. I would love to step trough secdrv.sys with winedbg, but it just hangs or crashes. The code in ntoskrnl prints the interesting buffer values that secdrv.sys checks for, it currently prints
trace:ntoskrnl:NtDeviceIoControlFile (0x40340ba8,(nil),(nil),(nil),0x4068d9c8,0xef002407,0x414e1498,0x00000514,0x414e19ac,0x00000610) trace:ntoskrnl:driver_control driver_control is at 0x405cea80 trace:ntoskrnl:driver_control Handling IoContorl, handle is 0x40340ba8, ControlCode is ef002407, OutputBufferLength is 610, InputBufferLength is 514 trace:ntoskrnl:driver_control InputBuffer[0xc] is 3c, InputBuffer[410] is 0 fixme:ntoskrnl:IofCompleteRequest stub! trace:ntoskrnl:driver_control IRP_MJ_DEVICE_CONTROL returned 0, IoStatus it c0000001, Infomation is 0 trace:ntoskrnl:driver_control Irp.UserBuffer[0x410] is 0, Irp.UserBuffer[0x40c] is 0
In case of success Irp.UserBuffer[0x410] should be 0x00000500 and Irp.UserBuffer[0x40c] should be 4. All that is needed to run safedisk up to the point where it can run ATM is at http://spazioinwind.libero.it/nonsolomicrosoft/safedisk.html Please get all your safedisk 1 games and try it out, the more people try it the better.