Skip to content
Snippets Groups Projects
Commit eef7025e authored by Alexandre Julliard's avatar Alexandre Julliard
Browse files

Added support for WriteProcessMemory through the server.

parent c76ad35a
No related branches found
No related tags found
No related merge requests found
......@@ -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
};
......
......@@ -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)
*
......
......@@ -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 );
}
}
......@@ -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 */
......
......@@ -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 ### */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment