1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ using NtApiDotNet . Win32 . Rpc . Transport ;
1516using System ;
1617using System . Collections . Generic ;
1718using System . Linq ;
@@ -34,7 +35,7 @@ public class RpcAlpcServer
3435 /// <summary>
3536 /// List of known endpoints potentially accessible via this RPC server.
3637 /// </summary>
37- public IEnumerable < RpcEndpoint > Endpoints { get ; }
38+ public IReadOnlyCollection < RpcEndpoint > Endpoints { get ; }
3839 /// <summary>
3940 /// The number of endpoints.
4041 /// </summary>
@@ -48,65 +49,93 @@ public class RpcAlpcServer
4849 /// </summary>
4950 public SecurityDescriptor SecurityDescriptor { get ; }
5051
51- private RpcAlpcServer ( NtHandle handle , List < RpcEndpoint > endpoints )
52+ private RpcAlpcServer ( int process_id , string name , SecurityDescriptor sd , string process_name , IEnumerable < RpcEndpoint > endpoints )
53+ {
54+ ProcessId = process_id ;
55+ ProcessName = process_name ;
56+ Name = name ;
57+ SecurityDescriptor = sd ;
58+ Endpoints = new List < RpcEndpoint > ( endpoints ) . AsReadOnly ( ) ;
59+ EndpointCount = Endpoints . Count ;
60+ }
61+
62+ private RpcAlpcServer ( NtHandle handle , string process_name , IEnumerable < RpcEndpoint > endpoints )
63+ : this ( handle . ProcessId , handle . Name , handle . SecurityDescriptor , process_name , endpoints )
5264 {
53- ProcessId = handle . ProcessId ;
54- using ( var proc = NtProcess . Open ( handle . ProcessId , ProcessAccessRights . QueryLimitedInformation , false ) )
55- {
56- if ( proc . IsSuccess )
57- {
58- ProcessName = proc . Result . Name ;
59- }
60- else
61- {
62- ProcessName = string . Empty ;
63- }
64- }
65- Name = handle . Name ;
66- SecurityDescriptor = handle . SecurityDescriptor ;
67- Endpoints = endpoints . AsReadOnly ( ) ;
68- EndpointCount = endpoints . Count ;
6965 }
7066
7167 /// <summary>
7268 /// Get RPC ALPC servers for a specific process.
7369 /// </summary>
7470 /// <param name="process_id">The ID of the process.</param>
7571 /// <returns>The list of RPC ALPC servers.</returns>
72+ /// <remarks>If the process is suspended or frozen this call can hang.</remarks>
7673 public static IEnumerable < RpcAlpcServer > GetAlpcServers ( int process_id )
7774 {
78- return GetAlpcServersInternal ( NtSystemInfo . GetHandles ( process_id , true ) ) . ToCached ( ) ;
75+ using ( var proc = NtProcess . Open ( process_id , ProcessAccessRights . QueryInformation | ProcessAccessRights . DupHandle ) )
76+ {
77+ List < RpcAlpcServer > ret = new List < RpcAlpcServer > ( ) ;
78+ GetAlpcServersInternal ( proc . Duplicate ( ) , NtObjectUtils . IsWindows7OrLess ? NtSystemInfo . GetHandles ( process_id , true ) :
79+ proc . GetHandles ( true ) , ret ) ;
80+ if ( ret . Count == 0 )
81+ Win32Error . RPC_S_SERVER_UNAVAILABLE . ToNtException ( ) ;
82+ return ret . AsReadOnly ( ) ;
83+ }
7984 }
8085
8186 /// <summary>
8287 /// Get a list of all RPC ALPC servers.
8388 /// </summary>
84- /// <remarks>This works by discovering any server ALPC ports owned by the process and querying for interfaces.</remarks>
89+ /// <remarks>This works by discovering any server ALPC ports owned by the process and querying for interfaces.
90+ /// This will ignore any frozen processes (primarily UWP) as they can't respond to the endpoint enumeration.</remarks>
8591 /// <returns>The list of RPC ALPC servers.</returns>
8692 public static IEnumerable < RpcAlpcServer > GetAlpcServers ( )
8793 {
88- return GetAlpcServersInternal ( NtSystemInfo . GetHandles ( ) ) . ToCached ( ) ;
94+ List < RpcAlpcServer > ret = new List < RpcAlpcServer > ( ) ;
95+
96+ foreach ( var group in NtSystemInfo . GetHandles ( ) . GroupBy ( h => h . ProcessId ) )
97+ {
98+ using ( var proc = NtProcess . Open ( group . Key ,
99+ ProcessAccessRights . QueryLimitedInformation | ProcessAccessRights . DupHandle , false ) )
100+ {
101+ if ( ! proc . IsSuccess )
102+ continue ;
103+ if ( proc . Result . Frozen )
104+ continue ;
105+ GetAlpcServersInternal ( proc . Result , group , ret ) ;
106+ }
107+ }
108+ return ret . AsReadOnly ( ) ;
109+ }
110+
111+ /// <summary>
112+ /// Get the RPC ALPC server for an ALPC port object path.
113+ /// </summary>
114+ /// <param name="path">The object manager path to the ALPC port.</param>
115+ /// <returns>The ALPC RPC server.</returns>
116+ /// <remarks>Needs an API which is only available from Windows 10 19H1.</remarks>
117+ [ SupportedVersion ( SupportedVersion . Windows10_19H1 ) ]
118+ public static RpcAlpcServer GetAlpcServer ( string path )
119+ {
120+ using ( var transport = new RpcAlpcClientTransport ( path , null ) )
121+ {
122+ var server = transport . ServerProcess ;
123+ return new RpcAlpcServer ( server . ProcessId , path , null , server . Name ,
124+ RpcEndpointMapper . QueryEndpointsForAlpcPort ( path ) ) ;
125+ }
89126 }
90127
91- private static IEnumerable < RpcAlpcServer > GetAlpcServersInternal ( IEnumerable < NtHandle > handles )
128+ private static void GetAlpcServersInternal ( NtProcess process , IEnumerable < NtHandle > handles , List < RpcAlpcServer > servers )
92129 {
93130 NtType alpc_type = NtType . GetTypeByType < NtAlpc > ( ) ;
94-
131+ string process_name = process . Name ;
95132 foreach ( var handle in handles . Where ( h => h . NtType == alpc_type
96- && h . Name . StartsWith ( @"\RPC Control\" , StringComparison . OrdinalIgnoreCase ) ) )
133+ && h . Name . IndexOf ( @"\RPC Control\" , StringComparison . OrdinalIgnoreCase ) >= 0 ) )
97134 {
98- List < RpcEndpoint > endpoints = new List < RpcEndpoint > ( ) ;
99- try
100- {
101- endpoints . AddRange ( RpcEndpointMapper . QueryEndpointsForAlpcPort ( handle . Name ) ) ;
102- }
103- catch ( SafeWin32Exception )
104- {
105- }
106-
107- if ( endpoints . Count > 0 )
135+ var eps = RpcEndpointMapper . QueryEndpointsForAlpcPort ( handle . Name , false ) ;
136+ if ( eps . IsSuccess )
108137 {
109- yield return new RpcAlpcServer ( handle , endpoints ) ;
138+ servers . Add ( new RpcAlpcServer ( handle , process_name , eps . Result ) ) ;
110139 }
111140 }
112141 }
0 commit comments