http://qs1969.pair.com?node_id=984280

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

Esteemed Monks,

I am having some trouble trying to print the actual contents of a specific memory address. Essentially, I am trying to emulate C-type pointer dereferencing with basic Perl commands (rather than any specially designed modules). While I can easily obtain the memory address of a given variable,
perl -e '$a=5;printf "%p\n", $a'
I do not know how to print the contents of a given memory address (e.g., '0xe98af0'). I am sure there is an easy way to do it in Perl but I haven't been able to find it.

Any help with this would be much appreciated.

Kind regards -

Pat

Replies are listed 'Best First'.
Re: How to access the contents of a specific memory address?
by moritz (Cardinal) on Jul 29, 2012 at 12:15 UTC

    Perl has references itself (see perlreftut, perlref), but it does not allow you access to arbitrary memory addresses. That's a feature, because it means you can't get segmentation fauls or bus errors if you stick to pure Perl code (no C code involved).

    What do you need C-Pointer dereferencing for? Maybe there's a better way to achieve your underlying goal.

      That's a feature, because it means you can't get segmentation fauls or bus errors if you stick to pure Perl code (no C code involved).

      I disagree.
      perl -e "print unpack('p', pack('J', 1))"
        Strange: When I try this, I get a segmentation fault. Am I overlooking some important detail?
        $ perl -e 'print unpack("p", pack("J", 1))' Segmentation fault
      Thanks for this response! It pretty much is a reflection of my understanding of Perl's memory addressing capabilities so far.
      As for my underlying objective, I am trying to understand the concept of buffer overflow and have been experimenting around with it a little. In particular, I have been unable to create a simple buffer overflow (in analogy to how this would be achieved in a simple C programme) and am therefore trying to gain deeper insight into how Perl manages memory allocation. It's exactly at this point that I would like to see what values certain memory addresses have been allocated.
        What do you want know on perl's memory allocation?

        If you want a 1 second glimpse, run
        use Devel::Peek; $num = 5; Dump($num); print $num."\n"; Dump($num);
        Output
        SV = IV(0xbf4958) at 0xbf495c REFCNT = 1 FLAGS = (IOK,pIOK) IV = 5 5 SV = PVIV(0x39df74) at 0xbf495c REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) IV = 5 PV = 0x84cb0c "5"\0 CUR = 1 LEN = 4
        If you want to know more, read illguts. Someone on perlmonks is bound to know whatever you ask about Perl's C side.

        I assume that you are using a perl array as a "buffer". In perl you do not have to predefine the length of an array. The array expands as you push additional elements into it. Use the length of the array to detect your maximum buffer length. Use splice to reset the length.

