On Sunday 03 November 2002 15:53, Mark Hannessen wrote:
> here we are.
>
> Zsolt about Safedisc 1.x
>
> > When the patch was published, there was a discussion, and the conclusion
> > was that the code is very probably legal, and is not against DMCA
> >
> > Are you sure about the above statements? Have you checked that, or it is
> > just your opinion?
>
> Carlos words regarding copy protection:
> > You aren't giving hints to decrypt some code, simply implementing the
> > win32 API, and sometimes implementing a PC architecture, it is far away
> > of decrypt code ;).
>
> well i'am not a lawyer, so i guess i was probably wrong about
> copyprotection being illegal after all.
>
> > Zsolt also said he could provide a safedisc patch against the current
> > cvs.
>
> Zsolt, could you give us a status of your safedisc patch ?

That is not my patch. It was developed by Laurent Pinchart. I tried to help 
him, but I could not (I'm not too good in reverse engineering, driver 
programming). Alexandre was also providing some code to him (some server 
communication fixes).

All I have done is to maintain it in my cvs checkout. (I had to readd some 
code Alexandre has removed, which broke the patch).
So I have it, and it works. I use a program (a dictionary) protected by 
safedisc every day.

> does it work with all winver versions or is this one limited to nt40 ?

It runs only in nt40, win2k or winxp. That is the NT architectures. (Though I 
have only tested nt40).
The reason is that the debugger detection code used by the safedisc enabled 
program is different if you run 9x or NT architectures. On 9x architecture it 
tries to play with the debug registers, and other nasty things. On NT it 
playes more nicely, because NT is a more restricted OS.
So it may be possible to adapt it to win9x, but you will need some severe 
knowledge of the x86 architecture.

> ( most games do not run in nt40 mode )

I dont know nothing about that. But many games run on win2k :)


> is it safedisc 1.x only or safedisc 2.x as well.

It is safedisc 1.x only. Laurent had plans to implement 2.x as well, but he 
did not have a program protected with it, so that never happened.
And after some time, he dissappeared from the list. (Last I heard about him 
was when the patch was broken by Alexandre's changes. I waited for him to 
provide an updated patch, but probably he was waiting for Alexandre to fix 
the issue. After some time, I have reverted some of the Alexandre's changes 
to make the patch work.)

> anyway, any work on copyprotection is very very usefull for everbody.
> so please impent everything you have.

I dont understand the 'impent' word :) But here is the patch against the cvs 
which I have done 1-2 weeks ago. I think it should apply to current cvs 
without major problems. If not let me know, and I will make an updated 
version.

Also, there was many discussion on wine-devel about this patch. Starting with 
my mail 'debugging longman dictionary' somewhere in March of 2002.
Then there is the safedisc FAQ posted by Laurent at Mon, 29 Apr 2002 21:32:29 
+0200
About the same time was the original patch posted to wine-patches.
There were some more discussion in May of 2002.
And also there was an attempt by Dustin Navea to resolve the (technical) 
issues about the patch, so it could be applied to cvs, but I could not find 
the mail in my archive, tough if I remember correctly then there is a mail 
with detailed explanation by Alexandre, of the reasons the patch is not 
applied.
Hope this is enough pointer for you to find the info you need in the mail 
archives.

