Files
cyberark-RPCMon/RPCMon/Control/Engine.cs
T
2022-07-31 14:15:49 +03:00

312 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace RPCMon.Control
{
public delegate void BuildRPCDBEventHandler(string i_File, string i_FileStatus, int i_NumOfFilesWithRPC, int i_TotalNumberOfFiles);
public delegate void DoneRPCSearchEventHandler(List<IEnumerable<NtApiDotNet.Win32.RpcServer>> i_RPCServers);
static class Engine
{
public static event BuildRPCDBEventHandler BuildRPCDBStatusUpdate;
public static event DoneRPCSearchEventHandler DoneRPCSearchUpdate;
private const string m_SymbolsPath = @"srv*c:\symbols*http://msdl.microsoft.com/download/symbols";
private static List<IEnumerable<NtApiDotNet.Win32.RpcServer>> m_RPCServersDB;
private static string m_DbgHelp = @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll";
private static int m_TotalNumberOfFiles, m_NumOfFilesWithRPC;
private const string c_FolderToSearch = @"C:\Windows\";
private static bool m_IsDoneRPCSearch = false;
private static Dictionary<string, bool> m_ExcludedFoldersMap = new Dictionary<string, bool>();
public static void StopRPCSearch()
{
m_IsDoneRPCSearch = true;
}
public static string DbgHelpFilePath
{
get { return m_DbgHelp; }
set { m_DbgHelp = value; }
}
public static void BuildRPCDataBase(string i_FolderToSearch, string i_SavedFilePath, bool i_Recursive, string[] i_ExcludedFolders, params string[] i_Extensions)
{
m_TotalNumberOfFiles = 0;
m_NumOfFilesWithRPC = 0;
m_IsDoneRPCSearch = false;
m_RPCServersDB = new List<IEnumerable<NtApiDotNet.Win32.RpcServer>>();
if (i_FolderToSearch == "")
{
i_FolderToSearch = c_FolderToSearch;
}
m_ExcludedFoldersMap.Clear();
foreach (string folder in i_ExcludedFolders)
{
m_ExcludedFoldersMap.Add(folder.ToLower(), true);
}
buildRPCServersList(i_FolderToSearch, i_Recursive, i_Extensions);
OnDoneRPCSearchUpdate(m_RPCServersDB);
saveDBAsJson(m_RPCServersDB, i_SavedFilePath);
// var a = NtApiDotNet.Win32.RpcAlpcServer.GetAlpcServers();
}
private static void saveDBAsJson(List<IEnumerable<NtApiDotNet.Win32.RpcServer>> i_RPCList, string i_FileName)
{
int i = 0;
Dictionary<string, RPCServerInfo> rpcDB = new Dictionary<string, RPCServerInfo>();
foreach (IEnumerable<NtApiDotNet.Win32.RpcServer> rpcServerEnumerator in i_RPCList)
{
foreach (NtApiDotNet.Win32.RpcServer rpcServer in rpcServerEnumerator)
{
// Maybe it is not enough to check only by UUID and add version to the check.
// But it will require to change the key.
if (rpcDB.ContainsKey(rpcServer.InterfaceId.ToString()))
{
continue;
}
i = 0;
List<string> functions = new List<string>();
foreach (var function in rpcServer.Procedures)
{
functions.Add(function.Name);
// We are assuming the functions are already in order, but are they?
// It is better to check with ProcNum of each function
//if (i != function.ProcNum)
//{
// int b = 2;
//}
i += 1;
}
RPCServerInfo serverInfo = new RPCServerInfo(
rpcServer.Name,
rpcServer.FilePath,
rpcServer.InterfaceId.ToString(),
rpcServer.Offset,
rpcServer.ProcedureCount,
functions,
rpcServer.ServiceName,
rpcServer.IsServiceRunning
);
rpcDB.Add(rpcServer.InterfaceId.ToString(), serverInfo);
}
}
string json = JsonConvert.SerializeObject(rpcDB);
File.WriteAllText(i_FileName, json);
}
public static void OnDoneRPCSearchUpdate(List<IEnumerable<NtApiDotNet.Win32.RpcServer>> i_RPCServers)
{
if (DoneRPCSearchUpdate != null)
{
DoneRPCSearchUpdate.Invoke(i_RPCServers);
}
}
public static void OnBuildRPCDBStatusUpdate(string i_File, string i_FileStatus, int i_NumOfFilesWithRPC, int i_TotalNumberOfFiles)
{
if (BuildRPCDBStatusUpdate != null)
{
BuildRPCDBStatusUpdate.Invoke(i_File, i_FileStatus, i_NumOfFilesWithRPC, i_TotalNumberOfFiles);
}
}
public static IEnumerable<FileInfo> GetFilesByExtensions(this DirectoryInfo dir, params string[] extensions)
{
if (extensions == null)
throw new ArgumentNullException("extensions");
IEnumerable<FileInfo> files = dir.EnumerateFiles();
return files.Where(f => extensions.Contains(f.Extension));
}
private static bool isBinaryMZFile(string i_FileName)
{
bool isBinary = false;
int numBytesToRead = 2;
int numBytesRead = 0;
byte[] bytes = new byte[2];
int n;
using (FileStream fsSource = new FileStream(i_FileName, FileMode.Open, FileAccess.Read))
{
n = fsSource.Read(bytes, numBytesRead, numBytesToRead);
}
//const Int32 BufferSize = 4;
//using (var fileStream = File.OpenRead(name))
//{
// using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize))
// {
// String line;
// line = streamReader.ReadLine();
// int a = line.Length;
// }
//}
// 77 = 'M', 90 = 'Z'
if (n > 0 && bytes[0] == 77 && bytes[1] == 90)
{
isBinary = true;
}
return isBinary;
}
// Original: https://stackoverflow.com/questions/172544/ignore-folders-files-when-directory-getfiles-is-denied-access
// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree
private static void buildRPCServersList(string root, bool isRecursive, params string[] extensions)
{
// Data structure to hold names of subfolders to be
// examined for files.
Stack<string> dirs = new Stack<string>(10);
IEnumerable<NtApiDotNet.Win32.RpcServer> rpcServer = Enumerable.Empty<NtApiDotNet.Win32.RpcServer>();
if (!System.IO.Directory.Exists(root))
{
throw new ArgumentException();
}
dirs.Push(root);
while (dirs.Count > 0)
{
if (m_IsDoneRPCSearch)
{
break;
}
string currentDir = dirs.Pop();
if (m_ExcludedFoldersMap.ContainsKey(currentDir.ToLower()))
{
continue;
}
//updateStatusToolStrip(currentDir);
string[] subDirs;
try
{
subDirs = System.IO.Directory.GetDirectories(currentDir);
}
// An UnauthorizedAccessException exception will be thrown if we do not have
// discovery permission on a folder or file. It may or may not be acceptable
// to ignore the exception and continue enumerating the remaining files and
// folders. It is also possible (but unlikely) that a DirectoryNotFound exception
// will be raised. This will happen if currentDir has been deleted by
// another application or thread after our call to Directory.Exists. The
// choice of which exceptions to catch depends entirely on the specific task
// you are intending to perform and also on how much you know with certainty
// about the systems on which this code will run.
catch (UnauthorizedAccessException e)
{
//Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
//Console.WriteLine(e.Message);
continue;
}
//string[] files = null;
IEnumerable<FileInfo> files;
try
{
//files = System.IO.Directory.GetFiles(currentDir, extension);
DirectoryInfo dInfo = new DirectoryInfo(currentDir);
files = dInfo.GetFilesByExtensions(extensions);
m_TotalNumberOfFiles += files.Count();
}
catch (UnauthorizedAccessException e)
{
//Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
//Console.WriteLine(e.Message);
continue;
}
// Perform the required action on each file here.
// Modify this block to perform your required task.
foreach (FileInfo file in files)
{
if (m_IsDoneRPCSearch)
{
break;
}
try
{
// Eviatar: Error when trying to load this file. There are more.
// string name = @"C:\Windows\winsxs\x86_wcf-system.identitymodel_b03f5f7f11d50a3a_10.0.19041.1_none_e690fdc7d17e3f70\System.IdentityModel.dll";
// We are doing this check to avoid the uncatchable exception of Bad Image
// It won't help against the file C:\Windows\winsxs\x86_microsoft-windows-n..nd-syswow64-payload_31bf3856ad364e35_1.0.19041.1_none_beac3411b23832d5\compobj.dll
// which have "MZ" in the beginning but Bad Image. I add work around to execlude some folders.
// The "MZ" is not enough because there are files like
// C:\Windows\winsxs\x86_microsoft-windows-n..nd-syswow64-payload_31bf3856ad364e35_1.0.19041.1_none_beac3411b23832d5\compobj.dll
// Which have bad image and starts with "MZ". The workaround might be by trying to load it as data file first and if succeed call the ParsePe function.
//if (isBinaryMZFile(file.FullName))
if (Win32NativeMethods.isSucceedLoadLibrary(file.FullName, LoadLibraryFlags.LoadLibraryAsDataFile))
{
rpcServer = NtApiDotNet.Win32.RpcServer.ParsePeFile(file.FullName, m_DbgHelp, m_SymbolsPath, NtApiDotNet.Win32.RpcServerParserFlags.None);
}
if (rpcServer.Count() > 0)
{
m_RPCServersDB.Add(rpcServer);
m_NumOfFilesWithRPC += 1;
OnBuildRPCDBStatusUpdate(file.FullName, "Yes", m_NumOfFilesWithRPC, m_TotalNumberOfFiles);
} else
{
OnBuildRPCDBStatusUpdate(file.FullName, "No", m_NumOfFilesWithRPC, m_TotalNumberOfFiles);
}
//ManifestInfo info = Engine.GetManifestInfo(file);
/*if (info != null && (String.Empty != info.Level + info.uiAccess + info.autoElevate + info.dpiAware))
{
if (UserMatchesFilters(info))
{
//if(isFilteredByCheckboxes(info)){
updateTable(info, file);
}
}*/
}
catch (System.IO.FileNotFoundException e)
{
// If file was deleted by a separate application
// or thread since the call to TraverseTree()
// then just continue.
//Console.WriteLine(e.Message);
continue;
}
}
if (!isRecursive)
{
break;
}
// Push the subdirectories onto the stack for traversal.
// This could also be done before handing the files.
foreach (string str in subDirs)
dirs.Push(str);
}
//this.toolStripStatusLabel1.Text = "Done";
}
}
}