diff --git a/include/server.h b/include/server.h
index 708fe742b8ba1733dfe77cef8ae63702c514d455..d492b88880225a1f7fbd413b99445c2dc686d1ca 100644
--- a/include/server.h
+++ b/include/server.h
@@ -817,6 +817,18 @@ struct read_process_memory_request
 };
 
 
+/* Write data to a process address space */
+struct write_process_memory_request
+{
+    IN  int          handle;       /* process handle */
+    IN  void*        addr;         /* addr to write to (must be int-aligned) */
+    IN  int          len;          /* number of ints to write */
+    IN  unsigned int first_mask;   /* mask for first word */
+    IN  unsigned int last_mask;    /* mask for last word */
+    IN  unsigned int data[1];      /* data to write */
+};
+
+
 /* Everything below this line is generated automatically by tools/make_requests */
 /* ### make_requests begin ### */
 
@@ -894,6 +906,7 @@ enum request
     REQ_CONTINUE_DEBUG_EVENT,
     REQ_DEBUG_PROCESS,
     REQ_READ_PROCESS_MEMORY,
+    REQ_WRITE_PROCESS_MEMORY,
     REQ_NB_REQUESTS
 };
 
diff --git a/scheduler/process.c b/scheduler/process.c
index 9c4d38a9f6c0128ed4fef9e125b855d1e9aaa262..d55c29e8a25a632f43f97f8d38576ecc455d9da7 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -1116,18 +1116,77 @@ BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWOR
 
 /***********************************************************************
  *           WriteProcessMemory    		(KERNEL32)
- * FIXME: check this, if we ever run win32 binaries in different addressspaces
- *	  ... and add a sizecheck
  */
-BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
-                                 LPVOID lpBuffer, DWORD nSize,
-                                 LPDWORD lpNumberOfBytesWritten )
+BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPVOID buffer, DWORD size,
+                                LPDWORD bytes_written )
 {
-	memcpy(lpBaseAddress,lpBuffer,nSize);
-	if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
-	return TRUE;
+    unsigned int first_offset, last_offset;
+    struct write_process_memory_request *req = get_req_buffer();
+    unsigned int max = server_remaining( req->data );  /* max length in one request */
+    unsigned int pos, last_mask;
+
+    if (!size)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    if (bytes_written) *bytes_written = size;
+
+    /* compute the mask for the first int */
+    req->first_mask = ~0;
+    first_offset = (unsigned int)addr % sizeof(int);
+    memset( &req->first_mask, 0, first_offset );
+
+    /* compute the mask for the last int */
+    last_offset = (size + first_offset) % sizeof(int);
+    last_mask = 0;
+    memset( &last_mask, 0xff, last_offset ? last_offset : sizeof(int) );
+
+    req->handle = process;
+    req->addr = (char *)addr - first_offset;
+    /* for the first request, use the total length */
+    req->len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
+
+    if (size + first_offset < max)  /* we can do it in one round */
+    {
+        memcpy( (char *)req->data + first_offset, buffer, size );
+        req->last_mask = last_mask;
+        if (server_call( REQ_WRITE_PROCESS_MEMORY )) goto error;
+        return TRUE;
+    }
+
+    /* needs multiple server calls */
+
+    memcpy( (char *)req->data + first_offset, buffer, max - first_offset );
+    req->last_mask = ~0;
+    if (server_call( REQ_WRITE_PROCESS_MEMORY )) goto error;
+    pos = max - first_offset;
+    size -= pos;
+    while (size)
+    {
+        if (size <= max)  /* last one */
+        {
+            req->last_mask = last_mask;
+            max = size;
+        }
+        req->handle = process;
+        req->addr = (char *)addr + pos;
+        req->len = (max + sizeof(int) - 1) / sizeof(int);
+        req->first_mask = ~0;
+        memcpy( req->data, buffer + pos, max );
+        if (server_call( REQ_WRITE_PROCESS_MEMORY )) goto error;
+        pos += max;
+        size -= max;
+    }
+    return TRUE;
+
+ error:
+    if (bytes_written) *bytes_written = 0;
+    return FALSE;
+
 }
 
