SafeDisc-1 question

Laurent Pinchart laurent.pinchart at skynet.be
Thu May 23 14:44:50 CDT 2002


> To Laurent Pinchart, is there any way you could rework
> the SafeDisc-1 Patch you made to compile against the
> current tree (clean or not) and send it here?  I may
> be able to do some cleaning up on it and submit it,
> god willing ;).  I would need both the possible DMCA
> violation and safe partions to be able to do anything
> though...

All you need to do is to ask :-)

Here are the 2 diffs against the latest CVS (a CVS commit which modified a 
file I was working on occured when I was preparing the patch, so I don't 
expect my 'latest' CVS to stay 'latest' for long :-)

You should apply safedisc-safe.diff first.

Please let me know if you need any other information.

Thanks for your help.

Laurent Pinchart
-------------- next part --------------
--- memory/emulate.c	Thu Jan  1 01:00:00 1970
+++ memory/emulate.c	Thu May  9 17:35:27 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__ */
Index: dlls/ntdll/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.27
diff -u -r1.27 Makefile.in
--- dlls/ntdll/Makefile.in	14 May 2002 20:55:01 -0000	1.27
+++ dlls/ntdll/Makefile.in	23 May 2002 18:54:33 -0000
@@ -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 \
Index: dlls/ntdll/signal_i386.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v
retrieving revision 1.35
diff -u -r1.35 signal_i386.c
--- dlls/ntdll/signal_i386.c	16 May 2002 20:32:16 -0000	1.35
+++ dlls/ntdll/signal_i386.c	23 May 2002 18:54:40 -0000
@@ -679,6 +679,7 @@
 {
     EXCEPTION_RECORD rec;
     DWORD page_fault_code = EXCEPTION_ACCESS_VIOLATION;
+    DWORD 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
Index: include/miscemu.h
===================================================================
RCS file: /home/wine/wine/include/miscemu.h,v
retrieving revision 1.46
diff -u -r1.46 miscemu.h
--- include/miscemu.h	10 Mar 2002 00:02:34 -0000	1.46
+++ include/miscemu.h	23 May 2002 18:54:49 -0000
@@ -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*);
Index: include/wine/server_protocol.h
===================================================================
RCS file: /home/wine/wine/include/wine/server_protocol.h,v
retrieving revision 1.35
diff -u -r1.35 server_protocol.h
--- include/wine/server_protocol.h	25 Apr 2002 22:58:59 -0000	1.35
+++ include/wine/server_protocol.h	23 May 2002 18:54:56 -0000
@@ -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 */
Index: memory/instr.c
===================================================================
RCS file: /home/wine/wine/memory/instr.c,v
retrieving revision 1.15
diff -u -r1.15 instr.c
--- memory/instr.c	11 May 2002 23:01:12 -0000	1.15
+++ memory/instr.c	23 May 2002 18:54:58 -0000
@@ -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
Index: scheduler/process.c
===================================================================
RCS file: /home/wine/wine/scheduler/process.c,v
retrieving revision 1.182
diff -u -r1.182 process.c
--- scheduler/process.c	22 May 2002 21:32:50 -0000	1.182
+++ scheduler/process.c	23 May 2002 18:55:04 -0000
@@ -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>
@@ -43,6 +44,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);
@@ -126,6 +128,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 );
@@ -416,6 +421,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();
 
@@ -440,7 +459,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;
@@ -481,7 +500,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;
 
@@ -513,6 +533,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",
Index: server/process.c
===================================================================
RCS file: /home/wine/wine/server/process.c,v
retrieving revision 1.83
diff -u -r1.83 process.c
--- server/process.c	26 Apr 2002 19:05:18 -0000	1.83
+++ server/process.c	23 May 2002 18:55:07 -0000
@@ -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 */
Index: server/process.h
===================================================================
RCS file: /home/wine/wine/server/process.h,v
retrieving revision 1.27
diff -u -r1.27 process.h
--- server/process.h	22 Mar 2002 00:21:23 -0000	1.27
+++ server/process.h	23 May 2002 18:55:07 -0000
@@ -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 );
 
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.36
diff -u -r1.36 protocol.def
--- server/protocol.def	25 Apr 2002 22:58:59 -0000	1.36
+++ server/protocol.def	23 May 2002 18:55:12 -0000
@@ -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
 
Index: server/ptrace.c
===================================================================
RCS file: /home/wine/wine/server/ptrace.c,v
retrieving revision 1.14
diff -u -r1.14 ptrace.c
--- server/ptrace.c	10 Mar 2002 00:18:36 -0000	1.14
+++ server/ptrace.c	23 May 2002 18:55:13 -0000
@@ -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 ))
Index: server/trace.c
===================================================================
RCS file: /home/wine/wine/server/trace.c,v
retrieving revision 1.132
diff -u -r1.132 trace.c
--- server/trace.c	26 Apr 2002 19:05:18 -0000	1.132
+++ server/trace.c	23 May 2002 18:55:20 -0000
@@ -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	Thu Jan  1 01:00:00 1970
+++ documentation/safedisc.txt	Fri May  3 00:49:13 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	Thu Jan  1 01:00:00 1970
+++ include/secdrv.h	Sat Apr  6 23:32:54 2002
@@ -0,0 +1,58 @@
+/*
+ * 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;
+    DWORD dwVersionMinor;
+    DWORD 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;
+    DWORD dwVersionMinor;
+    DWORD 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	Thu Jan  1 01:00:00 1970
+++ win32/secdrv.c	Thu May 23 20:52:08 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;
+static unsigned int 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 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 != 0\n" );
+		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;
+}
Index: dlls/ntdll/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.27
diff -u -r1.27 Makefile.in
--- dlls/ntdll/Makefile.in	14 May 2002 20:55:01 -0000	1.27
+++ dlls/ntdll/Makefile.in	23 May 2002 18:54:33 -0000
@@ -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 \
Index: win32/device.c
===================================================================
RCS file: /home/wine/wine/win32/device.c,v
retrieving revision 1.62
diff -u -r1.62 device.c
--- win32/device.c	23 May 2002 19:35:18 -0000	1.62
+++ win32/device.c	23 May 2002 19:42:22 -0000
@@ -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 }
 };
 
@@ -480,6 +490,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 );
@@ -1502,6 +1518,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-devel mailing list