Semi-cleaned SafeDisc-1

Dustin Navea speeddymon at yahoo.com
Fri May 24 15:21:00 CDT 2002


I know this probably isn't clean enough to put into
wine yet, but it is a start, so I am at least
attempting to get it put in, also, if someone wants to
download it for me for backup purposes, as I seem to
frequently delete the new copy of my patches rather
than the old one ;)

-Dustin

Note that these are created against 05/22/2002 tree
and may/may not apply cleanly to older/newer trees. 
Also note that you need to apply safedisc-safe.diff
before safedisc-dmca.diff in order to get the
functions in the correct order...

__________________________________________________
Do You Yahoo!?
LAUNCH - Your Yahoo! Music Experience
http://launch.yahoo.com
-------------- next part --------------
--- memory/emulate.c	Wed Dec 31 18:00:00 1969
+++ memory/emulate.c	Thu May 23 20:40:41 2002
@@ -0,0 +1,53 @@
+/*
+ * Emulation of privileged memory
+ *
+ * Copyright 2002 Laurent Pinchart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "windef.h"
+#include "wingdi.h"
+#include "wine/winuser16.h"
+#include "module.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(virtual);
+
+#ifdef __i386__
+
+/***********************************************************************
+ *           MEMORY_SharedUserData
+ *
+ * Handles exceptions for the SharedUserData access.
+ */
+BOOL MEMORY_SharedUserData( LPVOID arg, LPCVOID addr )
+{
+    DWORD dwProtection;
+    BOOL ret;
+
+    TRACE( "MEMORY_SharedUserData\n" );
+
+    ret = VirtualProtect( (LPVOID)0x7ffe0000, 0x10000, PAGE_READWRITE, &dwProtection );
+    if ( ret )
+    {
+	*(LPDWORD)0x7ffe0000 = 0x12345678;
+	ret = VirtualProtect( (LPVOID)0x7ffe0000, 0x10000, PAGE_READONLY, &dwProtection );
+    }
+
+    return ret;
+}
+
+#endif  /* __i386__ */
--- dlls/ntdll/Makefile.in	Tue May 14 15:55:01 2002
+++ dlls/ntdll/Makefile.in	Thu May 23 22:57:27 2002
@@ -32,6 +32,7 @@
 	$(TOPOBJDIR)/loader/ne/segment.c \
 	$(TOPOBJDIR)/memory/atom.c \
 	$(TOPOBJDIR)/memory/codepage.c \
+	$(TOPOBJDIR)/memory/emulate.c \
 	$(TOPOBJDIR)/memory/environ.c \
 	$(TOPOBJDIR)/memory/global.c \
 	$(TOPOBJDIR)/memory/heap.c \
--- dlls/ntdll/signal_i386.c	Thu May 16 15:32:16 2002
+++ dlls/ntdll/signal_i386.c	Thu May 23 22:23:28 2002
@@ -678,7 +678,8 @@
 static void do_segv( CONTEXT *context, int trap_code, void *cr2, int err_code )
 {
     EXCEPTION_RECORD rec;
-    DWORD page_fault_code = EXCEPTION_ACCESS_VIOLATION;
+    DWORD page_fault_code = EXCEPTION_ACCESS_VIOLATION,
+          priv_instr_code = EXCEPTION_PRIV_INSTRUCTION;

 #ifdef CR2_sig
     /* we want the page-fault case to be fast */
@@ -708,8 +709,8 @@
     case T_SEGNPFLT:  /* Segment not present exception */
     case T_PROTFLT:   /* General protection fault */
     case T_UNKNOWN:   /* Unknown fault code */
-        if (INSTR_EmulateInstruction( context )) return;
-        rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+        if (INSTR_EmulateInstruction( context, &priv_instr_code )) return;
+        rec.ExceptionCode = priv_instr_code;
         break;
     case T_PAGEFLT:  /* Page fault */
 #ifdef CR2_sig
--- include/miscemu.h	Sat Mar  9 18:02:34 2002
+++ include/miscemu.h	Thu May 23 21:22:23 2002
@@ -167,7 +167,7 @@
 extern UINT DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */

 /* memory/instr.c */
-extern BOOL INSTR_EmulateInstruction( CONTEXT86 *context );
+extern BOOL INSTR_EmulateInstruction( CONTEXT86 *context, DWORD *exception_code );

 /* msdos/interrupts.c */
 typedef void (WINAPI *INTPROC)(CONTEXT86*);
--- include/wine/server_protocol.h	Thu Apr 25 17:58:59 2002
+++ include/wine/server_protocol.h	Thu May 23 21:22:23 2002
@@ -296,6 +296,7 @@
 struct init_process_done_reply
 {
     struct reply_header __header;
+    int          suspended;
     int          debugged;
 };

@@ -3198,6 +3199,6 @@
     struct get_window_properties_reply get_window_properties_reply;
 };

