dotnet 教你寫一個可以搞炸本機所有 WCF 應用的程序方法


作為團隊里面挖掘機出身的我,怎么能不多挖一些坑好將小伙伴們都埋進去呢。本文來告訴大家一個有趣且簡單的方法,此方法可以將本機的 WCF 玩壞,不敢說真的搞炸本機所有 WCF 應用,但搞炸大部分基於 WCF 的軟件還是沒有問題的。閱讀本文,你可以不僅可以了解到有這樣的逗比方法,更重要的是在你的 WCF 模塊炸掉的時候,你知道要甩鍋給誰

本文如此逗比的方法是由 lsj 小伙伴發現的,但是他不想記錄如此逗比的方法,於是就交給我來水了

在開始之前,咱先來復習如何制作一個簡單的 WCF 服務端和客戶端的方法。用不着官方文檔提供的十分繁瑣的方式,咱直接明了,通過簡單的控制台,利用WCF實現本機 IPC 進程間通訊

咱將先制作一個簡單的 WCF 進程間通訊的服務端和客戶端兩個控制台項目,用來演示在管道下的 WCF 應用的運行情況。接着再添加一個用來搗亂的 WCF 服務器端的控制台項目,讓這個項目影響到原有工作的好好的演示項目

當前是 2021.08.22 社區版本發布了 WCF Core 的 0.2.0 版本,功能上還沒有追平 .NET Framework 的版本,因此本文依然使用 .NET Framework 版本的 WCF 進行演示

先來演示的 WCF 服務端的控制台應用,咱通過 .NET 5 創建出項目,接着編輯 csproj 文件,將 net5.0 修改為 net45 從而返回到 .NET Framework 版本。服務端的 csproj 文件代碼如下

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net45</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="System.ServiceModel" />
  </ItemGroup>

</Project>

使用 .NET 5 創建項目的優勢是新建出來的項目是 SDK 風格的,方便更改。為了使用上 WCF 在 csproj 上添加 System.ServiceModel 的引用

在 SDK Style 的 csproj 項目文件上,添加對 WCF 引用的方法是在 csproj 上添加如下代碼

  <ItemGroup>
    <Reference Include="System.ServiceModel" />
  </ItemGroup>

按照慣例,定義類型,此類型將包含一個類和一個接口。類是在服務端運行的,而接口是給客戶端使用的。這部分基礎知識不在本文描述,更多基礎知識請參閱本文最后的由換頭像大大編寫的入門博客

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
    public class DataService: IDataServer
    {
        public void Foo(string name)
        {
            Console.WriteLine(name);
        }
    }

    [ServiceContract]
    public interface IDataServer
    {
        [OperationContract]
        void Foo(string name);
    }

接着打開 Program.cs 文件,在此文件編寫入口函數,在入口函數啟動服務,如以下代碼

    class Program
    {
        static void Main(string[] args)
        {
            var dataService = new DataService();
            Uri address = new Uri("net.pipe://localhost/MyWCFConnection");
            using (ServiceHost host = new ServiceHost(dataService, address))
            {
                host.Open();

                while (true)
                {
                    Thread.Sleep(100);
                }
            }


        }
    }

上面代碼使用了 net.pipe://localhost/MyWCFConnection 啟動了使用管道的 WCF 服務

接着采用相同的方法,也是使用 .NET 5 創建控制台,修改為 .NET Framework 版本的客戶端控制台

在客戶端控制台的 csproj 文件代碼和服務端的相同。放心,在本文最后有所有的源代碼,部分細節還請忽略。在客戶端里面,添加上了剛才定義的 IDataServer 接口,抄代碼即可

在客戶端的入口添加如下代碼,用於連上服務端,然后遠程調用服務端的某個方法

    class Program
    {
        static void Main(string[] args)
        {
            Uri address = new Uri("net.pipe://localhost/MyWCFConnection");

            var dataServer = ChannelFactory<IDataServer>.CreateChannel(new NetNamedPipeBinding(),new EndpointAddress(address));
            dataServer.Foo("123");
        }
    }

先啟動服務端,再啟動客戶端。預期是服務端的 DataServer 的 Foo 方法將會被客戶端進行調用,被客戶端傳入了 "123" 在服務端的控制台輸出

