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 */
|
||||
/* ### make_requests begin ### */
|
||||
|
||||
|
@ -883,6 +893,7 @@ enum request
|
|||
REQ_SEND_DEBUG_EVENT,
|
||||
REQ_CONTINUE_DEBUG_EVENT,
|
||||
REQ_DEBUG_PROCESS,
|
||||
REQ_READ_PROCESS_MEMORY,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
|
|
@ -1065,20 +1065,55 @@ BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* 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,
|
||||
LPVOID lpBuffer, DWORD nSize,
|
||||
LPDWORD lpNumberOfBytesRead )
|
||||
BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWORD size,
|
||||
LPDWORD bytes_read )
|
||||
{
|
||||
memcpy(lpBuffer,lpBaseAddress,nSize);
|
||||
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
|
||||
return TRUE;
|
||||
struct read_process_memory_request *req = get_req_buffer();
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
* 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 ESPIPE: set_error( ERROR_SEEK ); 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/time.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 */
|
||||
struct process_snapshot *process_snap( int *count )
|
||||
{
|
||||
|
@ -440,3 +474,16 @@ DECL_HANDLER(set_process_info)
|
|||
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(continue_debug_event);
|
||||
DECL_HANDLER(debug_process);
|
||||
DECL_HANDLER(read_process_memory);
|
||||
|
||||
#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_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) },
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
|
@ -337,18 +337,19 @@ void continue_thread( struct thread *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;
|
||||
if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
|
||||
if (thread->suspend < MAXIMUM_SUSPEND_COUNT || !check_limit)
|
||||
{
|
||||
if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread );
|
||||
}
|
||||
else set_error( ERROR_SIGNAL_REFUSED );
|
||||
return old_count;
|
||||
}
|
||||
|
||||
/* resume a thread */
|
||||
static int resume_thread( struct thread *thread )
|
||||
int resume_thread( struct thread *thread )
|
||||
{
|
||||
int old_count = thread->suspend;
|
||||
if (thread->suspend > 0)
|
||||
|
@ -364,7 +365,7 @@ void suspend_all_threads( void )
|
|||
struct thread *thread;
|
||||
for ( thread = first_thread; thread; thread = thread->next )
|
||||
if ( thread != current )
|
||||
suspend_thread( thread );
|
||||
suspend_thread( thread, 0 );
|
||||
}
|
||||
|
||||
/* 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 )))
|
||||
{
|
||||
req->count = suspend_thread( thread );
|
||||
req->count = suspend_thread( thread, 1 );
|
||||
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 stop_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 resume_all_threads( void );
|
||||
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
|
|
|
@ -11,14 +11,35 @@
|
|||
#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 */
|
||||
|
||||
static void dump_varargs_select( struct select_request *req )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < req->count; i++)
|
||||
fprintf( stderr, "%c%d", i ? ',' : '{', req->handles[i] );
|
||||
fprintf( stderr, "}" );
|
||||
dump_ints( req->handles, req->count );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < FD_MAX_EVENTS; i++)
|
||||
fprintf( stderr, "%c%d", i ? ',' : '{', req->errors[i] );
|
||||
fprintf( stderr, "}" );
|
||||
dump_ints( req->errors, FD_MAX_EVENTS );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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] = {
|
||||
(dump_func)dump_new_process_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_continue_debug_event_request,
|
||||
(dump_func)dump_debug_process_request,
|
||||
(dump_func)dump_read_process_memory_request,
|
||||
};
|
||||
|
||||
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)0,
|
||||
(dump_func)0,
|
||||
(dump_func)dump_read_process_memory_reply,
|
||||
};
|
||||
|
||||
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",
|
||||
"continue_debug_event",
|
||||
"debug_process",
|
||||
"read_process_memory",
|
||||
};
|
||||
|
||||
/* ### make_requests end ### */
|
||||
|
|
Loading…
Reference in New Issue