-#define SERVER_PROTOCOL_VERSION 79
+#define SERVER_PROTOCOL_VERSION 80

 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
--- memory/instr.c	Sat May 11 18:01:12 2002
+++ memory/instr.c	Thu May 23 21:22:23 2002
@@ -396,7 +396,7 @@
  *
  * Emulate a privileged instruction. Returns TRUE if emulation successful.
  */
-BOOL INSTR_EmulateInstruction( CONTEXT86 *context )
+BOOL INSTR_EmulateInstruction( CONTEXT86 *context, DWORD *exception_code )
 {
     int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
     SEGPTR gpHandler;
@@ -686,7 +686,9 @@
         case 0xcd: /* int <XX> */
             if (long_op)
             {
-                ERR("int xx from 32-bit code is not supported.\n");
+                ERR("int 0x%02x from 32-bit code is not supported.\n", instr[1]);
+                if (instr[1] == 0x01)
+                    *exception_code = EXCEPTION_ACCESS_VIOLATION;
                 break;  /* Unable to emulate it */
             }
             else
--- scheduler/process.c	Tue May 21 14:42:31 2002
+++ scheduler/process.c	Thu May 23 21:22:23 2002
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -42,6 +43,7 @@
 #include "wine/server.h"
 #include "options.h"
 #include "wine/debug.h"
+#include "global.h"

 WINE_DEFAULT_DEBUG_CHANNEL(process);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
@@ -125,6 +127,9 @@
 /* scheduler/pthread.c */
 extern void PTHREAD_init_done(void);

+/* memory/emulate.c */
+extern BOOL MEMORY_SharedUserData(LPVOID, LPCVOID);
+
 extern BOOL MAIN_MainInit(void);

 typedef WORD (WINAPI *pUserSignalProc)( UINT, DWORD, DWORD, HMODULE16 );
@@ -306,6 +311,20 @@
 	SetStdHandle( STD_ERROR_HANDLE,  current_startupinfo.hStdError  );
     }

+    /* Reserves a PAGE_NOACCESS at 0x7ffe0000. That page is used as shared
+     * memory between kernel space and user space (see SharedUserData in
+     * ntddk.h). It looks like it is at 0xffdf0000 on NT5. That is still to
+     * be checked.
+     */
+    if ( VirtualAlloc( (LPVOID)0x7ffe0000, 0x10000, MEM_RESERVE|MEM_COMMIT, PAGE_NOACCESS ) == (LPCVOID)0x07ffe0000 )
+    {
+	VIRTUAL_SetFaultHandler( (LPCVOID)0x7ffe0000, MEMORY_SharedUserData, 0 );
+    }
+    else
+    {
+	WARN( "Unable to map SharedUserData, SafeDisc protection won't be supported\n" );
+    }
+
     /* Now we can use the pthreads routines */
     PTHREAD_init_done();

@@ -330,7 +349,7 @@
  */
 static void start_process(void)
 {
-    int debugged, console_app;
+    int suspended, debugged, console_app;
     LPTHREAD_START_ROUTINE entry;
     WINE_MODREF *wm;
     HFILE main_file = main_exe_file;
@@ -371,7 +390,8 @@
         req->gui      = !console_app;
         wine_server_add_data( req, main_exe_name, strlen(main_exe_name) );
         wine_server_call( req );
-        debugged = reply->debugged;
+        suspended = reply->suspended;
+        debugged  = reply->debugged;
     }
     SERVER_END_REQ;

@@ -403,6 +423,8 @@
     PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
     /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
     if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
+
+    if (suspended) raise( SIGSTOP );

     if (TRACE_ON(relay))
         DPRINTF( "%08lx:Starting process %s (entryproc=%p)\n",
--- server/process.c	Fri Apr 26 14:05:18 2002
+++ server/process.c	Thu May 23 21:22:23 2002
@@ -382,6 +382,14 @@
 }


