Console Application to discover Effective Named Pipe Path of a WCF net.pipe Endpoint

As I have promised in my previous post, I am making available a C++ console application to troubleshoot named pipes endpoints in WCF. Below is a screenshot of the application:

image

 

Application logic:

  1. It gets the endpoint from the command line and substitute the host name by +, * depending on the wildcard mode.
  2. It then add a “/” to the end if not present already and transform to up case all characters of pipe and path
  3. If the size of the resulting string is bigger than 128 characters a hash is applied to the resulting string  (not implemented)
  4. The final name is net.pipe:E + Base64 of string generated in item 2 or net.pipe:H + Base64 of string generated in item 3 if uri is bigger than 128 characters

 

Post detailing the problem:

http://blogs.msdn.com/b/rodneyviana/archive/2011/03/22/named-pipes-in-wcf-are-named-but-not-by-you-and-how-to-find-the-actual-windows-object-name.aspx

 

Source Code is as shown below (subject to this license: http://rodneyviana.codeplex.com/license).

// ReadMemory.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

void NormalizeEndPoint(const std::wstring &source, std::wstring& normal)
{
    normal.assign(source);

    if(!normal.compare(0, 10, L"net.pipe://"))
    {
        normal.clear();
        return;
    }

    int hoststart = normal.find_first_of(L"//");
    int hostend = normal.find(L"/", hoststart+2);

    std::wstring ending(normal.substr(hostend));
    std::wstring starting(normal.substr(0, hoststart).append(L"//+"));
    std::transform(ending.begin(), ending.end(), ending.begin(), (int(*)(int))std::toupper);
    std::wstring normalized(starting.append(ending));
    if(normalized.substr(normalized.length()-1).compare(L"/"))
    {
        normalized.append(L"/");
    }
   
    normal.assign(normalized);
    return;

}

void ShowSyntax(bool SyntaxError)
{
    std::wprintf(L"ReadMemory version 1.0\n");
    std::wprintf(L"Written by Rodney Viana –
http://blogs.msdn.com/rodneyviana\n");
    std::wprintf(L"\n");
    if(SyntaxError)
        std::wprintf(L"Syntax Error\n\n");

    std::wprintf(L"Syntax:\n");
    std::wprintf(L"ReadMemory <PipeNameEndPoint> | -file <MappedMemoryFile>\n");
    std::wprintf(L"Where:\t<PipeNameEndPoint> is a endpoint for a net.pipe in WCF in\n\t the format net.pipe://host/path\n");
    std::wprintf(L"\t<MappedMemoryFile> is a memory mapped file\n");
    std::wprintf(L"\n");
    std::wprintf(L"Examples\n");
    std::wprintf(L"\tReadMemory net.pipe://localhost/Service/Service1\n");
    std::wprintf(L"\tReadMemory -file \"net.pipe:EbmV0LnBpcGU6Ly8rLzhFNjFFRUM5LUYxOUEtNEIxNy04REE4LTM5NTc1QzhGMTU4QS8=\"\n");

}

int _tmain(int argc, _TCHAR* argv[])
{
    if(argc < 2)
    {
        ShowSyntax(false);
        return 0;
    }

    if(argc > 3)
    {
        ShowSyntax(true);
        return 1;

    }

    std::wstring original;
    std::wstring normalized;
    std::wstring mapFile;

    if(argc == 2)
    {
        original.append(argv[1]);
        NormalizeEndPoint(original, normalized);
        std::wprintf(L"\nOriginal Endpoint: %s", original.c_str());

        std::wprintf(L"\nNominal Endpoint: %s", normalized.c_str());

        char base64A[1000];

        CW2A ansiNormal(normalized.c_str());
        int size = 1000;
   
        Base64Encode((BYTE*)ansiNormal.m_psz, normalized.length(), base64A, &size, ATL_BASE64_FLAG_NOCRLF | ATL_BASE64_FLAG_NOPAD );

        base64A[size]=’=’;
        base64A[size+1]=”;

        CA2W base64W(base64A);

        mapFile.append(L"net.pipe:E");
        mapFile.append(base64W.m_psz);

    }

    if(argc == 3)
    {
        std::wstring force(argv[1]);
        std::transform(force.begin(), force.end(), force.begin(), (int(*)(int))std::toupper);
        if(!force.compare(0, 4, L"-FILE"))
        {
            ShowSyntax(true);
            return 2;
        }

        mapFile.append(argv[2]);

    }

    //original.append(L"net.pipe://localhost/TradeService/Service1");

    std::wprintf(L"\nMapped Memory Object Name: %s", mapFile.c_str());

    HANDLE map = OpenFileMapping(FILE_MAP_READ, FALSE, mapFile.c_str());
    MEMORY_BASIC_INFORMATION mi;
    if(map)
    {
        std::wprintf(L"\nGood News: Mapped memory Object was found. It shows that Host is enabled.");

        PVOID contents = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
        SIZE_T s = VirtualQuery(contents, &mi, sizeof(mi));

        if(s<sizeof(GUID)+4)
        {
            std::wprintf(L"\nMapped memory Object seems to be corrupted. Restart your WCF Host.\n");
        }
       
        PBYTE bytes = ((PBYTE)contents)+4;

        std::wprintf(L"\nRaw Bytes:\n");

        if(contents)
        {
            for(SIZE_T i=0;i<sizeof(GUID);i++)
            {
                printf("%02x ", *(bytes+i));
            }

            std::wprintf(L"\n");
           
            for(SIZE_T i=sizeof(GUID);i<s-4;i++)
            {
                printf("%02x ", *(bytes+i));
            }
       
            GUID *guid = (GUID*)bytes;
            RPC_WSTR guidStr;

            UuidToString(guid, &guidStr);
            std::wprintf(L"\nActual Named Pipe Name: %s", guidStr);
            std::wprintf(L"\nFull Named Pipe Name: \\Device\\NamedPipe\\%s", guidStr);
           
            std::wstring localPipe(_T("\\\\.\\pipe\\"));
            localPipe.append((LPWSTR)guidStr);

            std::wprintf(L"\nAttempting to connect to Named Pipe for 20 seconds …\n");

            if(!WaitNamedPipe(localPipe.c_str(), 20000))
            {
                std::wprintf(L"\nBad News: Unable to connect to local pipe: %s.\nReason: Time out.", localPipe.c_str());

            } else
            {
                std::wprintf(L"\nGood News: Local pipe \"%s\" is alive.", localPipe.c_str());
           
                HANDLE pipe;

                std::wprintf(L"\nAttempting to open Named Pipe…\n");

                pipe = CreateFile(localPipe.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);

           
                if(pipe == INVALID_HANDLE_VALUE)
                {
                    std::wprintf(L"\nBad News: Unable to open local pipe: %s.\nLast Error: %i.", localPipe.c_str(), GetLastError());
                } else
                {
                    std::wprintf(L"\nGood News: Named Pipe opened successfully.\n");

                    TCHAR* send = L"<bad><\\bad>\n";
                    DWORD bytesUsed;

                    if(!WriteFile(pipe, (void*)send, wcslen(send)*sizeof(TCHAR), &bytesUsed, NULL))
                    {
                        std::wprintf(L"\nBad News: Unable to send bytes.\n");

                    } else
                    {
                        std::wprintf(L"\nGood News: Pipe accepted bytes\n");
                        std::wprintf(L"\nTest completed successfully!\n");

                    }
                    CloseHandle(pipe);
                }

            }

       
        } else
        {
            std::wprintf(L"\nBad News: Host is not informing pipe id.");
           
        }
        UnmapViewOfFile(map);
    } else
    {
        std::wprintf(L"\nBad News: Mapped File %s was not found. LastError: %x", mapFile.c_str(), GetLastError());

    }
   
    CloseHandle(map);
    std::wprintf(L"\n");
    return 0;
}

 

Download the project/executable here:

WCF Named Pipes Identification

6 Comments