jettero has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to get Win32::API to work with Win32::Process. I don't know if that's even possible. I'm trying to do a memory dump of a process for hex-editor-like activities.
my $handle; my $thispid = Win32::Process::GetCurrentProcessID(); # differs from $$ + under cygwin Win32::Process::Open($handle, $thispid, 1);

That much works well. I can $handle->Kill(1) and it works correctly. Next, I've tried to import ReadProcessMemory using this ...

my $readmem = Win32::API->new( kernel32 => q| BOOL ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nS +ize, SIZE_T* lpNumberOfBytesRead )|);

... it didn't work cause it doesn't know LPCVOID. I discovered that it's really a pointer to a character string, so I changed it to LPSTR. Is that incorrect? I then call the thing like so:

my $buf = " " x 40; my $read = " " x 10; my $addr = "0"; my $len = length $buf; if( $readmem->Call($handle, $addr, $buf, $len, $read) ) { print "The read worked I guess($read): $!\n\t", unpack("H*", $buf) +, "\n"; } else { print "The read failed I guess($read): $!\n\t", unpack("H*", $buf) +, "\n"; }

I don't know if you can pass a Win32::Process handle or not, but I suspect that's my biggest problem. I also don't know what to put for the base address, but I'm hoping something like a "0" means "the beginning." Depending on what thing I tweak, I end up from anything to $!="no such file or directory" to segfaults. Am I misunderstanding Win32::API completely? Am I close?

Perhaps I should use something like

my $openpid = Win32::API->new( kernel32 => q|HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD + dwProcessId)| );

instead of Win32::Process?

My ultimate goal is to dump the memory of another pid from perl to a file.

-Paul

Replies are listed 'Best First'.
Re: Win32::API->new( ReadProcessMemory ) not working how I'd expect
by BrowserUk (Patriarch) on Aug 14, 2007 at 20:18 UTC

    It should work okay on the current process handle. OpenProcess is for attaching to another process. Your problem is that the lowest accessible address within a process is (usually) the process environment block which starts at 0x10000, so using 0 isn't going ot work. For starters, try setting the address to read from to the address of a perl variable. my $var = 'some text'; my $addr = 0+\$var;

    From that you should be able to decipher the values in the SV and track through to read back the contents of the variable. Use Perlguts Illustrated and/or Devel::Peek as a guide.

    Not sure where you are going with this, but be aware that Win32 processes are not made up of contiguous spaces. There are large gaps between 'sections'. You can use the 'debug' apis, in particular, CreateToolhelp32Snapshot() to iterate the sections and find their extents.

    The best information I found for these and related apis is an (horribly formatted) Under the Hood article by Matt Pietrek.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      ... usually) the process environment block which starts at 0x10000 ... Win32 processes are not made of of contiguous spaces ...

      Oh, I didn't realize any of this... It would seem I'm taking entirely the wrong approach and I'm glad I asked. I wish to dump the memory contents of a pid that is not the current pid. Hopefully CreateToolhelp32Snapshot() is more like what I want.

      Thanks.

      -Paul

        I wish to dump the memory contents of a pid that is not the current pid.

        Then you will need to use OpenProcess() to get a handle to the process in question.

        CreateToolhelp32Snapshot() doesn't snapshot the memory. It will give you lists of the modules (DLLs) that are a part of your process image which you can then iterate using Module32First/Next() and obtain the load addresses and extents.

        It will also give you a list of the heaps, runtime allocated memory used by alloc/free and stacks. You then use Heap32ListFirst/Next to iterate those and obtain their start addresses and extents.

        You then use those addresses with ReadProcessMemory() to actually read the ram.

        It's a fairly involved process, but reasonably well documented. Remember you will need appropriate permissons.

        Also, be sure to suspend the target process otherwise things could change the moment after you obtain your information. If the target process contains threads, you have another sets of loops to jump through.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.