+/* signal the parent that a process init is finished */
+void process_init_done( struct process *process )
+{
+    set_event( process->init_event );
+    release_object( process->init_event );
+    process->init_event = NULL;
+}
+
 /* get a process from an id (and increment the refcount) */
 struct process *get_process_from_id( void *id )
 {
@@ -896,13 +904,27 @@
     if ((process->exe.namelen = get_req_data_size()))
         process->exe.filename = memdup( get_req_data(), process->exe.namelen );

-    generate_startup_debug_events( current->process, req->entry );
-    set_event( process->init_event );
-    release_object( process->init_event );
-    process->init_event = NULL;
+    generate_startup_debug_events( process, req->entry );
     if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 );
-    if (current->suspend + current->process->suspend > 0) stop_thread( current );
-    reply->debugged = (current->process->debugger != 0);
+
+    reply->suspended = 0;
+    reply->debugged  = (current->process->debugger != 0);
+    if (current->suspend + current->process->suspend > 0)
+    {
+        /* temporarily clear the init event so that ptrace functions work */
+        struct event *init_event = process->init_event;
+        process->init_event = NULL;
+        stop_thread( current );
+        process->init_event = init_event;
+
+        if (current->attached)
+        {
+            reply->suspended = 1;
+            continue_thread( current );  /* it will suspend itself */
+            return;
+        }
+    }
+    process_init_done( process );
 }

 /* open a handle to a process */
--- server/process.h	Thu Mar 21 18:21:23 2002
+++ server/process.h	Thu May 23 21:22:23 2002
@@ -90,6 +90,7 @@
 extern struct thread *create_process( int fd );
 extern struct process *get_process_from_id( void *id );
 extern struct process *get_process_from_handle( handle_t handle, unsigned int access );
+extern void process_init_done( struct process *process );
 extern int process_set_debugger( struct process *process, struct thread *thread );
 extern int debugger_detach( struct process* process, struct thread* debugger );

--- server/protocol.def	Thu Apr 25 17:58:59 2002
+++ server/protocol.def	Thu May 23 21:22:23 2002
@@ -276,6 +276,7 @@
     int          gui;          /* is it a GUI process? */
     VARARG(filename,string);   /* file name of main exe */
 @REPLY
+    int          suspended;    /* created suspended? */
     int          debugged;     /* being debugged? */
 @END