+
 /***********************************************************************
  *           RegisterServiceProcess             (KERNEL, KERNEL32)
  *
diff --git a/server/process.c b/server/process.c
index 65500ba8bb7a149aaeabdb3507d6aac9025dbd45..034e90d28cbe969f7a3897f6713317b3d5cefadf 100644
--- a/server/process.c
+++ b/server/process.c
@@ -316,35 +316,125 @@ static void set_process_info( struct process *process,
     }
 }
 
+/* wrapper for reading an int with ptrace */
+static inline int read_word( int pid, const int *addr, int *data )
+{
+    if (((*data = ptrace( PT_READ_D, pid, addr )) == -1) && errno)
+    {
+        file_set_error();
+        return -1;
+    }
+    return 0;
+}
+
+/* wrapper for writing an int with ptrace */
+static inline int write_word( int pid, int *addr, int data, unsigned int mask )
+{
+    int res;
+    if (mask != ~0)
+    {
+        if (read_word( pid, addr, &res ) == -1) return -1;
+        data = (data & mask) | (res & ~mask);
+    }
+    if ((res = ptrace( PT_WRITE_D, pid, addr, data )) == -1) file_set_error();
+    return res;
+}
+
 /* read data from a process memory space */
-/* len is the total size (in ints), max is the size we can actually store in the input buffer */
+/* len is the total size (in ints), max is the size we can actually store in the output buffer */
 /* we read the total size in all cases to check for permissions */
-static void read_process_memory( struct process *process, const int *addr, int len,
-                                 int max, int *dest )
+static void read_process_memory( struct process *process, const int *addr,
+                                 size_t len, size_t max, int *dest )
 {
     struct thread *thread = process->thread_list;
     int pid = thread->unix_pid;
 
+    if ((unsigned int)addr % sizeof(int))  /* address must be aligned */
+    {
+        set_error( ERROR_INVALID_PARAMETER );
+        return;
+    }
     suspend_thread( thread, 0 );
     if (thread->attached)
     {
-        while (len-- > 0)
+        while (len > 0 && max)
+        {
+            if (read_word( pid, addr++, dest++ ) == -1) goto done;
+            max--;
+            len--;
+        }
+        /* check the rest for read permission */
+        if (len > 0)
         {
-            int data = ptrace( PT_READ_D, pid, addr );
-            if ((data == -1) && errno)
+            int dummy, page = get_page_size() / sizeof(int);
+            while (len >= page)
             {
-                file_set_error();
-                break;
+                addr += page;
+                len -= page;
+                if (read_word( pid, addr - 1, &dummy ) == -1) goto done;
             }
-            if (max)
+            if (len && (read_word( pid, addr + len - 1, &dummy ) == -1)) goto done;
+        }
+    }
+    else set_error( ERROR_ACCESS_DENIED );
+ done:
+    resume_thread( thread );
+}
+
+/* write data to a process memory space */
+/* len is the total size (in ints), max is the size we can actually read from the input buffer */
+/* we check the total size for write permissions */
+static void write_process_memory( struct process *process, int *addr, size_t len,
+                                  size_t max, unsigned int first_mask,
+                                  unsigned int last_mask, const int *src )
+{
+    struct thread *thread = process->thread_list;
+    int pid = thread->unix_pid;
+
+    if (!len || ((unsigned int)addr % sizeof(int)))  /* address must be aligned */
+    {
+        set_error( ERROR_INVALID_PARAMETER );
+        return;
+    }
+    suspend_thread( thread, 0 );
+    if (thread->attached)
+    {
+        /* first word is special */
+        if (len > 1)
+        {
+            if (write_word( pid, addr++, *src++, first_mask ) == -1) goto done;
+            len--;
+            max--;
+        }
+        else last_mask &= first_mask;
+
+        while (len > 1 && max)
+        {
+            if (write_word( pid, addr++, *src++, ~0 ) == -1) goto done;
+            max--;
+            len--;
+        }
+
+        if (max)
+        {
+            /* last word is special too */
+            if (write_word( pid, addr, *src, last_mask ) == -1) goto done;
+        }
+        else
+        {
+            /* check the rest for write permission */
+            int page = get_page_size() / sizeof(int);
+            while (len >= page)
             {
-                *dest++ = data;
-                max--;
+                addr += page;
+                len -= page;
+                if (write_word( pid, addr - 1, 0, 0 ) == -1) goto done;
             }
-            addr++;
+            if (len && (write_word( pid, addr + len - 1, 0, 0 ) == -1)) goto done;
         }
     }
     else set_error( ERROR_ACCESS_DENIED );
+ done:
     resume_thread( thread );
 }
 
