Get structure from memory in another process and unicode question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • michelqa

    Get structure from memory in another process and unicode question

    Hello,

    I can retrieve column text from a ListView in another process but I
    cant figure out how to access to structure elements (LVCOLUMN)

    <code>
    //Handle variable is a valid ListView handle

    LV_COLUMN ListViewItem = new LV_COLUMN();
    IntPtr ListViewItemPoi nter = IntPtr.Zero;
    byte[] ListViewItemBuf fer = new byte[512];
    IntPtr ListViewPointer _item = IntPtr.Zero;
    IntPtr ListViewProcess Pointer = IntPtr.Zero;

    //open the process
    int ProcessID;
    Win32.GetWindow ThreadProcessId (Handle, out ProcessID);
    ListViewProcess Pointer = Win32.OpenProce ss(Win32.PROCES S_VM_OPERATION
    | Win32.PROCESS_V M_READ | Win32.PROCESS_V M_WRITE |
    Win32.PROCESS_Q UERY_INFORMATIO N, false, (int)ProcessID) ;

    //allocate memory
    ListViewItemPoi nter = Win32.VirtualAl locEx(ListViewP rocessPointer,
    IntPtr.Zero, Marshal.SizeOf( typeof(LV_COLUM N)), Win32.MEM_COMMI T,
    Win32.PAGE_READ WRITE);
    ListViewPointer _item = Win32.VirtualAl locEx(ListViewP rocessPointer,
    IntPtr.Zero, 512, Win32.MEM_COMMI T, Win32.PAGE_READ WRITE);

    //Get column Text (pszText) and width (cx)
    int ColumnCnt=0;
    bool GetColumnResult =true;
    while (GetColumnResul t)
    {
    ListViewItem.ma sk=(int)Win32.L istViewConstant s.LVCF_TEXT|
    (int)Win32.List ViewConstants.L VCF_WIDTH;
    ListViewItem.cc hTextMax = 512;
    ListViewItem.ps zText = ListViewPointer _item;
    Win32.WriteProc essMemory(ListV iewProcessPoint er,
    ListViewItemPoi nter,
    ref ListViewItem, Marshal.SizeOf( typeof(LV_COLUM N)),
    IntPtr.Zero);
    GetColumnResult =Convert.ToBool ean((int)Win32. SendMessage(
    Handle, (int)Win32.Wind owsMessages.LVM _GETCOLUMN,
    (IntPtr)ColumnC nt, ListViewItemPoi nter));
    if (GetColumnResul t)
    {
    IntPtr bytesReaded;
    IntPtr buff = IntPtr.Zero;
    Win32.ReadProce ssMemory(ListVi ewProcessPointe r,
    ListViewPointer _item, ListViewItemBuf fer, 512, out bytesReaded);

    MessageBox.Show ("ColumnText =["+Encoding.Unic ode.GetString(L istViewItemBuff er)
    +"]");
    MessageBox.Show ("ColumnWidt h (not
    working)="+List ViewItem.cx.ToS tring());
    }
    ColumnCnt++;
    }
    Win32.VirtualFr eeEx(ListViewPr ocessPointer, ListViewItemPoi nter, 0,
    Win32.MEM_RELEA SE);
    Win32.VirtualFr eeEx(ListViewPr ocessPointer, ListViewPointer _item, 0,
    Win32.MEM_RELEA SE);
    </code:


    QUESTIONS
    ***************
    - How can I get my LVCOLUMN structure from memory to read the cv
    member to get the column Width ?
    - Unicode issue, When displaying the column name, look like there is
    something to trim because the last "]" character is missing when
    executing :
    MessageBox.Show ("ColumnText =["+Encoding.Unic ode.GetString(L istViewItemBuff er)
    +"]<-Text here is ignored why???"); Is anybody know the correct way
    to trim the string?

    I cant find an ugly workaround for the unicode issue but I really need
    to get access to the LVCOLUMN elements....the width by example
    LVCOLUMN.cx is suppose to contain the width of the column when using
    the mask LVCF_WIDTH.

    I'm working on this since a long time....please help me if you can.
    Thanks.
  • Jon Skeet [C# MVP]

    #2
    Re: Get structure from memory in another process and unicode question

    On Aug 12, 6:05 am, michelqa <miche...@yahoo .cawrote:

    <snip>
    - Unicode issue, When displaying the column name, look like there is
    something to trim because the last "]" character is missing when
    executing :
    MessageBox.Show ("ColumnText =["+Encoding.Unic ode.GetString(L istViewItemBuff er)
    +"]<-Text here is ignored why???");  Is anybody know the correct way
    to trim the string?
    Encoding.GetStr ing is converting *all* the data (because that's what
    you've asked it to do). That means you'll end up with a load of
    unicode character 0s at the end - and MesageBox.Show will stop when it
    sees character 0, thinking it's the end of the string. You should
    really only decode the correct number of bytes, but an alternative is
    to trim the end of the result of Encoding.GetStr ing with TrimEnd('\0')

    Jon

    Comment

    • michelqa

      #3
      Re: Get structure from memory in another process and unicode question

      Thanks Jon it work to fix my unicode problem

      I desperately still need help for my problem to retrive LV_COLUMN
      structure.

      Look like something is missing to get the struct with
      ListViewItemPoi nter... I try Marshal.PtrToSt ruct and different other
      things without success

      Comment

      • Pavel Minaev

        #4
        Re: Get structure from memory in another process and unicode question

        On Aug 12, 12:34 pm, michelqa <miche...@yahoo .cawrote:
        Thanks Jon it work to fix my unicode problem
        >
        I desperately still need help for my problem to retrive LV_COLUMN
        structure.
        >
        Look like something is missing to get the struct with
        ListViewItemPoi nter... I try Marshal.PtrToSt ruct and different other
        things without success
        If you're using the overload of PtrToStructure which takes a
        destination Object as a second argument (rather than a Type), keep in
        mind that it won't work if you pass it a value type. So, if you've
        declared ListViewItem as a struct , you should rather use the
        PtrToStructure( IntPtr, Type) overload - perhaps this is the problem?

        If not, then can you be more specific as to what exactly goes wrong
        for you?

        Comment

        • michelqa

          #5
          Re: Get structure from memory in another process and unicode question

          When I try to convert the pointer to structure I get a null
          exception : "Object reference not set to an instance of an object"

          I add the following code in the while loop

          LV_COLUMN TmpLvCol; //or LV_COLUMN TmpLvCol=new LV_COLUMN();
          TmpLvCol=(LV_CO LUMN)Marshal.Pt rToStructure(Li stViewItemPoint er,typeof(LV_CO LUMN)); //
          Return Object reference not set to an instance of an object.
          MessageBox.Show (TmpLvCol.cx.To String());


          If I use the PtrToStructure without the return value i get " The
          structure must not be a value class."

          LV_COLUMN TmpLvCol=new LV_COLUMN();
          Marshal.PtrToSt ructure(ListVie wItemPointer,Tm pLvCol);
          MessageBox.Show (TmpLvCol.cx.To String()); // return The structure must
          not be a value class.

          Is PtrToStructure is really the way to get my structure??
          Is ListViewItemPoi nter need some additionnal memory manipulation to be
          able to retreive the information?

          Comment

          • Pavel Minaev

            #6
            Re: Get structure from memory in another process and unicode question

            On Aug 12, 11:18 pm, michelqa <miche...@yahoo .cawrote:
            When I try to convert the pointer to structure I get a null
            exception : "Object reference not set to an instance of an object"
            >
            I add the following code in the while loop
            >
            LV_COLUMN TmpLvCol;    //or LV_COLUMN TmpLvCol=new LV_COLUMN();
            TmpLvCol=(LV_CO LUMN)Marshal.Pt rToStructure(Li stViewItemPoint er,typeof(LV_CO ­LUMN));  //
            Return Object reference not set to an instance of an object.
            MessageBox.Show (TmpLvCol.cx.To String());
            Marshal won't handle the bit about the pointer pointing to a memory
            block in another process by itself - you'll have to help it by copying
            the struct into your own process memory space manually, just like you
            do with the string, and then use PtrToStructure on the copy. Also, it
            will probably try to follow the LPTSTR pointer in the copied struct,
            so you'll need to marshal that between processes as well - copy the
            string data (you already did that), and modify the pointer in your
            copy of the struct to point to that data.
            If I use the PtrToStructure without the return value i get " The
            structure must not be a value class."
            Yes, this is what I mentioned earlier. Just don't use that overload.

            Comment

            • michelqa

              #7
              Re: Get structure from memory in another process and unicode question

              copying the struct into your own process memory space manually, just like you
              do with the string, and then use PtrToStructure on the copy.
              I have to admin that I'm totally confused with memory allocation
              between process...could you be just a little bit more explicit ? I
              try the following in the loop but it fails :

              IntPtr buff = IntPtr.Zero;
              bool ReadProcResul=W in32.ReadProces sMemory(ListVie wProcessPointer ,
              ListViewItemPoi nter, buff, (uint)Marshal.S izeOf(typeof(LV _COLUMN)),
              out bytesReaded); //--Fail
              if (!ReadProcResul )
              MessageBox.Show ("Read memory Fail");

              as I understand it the steps are
              - Allocate memory for the struct with virtualallocex( ), //already
              done in my initial code
              - Read the struct (copy from remote to local memory) with
              ReadProcessMemo ry()
              - Convert the IntPtr to the struct with PtrToStructure( )
              - ??understand what to do with the LPSTR in the struct when retreiving
              the struct...but I already have the text of the column

              still continue to play with this...

              Comment

              • michelqa

                #8
                Re: Get structure from memory in another process and unicode question


                here is my latest code I only want to get the access to LV_COLUMN
                returned infos for the first column.

                LV_COLUMN lv_col = new LV_COLUMN();
                /*** Open the process ***/
                int ProcessID;
                Win32.GetWindow ThreadProcessId (Handle, out ProcessID);
                IntPtr hProcess = Win32.OpenProce ss(Win32.PROCES S_VM_OPERATION |
                Win32.PROCESS_V M_READ | Win32.PROCESS_V M_WRITE |
                Win32.PROCESS_Q UERY_INFORMATIO N, false, (int)ProcessID) ;
                /*** Allocate memory for lv_col struct and lv_col.pszText ***/
                IntPtr lv_colPtr = Win32.VirtualAl locEx(hProcess, IntPtr.Zero,
                Marshal.SizeOf( typeof(LV_COLUM N)), Win32.MEM_COMMI T,
                Win32.PAGE_READ WRITE);
                IntPtr pszTextPtr= Win32.VirtualAl locEx(hProcess, IntPtr.Zero, 512,
                Win32.MEM_COMMI T, Win32.PAGE_READ WRITE);
                /*** Fill lv_col ***/
                lv_col.mask=(in t)Win32.ListVie wConstants.LVCF _TEXT|
                (int)Win32.List ViewConstants.L VCF_WIDTH;
                lv_col.cchTextM ax = 512;
                lv_col.pszText = pszTextPtr;
                /*** Write structure to memory ***/
                Win32.WriteProc essMemory(hProc ess, lv_colPtr, ref lv_col,
                Marshal.SizeOf( typeof(LV_COLUM N)), IntPtr.Zero);
                /*** Send LVM_GETCOLUMN to retreive information about first column
                ***/
                Win32.SendMessa ge(Handle, (int)Win32.Wind owsMessages.LVM _GETCOLUMN,
                (IntPtr)0, lv_colPtr));
                /*** Read the first column text ***/
                IntPtr bytesReaded;
                byte[] ListViewItemBuf fer = new byte[512];
                Win32.ReadProce ssMemory(hProce ss, pszTextPtr, ListViewItemBuf fer,
                512, out bytesReaded);

                MessageBox.Show ("ColumnText =["+Encoding.Unic ode.GetString(L istViewItemBuff er).TrimEnd('\0 ').Trim()
                +"]");
                /*** Nothing work from this point ReadProcessMemo ry fail ***/
                if (!Win32.ReadPro cessMemory(hPro cess, lv_colPtr, BuffPtr,
                (uint)Marshal.S izeOf(typeof(LV _COLUMN)), out bytesReaded)) // = fail
                MessageBox.Show ("read fail");
                LV_COLUMN lv_colTmp;

                lv_colTmp=(LV_C OLUMN)Marshal.P trToStructure(l v_colPtr,typeof (LV_COLUMN)); //
                = fail
                MessageBox.Show ("Column width="+lv_colT mp.cx.ToString( ));
                Win32.VirtualFr eeEx(hProcess, lv_colPtr, 0, Win32.MEM_RELEA SE);
                Win32.VirtualFr eeEx(hProcess, pszTextPtr, 0, Win32.MEM_RELEA SE);

                After hours of search in google, learn more about memory operation and
                trying to understand what could be wrong I still have no clue about
                this. Will continue to work on this today for the next 5 hours :(

                Comment

                • Pavel Minaev

                  #9
                  Re: Get structure from memory in another process and unicode question

                  On Aug 13, 1:08 am, michelqa <miche...@yahoo .cawrote:
                  copying the struct into your own process memory space manually, just like you
                  do with the string, and then use PtrToStructure on the copy.
                  >
                  I have to admin that I'm totally confused with memory allocation
                  between process...could you be just a little bit more explicit ?  I
                  try the following in the loop but it fails :
                  >
                  IntPtr buff = IntPtr.Zero;
                  bool ReadProcResul=W in32.ReadProces sMemory(ListVie wProcessPointer ,
                  ListViewItemPoi nter, buff, (uint)Marshal.S izeOf(typeof(LV _COLUMN)),
                  out bytesReaded);   //--Fail
                  if (!ReadProcResul )
                     MessageBox.Show ("Read memory Fail");
                  >
                  as I understand it the steps are
                  - Allocate memory for the struct with virtualallocex( ),   //already
                  done in my initial code
                  - Read the struct (copy from remote to local memory) with
                  ReadProcessMemo ry()
                  - Convert the IntPtr to the struct with PtrToStructure( )
                  Well yes, that's where it fails, most likely. See, you've read the
                  struct from another process' memory into your own. However, the struct
                  itself has a pointer field - pszText - and the value of that field is
                  still the same as in the process you've copied it from. There, it
                  pointed to the actual string data; in your process, it's just an
                  invalid pointer. I think that PtrToStructure( ) tries to treat it as a
                  proper string for unmarshalling, and ends up dereferencing that
                  invalid pointer.

                  To do this "properly", after you've copied the raw bytes of the struct
                  into your own memory, you'd need to fix that pointer in there -
                  overwrite the value inside with pointer to string data in your memory
                  (which you earlier obtained by copying the string itself). However, in
                  this case, since you've already got the string data elsewhere, you
                  might want to just zero out those bytes, since it's much simpler - the
                  marshaller should be able to handle this, and unmarshall it as a null
                  string. Offset of pszText within LVITEM is 20 bytes, so you just need
                  to zero bytes 21-24 within the memory block.

                  Comment

                  • michelqa

                    #10
                    Re: Get structure from memory in another process and unicode question

                    Finally.... It work now!!!

                    I found the solution with Pavel's precious advises and the following
                    example in VB : http://files.codes-sources.com/fichi...NET%5CIcons.vb

                    Pavel : Thanks again for your help :)

                    Comment

                    • Pavel Minaev

                      #11
                      Re: Get structure from memory in another process and unicode question

                      On Aug 13, 11:25 am, michelqa <miche...@yahoo .cawrote:
                      Finally.... It work now!!!
                      >
                      I found the solution with Pavel's precious advises and the following
                      example in VB :  http://files.codes-sources.com/fichi...prjSaveIcons.N...
                      >
                      Pavel : Thanks again for your help :)
                      You're welcome. Could you please clarify what was the nature of the
                      problem in the end (for those who might stumble onto this thread in
                      the future looking for a solution to the same problem)? Was my last
                      guess correct?

                      Comment

                      • michelqa

                        #12
                        Re: Get structure from memory in another process and unicode question

                        Dont even took the time really understand what was wrong
                        previously... I restart from scratch many times.

                        To close this thread... here is my last code (working) :

                        int ProcessID;
                        Win32.GetWindow ThreadProcessId (Handle, out ProcessID);
                        IntPtr hProcess = Win32.OpenProce ss(Win32.PROCES S_VM_OPERATION |
                        Win32.PROCESS_V M_READ | Win32.PROCESS_V M_WRITE |
                        Win32.PROCESS_Q UERY_INFORMATIO N, false, (int)ProcessID) ;
                        LV_COLUMN lv_col = new LV_COLUMN();
                        IntPtr pszTextPtr= Win32.VirtualAl locEx(hProcess, IntPtr.Zero, 512,
                        Win32.MEM_COMMI T|Win32.MEM_RES ERVE, Win32.PAGE_READ WRITE);
                        IntPtr lv_colPtr = Win32.VirtualAl locEx(hProcess, IntPtr.Zero,
                        Marshal.SizeOf( lv_col), Win32.MEM_COMMI T|Win32.MEM_RES ERVE,
                        Win32.PAGE_READ WRITE);
                        lv_col.mask=(in t)Win32.ListVie wConstants.LVCF _TEXT|
                        (int)Win32.List ViewConstants.L VCF_WIDTH;
                        lv_col.cchTextM ax = 512;
                        lv_col.pszText = pszTextPtr;
                        string L_buf=" ";
                        IntPtr TextPtr=Marshal .StringToHGloba lUni(L_buf);
                        IntPtr bytesReaded;
                        Win32.WriteProc essMemory(hProc ess, pszTextPtr, TextPtr, 512,
                        IntPtr.Zero);
                        Marshal.FreeHGl obal(TextPtr);
                        IntPtr ptr = Marshal.AllocHG lobal(Marshal.S izeOf(lv_col));
                        Marshal.Structu reToPtr(lv_col, ptr, true);
                        Win32.WriteProc essMemory(hProc ess, lv_colPtr,ptr,
                        Marshal.SizeOf( lv_col),IntPtr. Zero);
                        Marshal.FreeHGl obal(ptr);
                        Win32.SendMessa ge(Handle, (int)Win32.Wind owsMessages.LVM _GETCOLUMN,
                        (IntPtr)0, lv_colPtr);
                        ptr = Marshal.AllocHG lobal(512);
                        Win32.ReadProce ssMemory(hProce ss, pszTextPtr, ptr, 512, out
                        bytesReaded);
                        L_buf = Marshal.PtrToSt ringUni(ptr);
                        Marshal.FreeHGl obal(ptr);
                        ptr = Marshal.AllocHG lobal(Marshal.S izeOf(lv_col));
                        Win32.ReadProce ssMemory(hProce ss, lv_colPtr, ptr,(uint)
                        Marshal.SizeOf( lv_col), out bytesReaded);
                        lv_col = (LV_COLUMN) Marshal.PtrToSt ructure(ptr, lv_col.GetType( ));
                        Marshal.FreeHGl obal(ptr);
                        MessageBox.Show (lv_col.cx.ToSt ring());
                        MessageBox.Show (L_buf);
                        Win32.VirtualFr eeEx(hProcess, lv_colPtr, 0, Win32.MEM_RELEA SE);
                        Win32.VirtualFr eeEx(hProcess, pszTextPtr, 0, Win32.MEM_RELEA SE);

                        Comment

                        Working...