Regards
Zsolt
? include/secdrv.h
? memory/emulate.c
? win32/secdrv.c
Index: dlls/ntdll/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.38
diff -u -p -r1.38 Makefile.in
--- dlls/ntdll/Makefile.in	18 Oct 2002 23:46:29 -0000	1.38
+++ dlls/ntdll/Makefile.in	26 Oct 2002 15:25:31 -0000
@@ -32,6 +32,7 @@ C_SRCS = \
 	$(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 \
@@ -88,6 +89,7 @@ C_SRCS = \
 	$(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: dlls/ntdll/signal_i386.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v
retrieving revision 1.46
diff -u -p -r1.46 signal_i386.c
--- dlls/ntdll/signal_i386.c	12 Sep 2002 22:07:03 -0000	1.46
+++ dlls/ntdll/signal_i386.c	26 Oct 2002 15:25:44 -0000
@@ -729,6 +729,7 @@ static void do_segv( CONTEXT *context, i
 {
     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 */
@@ -758,8 +759,8 @@ static void do_segv( CONTEXT *context, i
     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.55
diff -u -p -r1.55 miscemu.h
--- include/miscemu.h	23 Oct 2002 22:24:10 -0000	1.55
+++ include/miscemu.h	26 Oct 2002 15:26:04 -0000
@@ -196,7 +196,7 @@ extern LPVOID DOSMEM_MapDosToLinear(UINT
 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.47
diff -u -p -r1.47 server_protocol.h
--- include/wine/server_protocol.h	21 Oct 2002 23:43:05 -0000	1.47
+++ include/wine/server_protocol.h	26 Oct 2002 15:26:13 -0000
@@ -220,6 +220,7 @@ struct get_new_process_info_reply
     thread_id_t  tid;
     obj_handle_t thandle;
     int          success;
+    obj_handle_t event;
 };
 
 
@@ -298,6 +299,7 @@ struct init_process_done_request
 struct init_process_done_reply
 {
     struct reply_header __header;
+    int          suspended;
     int          debugged;
 };
 
Index: memory/instr.c
===================================================================
RCS file: /home/wine/wine/memory/instr.c,v
retrieving revision 1.19
diff -u -p -r1.19 instr.c
--- memory/instr.c	23 Oct 2002 22:24:10 -0000	1.19
+++ memory/instr.c	26 Oct 2002 15:26:24 -0000
@@ -397,7 +397,7 @@ static void INSTR_outport( WORD port, in
  *
  * 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;
@@ -685,6 +685,11 @@ BOOL INSTR_EmulateInstruction( CONTEXT86
             break;  /* Unable to emulate it */
 
         case 0xcd: /* int <XX> */
+            if (long_op && instr[1] == 0x01)
+            {
+                *exception_code = EXCEPTION_ACCESS_VIOLATION;
+                break;
+            }
            if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem())
                ERR("could not initialize interrupt handling\n");
            else {
Index: scheduler/process.c
===================================================================
RCS file: /home/wine/wine/scheduler/process.c,v
retrieving revision 1.202
diff -u -p -r1.202 process.c
--- scheduler/process.c	17 Oct 2002 18:24:36 -0000	1.202
+++ scheduler/process.c	26 Oct 2002 15:26:32 -0000
@@ -46,6 +46,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);
@@ -130,6 +131,9 @@ extern STARTUPINFOA current_startupinfo;
 /* scheduler/pthread.c */
 extern void PTHREAD_init_done(void);
 
+/* memory/emulate.c */
+extern BOOL MEMORY_SharedUserData(LPVOID, LPCVOID);
+
 extern void RELAY_InitDebugLists(void);
 extern BOOL MAIN_MainInit(void);
 
@@ -457,6 +461,20 @@ static BOOL process_init( char *argv[] )
 	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();
 
@@ -482,7 +500,7 @@ static BOOL process_init( char *argv[] )
  */
 static void start_process(void)
 {
-    int debugged, console_app;
+    int suspended, debugged, console_app;
     LPTHREAD_START_ROUTINE entry;
     WINE_MODREF *wm;
     HANDLE main_file = main_exe_file;
@@ -521,7 +539,8 @@ static void start_process(void)
         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;
 
@@ -554,6 +573,8 @@ static void start_process(void)
     /* 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",
                  GetCurrentThreadId(), main_exe_name, entry );
@@ -956,6 +977,7 @@ static BOOL create_process( HANDLE hFile
 {
     BOOL ret, success = FALSE;
     HANDLE process_info;
+    HANDLE load_done_evt = 0;
     startup_info_t startup_info;
 
     /* fill the startup info structure */
@@ -1040,10 +1062,25 @@ static BOOL create_process( HANDLE hFile
             info->hProcess    = reply->phandle;
             info->hThread     = reply->thandle;
             success           = reply->success;
+	    load_done_evt     = reply->event;
         }
     }
     SERVER_END_REQ;
 
+    /* Wait until process is initialized (or initialization failed) */
+    if (ret && load_done_evt)
+    {
+	DWORD res;
+	HANDLE handles[2];
+
+	handles[0] = info->hProcess;
+	handles[1] = load_done_evt;
+	res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
+	CloseHandle( load_done_evt );
+	if (res == STATUS_WAIT_0)  /* the process died */
+	    success = 0;
+    }
+
     if (ret && !success)  /* new process failed to start */
     {
         DWORD exitcode;
@@ -1240,6 +1277,7 @@ BOOL WINAPI CreateProcessA( LPCSTR app_n
         TRACE( "starting %s as Windows binary\n", debugstr_a(name) );
         retv = create_process( hFile, name, tidy_cmdline, env, process_attr, thread_attr,
                                inherit, flags, startup_info, info, unixdir );
+        TRACE( "starting of %s done\n", debugstr_a(name) );
         break;
     case BINARY_OS216:
         FIXME( "%s is OS/2 binary, not supported\n", debugstr_a(name) );
Index: server/process.c
===================================================================
RCS file: /home/wine/wine/server/process.c,v
retrieving revision 1.91
diff -u -p -r1.91 process.c
--- server/process.c	19 Oct 2002 01:00:59 -0000	1.91
+++ server/process.c	26 Oct 2002 15:26:34 -0000
@@ -208,6 +208,7 @@ struct thread *create_process( int fd )
     process->startup_state   = STARTUP_IN_PROGRESS;
     process->startup_info    = NULL;
     process->idle_event      = NULL;
+    process->init_event      = NULL;
     process->queue           = NULL;
     process->atom_table      = NULL;
     process->ldt_copy        = NULL;
@@ -224,6 +225,8 @@ struct thread *create_process( int fd )
     if ((process->next = first_process) != NULL) process->next->prev = process;
     first_process = process;
 
+    if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error;
+
     /* create the main thread */
     if (pipe( request_pipe ) == -1)
     {
@@ -334,6 +337,7 @@ static void process_destroy( struct obje
     if (process->prev) process->prev->next = process->next;
     else first_process = process->next;
     if (process->idle_event) release_object( process->idle_event );
+    if (process->init_event) release_object( process->init_event );
     if (process->queue) release_object( process->queue );
     if (process->atom_table) release_object( process->atom_table );
     if (process->exe.file) release_object( process->exe.file );
@@ -396,6 +400,15 @@ static int startup_info_signaled( struct
     return info->process && is_process_init_done(info->process);
 }
 
+/* signal the parent that a process init is finished */
+void process_init_done( struct process *process )
+{
+    set_process_startup_state( process, STARTUP_DONE );
+    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( process_id_t id )
 {
@@ -840,6 +853,8 @@ DECL_HANDLER(get_new_process_info)
 {
     struct startup_info *info;
 
+    reply->event = 0;
+
     if ((info = (struct startup_info *)get_handle_obj( current->process, req->info,
                                                        0, &startup_info_ops )))
     {
@@ -849,6 +864,10 @@ DECL_HANDLER(get_new_process_info)
                                        PROCESS_ALL_ACCESS, req->pinherit );
         reply->thandle = alloc_handle( current->process, info->thread,
                                        THREAD_ALL_ACCESS, req->tinherit );
+	if (info->process->init_event)
+	    reply->event = alloc_handle( current->process, info->process->init_event,
+		    EVENT_ALL_ACCESS, 0 );
+
         reply->success = is_process_init_done( info->process );
         release_object( info );
     }
@@ -904,6 +923,12 @@ DECL_HANDLER(init_process_done)
     struct file *file = NULL;
     struct process *process = current->process;
 
+    if (!process->init_event)
+    {
+	fatal_protocol_error( current, "init_process_done: no event\n" );
+	return;
+    }
+
     if (is_process_init_done(process))
     {
         fatal_protocol_error( current, "init_process_done: called twice\n" );
@@ -926,11 +951,29 @@ DECL_HANDLER(init_process_done)
         process->exe.filename = memdup( get_req_data(), process->exe.namelen );
 
     generate_startup_debug_events( process, req->entry );
-    set_process_startup_state( process, STARTUP_DONE );
+    //set_process_startup_state( process, STARTUP_DONE );
 
     if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 );
-    if (current->suspend + process->suspend > 0) stop_thread( current );
+    //if (current->suspend + process->suspend > 0) stop_thread( current );
+    reply->suspended = 0;
     reply->debugged = (process->debugger != 0);
+    // my code
+    if (current->suspend + process->suspend > 0)
+    {
+	/* temporarily set the startup state so that ptrace functions work */
+	enum startup_state tstate = process->startup_state;
+	process->startup_state = STARTUP_DONE;
+	stop_thread( current );
+	process->startup_state = tstate;
+
+	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.34
diff -u -p -r1.34 process.h
--- server/process.h	3 Oct 2002 19:54:58 -0000	1.34
+++ server/process.h	26 Oct 2002 15:26:35 -0000
@@ -68,6 +68,7 @@ struct process
     enum startup_state   startup_state;   /* startup state */
     struct startup_info *startup_info;    /* startup info while init is in progress */
     struct event        *idle_event;      /* event for input idle */
+    struct event        *init_event;      /* event for input idle */
     struct msg_queue    *queue;           /* main message queue */
     struct atom_table   *atom_table;      /* pointer to local atom table */
     struct process_dll   exe;             /* main exe file */
@@ -97,6 +98,7 @@ struct module_snapshot
 extern struct thread *create_process( int fd );
 extern struct process *get_process_from_id( process_id_t id );
 extern struct process *get_process_from_handle( obj_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.48
diff -u -p -r1.48 protocol.def
--- server/protocol.def	21 Oct 2002 23:43:04 -0000	1.48
+++ server/protocol.def	26 Oct 2002 15:26:49 -0000
@@ -226,6 +226,7 @@ typedef struct
     thread_id_t  tid;          /* thread id */
     obj_handle_t thandle;      /* thread handle (in the current process) */
     int          success;      /* did the process start successfully? */
+    obj_handle_t event;        /* event handle to signal startup */
 @END
 
 
@@ -278,6 +279,7 @@ typedef struct
     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.15
diff -u -p -r1.15 ptrace.c
--- server/ptrace.c	24 May 2002 21:20:27 -0000	1.15
+++ server/ptrace.c	26 Oct 2002 15:26:49 -0000
@@ -79,7 +79,13 @@ static int handle_child_status( struct t
         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 (!is_process_init_done(thread->process))
+		    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.143
diff -u -p -r1.143 trace.c
--- server/trace.c	19 Oct 2002 01:00:59 -0000	1.143
+++ server/trace.c	26 Oct 2002 15:26:58 -0000
@@ -438,6 +438,7 @@ static void dump_init_process_done_reque
 
 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 );
 }
 
Index: win32/device.c
===================================================================
RCS file: /home/wine/wine/win32/device.c,v
retrieving revision 1.71
diff -u -p -r1.71 device.c
--- win32/device.c	3 Oct 2002 19:46:27 -0000	1.71
+++ win32/device.c	26 Oct 2002 15:27:18 -0000
@@ -42,6 +42,7 @@
 #include "msdos.h"
 #include "miscemu.h"
 #include "stackframe.h"
+#include "secdrv.h"
 #include "wine/server.h"
 #include "wine/debug.h"
 
@@ -107,6 +108,12 @@ static BOOL DeviceIo_HASP (DWORD dwIoCon
 			      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
  */
@@ -253,6 +260,9 @@ static const struct VxDInfo VxDList[] =
     /* WINE additions, ids unknown */
     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
 
+    /* SafeDisc copy protection */
+    { "SECDRV", 0xef00, NULL, NULL },
+
     { NULL,       0,      NULL, NULL }
 };
 
@@ -359,8 +369,15 @@ HANDLE DEVICE_Open( LPCWSTR filenameW, D
         if (!strncasecmp( info->name, filename, strlen(info->name) ))
             return FILE_CreateDevice( info->id | 0x10000, access, sa );
 
-    FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
-           filename);
+    if (FIXME_ON(file))
+    {
+	if ( strcmp("NTICE", filename) !=0 && strcmp("SICE", filename) !=0 )
+	    FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
+		    filename);
+	else
+	    TRACE( "Unsupported VxD %s. Programs with copy protection look for it, and if found "
+		    "they are not willing to run.\n", filename);
+    }
     SetLastError( ERROR_FILE_NOT_FOUND );
     return 0;
 }
@@ -489,6 +506,12 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevi
     			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 );
@@ -2076,6 +2099,31 @@ static BOOL DeviceIo_MONODEBG(DWORD dwIo
 	}
 	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,
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ include/secdrv.h	Tue Apr 30 17:11:03 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 */
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ memory/emulate.c	Tue Apr 30 17:08:22 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__ */
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ win32/secdrv.c	Tue Apr 30 17:11:03 2002
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+	if ( ! pInBuffer || ! pOutBuffer )
+		return FALSE;
+
+	if ( cbInBuffer != 0x514 || cbOutBuffer != 0x610 )
+		return FALSE;
+
+	retv = FALSE;
+
+	switch( pInBuffer->dwCommand ) {
+	case SECDRV_CMD_INFO_DR:
+		retv = SECDRV_GetDRInfo( pInBuffer->bUserData, pInBuffer->cbUserData,
+					 pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	case SECDRV_CMD_INFO_IDT:
+		retv = SECDRV_GetIdtInfo( pInBuffer->bUserData, pInBuffer->cbUserData,
+					  pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	case SECDRV_CMD_SETUP:
+		retv = SECDRV_Setup( pInBuffer->bUserData, pInBuffer->cbUserData,
+				     pOutBuffer->bUserData, &pOutBuffer->cbUserData );
+		break;
+	default:
+		FIXME( "unsupported command\n" );
+		break;
+	}
+
+	if ( retv )
+	{
+	    pOutBuffer->dwVersionMajor = 1;
+	    pOutBuffer->dwVersionMinor = 3;
+	    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;
+
+//	FIXME( "SECDRV_GetDRInfo not supported yet\n" );
+
+	if ( cbInBuffer != 0 )
+	{
+		FIXME( "cbInBuffer != 0\n" );
+		return FALSE;
+	}
+
+	if ( contextDr1 == 0xbd331200 )
+	{
+		/* I don't understand why. It's not even a valid DR7 value */
+		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;
+}

Reply via email to