@@ -487,3 +577,16 @@ DECL_HANDLER(read_process_memory)
         release_object( process );
     }
 }
+
+/* write data to a process address space */
+DECL_HANDLER(write_process_memory)
+{
+    struct process *process;
+
+    if ((process = get_process_from_handle( req->handle, PROCESS_VM_WRITE )))
+    {
+        write_process_memory( process, req->addr, req->len, get_req_size( req->data, sizeof(int) ),
+                              req->first_mask, req->last_mask, req->data );
+        release_object( process );
+    }
+}
diff --git a/server/request.h b/server/request.h
index f46edae5770780906a97a4c6f10730ac80b047a0..1d05bd90467b8369f8e718c317e48f0202143bca 100644
--- a/server/request.h
+++ b/server/request.h
@@ -133,6 +133,7 @@ DECL_HANDLER(send_debug_event);
 DECL_HANDLER(continue_debug_event);
 DECL_HANDLER(debug_process);
 DECL_HANDLER(read_process_memory);
+DECL_HANDLER(write_process_memory);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -212,6 +213,7 @@ static const struct handler {
     { (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) },
     { (void(*)())req_debug_process, sizeof(struct debug_process_request) },
     { (void(*)())req_read_process_memory, sizeof(struct read_process_memory_request) },
+    { (void(*)())req_write_process_memory, sizeof(struct write_process_memory_request) },
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index ff49ed972cc687c6f2249f952e4aee440283f8da..df2a4feed4fee5afad614dc0d2627a4edcf6e75c 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -61,6 +61,12 @@ static void dump_varargs_read_process_memory( struct read_process_memory_request
     dump_bytes( (unsigned char *)req->data, count * sizeof(int) );
 }
 
+static void dump_varargs_write_process_memory( struct write_process_memory_request *req )
+{
+    int count = MIN( req->len, get_req_size( req->data, sizeof(int) ) );
+    dump_bytes( (unsigned char *)req->data, count * sizeof(int) );
+}
+
 
 typedef void (*dump_func)( const void *req );
 
@@ -800,6 +806,17 @@ static void dump_read_process_memory_reply( struct read_process_memory_request *
     dump_varargs_read_process_memory( req );
 }
 
+static void dump_write_process_memory_request( struct write_process_memory_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " addr=%p,", req->addr );
+    fprintf( stderr, " len=%d,", req->len );
+    fprintf( stderr, " first_mask=%08x,", req->first_mask );
+    fprintf( stderr, " last_mask=%08x,", req->last_mask );
+    fprintf( stderr, " data=" );
+    dump_varargs_write_process_memory( req );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_new_thread_request,
@@ -873,6 +890,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_continue_debug_event_request,
     (dump_func)dump_debug_process_request,
     (dump_func)dump_read_process_memory_request,
+    (dump_func)dump_write_process_memory_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -948,6 +966,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)0,
     (dump_func)0,
     (dump_func)dump_read_process_memory_reply,
+    (dump_func)0,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -1023,6 +1042,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "continue_debug_event",
     "debug_process",
     "read_process_memory",
+    "write_process_memory",
 };
 
 /* ### make_requests end ### */