Announcement

Collapse

Maintenance

The forum could be offline for 30-60 minutes in the very near future for maintenance (said 3pm Pacific). I was behind on getting this notice. I do apologize.
See more
See less

Need help understaind Pointers

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Need help understaind Pointers

    I briefly remember pointers in C++ but I still need some
    understanding because the following code I can't get to
    run correctly. What I am wanting to do is actually read the
    bytes of a function in memory.

    Code:
    #COMPILE EXE
    'test
    
    SUB example()
        MSGBOX "o"
        MSGBOX "hi"
    END SUB
    
    FUNCTION PBMAIN() AS LONG
    DIM PrtMySubCall AS DWORD
    DIM Ptr1 AS STRING PTR
    DIM thedata AS STRING
        PrtMySubCall = CODEPTR(example)
        Ptr1 = PrtMySubCall
        thedata = @Ptr1
        MSGBOX thedata
    END FUNCTION
    this causes a GPF, windows 2000 tells me it can't call the
    memory address. But if I do a call dword on the address
    it executes fine. Am I doing something wrong?

    This is just some stuff I've been messing with just to
    understand pointers a little better. I am trying to
    understand how to implement self modifying code. But mainly
    I want to be able to do this with PB/DLL.

    Thanks

    ------------------
    -Greg
    -Greg
    [email protected]
    MCP,MCSA,MCSE,MCSD

  • #2
    Hi Greg

    I changed your code and put some comments in it which I hope
    will make the use of pointers clearer:

    Code:
    #COMPILE EXE
    'test
     
    'when using call DWORD with a function you need to "prototype" the parameters and the return
    'values the function accepts
    DECLARE FUNCTION example_1( BYVAL sMessage AS STRING) AS STRING
     
    FUNCTION example_1 ( BYVAL sMessage AS STRING) AS STRING
       FUNCTION = REPEAT$(2, sMessage)
    END FUNCTION
     
    SUB example()
        MSGBOX "o"
        MSGBOX "hi"
    END SUB
     
    FUNCTION PBMAIN() AS LONG
    DIM PrtMySubCall AS DWORD
    DIM PtrMyFunctionCall AS DWORD
    DIM Ptr1 AS STRING PTR
    DIM Ptr2 AS ASCIIZ PTR
    DIM Ptr3 AS STRING PTR
    DIM thedata AS STRING
     
        PrtMySubCall = CODEPTR(example) ' a code pointer is a pointer to a sub/function/subroutine
        CALL DWORD PrtMySubCall 'you need to call it
        
        'now a function call with a return value which accepts arguments
        PtrMyFunctionCall = CODEPTR(example_1)
        'need to tell compiler which variables to push and what return to expect
        CALL DWORD PtrMyFunctionCall USING example_1( "REPEAT MY MESSAGE" ) TO thedata
        
        MSGBOX "RETURNED FROM FUNCTION: " + thedata
        'now assign the pointer Ptr1 to point to the pre-allocated string "thedata"
        Ptr1 = VARPTR(thedata) 'Use VARPTR to get the string handle
        MSGBOX "PTR1: " + @Ptr1
        
        'a pointer must always point to a valid memory address - otherwise you get a GPF
        Ptr2 = STRPTR(thedata) 'Use STRPTR to get the string address (needed for ASCIIZ PTR)
        MSGBOX "PTR2: " + @Ptr2
        
        Ptr3 = VARPTR(Ptr1) 'Ptr3 is a pointer to Ptr1
        MSGBOX "PTR3: " + @@Ptr3 'use as many @ as there are levels of indirection
        
        'And now change Ptr3 to another value
        @@Ptr3 = "AND NOW FOR SOMETHING COMPLETELY DIFFERENT"
        MSGBOX "ORIGINAL STRING: " + thedata 'Ptr3 was just pointing to thedata - changing Ptr3 changed
        'the value of thedata
        
        'all pointers point the the declared string
        MSGBOX "PTR1 (after change): " + @Ptr1
     
        'a pointer must always point to a valid memory address - otherwise you get a GPF
        MSGBOX "PTR2 (after change): " + @Ptr2
        
    END FUNCTION
    Pointers are very powerful - they literally point to an area of
    memory.

    Cheers

    Florent


    [This message has been edited by Florent Heyworth (edited July 25, 2000).]

    Comment


    • #3
      Florent,

      Thank you ver much for the well commented code. It helped me a
      lot. I was wondering if this is possible, because this is
      what I was originally wanting:

      sub example()
      dim g as string
      g = "example"
      end sub

      ok somehow get the actual machine code for the function example?
      is that possible?

      What I am wanting to try and do is get the code and store it in
      a file and then load it up and call it later. I'm just trying
      to see how that would work or if it would at all.

      See your example just returns the value of the function or
      simply does a call dword, I understand that easily but why
      can't I do this:

      dim pointer as ASCIIZ PTR
      pointer = example
      msgbox @pointer <----- the binary data of the sub example?

      and then if I can do that can I do this?

      buffer = binary data from file
      dim pointer as ASCIIZ PTR
      pointer = 3454
      @pointer = buffer
      call dword pointer

      Just messing around but I think it would be neato if it worked.

      Thanks


      and actually put the contents at the memor

      ------------------
      -Greg
      -Greg
      [email protected]
      MCP,MCSA,MCSE,MCSD

      Comment


      • #4
        here is a better source of what I'm trying to do and it crashes:

        Code:
        #COMPILE EXE
        
        SUB example()
            DIM g AS STRING
            g = "hi"
            MSGBOX g
        END SUB
        
        FUNCTION PBMAIN() AS LONG
        DIM PrtMySubCall AS DWORD
        DIM Ptr2 AS ASCIIZ PTR
        DIM Ptr3 AS ASCIIZ PTR
        DIM buffer AS STRING
            PrtMySubCall = CODEPTR(example) ' a code pointer is a pointer to a sub/function/subroutine
            Ptr2 = PrtMySubCall
            buffer = @Ptr2
            Ptr3 = STRPTR(buffer)
            MSGBOX @Ptr3 & $CRLF & @Ptr2
            CALL DWORD Ptr2
        ' This doesn't work!
            CALL DWORD Ptr3 '  <------- doesn't work
        END FUNCTION

        what it does is get the address of the sub example and put that
        it pointer2 and then but the contents of pointer2 (the binary
        assembly language I assume) in a buffer and then
        put that in a new pointer and display the results they
        both contain the same info but when I call dword on the new
        pointer it crashes.

        Thanks

        ------------------
        -Greg
        -Greg
        [email protected]
        MCP,MCSA,MCSE,MCSD

        Comment


        • #5
          Greg, it seems you may be confusing code pointers with [string and/or data] pointers. In these circumstances, a GPF is most expected outcome.

          Every Sub and Function that CODEPTR() references will only ever address executable code, not the string literals and data that may be contained or referenced within that Sub or Function.

          The solution is to execute your function, yet make it return a pointer to the [string] data. This storage must not be local to that Sub or Function or it will be released as the sub/function terminates and the pointer would then be invalid.

          In psuedocode: (note, I typed this online without tesing, so it is strictly E&OE!)
          Code:
          FUNCTION GetData() AS DWORD
           STATIC MyData AS STRING
           MyData = "some data"
           FUNCTION = STRPTR(MyData)
          END FUNCTION
          ...
          DIM x AS ASCIIZ PTR
          x = GetData() ' returns the pointer to the persistent string, but treated as an asciiz for convenience.
          MSGBOX @x
          If you wish to use a string pointer, try this variation instead:

          Code:
          FUNCTION GetData() AS DWORD
           STATIC MyData AS STRING
           MyData = "some data"
           FUNCTION = VARPTR(MyData) ' return a pointer to the string handle
          END FUNCTION
          ...
          DIM x AS STRING PTR
          x = GetData() ' returns the pointer to the string handle.
          MSGBOX @x

          ------------------
          Lance
          PowerBASIC Support
          mailto:[email protected][email protected]</A>
          Lance
          mailto:[email protected]

          Comment


          • #6
            [deleted] because I saw Lance answer


            [This message has been edited by Semen Matusovski (edited July 25, 2000).]

            Comment


            • #7
              Lance,

              I'm wanting to copy the executible code of a function or sub into
              a string. Not the value returned from a function.

              The actual machine code of a function. And then I'm wanting to
              take that machine code and put it back and run it from a new
              pointer. Basically I'm trying to load machine code from
              a file and put it in memory and run it, can this be done?

              ....
              buffer = file input
              pointer = buffer
              call dword pointer
              ....

              ------------------
              -Greg
              -Greg
              [email protected]
              MCP,MCSA,MCSE,MCSD

              Comment


              • #8
                Perhaps you can create an exported function with at least the number of bytes
                you wish to replace allocated by inline asm instructions.
                Then disassemble the function to determine where your code begins
                in the function (following the PB function startup code). Add a label to the end of the function
                to which you can add a jump in the replacement code.

                Haven't tried this. Access violation city???



                ------------------
                Ron

                Comment


                • #9
                  Greg,

                  I gather that you are trying to read your code section as data.

                  This is not an easy task in PowerBASIC because you cannot access labels in
                  other functions. I think it can be done but it means trying to get the
                  starting address of the function with CodePtr() and then reading up to a
                  marker that you will have to put in yourself.

                  I would suggest code something like as follows,

                  In the function, put a couple of NOPs and use them as the end indicator.

                  Allocate a string buffer at least as big as the function you want to read
                  and you can safely err on the side of larger.
                  Code:
                      a$   = space$(YourLength)
                      lpB& = StrPtr(a$)
                      lpF& = CodePtr(YourFunction)
                    
                      ! cld           ; should already be clear but to be safe, include it
                    
                      ! mov esi, lpF& ; function address as source
                      ! mov edi, lpB& ; string buffer as destination
                    Label:
                      ! lodsb
                      ! stosb
                      ! cmp al, &H90  ; NOP
                      ! jne Label     ; exit if byte &H90 (NOP)
                    
                      pos& = instr(a$,str$(&H90))
                    
                      result$ = left$(a$,pos& - 1)
                  You will have to examine the code at the beginning of the string as you
                  will probably get the stack code as well.

                  Hope it works out OK.

                  Regards,

                  [email protected]

                  ------------------
                  hutch at movsd dot com
                  The MASM Forum

                  www.masm32.com

                  Comment


                  • #10
                    Steve,

                    That is exactly what I'm trying to do, here is a sample source
                    code

                    #COMPILE EXE

                    '// a$ = space$(YourLength)
                    '// lpB& = StrPtr(a$)
                    '// lpF& = CodePtr(YourFunction)
                    '//
                    '// ! cld ; should already be clear but to be safe, include it
                    '//
                    '// ! mov esi, lpF& ; function address as source
                    '// ! mov edi, lpB& ; string buffer as destination
                    '// Label:
                    '// ! lodsb
                    '// ! stosb
                    '// ! cmp al, &H90 ; NOP
                    '// ! jne Label ; exit if byte &H90 (NOP)
                    '//
                    '// pos& = instr(a$,str$(&H90))
                    '//
                    '// result$ = left$(a$,pos& - 1)

                    Code:
                    FUNCTION GetData() AS DWORD
                    STATIC MyData AS STRING
                    MyData = "some data"
                    END FUNCTION
                    
                    
                    SUB example()
                     DIM a AS STRING
                     DIM b AS STRING
                     a = "greg"
                     b = "yo"
                    END SUB
                    
                    FUNCTION PBMAIN() AS LONG
                    DIM PrtMySubCall AS DWORD
                    DIM PtrMyFunctionCall AS DWORD
                    DIM Ptr1 AS STRING PTR
                    DIM Ptr2 AS ASCIIZ PTR
                    DIM Ptr3 AS ASCIIZ PTR
                    DIM LpB AS long PTR
                    DIM lpF AS long PTR
                    register pos AS long
                    DIM a AS STRING
                    DIM result AS STRING
                    
                    a = SPACE$(500)
                    lpB& = STRPTR(a$)
                    lpF& = CODEPTR(Example)
                     ! cld           ; should already be clear but to be safe, include it
                     ! mov esi, lpF& ; function address as source
                     ! mov edi, lpB& ; string buffer as destination
                    lLABEL:
                     ! lodsb
                     ! stosb
                     ! cmp al, &H90  ; NOP
                     ! jne lLabel     ; exit if byte &H90 (NOP)
                    
                      pos& = instr(a$,str$(&H90))
                     
                      result$ = a$
                    'CALL DWORD lpB&
                    MSGBOX result$
                    END FUNCTION
                    as you can see I'm reading the value of one pointer and then
                    putting it in another pointer and calling a dword on the new
                    pointer. Of course it GPF's any insight?

                    ------------------
                    -Greg
                    -Greg
                    [email protected]
                    MCP,MCSA,MCSE,MCSD

                    Comment


                    • #11
                      You want CHR$(&H90), not STR$(&H90).

                      Please note that code is generally not relocatable. That is, if you move code from one area of memory to another, it is not likely to run properly. I am also not clear on how happy Windows would be about attempts to execute code from a data area.

                      ------------------
                      Tom Hanlin
                      PowerBASIC Staff

                      Comment


                      • #12
                        1) It seems to me that it possible to read a procedure by simple
                        Buffer$ = Peek$(CodePtr(Example), CodePtr(PbMain) - CodePtr(Example))
                        2) Some monthes ago I read in Win32.Hlp that it possible to use LoadLibrary to load exe also.
                        So, I decided to try to call exported functions.
                        Unlike internals of new instance were the same, if to start a program by Explorer, I was not able to run subs (GPF).
                        I lost one hour and decided to look MSDN. In MSDN I found exact phrase - you can't run a program by such way.
                        3) But what is interesting .. There are programs, which decrypts itself during execution.
                        Where ? On HDD - don't beleive, it's not interesting.
                        In memory ? But how ?



                        ------------------

                        Comment


                        • #13
                          Semen,

                          I think your right. It seems that I have no trouble reading the
                          data but it seems that a codeptr is read only if I try to
                          write to it, a GPF occurs and if I copy the information to
                          a data location and run a call dword it causes a GPF. So, hmmm
                          I think those programs that decrypt are doing it in hard drive
                          space, that is the only thing I can think of. If I could
                          actually write to the CODEPTR then I think it would work
                          because I could set up two subs

                          sub example()
                          msgbox "hi"
                          end sub

                          sub dummy()
                          end sub

                          a = CODEPTR(example)
                          b = codeptr(dummy)

                          @b = @a

                          call dword b

                          I think in a perfect world this would work but it doesnt' seem
                          that it will.

                          ------------------
                          -Greg
                          -Greg
                          [email protected]
                          MCP,MCSA,MCSE,MCSD

                          Comment


                          • #14
                            Greg,

                            Its normal for the code section to be readable so as long as you can find
                            a way to identify the offset where you need to read from, you can read
                            from the code section with no problems. getting the data into a string is
                            no big deal but the next step of writing to a code section is very messy
                            to do and very hard to get going properly.

                            Essentially what you are trying to do can be done if you have enough space
                            in the code section and this is easy enough to do, make a function that is
                            larger than the code you wish to run and then overwrite the function with
                            the code you want to run. Doing this however is not an easy task to do as
                            normally the code section is not writable.

                            If you look up the data on PE file headers, you can change the header so
                            that the code section can be written to. The other choice is to mess
                            around with WriteProcesMemory() and write your code to the address of the
                            spare function.

                            Now if you can get this to work which is no joy in itself, the next
                            problem is that the code that you have read from the code section before
                            has the wrong offsets in it so if you succeed in writing it, it will not
                            have the correct addresses as its position in the compiled EXE code as
                            loaded in memory will be incorrect.

                            The way around this is to write all of the code with addresses of GLOBAL
                            variables as these do not depend on the stack or their position within
                            a function.

                            I have a working example in the code with MASM but this type of code is
                            not well suited in the current version of PowerBASIC because for very
                            sensible reasons, module level code is not supported. It could be done
                            in the last version because labels were GLOBAL and you could access them
                            using CodePtr().

                            Good luck with the idea, sad to say you will need it to get it going.

                            [email protected]

                            ------------------
                            hutch at movsd dot com
                            The MASM Forum

                            www.masm32.com

                            Comment


                            • #15
                              Steve,

                              Thanks for your ideas. Now that you bring up the PE header I
                              remember a discussion about that not to long ago on this forum.

                              I will look into that and see what happens. If I can modify the
                              PE header of my executible and create one module and simply
                              do a codeptr on line labels within that module I think the
                              offset might be correct.

                              I'll keep you posted.

                              ------------------
                              -Greg
                              -Greg
                              [email protected]
                              MCP,MCSA,MCSE,MCSD

                              Comment

                              Working...
                              X