Re: How to access the contents of a specific memory address?
by bulk88 (Priest) on Jul 29, 2012 at 15:46 UTC
    my $astring = "some string"; my $svptr = (\$astring)+0; #works on 32 bit ONLY my $packesvptr = pack('L', $svptr); my $svbinary = unpack('P[L4]', $packesvptr); my $packedPV = substr($svbinary, 4*3, 4); print "\"".unpack('p', $packedPV)."\"";#null terminated, use 'P[12345] +' for binary data print "\n\nExample 2\n\n"; $packedPV = pack('p', $astring ); print "\"".unpack('p', $packedPV)."\"";
    This is pretty much all of Perl's Perl Language pointer API. You can get a pointer to a scalar string (not a pointer to a scalar integers!!!, egh, actually you can, but if you need to do it, you know how to do it) and you can get a SV *and you can read an arbitrary memory location into a scalar string, null terminated or fixed length. pack wants pointers in packed binary "\x01\x02\x03\x04" format, not english/readable/perl scalar integers "1234567" format. Only major limitation is Perl language can't copy scalar strings to arbitrary memory address (but see this hack Pure Perl module(246 lines, Linux/Win32) that calls external libraries - no XS file., but its not pure Perl language (Dynaloader Module), so that doesn't meet the standard of pure Perl language, also there is syscall, I dont use unix, so I dont know if there is a way to call a C memcpy with syscall). My code is 32 bit only. Changes would have to be made for it to work on 64 bits.

    update: after reading Re^4: How to access the contents of a specific memory address?, I'll add this

    pointer dereferencing with basic Perl commands (rather than any specially designed modules)


    You mentioned with the basic Perl language. malloc and memcpy and free are all available somewhere someway on CPAN as XS modules, and they will work correctly without any crashes except for cases where they will crash in C and in Perl together, always (access vio, corrupting malloc headers, etc). Some monks here question why on earth you need pointers in Perl? They are correct, you can't save a pointer to a disk, it will never be valid in another process. You can't send a pointer through IPC to another process, its not valid in the other process. You can't send a pointer through the network to another PC, it is not valid on that other PC. No perl basic language commands take integer pointers (except for syscall maybe). To use your integer pointers you would need a FFI XS module, or a XS module that wants SVIVs with pointers in them as parameters (a possible design choice for a XS library to keep the XS code as small as possible, and put the parameter conversion logic into Perl, even though its quite slower then) for passing to a C function.
      Thanks for this post!

      I had actually been experimenting with pack() and unpack() before as well but somehow did not get them to work the way I wanted it, probably because of the incorrect input address format. I'll try to understand your sample code and may get back with further questions in case I cannot fathom all depths of it.
Re: How to access the contents of a specific memory address?
by Marshall (Canon) on Jul 29, 2012 at 23:16 UTC
    Basically the posts here not with standing:
    The answer is NO.

    Perl cannot access an absolute physical memory address.

    In "C" there are ways to "map" a piece of physical memory to an array - maybe for memory mapped I/O?
    But such a thing has to run as a kernel process (device driver, etc).

    A user process like Perl simply cannot do it. Thats it.

    A user process can access its own DATA space, but this is an offset from a physical address of which the user process is completely unaware - the hardware does some magic. Since Perl is a "user" process, it cannot know and it cannot access an actual physical memory address like say, "0x000" - the OS will prevent such a thing - its just that simple. NO, Absolutely NOT!

      In "C" there are ways to "map" a piece of physical memory ... Since Perl ... cannot access an actual physical memory address.

      Sorry, but I think you are just muddying the waters with this post. The OP didn't ask how to do that.

      Nowhere in the OP did he mention "physical memory", just a specific memory address & the memory address of a given variable & a given memory address; all of which are generically taken to mean: addresses within the virtual address space of the current process unless explicitly qualified otherwise.

      Outside the auspices of deep technical discussion at the operating system or hardware level, this -- along with your other occasional overreach in to technicalities: there's no such thing as a file -- just come across as clever dickiness rather than constructive attempts to help.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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.

      The start of some sanity?

        Ok. My effort failed. My intent was not to be "dicky" whatever that means. So what is the best practical "how to" answer for the OP?
Re: How to access the contents of a specific memory address?
by Khen1950fx (Canon) on Jul 30, 2012 at 00:23 UTC
    When you try to access the contents of a specific memory address, the only thing that can happen is a segmentation fault. I experimented with this:
    #!/usr/bin/perl BEGIN { $| = 1; $^W = 1; } use strict; use autodie; use warnings FATAL => 'syntax'; use Data::Dumper::Concise; use POSIX; use POSIX::RT::Signal qw/sigwaitinfo sigqueue/; use threads; use Scalar::Util qw/refaddr/; use Devel::Pointer::PP; POSIX::sigprocmask( POSIX::SIG_BLOCK, POSIX::SigSet->new(&POSIX::SIGRT +MIN) ); my $thr = threads->create( \&_thread ); sub _thread { my $sigset = POSIX::SigSet->new(&POSIX::SIGRTMIN); my $info = sigwaitinfo($sigset); } my $address = 5; refaddr( \$address ); my $new_address = \$address; $$new_address = $$new_address * 4; sigqueue( $$, &POSIX::SIGRTMIN, $address ); $thr->join(); print Dumper($address); my $smash = unsmash_sv( 0 + $address ); print Dumper($smash); exit(0);
      my $address = 5; refaddr( \$address ); my $new_address = \$address; $$new_address = $$new_address * 4; sigqueue( $$, &POSIX::SIGRTMIN, $address ); $thr->join(); print Dumper($address); my $smash = unsmash_sv( 0 + $address );
      I can't understand what you are doing here. times 4? "(char *) 5" will of course crash, so will "(char *) 20". If you use Windows, learn what WONT seg fault, Virtual Memory Map Viewer (FOSS I think) and VMMAP more advanced.