接下來開始開發一個用來搗亂的 WCF 控制台,這是一個 WCF 服務端。這個控制台應用的 csproj 和上面兩個相同,唯一不同的是在入口程序的定義和運行的方式。在入口里面使用如下代碼啟動服務

    class Program
    {
        static void Main(string[] args)
        {
            var dataService = new DataService();
            Uri address = new Uri("net.pipe://localhost/");
            using (ServiceHost host = new ServiceHost(dataService, address))
            {
                host.Open();

                while (true)
                {
                    Thread.Sleep(100);
                }
            }
        }
    }

可以看到,以上的寫法是不被推薦的,采用了不加上具體的邏輯的管道

  • net.pipe://localhost/MyWCFConnection 這是通用的方式
  • net.pipe://localhost/ 這是不符合約定的

接着構建出這個搗亂的應用,使用管理員權限打開他。然后再嘗試啟動原本可以好好干活的演示應用,可以看到演示應用的客戶端炸掉了,提示如下

System.ServiceModel.EndpointNotFoundException:“由於 AddressFilter 在 EndpointDispatcher 不匹配,To 為“net.pipe://localhost/MyWCFConnection”的消息無法在接收方處理。請檢查發送方和接收方的 EndpointAddresses 是否一致。”

以上的錯誤提示和服務端 WCF 沒有啟動或者在客戶端配置的連接字符串和服務端配置的不相同的是一樣的提示方式

原因其實比較復雜一點,簡單說就是 WCF 的連接字符串,在通過管道的方式的時候,不是直接作為管道名的。而是將此連接字符串映射到某個共享內存里面,在共享內存里面存放實際的管道名。而上面用來搗亂的應用就是用了不符合約定的方式,讓客戶端在嘗試發現服務端的時候,先碰到了搗亂的應用,又因為權限不足從而失敗。如果此時將演示用的服務端也采用管理員權限運行,而演示用的客戶端依然是非管理員權限運行,那么演示程序還能正常工作

想要寫一個用來搞炸本機大部分的基於 WCF 做 IPC 進程間通訊的搗亂應用,只需要設置 WCF 連接字符串為 net.pipe://localhost/ 接着使用管理員運行即可,如運行為服務

這個問題其實是某個用戶報告給我的,經過了 lsj 使用了各個黑科技的方式調試,加上堆棧網大佬們的回復,了解到了是 DropboxOEM.exe 服務挖的坑。然而除此之外,在堆棧網上面也列出了其他的很多應用也會導致此問題。這個問題其實 WCF 和應用兩邊都有鍋

在 WCF 上,為了安全考慮,反而挖了如此的坑,會讓應用受到了本機內其他在運行的應用的影響。另一方面,其實 WCF 也算背鍋,因為如果應用亂來,導致影響其他應用,似乎在 Win32 設計層面本身就有這樣的問題,如應用自己去刪掉了某個系統關鍵文件等。只是 WCF 這個鍋不好定位在於,使用 WCF 不屬於唯一方式,這就意味着其他的 IPC 也許能活,給用戶的感覺就是為什么我其他的應用都能工作好好的,就你的應用炸了

另外,我還測試了其他的組合:

  • 演示程序的 WCF 連接字符串: net.pipe://127.0.0.1/MyWCFConnection
  • 搗亂程序 WCF 連接字符串: "net.pipe://localhost/"
  • 搗亂程序使用管理員權限運行

結論:炸

后續為了升級到 .NET Core 或 .NET 5 等更高版本的 .NET 我開源了一個追求穩定的 IPC 庫,請看 dotnet-campus/dotnetCampus.Ipc: 本機內多進程通訊庫

當前此開源庫還沒有實際落地,缺乏大量的詭異的用戶環境的適配。預計大概到 2022 的時候,這個庫能更加穩定

本文所有代碼放在githubgitee 歡迎訪問

可以通過如下方式獲取本文的源代碼,先創建一個空文件夾,接着使用命令行 cd 命令進入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 26aa3294d0bc40ba7e312891c958fa170c3d51f0

以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

獲取代碼之后,進入 ChigiwejefiKemhakerhawee 文件夾

此問題也能在堆棧網找到,請看 .net - 3rd party app breaks our WCF application - Stack Overflow

更多 WCF 請參閱:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM