/// <summary> /// Constructor. /// </summary> /// <param name="process">Process to parse from.</param> /// <param name="symbol_resolver">Specify a symbol resolver to use for looking up symbols.</param> /// <param name="parser_flags">Flags which affect the parsing operation.</param> public NdrParser(NtProcess process, ISymbolResolver symbol_resolver, NdrParserFlags parser_flags) { CheckSymbolResolver(process, symbol_resolver); if (process == null || process.ProcessId == NtProcess.Current.ProcessId) { _reader = new CurrentProcessMemoryReader(); } else { if (!Environment.Is64BitProcess && process.Is64Bit) { throw new ArgumentException("Do not support 32 to 64 bit reading."); } if (Environment.Is64BitProcess != process.Is64Bit) { _reader = new CrossBitnessProcessMemoryReader(process); } else { _reader = new ProcessMemoryReader(process); } } _symbol_resolver = symbol_resolver; _type_cache = new NdrTypeCache(); _parser_flags = parser_flags; }
/// <summary> /// Constructor. /// </summary> /// <param name="reader">Memory reader to parse from.</param> /// <param name="process">Process to read from.</param> /// <param name="symbol_resolver">Specify a symbol resolver to use for looking up symbols.</param> /// <param name="parser_flags">Flags which affect the parsing operation.</param> internal NdrParser(IMemoryReader reader, NtProcess process, ISymbolResolver symbol_resolver, NdrParserFlags parser_flags) { CheckSymbolResolver(process, symbol_resolver); _reader = reader; _symbol_resolver = symbol_resolver; _type_cache = new NdrTypeCache(); _parser_flags = parser_flags; }
internal NdrParseContext(NdrTypeCache type_cache, ISymbolResolver symbol_resolver, MIDL_STUB_DESC stub_desc, IntPtr type_desc, int desc_size, IMemoryReader reader, NdrParserFlags parser_flags) { TypeCache = type_cache; SymbolResolver = symbol_resolver; StubDesc = stub_desc; TypeDesc = type_desc; CorrDescSize = desc_size; Reader = reader; Flags = parser_flags; }
internal NdrParseContext(NdrTypeCache type_cache, ISymbolResolver symbol_resolver, MIDL_STUB_DESC stub_desc, IntPtr type_desc, NDR_EXPR_DESC expr_desc, NdrInterpreterOptFlags2 opt_flags, IMemoryReader reader, NdrParserFlags parser_flags) { TypeCache = type_cache; SymbolResolver = symbol_resolver; StubDesc = stub_desc; TypeDesc = type_desc; ExprDesc = expr_desc; OptFlags = opt_flags; Reader = reader; Flags = parser_flags; }
/// <summary> /// Parse all RPC servers from a PE file. /// </summary> /// <param name="file">The PE file to parse.</param> /// <param name="dbghelp_path">Path to a DBGHELP DLL to resolve symbols.</param> /// <param name="symbol_path">Symbol path for DBGHELP</param> /// <param name="flags">Flags for the RPC parser.</param> /// <remarks>This only works for PE files with the same bitness as the current process.</remarks> /// <returns>A list of parsed RPC server.</returns> public static IEnumerable <RpcServer> ParsePeFile(string file, string dbghelp_path, string symbol_path, RpcServerParserFlags flags) { List <RpcServer> servers = new List <RpcServer>(); using (var result = SafeLoadLibraryHandle.LoadLibrary(file, LoadLibraryFlags.DontResolveDllReferences, false)) { if (!result.IsSuccess) { return(servers.AsReadOnly()); } var lib = result.Result; var sections = lib.GetImageSections(); var offsets = sections.SelectMany(s => FindRpcServerInterfaces(s, flags.HasFlagSet(RpcServerParserFlags.ParseClients))); if (offsets.Any()) { SymbolResolverFlags symbol_flags = flags.HasFlagSet(RpcServerParserFlags.SymSrvFallback) ? SymbolResolverFlags.SymSrvFallback : SymbolResolverFlags.None; using (var sym_resolver = !flags.HasFlagSet(RpcServerParserFlags.IgnoreSymbols) ? SymbolResolver.Create(NtProcess.Current, dbghelp_path, symbol_path, symbol_flags, null) : null) { NdrParserFlags parser_flags = NdrParserFlags.IgnoreUserMarshal; if (flags.HasFlagSet(RpcServerParserFlags.ResolveStructureNames)) { parser_flags |= NdrParserFlags.ResolveStructureNames; } foreach (var offset in offsets) { IMemoryReader reader = new CurrentProcessMemoryReader(sections.Select(s => Tuple.Create(s.Data.DangerousGetHandle().ToInt64(), (int)s.Data.ByteLength))); NdrParser parser = new NdrParser(reader, NtProcess.Current, sym_resolver, parser_flags); IntPtr ifspec = lib.DangerousGetHandle() + (int)offset.Offset; try { var rpc = parser.ReadFromRpcServerInterface(ifspec, lib.DangerousGetHandle()); servers.Add(new RpcServer(rpc, parser.ComplexTypes, file, offset.Offset, offset.Client)); } catch (NdrParserException) { } } } } } return(servers.AsReadOnly()); }
private static void FixupStructureNames(List <NdrProcedureDefinition> procs, ISymbolResolver symbol_resolver, NdrParserFlags parser_flags) { if (!parser_flags.HasFlagSet(NdrParserFlags.ResolveStructureNames) || !(symbol_resolver is ISymbolTypeResolver type_resolver)) { return; } var complex_types = new Dictionary <NdrComplexTypeReference, UserDefinedTypeInformation>(); foreach (var proc in procs) { if (!(type_resolver.GetTypeForSymbolByAddress(proc.DispatchFunction) is FunctionTypeInformation func_type)) { continue; } if (func_type.Parameters.Count != proc.Params.Count) { continue; } for (int i = 0; i < func_type.Parameters.Count; ++i) { proc.Params[i].Name = func_type.Parameters[i].Name; UpdateComplexTypes(complex_types, func_type.Parameters[i].ParameterType, proc.Params[i].Type); } if (proc.ReturnValue != null && func_type.ReturnType != null) { UpdateComplexTypes(complex_types, func_type.ReturnType, proc.ReturnValue.Type); } } HashSet <NdrComplexTypeReference> fixup_set = new HashSet <NdrComplexTypeReference>(); foreach (var pair in complex_types) { FixupComplexType(fixup_set, pair.Key, pair.Value); } }
/// <summary> /// Constructor. /// </summary> /// <param name="process">Process to parse from.</param> /// <param name="symbol_resolver">Specify a symbol resolver to use for looking up symbols.</param> /// <param name="parser_flags">Flags which affect the parsing operation.</param> public NdrParser(NtProcess process, ISymbolResolver symbol_resolver, NdrParserFlags parser_flags) : this(CreateReader(process), process, symbol_resolver, parser_flags) { }
private static IEnumerable <NdrProcedureDefinition> ReadProcs(IMemoryReader reader, MIDL_SERVER_INFO server_info, int start_offset, int dispatch_count, NdrTypeCache type_cache, ISymbolResolver symbol_resolver, IList <string> names, NdrParserFlags parser_flags) { RPC_SYNTAX_IDENTIFIER transfer_syntax = server_info.GetTransferSyntax(reader); IntPtr proc_str = IntPtr.Zero; IntPtr fmt_str_ofs = IntPtr.Zero; if (transfer_syntax.SyntaxGUID != NdrNativeUtils.DCE_TransferSyntax) { MIDL_SYNTAX_INFO[] syntax_info = server_info.GetSyntaxInfo(reader); if (!syntax_info.Any(s => s.TransferSyntax.SyntaxGUID == NdrNativeUtils.DCE_TransferSyntax)) { throw new NdrParserException("Can't parse NDR64 syntax data"); } MIDL_SYNTAX_INFO dce_syntax_info = syntax_info.First(s => s.TransferSyntax.SyntaxGUID == NdrNativeUtils.DCE_TransferSyntax); proc_str = dce_syntax_info.ProcString; fmt_str_ofs = dce_syntax_info.FmtStringOffset; } else { proc_str = server_info.ProcString; fmt_str_ofs = server_info.FmtStringOffset; } IntPtr[] dispatch_funcs = server_info.GetDispatchTable(reader, dispatch_count); MIDL_STUB_DESC stub_desc = server_info.GetStubDesc(reader); IntPtr type_desc = stub_desc.pFormatTypes; NDR_EXPR_DESC expr_desc = stub_desc.GetExprDesc(reader); List <NdrProcedureDefinition> procs = new List <NdrProcedureDefinition>(); if (fmt_str_ofs != IntPtr.Zero) { for (int i = start_offset; i < dispatch_count; ++i) { int fmt_ofs = reader.ReadInt16(fmt_str_ofs + i * 2); if (fmt_ofs >= 0) { string name = null; if (names != null) { name = names[i - start_offset]; } procs.Add(new NdrProcedureDefinition(reader, type_cache, symbol_resolver, stub_desc, proc_str + fmt_ofs, type_desc, expr_desc, dispatch_funcs[i], name, parser_flags)); } } } return(procs.AsReadOnly()); }
private static NdrRpcServerInterface ReadRpcServerInterface(IMemoryReader reader, RPC_SERVER_INTERFACE server_interface, NdrTypeCache type_cache, ISymbolResolver symbol_resolver, NdrParserFlags parser_flags) { RPC_DISPATCH_TABLE dispatch_table = server_interface.GetDispatchTable(reader); var procs = ReadProcs(reader, server_interface.GetServerInfo(reader), 0, dispatch_table.DispatchTableCount, type_cache, symbol_resolver, null, parser_flags); return(new NdrRpcServerInterface(server_interface.InterfaceId, server_interface.TransferSyntax, procs, server_interface.GetProtSeq(reader).Select(s => new NdrProtocolSequenceEndpoint(s, reader)))); }
public bool HasFlag(NdrParserFlags flags) { return((Flags & flags) == flags); }
internal NdrProcedureDefinition(IMemoryReader mem_reader, NdrTypeCache type_cache, ISymbolResolver symbol_resolver, MIDL_STUB_DESC stub_desc, IntPtr proc_desc, IntPtr type_desc, NDR_EXPR_DESC expr_desc, IntPtr dispatch_func, string name, NdrParserFlags parser_flags) { BinaryReader reader = mem_reader.GetReader(proc_desc); NdrFormatCharacter handle_type = (NdrFormatCharacter)reader.ReadByte(); NdrInterpreterFlags old_oi_flags = (NdrInterpreterFlags)reader.ReadByte(); if ((old_oi_flags & NdrInterpreterFlags.HasRpcFlags) == NdrInterpreterFlags.HasRpcFlags) { RpcFlags = reader.ReadUInt32(); } ProcNum = reader.ReadUInt16(); if (string.IsNullOrWhiteSpace(name)) { if (symbol_resolver != null && dispatch_func != IntPtr.Zero) { Name = symbol_resolver.GetSymbolForAddress(dispatch_func, false, true); } Name = Name ?? $"Proc{ProcNum}"; } else { Name = name; } StackSize = reader.ReadUInt16(); if (handle_type == 0) { // read out handle type. handle_type = (NdrFormatCharacter)reader.ReadByte(); NdrHandleParamFlags flags = (NdrHandleParamFlags)reader.ReadByte(); ushort handle_offset = reader.ReadUInt16(); NdrBaseTypeReference base_type = new NdrSimpleTypeReference(handle_type); if (handle_type == NdrFormatCharacter.FC_BIND_PRIMITIVE) { flags = flags != 0 ? NdrHandleParamFlags.HANDLE_PARAM_IS_VIA_PTR : 0; } else if (handle_type == NdrFormatCharacter.FC_BIND_GENERIC) { // Remove the size field, we might do something with this later. flags = (NdrHandleParamFlags)((byte)flags & 0xF0); // Read out the remaining data. reader.ReadByte(); reader.ReadByte(); } else if (handle_type == NdrFormatCharacter.FC_BIND_CONTEXT) { // Read out the remaining data. reader.ReadByte(); reader.ReadByte(); } else { throw new ArgumentException($"Unsupported explicit handle type {handle_type}"); } Handle = new NdrProcedureHandleParameter(0, (flags & NdrHandleParamFlags.HANDLE_PARAM_IS_VIA_PTR) != 0 ? new NdrPointerTypeReference(base_type) : base_type, handle_offset, true, flags, handle_type == NdrFormatCharacter.FC_BIND_GENERIC); } else { Handle = new NdrProcedureHandleParameter(0, new NdrSimpleTypeReference(handle_type), 0, false, 0, false); } ushort constant_client_buffer_size = reader.ReadUInt16(); ushort constant_server_buffer_size = reader.ReadUInt16(); InterpreterFlags = (NdrInterpreterOptFlags)reader.ReadByte(); int number_of_params = reader.ReadByte(); NdrProcHeaderExts exts = new NdrProcHeaderExts(); if ((InterpreterFlags & NdrInterpreterOptFlags.HasExtensions) == NdrInterpreterOptFlags.HasExtensions) { int ext_size = reader.ReadByte(); reader.BaseStream.Position -= 1; // Read out extension bytes. byte[] extension = reader.ReadAll(ext_size); if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(NdrProcHeaderExts)) <= ext_size) { using (var buffer = new SafeStructureInOutBuffer <NdrProcHeaderExts>(ext_size, false)) { buffer.WriteArray(0, extension, 0, ext_size); exts = buffer.Result; } } } NdrParseContext context = new NdrParseContext(type_cache, symbol_resolver, stub_desc, type_desc, expr_desc, exts.Flags2, mem_reader, parser_flags); List <NdrProcedureParameter> ps = new List <NdrProcedureParameter>(); bool has_return = InterpreterFlags.HasFlag(NdrInterpreterOptFlags.HasReturn); int param_count = has_return ? number_of_params - 1 : number_of_params; for (int param = 0; param < param_count; ++param) { ps.Add(new NdrProcedureParameter(context, reader, $"p{param}")); } if (Handle.Explicit && !Handle.Generic) { // Insert handle into parameter list at the best location. int index = 0; while (index < ps.Count) { if (ps[index].Offset > Handle.Offset) { ps.Insert(index, Handle); break; } index++; } } Params = ps.AsReadOnly(); if (has_return) { ReturnValue = new NdrProcedureParameter(context, reader, "retval"); } DispatchFunction = dispatch_func; }
/// <summary> /// Parse NDR complex type information from a pickling structure. Used to extract explicit Encode/Decode method information. /// </summary> /// <param name="process">The process to read from.</param> /// <param name="midl_type_pickling_info">Pointer to the MIDL_TYPE_PICKLING_INFO structure.</param> /// <param name="midl_stub_desc">The pointer to the MIDL_STUB_DESC structure.</param> /// <param name="start_offsets">Offsets into the format string to the start of the types.</param> /// <param name="parser_flags">Specify additional parser flags.</param> /// <returns>The list of complex types.</returns> /// <remarks>This function is used to extract type information for calls to NdrMesTypeDecode2. MIDL_TYPE_PICKLING_INFO is the second parameter, /// MIDL_STUB_DESC is the third (minus the offset).</remarks> public static IEnumerable <NdrComplexTypeReference> ReadPicklingComplexTypes(NtProcess process, IntPtr midl_type_pickling_info, IntPtr midl_stub_desc, int[] start_offsets, NdrParserFlags parser_flags) { if (start_offsets.Length == 0) { return(new NdrComplexTypeReference[0]); } return(ReadPicklingComplexTypes(parser_flags, process, midl_type_pickling_info, midl_stub_desc, false, (r, f) => start_offsets)); }
/// <summary> /// Parse NDR complex type information from a pickling structure. Used to extract explicit Encode/Decode method information. /// </summary> /// <param name="process">The process to read from.</param> /// <param name="midl_type_pickling_info">Pointer to the MIDL_TYPE_PICKLING_INFO structure.</param> /// <param name="midl_stubless_proxy">The pointer to the MIDL_STUBLESS_PROXY_INFO structure.</param> /// <param name="type_pickling_offset_table">Pointer to the type pickling offset table.</param> /// <param name="type_index">Index into type_pickling_offset_table array.</param> /// <param name="parser_flags">Specify additional parser flags.</param> /// <returns>The list of complex types.</returns> /// <remarks>This function is used to extract type information for calls to NdrMesTypeDecode3. MIDL_TYPE_PICKLING_INFO is the second parameter, /// MIDL_STUBLESS_PROXY_INFO is the third, the type pickling offset table is the fourth and the type index is the fifth.</remarks> public static IEnumerable <NdrComplexTypeReference> ReadPicklingComplexTypes(NtProcess process, IntPtr midl_type_pickling_info, IntPtr midl_stubless_proxy, IntPtr type_pickling_offset_table, int[] type_index, NdrParserFlags parser_flags) { if (type_index.Length == 0) { return(new NdrComplexTypeReference[0]); } return(ReadPicklingComplexTypes(parser_flags, process, midl_type_pickling_info, midl_stubless_proxy, true, (r, f) => GetPicklingTableOffsets(r, type_pickling_offset_table, type_index))); }
/// <summary> /// Parse NDR complex type information from a pickling structure. Used to extract explicit Encode/Decode method information. /// </summary> /// <param name="process">The process to read from.</param> /// <param name="midl_type_pickling_info">Pointer to the MIDL_TYPE_PICKLING_INFO structure.</param> /// <param name="midl_stub_desc">The pointer to the MIDL_STUB_DESC structure.</param> /// <param name="type_offsets">Pointers to the the format string to the start of the types.</param> /// <param name="parser_flags">Specify additional parser flags.</param> /// <returns>The list of complex types.</returns> /// <remarks>This function is used to extract type information for calls to NdrMesTypeDecode2. MIDL_TYPE_PICKLING_INFO is the second parameter, /// MIDL_STUB_DESC is the third, the Type Offsets is the fourth parameter.</remarks> public static IEnumerable <NdrComplexTypeReference> ReadPicklingComplexTypes(NtProcess process, IntPtr midl_type_pickling_info, IntPtr midl_stub_desc, IntPtr[] type_offsets, NdrParserFlags parser_flags) { if (type_offsets.Length == 0) { return(new NdrComplexTypeReference[0]); } return(ReadPicklingComplexTypes(parser_flags, process, midl_type_pickling_info, midl_stub_desc, false, (r, f) => type_offsets.Select(p => (int)(p.ToInt64() - f.ToInt64())))); }
private static IEnumerable <NdrComplexTypeReference> ReadPicklingComplexTypes(NdrParserFlags parser_flags, NtProcess process, IntPtr midl_type_pickling_info, IntPtr midl_stub_desc, bool deref_stub_desc, Func <IMemoryReader, IntPtr, IEnumerable <int> > get_offsets) { NdrParser parser = new NdrParser(process, null, parser_flags); RunWithAccessCatch(() => parser.ReadTypes(midl_type_pickling_info, midl_stub_desc, deref_stub_desc, get_offsets)); return(parser.ComplexTypes); }