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