146 lines
5.3 KiB
Plaintext
146 lines
5.3 KiB
Plaintext
VirtualString
|
|
=============
|
|
|
|
This class is an abstract representation of an arbitrary sized byte array
|
|
with methods to load parts of it on demand. It is useful to represent
|
|
a program virtual memory and allow metasm to work on it while only reading
|
|
bytes from it when actually needed.
|
|
|
|
The base class is defined in `metasm/os/main.rb`.
|
|
|
|
|
|
Basics
|
|
------
|
|
|
|
The API of the object is designed to be compatible with a standard String (ASCII-8BIT).
|
|
The main restriction is that the size of this string cannot be changed:
|
|
concatenation / shortening is not supported.
|
|
|
|
The main operation on the object should be `[]` and `[]=`, that is,
|
|
reading some subpart of the string, or overwriting some substring.
|
|
The arguments are the same as for a String, with the exception that
|
|
rewrite raises an IndexError if the rewriting would change the string
|
|
length.
|
|
|
|
A few methods are written specifically with the VirtualString semantics,
|
|
others are redirected to a temporary real String generated with `realstring`.
|
|
|
|
The VirtualString works with a `page` concept, that represents some arbitrary
|
|
chunks of data that can be actually read from the underlying target, e.g. a
|
|
memory page (4096 bytes) when mapping a process virtual address space.
|
|
Instances get to define a `pagelength` sound for the specific implementation.
|
|
|
|
Whenever a substring is requested from a VirtualString, if the substring
|
|
length is less than the page size, an actual read is made and a String is
|
|
returned.
|
|
|
|
If the length is greater however, a new VirtualString is created to map this
|
|
new *view* without actually reading.
|
|
|
|
To force the conversion to a String, use the `realstring` or `to_str` method.
|
|
The latter is prefered, as it works on both Strings and VirtualStrings.
|
|
|
|
To force the creation of a new VirtualString, use the `dup(start, len)` method.
|
|
|
|
When reading actual bytes, a local page cache is used. By default is has only 4
|
|
pages, and can be invalidated using `invalidate`.
|
|
The cache is automatically invalidated when part of the string is written to.
|
|
|
|
The VirtualString may index *invalid* pages (e.g. unmapped memory range in a
|
|
process address space) ; you can check that with `page_invalid?` with an index
|
|
as parameter.
|
|
|
|
|
|
Creation
|
|
--------
|
|
|
|
To create your own flavor of VirtualString, you must:
|
|
|
|
* define your subclass that inherits from `VirtualString`
|
|
* define your initializer, that takes whatever arguments make sense (e.g. a
|
|
*pid*, *handle*, Socket..)
|
|
* your initializer must call super(a, l) with arguments:
|
|
** current view absolute address (should default to 0), will be saved in
|
|
`@addr_start`
|
|
** current view size (should default to something sensible, like 1<<32), saved
|
|
in `@length`
|
|
* your initializer can override the default page size by defining the
|
|
`@pagelength` variable.
|
|
* implement a `dup` method that takes optional arguments:
|
|
** new base address (default=`@addr_start`)
|
|
** new length (default=`@length`)
|
|
** returns a new instance of your class mapping over the specified window
|
|
* implement a `get_page` method, whose arguments are:
|
|
** absolute page address (will always be page-aligned)
|
|
** optional length, default=`@pagelength`
|
|
** returns a String of `length` bytes, or `nil` (e.g. unmapped area)
|
|
* optionally implement a `rewrite_at` method, to make your string writeable.
|
|
Arguments are the absolute write address, and the data to write there (a String).
|
|
|
|
Feel free to override any other method with an optimized version.
|
|
For exemple, the default `realstring` will repeatadly call `get_page` with
|
|
each page in the range 0..`length`, you may have a more efficient alternative.
|
|
|
|
You can alter the cache size by rewriting the `@pagecache_len` variable
|
|
**after** calling `super()` in `initialize`. The default value is 4, which you
|
|
may want to increase.
|
|
|
|
See the `WindowsRemoteString` source for a simple exemple (ignore the `open_pid`
|
|
method).
|
|
|
|
Standard subclasses
|
|
-------------------
|
|
|
|
VirtualFile
|
|
###########
|
|
|
|
Defined in `metasm/os/main.rb`.
|
|
|
|
This class maps over an open file descriptor, and allows reading data on-demand.
|
|
It implements the `read` class method, similar to `File.read`, with the
|
|
file opened in binary mode. For a small file (<=4096), the content is
|
|
directly returned, otherwise a VirtualString is created.
|
|
|
|
This class is used by the default <core/ExeFormat.txt> `decode_file[_header]`
|
|
methods.
|
|
|
|
|
|
LinuxRemoteString
|
|
#################
|
|
|
|
Defined in `metasm/os/linux.rb`.
|
|
|
|
This class maps over the virtual memory of a Linux process.
|
|
Accesses are done through the `/proc/<pid>/mem` for reading.
|
|
The linux kernel requires that the target process be ptraced before we can
|
|
read this file, so the object will use the debugger instance passed to the
|
|
constructor, or create a new <core/PTrace.txt> object to stop the process
|
|
and read its memory during `get_page`.
|
|
|
|
If a <core/Debugger.txt> object was given, `get_page` will return `nil` if the
|
|
debugger indicates that the target is not stopped.
|
|
|
|
Writing is done through `PTrace#writemem` using `PTRACE_POKEDATA`.
|
|
|
|
|
|
WindowsRemoteString
|
|
###################
|
|
|
|
Defined in `metasm/os/windows.rb`.
|
|
|
|
This class maps over the virtual memory of a Windows process.
|
|
|
|
The memory accesses are done using the `Read/WriteProcessMemory` API.
|
|
|
|
The class method `open_pid` is defined, that will try to `OpenProcess`
|
|
first in read/write, and fallback to read-only mode.
|
|
|
|
|
|
GdbRemoteString
|
|
###############
|
|
|
|
Defined in `metasm/os/remote.rb`.
|
|
|
|
Maps over the virtual memory of a remote process debugged with a
|
|
<core/GdbClient.txt> instance, using `setmem` and `getmem`.
|