線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1895
推到 Plurk!
推到 Facebook!

Debugging with the Socket Spy

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-02-24 21:07:29 IP:218.175.xxx.xxx 未訂閱
http://docs.rinet.ru/Plugi/ch24.htm     
 Chapter 24
Debugging with the Socket Spy     --------------------------------------------------------------------------------        CONTENTS 
Introduction 
The Socket Interface 
Tricking Socket Applications 
Using the Socket Spy with Netscape 
Editing NETSCAPE.EXE 
Getting the Files and Building 
Under the Hood 
The Data Files 
Running the Socket Spy 
Conclusion 
What's Next?     --------------------------------------------------------------------------------    Introduction 
Netscape Navigator communicates with the Internet through a generic socket interface. In Windows 95, this interface is implemented as a DLL called WSOCK32.DLL. This DLL provides an API for all socket-based applications ranging from Web browsers to telnet applications. Any application that uses this socket DLL simply loads it and calls the socket routines. Multiple applications can use WSOCK32.DLL at the same time.     A Netscape Navigator plug-in module normally does not use the Windows socket interface directly. A plug-in uses the plug-in API to communicate its needs to the Navigator, which in turn uses sockets to fulfill any network-related requests.     In many cases, it is nice to know what data the Navigator is reading from and writing to the socket interface. This data can be very helpful in debugging plug-in problems. The Socket Spy enables you to easily monitor this data flow using a standard source-level debugger. It also writes out this data to the files send.dat and recv.dat for each Navigator session. The Socket Spy is implemented as a DLL called WSOCK00.DLL. This DLL is inserted between the Navigator and the socket interface by making Navigator load WSOCK00.DLL instead of WSOCK32.DLL. To do this, you must edit NETSCAPE.EXE with a binary editor and change wsock32 to wsock00. This technique works for any application that uses WSOCK32.DLL and is explained in more detail later in this chapter.     The Socket Interface
Every day more and more socket-based applications are appearing on the scene. These applications can be Web browsers, FTP programs, telnet applications, and any other software that wants to talk on the Internet. In Windows 95, these applications all use the dynamic link library, WSOCK32.DLL, for socket communication. This DLL is shipped with Windows 95, along with a TCP/IP stack. Figure 24.1 shows WinSock interface with the WSOCK32.DLL WinSock DLL.     Figure 24.1 : WinSock applications and the socket interface.     Tricking Socket Applications
The Socket Spy is implemented by changing the name of the socket DLL within the socket application. This is done using a binary editor on the program executable. With the editor, all occurrences of the string wsock32 are changed to wsock00. After you have modified the socket program, it loads WSOCK00.DLL, thinking that it is really WSOCK32.DLL. Because the Socket Spy DLL has all the proper entry points, the socket application links to the new DLL with no problems. Figure 24.2 shows how the Socket Spy DLL, WSOCK00.DLL, intercepts socket calls to and from Netscape's Navigator. Notice that the new DLL does not replace WSOCK32.DLL but acts as an intermediary between the socket application and the WSOCK32.DLL. Also notice that other WinSock applications still have direct access to the original WinSock DLL.     Figure 24.2 : Winsock applications with the Socket Spy.     Warning 
This practice of modifying executables is strictly for in-house debugging because the executable checksums will be incorrect. Virus detection software really hates this!      Using the Socket Spy with Netscape
You can use the Socket Spy with any WinSock application. To use Socket Spy with Netscape's Navigator in a debugging session, you must edit the Navigator's binary executable with binary editor and compile the Socket Spy DLL in debug.     Editing NETSCAPE.EXE
To set up the Socket Spy for use with Netscape, first find the file NETSCAPE.EXE. This file should be located in the directory above the plugins directory. Make sure to make a backup copy of NETSCAPE.EXE. Now get your favorite binary editor that can handle large files, and open the file. Use the editor's search facility and search for all occurrences of the string wsock32. Navigator 2.x and 3.x have only one such string. Change wsock32 to wsock00 and save the file. A good shareware binary editor is Hedit 1.2 by Yuri Software, which is shown in Figure 24.3.     Figure 24.3 : Changing wsock32 to wsock00 with Hedit 1.2 by Yuri Software.     If you don't have a binary editor but you know the offset of the string within the file, you can use Microsoft Visual C to make the change. For example, Navigator 3.0 Beta 2 has the string at offset 0x1E8730. Select the menu item File|Open and pick Open As Binary (see Figure 24.4) in the lower portion of the Open dialog. Don't use the automatic open mode because it opens the file as Resources, which is not what you want.     Figure 24.4 : Opening a file as binary with Microsoft Visual C   4.0.     After the file is open and you can see the standard hexadecimal display, go to the offset with the Edit|Go To menu. Figure 24.5 shows the offset 0x1E8730 entered after Offset is selected in the list box.     Figure 24.5 : The Go To dialog in Microsoft Visual C   4.0.     Now change wsock32 to wsock00 and save the file.     Getting the Files and Building
The next step is copying the files from the CD to a directory on your hard drive. The following files are located in the \CODE\SOCKSPY directory and should be copied:     SOCKSPY.CPP
SOCKCPY.H
SOCKSPY.DEF
SOCKSPY.MAK 
Now build the DLL. With Visual C  , set your Output file name to [drive]: \windows\system\wsock00.dll. This allows the Navigator to find the DLL. Figure 24.6 shows how to set the Output filename with Microsoft's Developer Studio.     Figure 24.6 : Setting the output filename in Microsoft Visual C   4.0.     Also set the Executable for debug session and Working directory in the Debug area of your build settings. Figure 24.7 shows how to set the executable and working directory for D:\Program Files\Netscape\Navigator\Program\netscape.exe.     Figure 24.7 : Setting the executable and working directory.     Now verify that things are working properly by setting a breakpoint in SOCKSPY.CPP on the WSAStartup routine and running the Navigator from within the debugger. Figure 24.8 shows this breakpoint with the Microsoft Debugger.     Figure 24.8 : Setting a breakpoint on WSAStartup.     When you have that working, you can set breakpoints in any of the socket routines while debugging your plug-in!     Under the Hood
The Socket Spy DLL is kind of an odd creature. Because the routines within the Spy DLL have the same names as the WSOCK32 routines, it can't use the standard wsock32.lib to build the Spy DLL. Instead, each API address must be saved to a function pointer using GetProcAddress. This is done during the DLL initialization routine, DllEntryPoint. You might want to consult Chapter 4, "Helper Applications and Network Communications," for a quick refresher on WinSock APIs.     The following code listing shows WinSock APIs being mapped to Socket Spy routines:     //
// This routine is called when your DLL is loaded.
//
BOOL WINAPI DllEntryPoint (HINSTANCE  hinstDLL,    // handle of DLL module
    DWORD  fdwReason,    // reason for calling function
    LPVOID  lpvReserved)
{    if (fdwReason == DLL_PROCESS_ATTACH)
{
if (!ulAttachCount  )
{
    HINSTANCE h;        // Load the real winsock library        if (!(h = LoadLibrary ("wsock32.dll"))) 
        return FALSE;         // Get all the APIs        pfnWinSock.accept = (DEFaccept)GetProcAddress (h, "accept");
    pfnWinSock.bind = (DEFbind)GetProcAddress (h, "bind");
    pfnWinSock.closesocket = (DEFclosesocket)GetProcAddress (h, "closesocket");
    pfnWinSock.connect = (DEFconnect)GetProcAddress (h, "connect");
    pfnWinSock.getsockname = (DEFgetsockname)GetProcAddress (h, "getsockname");
    pfnWinSock.getpeername = (DEFgetpeername)GetProcAddress (h, "getpeername");
    pfnWinSock.getsockopt = (DEFgetsockopt)GetProcAddress (h, 
                "getsockopt"); 
    pfnWinSock.htonl = (DEFhtonl)GetProcAddress (h, "htonl");
    pfnWinSock.htons = (DEFhtons)GetProcAddress (h, "htons");
    pfnWinSock.inet_addr = (DEFinet_addr)GetProcAddress (h, "inet_addr");
    pfnWinSock.inet_ntoa = (DEFinet_ntoa)GetProcAddress (h, "inet_ntoa");
    pfnWinSock.ioctlsocket = (DEFioctlsocket)GetProcAddress (h, "ioctlsocket");
    pfnWinSock.listen = (DEFlisten)GetProcAddress (h, "listen");
    pfnWinSock.ntohl = (DEFntohl)GetProcAddress (h, "ntohl");
    pfnWinSock.ntohs = (DEFntohs)GetProcAddress (h, "ntohs");
    pfnWinSock.recv = (DEFrecv)GetProcAddress (h, "recv");
    pfnWinSock.recvfrom = (DEFrecvfrom)GetProcAddress (h, "recvfrom");
    pfnWinSock.select = (DEFselect)GetProcAddress (h, "select");
    pfnWinSock.send = (DEFsend)GetProcAddress (h, "send");
    pfnWinSock.sendto = (DEFsendto)GetProcAddress (h, "sendto");
    pfnWinSock.setsockopt = (DEFsetsockopt)GetProcAddress (h, "setsockopt");
    pfnWinSock.shutdown = (DEFshutdown)GetProcAddress (h, "shutdown");
    pfnWinSock.socket = (DEFsocket)GetProcAddress (h, "socket");
    pfnWinSock.gethostbyaddr = (DEFgethostbyaddr)GetProcAddress (h, 
        "gethostbyaddr"); 
    pfnWinSock.gethostbyname = (DEFgethostbyname)GetProcAddress (h, 
        "gethostbyname"); 
    pfnWinSock.getprotobyname = (DEFgetprotobyname)GetProcAddress (h, 
        "getprotobyname"); 
    pfnWinSock.getprotobynumber = (DEFgetprotobynumber)GetProcAddress (h, 
        "getprotobynumber"); 
    pfnWinSock.getservbyname = (DEFgetservbyname)GetProcAddress (h, 
        "getservbyname"); 
    pfnWinSock.getservbyport = (DEFgetservbyport)GetProcAddress (h, 
        "getservbyport"); 
    pfnWinSock.gethostname = (DEFgethostname)GetProcAddress (h, 
        "gethostname"); 
    pfnWinSock.WSAAsyncSelect = (DEFWSAAsyncSelect)GetProcAddress (h, 
        "WSAAsyncSelect"); 
    pfnWinSock.WSAAsyncGetHostByAddr = (DEFWSAAsyncGetHostByAddr) 
        GetProcAddress (h, "WSAAsyncGetHostByAddr");
    pfnWinSock.WSAAsyncGetHostByName = (DEFWSAAsyncGetHostByName) 
        GetProcAddress (h, "WSAAsyncGetHostByName");
    pfnWinSock.WSAAsyncGetProtoByNumber = (DEFWSAAsyncGetProtoByNumber)
        GetProcAddress (h, "WSAAsyncGetProtoByNumber");
    pfnWinSock.WSAAsyncGetProtoByName = (DEFWSAAsyncGetProtoByName) 
        GetProcAddress (h, "WSAAsyncGetProtoByName");
    pfnWinSock.WSAAsyncGetServByPort = (DEFWSAAsyncGetServByPort) 
        GetProcAddress (h, "WSAAsyncGetServByPort");
    pfnWinSock.WSAAsyncGetServByName = (DEFWSAAsyncGetServByName) 
        GetProcAddress (h, "WSAAsyncGetServByName");
    pfnWinSock.WSACancelAsyncRequest = (DEFWSACancelAsyncRequest) 
        GetProcAddress (h, "WSACancelAsyncRequest");
    pfnWinSock.WSASetBlockingHook = (DEFWSASetBlockingHook) 
        GetProcAddress (h, "WSASetBlockingHook");
    pfnWinSock.WSAUnhookBlockingHook = (DEFWSAUnhookBlockingHook) 
        GetProcAddress (h, "WSAUnhookBlockingHook");
    pfnWinSock.WSAGetLastError = (DEFWSAGetLastError) 
        GetProcAddress (h, "WSAGetLastError");
    pfnWinSock.WSASetLastError = (DEFWSASetLastError) 
        GetProcAddress (h, "WSASetLastError");
    pfnWinSock.WSACancelBlockingCall = (DEFWSACancelBlockingCall) 
        GetProcAddress (h, "WSACancelBlockingCall");
    pfnWinSock.WSAIsBlocking = (DEFWSAIsBlocking) 
        GetProcAddress (h, "WSAIsBlocking");
    pfnWinSock.WSAStartup = (DEFWSAStartup)GetProcAddress (h, "WSAStartup");
    pfnWinSock.WSACleanup = (DEFWSACleanup)GetProcAddress (h, "WSACleanup");
    pfnWinSock.WSARecvEx = (DEFWSARecvEx)GetProcAddress (h, "WSARecvEx");
    pfnWinSock.__WSAFDIsSet = (DEF__WSAFDIsSet) 
        GetProcAddress (h, "__WSAFDIsSet");
    }
    }
    return TRUE;
} 
All of the wsock32 API pointers are saved to a structure called WinSock. When an application such as Netscape's Navigator calls the Socket Spy, the appropriate wsock32 API is called. For example, if the Navigator calls the socket API connect, it is routed to the real API saved with pfnWinSock.connect:     int PASCAL FAR connect (SOCKET s, 
    const struct sockaddr FAR *name, 
    int namelen)
{
    return pfnWinSock.connect (s, name, namelen); 
} 
In this case, the typedef for the function prototype is declared as follows:     typedef int (WINAPI *DEFconnect) (SOCKET s, const struct sockaddr  *name, int Ânamelen); 
The WinSock structure member is as follows:     DEFconnect connect; 
This design enables you to put a breakpoint in any of the socket APIs or even add code.     The Data Files
The Socket Spy creates and writes to data files during its normal operation. These files are created during WSAStartup, which is always called by a socket application:     int PASCAL FAR WSAStartup (WORD wVersionRequired, LPWSADATA lpWSAData)
{
    if (!hSend)
        hSend = CreateFile ("send.dat", GENERIC_WRITE, FILE_SHARE_READ, 0,
            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);        if (!hRecv)
        hRecv = CreateFile ("recv.dat", GENERIC_WRITE, FILE_SHARE_READ, 0,
            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);          int rc = pfnWinSock.WSAStartup (wVersionRequired, lpWSAData);        return rc;
} 
Notice that the files are created as FILE_SHARE_READ. This allows another application to read the data as the Socket Spy is writing it. For example, if you have a UNIX-like tail program, you can watch the data as it comes across. Try this:     tail -f send.dat 
After creation, the send.dat file is written to during the send API. The send.dat file captures to disk all data transferred via the send API called by the WinSock application. You can put a breakpoint in this routine to view send buffers while debugging. The following code shows socket data as it is written to disk by the Windows WriteFile API. After the data is written to file, the WinSock API is called via the pfnWinSock.send function pointer:     //
// Netscape uses this routine to send data. Put a breakpoint here and
// take a look at the buffer.
//
int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags)
{
    // Write the buffer to our debug file         DWORD bytesWritten;        if (hSend)
        BOOL rc = WriteFile (hSend, buf, len, &bytesWritten, 0);        // Send the data        int rc = pfnWinSock.send (s, buf, len, flags);        return rc;
} 
Just like the send.dat data file, the recv.dat data file also captures data to disk but does it in the reverse direction (from the network to the WinSock application). Notice that the WinSock recv API is called by the pfnWinSock.recv function pointer before data is written to file with the Windows WriteFile API. Again, you might want to put a breakpoint here to view socket data on the fly:     //
// Netscape uses this routine to receive data. Put a breakpoint here and
// take a look at the buffer.
//
int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags) 
{
    // Receive the data        int bytesRecv = pfnWinSock.recv (s, buf, len, flags);        if (bytesRecv != SOCKET_ERROR)
    {
        // Write the data to our debug file            DWORD bytesWritten;             if (hRecv)
            BOOL rc = WriteFile (hRecv, buf, bytesRecv, &bytesWritten, 0); 
     }        return bytesRecv;
} 
The WSACleanup WinSock API is called when a Windows WinSock application is finished using Windows sockets. During this time, the Socket Spy closes its data files, send.dat and recv.dat, with the Windows API CloseHandle:     int PASCAL FAR WSACleanup(void)
{
    if (hSend)
        CloseHandle (hSend);         if (hRecv)
        CloseHandle (hRecv);         return pfnWinSock.WSACleanup ();
} 
Running the Socket Spy
Don't be afraid to leave the Socket Spy in place with the modified version of the Navigator. It's nice to take a peek at the data files occasionally to see what Navigator is up to. For example, when running the CPU Monitor Plug-in Sample, the send.dat file shows the GET request sent to the HTTP server that runs a CGI program:     GET /zan-bin/vmstat.cgi HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/3.0B2 (Win95; I)
Pragma: no-cache
Host: www.swcp.com
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* 
The CGI program called vmstat.cgi performs a vmstat on the UNIX end and sends back the output. This output can be seen in the recv.dat file:     HTTP/1.0 200 Document follows
Date: Sun, 14 Apr 1996 20:05:57 GMT
Server: NCSA/1.4.2
Content-type: text/plain    VMSTAT 1 second intervals.
procs     memory              page               disk       faults     cpu
r b w   avm   fre  re at  pi  po  fr  de  sr d0 s1 s2 s3  in  sy  cs us sy id 
0 0 0     0  1280   0  5   3   3   1   0  16  4  8 10  0 223 607 134 20 25 55
0 0 0     0  1280   0  0  32   0   0   0   0  0  1  0  0 112 319  79  3 10 87 
These data files were helpful in developing the CPU Monitor Sample.     Conclusion 
Modify a socket application executable with a binary editor to make it load WSOCK00.DLL instead of WSOCK32.DLL. This allows the Socket Spy to filter all socket APIs. Put breakpoints in the Socket Spy source file sockspy.cpp and look at data buffers. Add code to Socket Spy for special debugging needs.     Allow the modified version of Netscape's Navigator to run at all times. The performance impact is negligible.     Feel free to try Socket Spy with any Windows 95 socket applications.     What's Next? 
Part IV of this book, "Plug-In Programming Resources for Windows," gives step by step instructions for building a Navigator plug-in with the Borland, Microsoft, and Watcom C   compilers. This section starts with an introduction to the Windows C   compilers and moves on to separate chapters for each compiler. 
系統時間:2024-05-07 5:32:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!