// // Copyright (c) 2022-present, Trail of Bits, Inc. // All rights reserved. // // This source code is licensed in accordance with the terms specified in // the LICENSE file found in the root directory of this source tree. // using BrightIdeasSoftware; using NtApiDotNet; using NtApiDotNet.Win32; using RpcInvestigator.TabPages; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; namespace RpcInvestigator { using static TraceLogger; public class RpcServerList : TabPage { public FastObjectListView m_Listview; private TabManager m_Manager; public RpcServerList(TabManager Manager) { m_Manager = Manager; m_Listview = new FastObjectListView(); Random random = new Random(); string rand = random.Next().ToString(); m_Listview.OwnerDraw = true; m_Listview.BorderStyle = BorderStyle.FixedSingle; m_Listview.CellEditUseWholeCell = false; m_Listview.Cursor = Cursors.Default; m_Listview.Dock = DockStyle.Fill; m_Listview.FullRowSelect = true; m_Listview.GridLines = true; m_Listview.HideSelection = false; m_Listview.Location = new Point(0, 0); m_Listview.Margin = new Padding(5); m_Listview.Name = "RpcServerListview" + rand; m_Listview.UseAlternatingBackColors = true; m_Listview.AlternateRowBackColor = Color.LightBlue; m_Listview.UseCompatibleStateImageBehavior = false; m_Listview.View = View.Details; m_Listview.VirtualMode = true; m_Listview.ShowGroups = false; m_Listview.Alignment = ListViewAlignment.Left; Generator.GenerateColumns(m_Listview, typeof(RpcServer), true); foreach (var column in m_Listview.AllColumns) { if (column.Name.ToLower() == "procedures" || column.Name.ToLower() == "complextypes" || column.Name.ToLower() == "name" || column.Name.ToLower() == "offset" || column.Name.ToLower() == "endpoints") { column.IsVisible = false; } column.MaximumWidth = -1; } // // When a listview row is double-clicked, a new tab will open with procedures // for the selected interface on the given RPC server. When a row is right-clicked, // a context menu shows. // m_Listview.DoubleClick += new EventHandler((object obj, EventArgs e2) => { if (m_Listview.SelectedObjects == null || m_Listview.SelectedObjects.Count == 0) { return; } var selectedRow = m_Listview.SelectedObjects.Cast().ToList()[0]; m_Manager.LoadRpcProceduresTab(selectedRow.Name, selectedRow.Procedures.ToList()); }); m_Listview.CellRightClick += RightClickHandler; Controls.Add(m_Listview); } public void Build ( List FileNames, Settings Settings, RpcLibrary Library ) { Text = BuildTabTitle(FileNames); ImageIndex = 0; try { using (NtToken token = NtProcess.Current.OpenToken()) { var allservers = new List(); token.SetPrivilege(TokenPrivilegeValue.SeDebugPrivilege, PrivilegeAttributes.Enabled, true); foreach (var filename in FileNames) { try { var servers = RpcServer.ParsePeFile(filename, Settings.m_DbghelpPath, Settings.m_SymbolPath); if (servers.Count() == 0) { Trace(TraceLoggerType.RpcServerList, TraceEventType.Warning, "No RPC servers in file '" + filename + "'"); continue; } allservers.AddRange(servers); } catch (Exception ex) { Trace(TraceLoggerType.RpcServerList, TraceEventType.Error, "Unable to retrieve RPC server list for file '" + filename + "': " + ex.Message); } } if (allservers.Count > 0) { m_Listview.ClearObjects(); m_Listview.SetObjects(allservers); m_Listview.RebuildColumns(); m_Listview.AutoResizeColumns(); // // Cache any new RPC servers from this binary. // if (!Library.Merge(allservers)) { Trace(TraceLoggerType.RpcServerList, TraceEventType.Error, "Unable to merge new RPC servers to database."); } } } } catch (Exception ex) { Trace(TraceLoggerType.RpcServerList, TraceEventType.Error, "Unable to retrieve RPC server list: " + ex.Message); } } public int GetCount() { if (m_Listview.Objects == null) { return 0; } return m_Listview.Objects.Cast().Count(); } public List GetAll() { if (m_Listview.Objects == null) { return new List(); } return m_Listview.Objects.Cast().ToList(); } private void RightClickHandler( object Obj, CellRightClickEventArgs Args ) { TabPages.ContextMenu.BuildRightClickMenu(Args, new List{ new ToolStripMenuItem("New Client", null, ContextMenuNewClient), }); } private void ContextMenuNewClient(object Sender, EventArgs Args) { object tag = ((ToolStripMenuItem)Sender).Tag; if (tag == null) { return; } var args = (CellRightClickEventArgs)tag; // // RpcServer type comes from parsing RPC server information out of a // binary (such as a DLL), so we have to scan for an ALPC port hosting // the interface using the RPC endpoint mapper. // var server = args.Model as RpcServer; var id = server.InterfaceId; var version = server.InterfaceVersion; var endpoint = RpcAlpcServerList.FindEndpoint(id, version); if (endpoint == null) { MessageBox.Show("Unable to locate an endpoint for RPC server UUID " + id.ToString() + ", version " + version.ToString()); return; } var clientWindow = new Client(server, endpoint); clientWindow.ShowDialog(); } private static string BuildTabTitle(List FileNames) { if (FileNames.Count == 1) { var path = Path.GetDirectoryName(FileNames[0]); string title = FileNames[0]; if (path.Length > 25) { title = path.Substring(0, 20) + "...\\" + Path.GetFileName(FileNames[0]); } return title; } return "Multiple files"; } } }