--- server/ptrace.c	Sat Mar  9 18:18:36 2002
+++ server/ptrace.c	Thu May 23 21:22:23 2002
@@ -79,7 +79,12 @@
         switch(sig)
         {
         case SIGSTOP:  /* continue at once if not suspended */
-            if (thread && (thread->process->suspend + thread->suspend)) break;
+            if (thread && (thread->process->suspend + thread->suspend))
+            {
+                /* check if this was the self-suspend upon process init */
+                if (thread->process->init_event) process_init_done( thread->process );
+                break;
+            }
             /* fall through */
         default:  /* ignore other signals for now */
             if (thread && get_thread_single_step( thread ))
--- server/trace.c	Fri Apr 26 14:05:18 2002
+++ server/trace.c	Thu May 23 21:22:23 2002
@@ -441,6 +441,7 @@

 static void dump_init_process_done_reply( const struct init_process_done_reply *req )
 {
+    fprintf( stderr, " suspended=%d,", req->suspended );
     fprintf( stderr, " debugged=%d", req->debugged );
 }

-------------- next part --------------
--- documentation/safedisc.txt	Wed Dec 31 18:00:00 1969
+++ documentation/safedisc.txt	Thu May 23 20:41:03 2002
@@ -0,0 +1,165 @@
+SafeDisc FAQ
+
+What is SafeDisc ?
+==================
+
+SafeDisc is a CD copy protection system designed for Microsoft Windows. It is
+widely used, especially to protect games. There are currently 2 main versions
+of SafeDisc around: SafeDisc 1 and SafeDisc 2.
+
+
+Is my program protected by SafeDisc ?
+=====================================
+
+Look at the root directory of the program CD. The following files are present
+on SafeDisc 1 protected programs:
+
+secdrv.sys
+drvmgt.dll
+clcd16.dll
+clcd32.dll
+clokspl.exe
+dplayerx.dll     (not present on the very first version of SafeDisc)
+
+In addition to these files, a .icd file contains the encrypted binary, while
+the main executable (usually game.exe) is only a wrapper used to load and
+decrypt the .icd file. Those two files are sometimes not stored directly in
+the root directory of the CD but only in the location of the installed
+program on your hard drive.
+
+For SafeDisc 2, only secdrv.sys and drvmgt.dll can be found on the CD. The
+encrypted binary and dplayerx.dll are now stored inside the wrapper (usually
+game.exe).
+
+
+How do I run SafeDisc protected programs with Wine ?
+====================================================
+
+If your version of SafeDisc is supported (see below), your program will run
+out-of-the-box (at least for SafeDisc related code :-) if you use NT mode
+(--winver nt40, --winver win2k or --winver winxp). Pick the version of NT that
+your program is the most likely to support (winxp with a 5 years old program
+isn't a good idea).
+
+
+How do I find out which version of SafeDisc my program uses ?
+=============================================================
+
+There is no publicaly available version numbering for SafeDisc. However, it
+seems that the version number is stored in the executable as 3 unsigned 32-bit
+integers. Using an hexadecimal editor, locate the following byte pattern in
+the wrapper (game.exe)
+
+> 426f475f 202a3930 2e302621 21202059   BoG_ *90.0&!!  Y
+> 793e0000                              y>..
+
+There should be 3 unsigned integers right after that, which are respectively
+the version, subversion an revision number.
+
+On some versions of SafeDisc there are 3 null integers following the pattern,
+before the version number. You'll then have to look at the 3 unsigned 32-bit
+integers right after
+
+> 426f475f 202a3930 2e302621 21202059   BoG_ *90.0&!!  Y
+> 793e0000 00000000 00000000 00000000   y>..............
+
+Don't forget that the numbers are stored in little endian and in hexadecimal.
+To convert numbers stored in little endian format, invert the 4 bytes of the
+32 bits integer (e.g. 2d000000 becomes 0000002d which is 45 in decimal).
+
+So, for instance, a version of 1.35.0 (0x00000001 0x00000023 0x00000000) would
+be coded as (in hex)
+
+> 01 00 00 00 23 00 00 00 00 00 00 00
+
+For SafeDisc 1 you can alternatively check the size of the dplayerx.dll file.
+
+dplayerx.dll size		SafeDisc version number
+-------------------------------------------------------
+156.160 bytes                   1.11.0
+165.888 bytes			1.35.0
+172.544 bytes                   1.40.4
+173.568 bytes                   1.45.0
+
+Another very important information is the secdrv.sys version number, which is
+unfortunately not easy to determine. For known secdrv.sys versions, you can
+check the file size according to the table below.
+
+secdrv.sys size			secdrv.sys version number
+---------------------------------------------------------
+14.304 bytes                    1.3.0 (SafeDisc 1.11.0)
+14.368 bytes			1.3.0 (SafeDisc 1.35.0)
+10.848 bytes                    1.3.0 (SafeDisc 1.40.4, 1.45.0)
+18.768 bytes			2.2.0 (SafeDisc 2.5.30)
+
+If you have another version of SafeDisc please contribute to these tables.
+
+
+Which version of SafeDisc are currently supported ?
+===================================================
+
+This hasn't been determined yet. SafeDisc support for Wine has been developped
+using a game protected with SafeDisc 1.35.0. SafeDisc 1.40.4 and 1.45.0 have
+been reported to work too. All SafeDisc versions which use secdrv.sys 1.3.0
+should work.
+
+Lower version of secdrv.sys might work too. SafeDisc 2 is not supported yet.
+
+
+How does SafeDisc 1 work ?
+==========================
+
+SafeDisc encrypts the real executable into a .icd file, and uses a wrapper to
+decrypt the executable.
+
+The wrapper contains 3 code sections: `.text', `.txt' and `.txt2'. `.txt' is
+encrypted.
+
+The wrapper starts by decrypting itself, using the checksum of `.text', the
+binary content of `.txt2' and some values which depend on debugger detection
+tests. If a debugger is loaded, if a software breakpoint is set in the first 8
+bytes of any of the kernel32.dll functions, or if the `.text' and `.txt2'
+sections have been modified (this includes setting a software breakpoint in
+the code), the `.txt' section won't be decrypted correctly and a crash will
+occur.
+
+On NT, the process of detecting a debugger involves loading the kernel-space
+driver secdrv.sys, which I implemented as a user-space code for Wine. On
+Windows 95, 98 or Me, it involves executing arbitrary code in ring 0 mode
+(kernel mode). This is not supported by Wine (as the underlying OS isn't as
+broken as win9x), so that's why you have to use NT mode.
+
+When the `.txt' section has been decrypted, the wrapper will then check for
+the CD key using direct SCSI operations on the CD driver. If the CD key
+doesn't match the expected value, a message box pops up to ask you to insert
+the original CD in the drive.
+
+The wrapper then loads and starts clokspl.exe for a still unknown purpose.
+
+The last stage consists in creating the game.icd in a suspended state. The
+suspended process memory is then written with some initialization code, and
+SetThreadContext is called to jump to that code. The initialization code will
+load dplayerx.dll (which is encrypted in the same way as the wrapper, with 3
+code sections), and will decrypt the main executable. Control is then
+transfered to the main executable, and the game starts.
+
+Have you ever tried to rename game.icd to game.exe, and run it ? It will
+crash, because WinMain is encrypted. It needs to be decrypted by the
+initialization code, which is found in the wrapper and in dplayerx.dll.
+
+That's pretty much all I know about SafeDisc. Don't ask me how to remove
+SafeDisc from a game. I don't know how to do so.
+
+If you have more information, especially about debugger detection and
+secdrv.sys, please let me know.
+
+
+My version of SafeDisc is not supported. What should I do ?
+===========================================================
+
+Implement support for it :-)
+
+For unsupported SafeDisc 1 versions you will probably 'only' need to implement
+the secdrv.sys that comes with your program. For SafeDisc 2 things are more
+difficult. I'm currently working on that, but please be patient.
+
--- include/secdrv.h	Wed Dec 31 18:00:00 1969
+++ include/secdrv.h	Thu May 23 21:51:29 2002
@@ -0,0 +1,54 @@
+/*
+ * SafeDisc copy protection driver
+ *
+ * Copyright 2002 Laurent Pinchart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WINE_SECDRV_H
+#define __WINE_SECDRV_H
+
+#include "windef.h"
+
+typedef struct _SECDRV_IOC_IN_BUFFER
+{
+    DWORD dwVersionMajor, dwVersionMinor, dwVersionPatch;
+
+    DWORD dwCommand;
+    BYTE bVerificationData[0x400];
+
+    DWORD cbUserData;
+    BYTE  bUserData[0x100];
+} SECDRV_IOC_IN_BUFFER, *PSECDRV_IOC_IN_BUFFER;
+
+typedef struct _SECDRV_IOC_OUT_BUFFER
+{
+    DWORD dwVersionMajor, dwVersionMinor, dwVersionPatch;
+
+    BYTE  bVerificationData[0x400];
+
+    DWORD cbUserData;
+    BYTE  bUserData[0x200];
+} SECDRV_IOC_OUT_BUFFER, *PSECDRV_IOC_OUT_BUFFER;
+
+#define SECDRV_CMD_INFO_DR		(0x0000003c)
+#define SECDRV_CMD_INFO_IDT		(0x0000003d)
+#define SECDRV_CMD_SETUP		(0x0000003e)
+
+extern BOOL SECDRV_DeviceIo_SafeDisc( LPVOID lpvInBuffer, DWORD cbInBuffer,
+				      LPVOID lpvOutBuffer, DWORD cbOutBuffer );
+
+#endif /* __WINE_SECDRV_H */
--- win32/secdrv.c	Wed Dec 31 18:00:00 1969
+++ win32/secdrv.c	Thu May 23 22:12:11 2002
@@ -0,0 +1,206 @@
+/*
+ * SafeDisc copy protection driver
+ *
+ * Copyright 2002 Laurent Pinchart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winerror.h"
+#include "file.h"
+#include "winioctl.h"
+#include "winnt.h"
+#include "secdrv.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(vxd);
+
+static BOOL SECDRV_GetDRInfo( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			      LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer );
+static BOOL SECDRV_GetIdtInfo( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			       LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer );
+static BOOL SECDRV_Setup( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			  LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer );
+static VOID SECDRV_BuildVerificationData( LPVOID lpBuffer );
+
+static unsigned int contextDr1 = 0x00000000, contextDr7 = 0x00000400;
+
+BOOL SECDRV_DeviceIo_SafeDisc( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			       LPVOID lpvOutBuffer, DWORD cbOutBuffer )
+{
+	PSECDRV_IOC_IN_BUFFER pInBuffer   = (PSECDRV_IOC_IN_BUFFER)lpvInBuffer;
+	PSECDRV_IOC_OUT_BUFFER pOutBuffer = (PSECDRV_IOC_OUT_BUFFER)lpvOutBuffer;
+	BOOL retv;
+
+	TRACE( "Secdrv %ld.%ld.%ld\n",
+	       pInBuffer->dwVersionMajor,
+	       pInBuffer->dwVersionMinor,
+	       pInBuffer->dwVersionPatch );
+
+	if ( ! pInBuffer || ! pOutBuffer )
+	{
+		FIXME( "pInBuffer: %p pOutBuffer: %p\n", pInBuffer, pOutBuffer );
+		return FALSE;
+	}
+
+	if ( cbInBuffer != 0x514 )
+	{
+		FIXME( "cbInBuffer: %lx\n", cbInBuffer );
+		return FALSE;
+	}
+
+	if ( cbOutBuffer != 0x610 && cbOutBuffer != 0xc18 )
+	{
+		FIXME( "cbOutBuffer: %lx\n", cbOutBuffer );
+		return FALSE;
+	}
+
+	retv = FALSE;
+
+	switch( pInBuffer->dwCommand ) {
+	case SECDRV_CMD_INFO_DR:
+		TRACE( "SECDRV_CMD_INFO_DR\n" );
+		retv = SECDRV_GetDRInfo( pInBuffer->bUserData, pInBuffer->cbUserData,
+					 pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	case SECDRV_CMD_INFO_IDT:
+		TRACE( "SECDRV_CMD_INFO_IDT\n" );
+		retv = SECDRV_GetIdtInfo( pInBuffer->bUserData, pInBuffer->cbUserData,
+					  pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	case SECDRV_CMD_SETUP:
+		TRACE( "SECDRV_CMD_INFO_SETUP\n" );
+		retv = SECDRV_Setup( pInBuffer->bUserData, pInBuffer->cbUserData,
+				     pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	default:
+		FIXME( "unsupported SafeDisc-1 command %lx\n", pInBuffer->dwCommand );
+		break;
+	}
+
+	if ( retv )
+	{
+	    pOutBuffer->dwVersionMajor = 3;
+	    pOutBuffer->dwVersionMinor = 5;
+	    pOutBuffer->dwVersionPatch = 0;
+	    SECDRV_BuildVerificationData( pOutBuffer->bVerificationData );
+	}
+
+	return retv;
+}
+
+static VOID SECDRV_BuildVerificationData( LPVOID lpBuffer )
+{
+	DWORD dwRandom = 0xf367ac7f;
+	LPDWORD lpDwBuffer = (LPDWORD)lpBuffer;
+	int i;
+
+	/* lpDwBuffer[0] should be initialized with KeTickCount.LowPart.
+	 * If done, KeTickCount.LowPart should also be accessible from user
+	 * space by a read operation at address 0x7ffe0000.
+	 */
+	lpDwBuffer[0] = 0x12345678;
+
+	for ( i = 3; i != 0; --i )
+	{
+		dwRandom = 0x361962e9 - dwRandom * 0x0d5acb1b;
+		lpDwBuffer[i]  = dwRandom;
+		lpDwBuffer[0] ^= dwRandom;
+	}
+}
+
+static BOOL SECDRV_GetDRInfo( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			      LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer )
+{
+	unsigned int dwDebugRegister;
+
+	if ( cbInBuffer != 0 )
+	{
+		FIXME( "cbInBuffer == %ld when it should be\n
+			cbInBuffer == 0", cbInBuffer );
+		return FALSE;
+	}
+
+	if ( contextDr1 == 0xbd331200 )
+	{
+		dwDebugRegister = 0x3871dd10;
+	}
+	else
+	{
+		dwDebugRegister = contextDr7;
+	}
+
+	*(LPDWORD)lpvOutBuffer = dwDebugRegister & 0x00000500;
+	*lpCbOutBuffer = 4;
+
+	return TRUE;
+}
+			      
+static BOOL SECDRV_GetIdtInfo( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			       LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer )
+{
+	struct _IDTR {
+		WORD limit;
+		DWORD base;
+	} idtr;
+
+	ULONGLONG *idt;
+	DWORD dwOffset;
+
+	if ( cbInBuffer != 0 )
+		return FALSE;
+
+	asm( "sidtl %0" : "=m"(idtr) );
+	idt = (ULONGLONG*)idtr.base;
+
+	/* dwOffset = ( idt[3] & 0x0000ffff ) - ( idt[1] & 0x0000ffff ); */
+	dwOffset = 0x1000;
+
+	if ( dwOffset > 0x100 )
+	{
+		*(LPDWORD)lpvOutBuffer = 0x2c8;
+	}
+	else
+	{
+		*(LPDWORD)lpvOutBuffer = dwOffset;
+		contextDr1 = 0xbd331200;
+	}
+
+	*lpCbOutBuffer = 4;
+
+	return TRUE;
+}
+
+static BOOL SECDRV_Setup( LPVOID lpvInBuffer, DWORD cbInBuffer,
+			  LPVOID lpvOutBuffer, LPDWORD lpCbOutBuffer )
+{
+	if ( cbInBuffer != 0 )
+		return FALSE;
+
+	*(LPDWORD)lpvOutBuffer = 0x5278d11b;
+	*lpCbOutBuffer = 4;
+
+	return TRUE;
+}
--- dlls/ntdll/Makefile.in	Thu May 23 23:14:32 2002
+++ dlls/ntdll/Makefile.in	Thu May 23 21:22:51 2002
@@ -93,6 +93,7 @@
 	$(TOPOBJDIR)/win32/init.c \
 	$(TOPOBJDIR)/win32/kernel32.c \
 	$(TOPOBJDIR)/win32/newfns.c \
+	$(TOPOBJDIR)/win32/secdrv.c \
 	$(TOPOBJDIR)/win32/time.c \
 	cdrom.c \
 	critsection.c \
--- win32/device.c	Thu May 16 22:31:09 2002
+++ win32/device.c	Thu May 23 21:22:51 2002
@@ -40,6 +40,7 @@
 #include "msdos.h"
 #include "miscemu.h"
 #include "stackframe.h"
+#include "secdrv.h"
 #include "wine/server.h"
 #include "wine/debug.h"
 
@@ -105,6 +106,12 @@
 			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
 			      LPDWORD lpcbBytesReturned,
 			      LPOVERLAPPED lpOverlapped);
+
+static BOOL DeviceIo_SECDRV (DWORD dwIoControlCode, 
+			      LPVOID lpvInBuffer, DWORD cbInBuffer,
+			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
+			      LPDWORD lpcbBytesReturned,
+			      LPOVERLAPPED lpOverlapped);
 /*
  * VxD names are taken from the Win95 DDK
  */
@@ -251,6 +258,9 @@
     /* WINE additions, ids unknown */
     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
 
+    /* SafeDisc copy protection */
+    { "SECDRV", 0xef00, NULL, NULL },
+
     { NULL,       0,      NULL, NULL }
 };
 
@@ -479,6 +489,12 @@
     			SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
     			return FALSE;
     			break;
+		case CTL_CODE( 0xef00, 0x901, METHOD_NEITHER, FILE_ANY_ACCESS ):
+			return DeviceIo_SECDRV( dwIoControlCode,
+                                                lpvInBuffer, cbInBuffer,
+                                                lpvOutBuffer, cbOutBuffer, 
+                                                lpcbBytesReturned, lpOverlapped );
+			break;
 		default:
     			FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
     			SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
@@ -1501,6 +1517,31 @@
 	}
 	return TRUE;
 }
+
+/* this is used by SafeDisc copy protection */
+static BOOL DeviceIo_SECDRV(DWORD dwIoControlCode, 
+			    LPVOID lpvInBuffer, DWORD cbInBuffer,
+			    LPVOID lpvOutBuffer, DWORD cbOutBuffer,
+			    LPDWORD lpcbBytesReturned,
+			    LPOVERLAPPED lpOverlapped)
+{
+	switch ((dwIoControlCode >> 2) & 0x0fff) {
+	case 0x901:	/* SafeDisc */
+		return SECDRV_DeviceIo_SafeDisc(lpvInBuffer, cbInBuffer,
+					        lpvOutBuffer, cbOutBuffer);
+	default:
+		FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
+			dwIoControlCode,
+			lpvInBuffer,cbInBuffer,
+			lpvOutBuffer,cbOutBuffer,
+			lpcbBytesReturned,
+			lpOverlapped
+		);
+		break;
+	}
+	return FALSE;
+}
+
 /* pccard */
 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
 			      LPVOID lpvInBuffer, DWORD cbInBuffer,


More information about the wine-patches mailing list