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; +}