Added support for ReadProcessMemory through the server.
This commit is contained in:
parent
ec7bb2391d
commit
8b8828f578
|
@ -807,6 +807,16 @@ struct debug_process_request
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Read data from a process address space */
|
||||||
|
struct read_process_memory_request
|
||||||
|
{
|
||||||
|
IN int handle; /* process handle */
|
||||||
|
IN void* addr; /* addr to read from (must be int-aligned) */
|
||||||
|
IN int len; /* number of ints to read */
|
||||||
|
OUT unsigned int data[1]; /* result data */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Everything below this line is generated automatically by tools/make_requests */
|
/* Everything below this line is generated automatically by tools/make_requests */
|
||||||
/* ### make_requests begin ### */
|
/* ### make_requests begin ### */
|
||||||
|
|
||||||
|
@ -883,6 +893,7 @@ enum request
|
||||||
REQ_SEND_DEBUG_EVENT,
|
REQ_SEND_DEBUG_EVENT,
|
||||||
REQ_CONTINUE_DEBUG_EVENT,
|
REQ_CONTINUE_DEBUG_EVENT,
|
||||||
REQ_DEBUG_PROCESS,
|
REQ_DEBUG_PROCESS,
|
||||||
|
REQ_READ_PROCESS_MEMORY,
|
||||||
REQ_NB_REQUESTS
|
REQ_NB_REQUESTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1065,20 +1065,55 @@ BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ReadProcessMemory (KERNEL32)
|
* ReadProcessMemory (KERNEL32)
|
||||||
* FIXME: check this, if we ever run win32 binaries in different addressspaces
|
|
||||||
* ... and add a sizecheck
|
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
|
BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWORD size,
|
||||||
LPVOID lpBuffer, DWORD nSize,
|
LPDWORD bytes_read )
|
||||||
LPDWORD lpNumberOfBytesRead )
|
|
||||||
{
|
{
|
||||||
memcpy(lpBuffer,lpBaseAddress,nSize);
|
struct read_process_memory_request *req = get_req_buffer();
|
||||||
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
|
unsigned int offset = (unsigned int)addr % sizeof(int);
|
||||||
|
unsigned int max = server_remaining( req->data ); /* max length in one request */
|
||||||
|
unsigned int pos;
|
||||||
|
|
||||||
|
if (bytes_read) *bytes_read = size;
|
||||||
|
|
||||||
|
/* first time, read total length to check for permissions */
|
||||||
|
req->handle = process;
|
||||||
|
req->addr = (char *)addr - offset;
|
||||||
|
req->len = (size + offset + sizeof(int) - 1) / sizeof(int);
|
||||||
|
if (server_call( REQ_READ_PROCESS_MEMORY )) goto error;
|
||||||
|
|
||||||
|
if (size <= max - offset)
|
||||||
|
{
|
||||||
|
memcpy( buffer, (char *)req->data + offset, size );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* now take care of the remaining data */
|
||||||
|
memcpy( buffer, (char *)req->data + offset, max - offset );
|
||||||
|
pos = max - offset;
|
||||||
|
size -= pos;
|
||||||
|
while (size)
|
||||||
|
{
|
||||||
|
if (max > size) max = size;
|
||||||
|
req->handle = process;
|
||||||
|
req->addr = (char *)addr + pos;
|
||||||
|
req->len = (max + sizeof(int) - 1) / sizeof(int);
|
||||||
|
if (server_call( REQ_READ_PROCESS_MEMORY )) goto error;
|
||||||
|
memcpy( (char *)buffer + pos, (char *)req->data, max );
|
||||||
|
size -= max;
|
||||||
|
pos += max;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (bytes_read) *bytes_read = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* WriteProcessMemory (KERNEL32)
|
* WriteProcessMemory (KERNEL32)
|
||||||
* FIXME: check this, if we ever run win32 binaries in different addressspaces
|
* FIXME: check this, if we ever run win32 binaries in different addressspaces
|
||||||
|
|
|
@ -366,6 +366,7 @@ void file_set_error(void)
|
||||||
case EINVAL: set_error( ERROR_INVALID_PARAMETER ); break;
|
case EINVAL: set_error( ERROR_INVALID_PARAMETER ); break;
|
||||||
case ESPIPE: set_error( ERROR_SEEK ); break;
|
case ESPIPE: set_error( ERROR_SEEK ); break;
|
||||||
case ENOTEMPTY: set_error( ERROR_DIR_NOT_EMPTY ); break;
|
case ENOTEMPTY: set_error( ERROR_DIR_NOT_EMPTY ); break;
|
||||||
|
case EIO: set_error( ERROR_NOACCESS ); break;
|
||||||
default: perror("file_set_error"); set_error( ERROR_UNKNOWN ); break;
|
default: perror("file_set_error"); set_error( ERROR_UNKNOWN ); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -314,6 +316,38 @@ static void set_process_info( struct process *process,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
/* 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 )
|
||||||
|
{
|
||||||
|
struct thread *thread = process->thread_list;
|
||||||
|
int pid = thread->unix_pid;
|
||||||
|
|
||||||
|
suspend_thread( thread, 0 );
|
||||||
|
if (thread->attached)
|
||||||
|
{
|
||||||
|
while (len-- > 0)
|
||||||
|
{
|
||||||
|
int data = ptrace( PT_READ_D, pid, addr );
|
||||||
|
if ((data == -1) && errno)
|
||||||
|
{
|
||||||
|
file_set_error();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (max)
|
||||||
|
{
|
||||||
|
*dest++ = data;
|
||||||
|
max--;
|
||||||
|
}
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else set_error( ERROR_ACCESS_DENIED );
|
||||||
|
resume_thread( thread );
|
||||||
|
}
|
||||||
|
|
||||||
/* take a snapshot of currently running processes */
|
/* take a snapshot of currently running processes */
|
||||||
struct process_snapshot *process_snap( int *count )
|
struct process_snapshot *process_snap( int *count )
|
||||||
{
|
{
|
||||||
|
@ -440,3 +474,16 @@ DECL_HANDLER(set_process_info)
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read data from a process address space */
|
||||||
|
DECL_HANDLER(read_process_memory)
|
||||||
|
{
|
||||||
|
struct process *process;
|
||||||
|
|
||||||
|
if ((process = get_process_from_handle( req->handle, PROCESS_VM_READ )))
|
||||||
|
{
|
||||||
|
read_process_memory( process, req->addr, req->len,
|
||||||
|
get_req_size( req->data, sizeof(int) ), req->data );
|
||||||
|
release_object( process );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@ DECL_HANDLER(wait_debug_event);
|
||||||
DECL_HANDLER(send_debug_event);
|
DECL_HANDLER(send_debug_event);
|
||||||
DECL_HANDLER(continue_debug_event);
|
DECL_HANDLER(continue_debug_event);
|
||||||
DECL_HANDLER(debug_process);
|
DECL_HANDLER(debug_process);
|
||||||
|
DECL_HANDLER(read_process_memory);
|
||||||
|
|
||||||
#ifdef WANT_REQUEST_HANDLERS
|
#ifdef WANT_REQUEST_HANDLERS
|
||||||
|
|
||||||
|
@ -210,6 +211,7 @@ static const struct handler {
|
||||||
{ (void(*)())req_send_debug_event, sizeof(struct send_debug_event_request) },
|
{ (void(*)())req_send_debug_event, sizeof(struct send_debug_event_request) },
|
||||||
{ (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) },
|
{ (void(*)())req_continue_debug_event, sizeof(struct continue_debug_event_request) },
|
||||||
{ (void(*)())req_debug_process, sizeof(struct debug_process_request) },
|
{ (void(*)())req_debug_process, sizeof(struct debug_process_request) },
|
||||||
|
{ (void(*)())req_read_process_memory, sizeof(struct read_process_memory_request) },
|
||||||
};
|
};
|
||||||
#endif /* WANT_REQUEST_HANDLERS */
|
#endif /* WANT_REQUEST_HANDLERS */
|
||||||
|
|
||||||
|
|
|
@ -337,18 +337,19 @@ void continue_thread( struct thread *thread )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* suspend a thread */
|
/* suspend a thread */
|
||||||
static int suspend_thread( struct thread *thread )
|
int suspend_thread( struct thread *thread, int check_limit )
|
||||||
{
|
{
|
||||||
int old_count = thread->suspend;
|
int old_count = thread->suspend;
|
||||||
if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
|
if (thread->suspend < MAXIMUM_SUSPEND_COUNT || !check_limit)
|
||||||
{
|
{
|
||||||
if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
|
if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
|
||||||
}
|
}
|
||||||
|
else set_error( ERROR_SIGNAL_REFUSED );
|
||||||
return old_count;
|
return old_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resume a thread */
|
/* resume a thread */
|
||||||
static int resume_thread( struct thread *thread )
|
int resume_thread( struct thread *thread )
|
||||||
{
|
{
|
||||||
int old_count = thread->suspend;
|
int old_count = thread->suspend;
|
||||||
if (thread->suspend > 0)
|
if (thread->suspend > 0)
|
||||||
|
@ -364,7 +365,7 @@ void suspend_all_threads( void )
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
for ( thread = first_thread; thread; thread = thread->next )
|
for ( thread = first_thread; thread; thread = thread->next )
|
||||||
if ( thread != current )
|
if ( thread != current )
|
||||||
suspend_thread( thread );
|
suspend_thread( thread, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resume all threads but the current */
|
/* resume all threads but the current */
|
||||||
|
@ -709,7 +710,7 @@ DECL_HANDLER(suspend_thread)
|
||||||
|
|
||||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||||
{
|
{
|
||||||
req->count = suspend_thread( thread );
|
req->count = suspend_thread( thread, 1 );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ extern struct thread *get_thread_from_handle( int handle, unsigned int access );
|
||||||
extern void wait4_thread( struct thread *thread, int wait );
|
extern void wait4_thread( struct thread *thread, int wait );
|
||||||
extern void stop_thread( struct thread *thread );
|
extern void stop_thread( struct thread *thread );
|
||||||
extern void continue_thread( struct thread *thread );
|
extern void continue_thread( struct thread *thread );
|
||||||
|
extern int suspend_thread( struct thread *thread, int check_limit );
|
||||||
|
extern int resume_thread( struct thread *thread );
|
||||||
extern void suspend_all_threads( void );
|
extern void suspend_all_threads( void );
|
||||||
extern void resume_all_threads( void );
|
extern void resume_all_threads( void );
|
||||||
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
|
|
|
@ -11,14 +11,35 @@
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* utility functions */
|
||||||
|
|
||||||
|
static void dump_ints( const int *ptr, int len )
|
||||||
|
{
|
||||||
|
fputc( '{', stderr );
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
fprintf( stderr, "%d", *ptr++ );
|
||||||
|
if (--len) fputc( ',', stderr );
|
||||||
|
}
|
||||||
|
fputc( '}', stderr );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_bytes( const unsigned char *ptr, int len )
|
||||||
|
{
|
||||||
|
fputc( '{', stderr );
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
fprintf( stderr, "%02x", *ptr++ );
|
||||||
|
if (--len) fputc( ',', stderr );
|
||||||
|
}
|
||||||
|
fputc( '}', stderr );
|
||||||
|
}
|
||||||
|
|
||||||
/* dumping for functions for requests that have a variable part */
|
/* dumping for functions for requests that have a variable part */
|
||||||
|
|
||||||
static void dump_varargs_select( struct select_request *req )
|
static void dump_varargs_select( struct select_request *req )
|
||||||
{
|
{
|
||||||
int i;
|
dump_ints( req->handles, req->count );
|
||||||
for (i = 0; i < req->count; i++)
|
|
||||||
fprintf( stderr, "%c%d", i ? ',' : '{', req->handles[i] );
|
|
||||||
fprintf( stderr, "}" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_varargs_get_apcs( struct get_apcs_request *req )
|
static void dump_varargs_get_apcs( struct get_apcs_request *req )
|
||||||
|
@ -31,10 +52,13 @@ static void dump_varargs_get_apcs( struct get_apcs_request *req )
|
||||||
|
|
||||||
static void dump_varargs_get_socket_event( struct get_socket_event_request *req )
|
static void dump_varargs_get_socket_event( struct get_socket_event_request *req )
|
||||||
{
|
{
|
||||||
int i;
|
dump_ints( req->errors, FD_MAX_EVENTS );
|
||||||
for (i = 0; i < FD_MAX_EVENTS; i++)
|
}
|
||||||
fprintf( stderr, "%c%d", i ? ',' : '{', req->errors[i] );
|
|
||||||
fprintf( stderr, "}" );
|
static void dump_varargs_read_process_memory( struct read_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) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -763,6 +787,19 @@ static void dump_debug_process_request( struct debug_process_request *req )
|
||||||
fprintf( stderr, " pid=%p", req->pid );
|
fprintf( stderr, " pid=%p", req->pid );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_read_process_memory_request( struct read_process_memory_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " handle=%d,", req->handle );
|
||||||
|
fprintf( stderr, " addr=%p,", req->addr );
|
||||||
|
fprintf( stderr, " len=%d", req->len );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_read_process_memory_reply( struct read_process_memory_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " data=" );
|
||||||
|
dump_varargs_read_process_memory( req );
|
||||||
|
}
|
||||||
|
|
||||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_new_process_request,
|
(dump_func)dump_new_process_request,
|
||||||
(dump_func)dump_new_thread_request,
|
(dump_func)dump_new_thread_request,
|
||||||
|
@ -835,6 +872,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_send_debug_event_request,
|
(dump_func)dump_send_debug_event_request,
|
||||||
(dump_func)dump_continue_debug_event_request,
|
(dump_func)dump_continue_debug_event_request,
|
||||||
(dump_func)dump_debug_process_request,
|
(dump_func)dump_debug_process_request,
|
||||||
|
(dump_func)dump_read_process_memory_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
|
@ -909,6 +947,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_send_debug_event_reply,
|
(dump_func)dump_send_debug_event_reply,
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
|
(dump_func)dump_read_process_memory_reply,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const req_names[REQ_NB_REQUESTS] = {
|
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
|
@ -983,6 +1022,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"send_debug_event",
|
"send_debug_event",
|
||||||
"continue_debug_event",
|
"continue_debug_event",
|
||||||
"debug_process",
|
"debug_process",
|
||||||
|
"read_process_memory",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ### make_requests end ### */
|
/* ### make_requests end ### */
|
||||||
|
|
Loading…
Reference in New Issue