• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            Using WM_COPYDATA

            來源:http://www.flounder.com/wm_copydata.htm

            I have experienced several problems, not of my own creation, in using WM_COPYDATA. Now, when I need to use it, I use a mechanism that protects me against the sort of problems I experienced. This essay describes those techniques for creating programs that can reliably and with some assurances of security use WM_COPYDATA.

             

             

            Introduction to WM_COPYDATA

            The WM_COPYDATA message is used to send large blocks of data across process boundaries. It is defined as 

            
            
            SendMessage(target, WM_COPYDATA, (WPARAM)sender, (LPARAM)&COPYDATASTRUCT)

            The WPARAM is the handle of the sending window. The LPARAM is a pointer to a structure of the form

            
            
            typedef struct tagCOPYDATASTRUCT 
                ULONG_PTR dwData; 
                DWORD     cbData; 
                PVOID     lpData; 
            }
             COPYDATASTRUCT, *PCOPYDATASTRUCT; 

            Presumably the dwData member is a small integer that tells the receiving window how to interpret the data referenced by lpData. The cbData value tells how many bytes of data are being passed.

            This message can only be sent via SendMessage, which means that it will hang indefinitely if the receiving thread is blocked, or via SendMessageTimeout, if you want reliability. However, it cannot be send via PostMessage.

            The data specified appears in the receiver's address space, and is pointed to by a similar COPYDATASTRUCT seen by the receiver. The receiver can examine the dwData to determine what to do, and use at most cbData bytes of the data pointed to by the lpData pointer. The data is intact only as long as the message is being processed. When you return from the OnCopyData handler, the data will disappear from the receiver's address space, so you must not store a copy of the lpData pointer. Instead, if you need the data after the handler returns, you must, in the receiving process, copy the data to a place in the program where it will remain available.


            WM_COPYDATA hazards

            I don't trust WM_COPYDATA.

            It is not that I don't trust it to work. Indeed, it is reliable. It is not that I don't trust it to actually deliver data. It does that, too.

            What I don't trust, as the receiver, is the sender. Having the WPARAM value which tells me the sender window handle doesn't help much, because the sender window could be any window of an application, not just the main frame. I have actually been the victim of an incorrect WM_COPYDATA message. The programmer who was sending it had no idea how to find the desired target window, so instead, "cleverly" decided to broadcast the WM_COPYDATA message to all top-level windows, knowing that his window would eventually get it. Of course, mine did also.

            Furthermore, sending a bogus WM_COPYDATA is something a malicious program might choose to do in order to cause other programs to crash. I want to be robust against this sort of attack.



            Making WM_COPYDATA safe

            What I do for security is create a GUID. In this case, I don't want the textual form, I want the binary form. I then place this GUID, which is a 128-bit value, in the first part of my data. When I code the receiver, I test the first 16 bytes of every WM_COPYDATA packet (and there must be at least 16 bytes in the WM_COPYDATA packet, or I ignore it). If the first 16 bytes of the message do not match the GUID, I simply return 0 and ignore the message. Since I started doing this, I have never been the victim of an erroneous WM_COPYDATA send to my application (even in the environment of rogue WM_COPYDATA messages).

            Here's an example of the kind of message I send. In this case, I sent it to my own process, but it would work identically across process boundaries. Note the first 16 bytes are the GUID, which will be shown later. I have three other buttons, one to send a message that is too short, one to send a message with a bad GUID, and one to send a message with an unknown dwType.

            This shows what happens if I send fewer than sizeof(GUID) bytes:

            If I send a bad GUID (look at the 5th byte in the first line and compare it to the first version, above), I get

            and if I send a bad type, I get the following result. Note that the dwData field is 2, and I was only prepared to accept 1.

            Here's my set of related classes, a file I call CopyData.h.

            #ifndef MAX_COPY_LENGTH
            #define MAX_COPY_LENGTH 128
            #endif

            class CopyPacket {
                
            public:
                   GUID Signature;
                   BYTE data[MAX_COPY_LENGTH];
                
            public:
                   BOOL Same(
            const GUID & s)
                     
            return memcmp(&Signature, &s, sizeof(GUID)) == 0; }
            }
            ;
               

            class CopyData {
                
            public:
                   CopyData(UINT id, GUID s)
                     
            { packet.Signature = s; cds.dwData = id; cds.cbData = 0; cds.lpData = &packet; }
                   UINT SetLength(UINT n)
                     
            { cds.cbData = sizeof(packet.Signature) + n; return cds.cbData; }
                   
            void SetData(LPCVOID src, size_t length)
                     
            { ::CopyMemory(packet.data, src, length); }
                   LRESULT Send(HWND target, HWND sender)
                     
            return ::SendMessage(target, WM_COPYDATA, (WPARAM)sender, (LPARAM)&cds); }
                   
            static UINT GetMinimumLength()
                     
            return sizeof(GUID); }
                
            protected:
                   COPYDATASTRUCT cds;
                   CopyPacket packet;
            }
            ;



            To create the signature, I use GUIDGen, and create a GUID using the option shown: If you are not aware of it, a GUID is globally unique; that is, once you create one, it is the only one which will ever exist, anywhere in the world. No one else will ever re-create the same GUID.

            OK, a fine point. If you don't have a network card, there is something like 1 chance in 263 or something equally large that two 128-bit GUIDs could coincide. Figure out how many computers need to create how many GUIDs at what rate and you'll see this is not a Major Issue To Be Concerned With.

            The option I show is the closest one to what I want. I click on the Copy button, then I paste the text into a file called signature.h. I replace the first line with 

            #define SIGNATURE \

            I then declare, in my implementation files, a static global variable which defines the signature. Each module that wants to send or receive a message must contain this declaration.

             

            static const GUID Signature = SIGNATURE;


            I need a dwType to distinguish what kind of message I'm sending. In this case, I am only sending one type of message, which I have decided to call COPYDATA_TYPE_1, which I define as the constant 1 (a whimsical choice).

            To send a message, such as the valid sending, I do something like shown below (this is simplified, because I use the various check boxes and options to derive the window handles). Also, in my case, I'm sending the message from my application to itself, so the first parameter (target) and the second parameter (sender) are both m_hWnd.

             

            void CCopyDataDlg::OnSendvalid() 
               
            {
                CopyData sendData(COPYDATA_TYPE_1, Signature);
                CString s;
                c_Input.GetWindowText(s);

                sendData.SetData((LPCVOID)(LPCTSTR)s, s.GetLength()
            +1);
                sendData.SetLength(s.GetLength() 
            + 1);
                sendData.Send(m_hWnd, m_hWnd);
               }

            The receive code, minus the code that loads the messages into the status boxes, 
            is then quite simple:

            BOOL CCopyDataDlg::OnCopyData(CWnd
            * pWnd, COPYDATASTRUCT* cds) 
               
            {
                CopyPacket 
            * cp = (CopyPacket *)cds->lpData;
                BOOL result 
            = TRUE;

                
            if(cds->dwData != COPYDATA_TYPE_1)
                   
            /* bad type */
                result 
            = FALSE;
                   }
             /* bad type */

                
            if(cds->cbData < CopyData::GetMinimumLength())
                   
            /* record too short */
                result 
            = FALSE;
                   }
             /* record too short */

                
            if(!cp->Same(Signature))
                   
            /* record bad signature */
                result 
            = FALSE;
                   }
             /* record bad signature */

                
            if(result)
                   
            /* success */
                
            do something with the message
                   }
             /* success */

                
            return result;
                
            }

             


            Broadcast Usage

            Note that using HWND_BROADCAST as the target window will send the message to every window. In this example, I have two copies of my program running, and the upper-left window receives the same data as the lower right window. However, every other application window in my desktop received this message. I was lucky. None of them were bothered by the WM_COPYDATA. This is not always going to be the case. So sending a message like this using HWND_BROADCAST is to be considered a seriously antisocial act. If you download my files and try to send using HWND_BROADCAST (checking the Broadcast box), you may well crash programs you have running. If so, Let That Be A Lesson To You.




            Passing Pointers

            Note that everything inside the WM_COPYDATA block must be part of the block. You can't use it to pass a pointer to something. For example, it would be a fatal error to pass a CString variable in the WM_COPYDATA block because the string itself would still be in the address space of the sender. If you need to pass a complex structure, you have to make all of the pointers in the WM_COPYDATA block be based pointers that reference the contents of the data block. That is an essay I may write someday.



            Summary

            WM_COPYDATA is a powerful and convenient means for transferring information between two processes. It is not without risks. These techniques were developed to minimize those risks.

            download.gif (1234 bytes)You can download the code for my test app and my CopyData.h file. However, you should not reuse my GUID because there is always the chance someone else will have also copied it, and you lose the security that having a unique ID provides.

            posted on 2009-09-28 21:04 楊粼波 閱讀(1535) 評論(0)  編輯 收藏 引用

            久久青草国产手机看片福利盒子 | 无码久久精品国产亚洲Av影片| 久久天天躁狠狠躁夜夜2020| 日韩电影久久久被窝网| 亚洲国产一成久久精品国产成人综合| 中文精品99久久国产| 日韩AV无码久久一区二区| 99久久精品国产毛片| 热99RE久久精品这里都是精品免费 | 精品熟女少妇av免费久久| 日本久久久精品中文字幕| 久久影视国产亚洲| 无码AV中文字幕久久专区| 伊人久久大香线焦综合四虎| 亚洲国产成人久久综合野外| 久久久精品午夜免费不卡| 伊人久久大香线蕉综合热线| 伊人久久大香线蕉综合影院首页| 97精品国产91久久久久久| 日产久久强奸免费的看| 91精品国产91久久久久久| 精产国品久久一二三产区区别| 91精品国产91久久久久久蜜臀 | 久久精品国产精品亚洲精品| 青青青国产精品国产精品久久久久| 午夜肉伦伦影院久久精品免费看国产一区二区三区| 国产精品久久久香蕉| 久久综合伊人77777麻豆| 国内精品久久久久久久久| 国产午夜精品久久久久免费视| 少妇熟女久久综合网色欲| 激情综合色综合久久综合| 久久91精品国产91久久麻豆| 色诱久久久久综合网ywww| 久久亚洲精品成人AV| 亚洲中文字幕无码久久2017| 久久妇女高潮几次MBA| 97精品依人久久久大香线蕉97| 三级三级久久三级久久| 18禁黄久久久AAA片| 伊人久久大香线蕉av一区|