tom.wolanski
tom.wolanski

Reputation: 53

Programically get the system name of named pipe

I am writing a inter-process comunication using WCF NetNamedPipeBinding.

My goal is to have service running at "net.pipe://localhost/service", so I running the simplest host:

host = new ServiceHost(contract, new Uri[] { "net.pipe://localhost" });
host.AddServiceEndpoint(typeof (IContract),
    new NetNamedPipeBinding(), "service");
host.Open();

According to 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 the name is hidden behind system-generated guid.

And here comes the question.

Is there any possible way to get the name generated by system (guid) inside my program, so I could get path like "\Device\NamedPipe\GUID", like in the procexp, so it will be easier to sniff it? (Except running sys internals executables in separate process and parsing its output?)

Upvotes: 4

Views: 2688

Answers (2)

Divi
Divi

Reputation: 7701

After a lot of fiddling around and breaking my head against the wall, I finally got this working:

Guid pipeGuid;
if (PipeName.Equals("*", StringComparison.InvariantCultureIgnoreCase) || PipeName.Equals("localhost", StringComparison.InvariantCultureIgnoreCase))
     PipeName = "*";

string s = string.Format(@"net.pipe://{0}/", PipeName.ToUpper());

if(!string.IsNullOrWhiteSpace(ServiceName))
     s = string.Format(@"net.pipe://*/{0}/", ServiceName.ToUpper());

var bytes = Encoding.UTF8.GetBytes(s);
var base64 = Convert.ToBase64String(bytes);

string namedPipeMMFName = string.Format(@"Global\net.pipe:E{0}", base64);

MemoryMappedFileSecurity mSec = new MemoryMappedFileSecurity();
mSec.AddAccessRule(new AccessRule<MemoryMappedFileRights>(new     SecurityIdentifier(WellKnownSidType.WorldSid, null),  MemoryMappedFileRights.FullControl, AccessControlType.Allow));

using (var mmf = MemoryMappedFile.OpenExisting(namedPipeMMFName, MemoryMappedFileRights.Read))
{
    using (var accessor = mmf.CreateViewAccessor(4, 45, MemoryMappedFileAccess.Read))
    {
        accessor.Read<Guid>(0, out pipeGuid);
    }
}

using (NamedPipeClientStream client = new NamedPipeClientStream(GetResolvedText(ServerName), pipeGuid, PipeDirection.InOut,
                        PipeOptions.None, TokenImpersonationLevel.Impersonation))
{
    client.Connect(10000);
}

I must thank Rodney Viana for his article and @Avner Shahar-Kashtan for his answer and numerous other articles I read. I hope that my answer can help someone in the future.

Upvotes: 4

Avner Shahar-Kashtan
Avner Shahar-Kashtan

Reputation: 14700

As the article you link to shows, WCF stores the named pipe name in a memory mapped file. To access it, you need to do the following:

  • Endpoint: net.pipe://localhost/TradeService/Service1
  • Normalized Endpoint: net.pipe://+/TRADESERVICE/SERVICE1/
  • Base 64 representation: bmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=
  • Final memory mapped file: net.pipe:EbmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=

Now you take the final MMF name and open it. Here's an article on using MMFs on MSDN: https://msdn.microsoft.com/en-us/library/dd267590(v=vs.110).aspx

// Open the MMF.
using (var mmf = MemoryMappedFile.OpenExisting(namedPipeMMFName))
{
     // Create an accessor for 16 bytes (Size of GUID) starting at 
     // offset 5 (as the article states)
     using (var accessor = mmf.CreateViewAccessor(5, 16))
     {
         Guid pipeGuid;
         accessor.Read<Guid>(0, out pipeGuid);
         Console.WriteLine("This should be the pipe name: " + pipeGuid);
     }
}

Upvotes: 3

Related Questions