BadPotato/RPC/rpcapi.cs

324 lines
14 KiB
C#

//
// Copyright (c) Ping Castle. All rights reserved.
// https://www.pingcastle.com
//
// Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
namespace PingCastle.RPC
{
public abstract class rpcapi
{
private byte[] MIDL_ProcFormatString;
private byte[] MIDL_TypeFormatString;
private GCHandle procString;
private GCHandle formatString;
private GCHandle stub;
private GCHandle faultoffsets;
private GCHandle clientinterface;
private GCHandle bindinghandle;
private string PipeName;
// important: keep a reference on delegate to avoid CallbackOnCollectedDelegate exception
bind BindDelegate;
unbind UnbindDelegate;
allocmemory AllocateMemoryDelegate = AllocateMemory;
freememory FreeMemoryDelegate = FreeMemory;
public bool UseNullSession { get; set; }
// 5 seconds
public UInt32 RPCTimeOut = 5000;
[StructLayout(LayoutKind.Sequential)]
private struct COMM_FAULT_OFFSETS
{
public short CommOffset;
public short FaultOffset;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable"), StructLayout(LayoutKind.Sequential)]
private struct GENERIC_BINDING_ROUTINE_PAIR
{
public IntPtr Bind;
public IntPtr Unbind;
}
[StructLayout(LayoutKind.Sequential)]
private struct RPC_VERSION
{
public ushort MajorVersion;
public ushort MinorVersion;
public static readonly RPC_VERSION INTERFACE_VERSION = new RPC_VERSION() { MajorVersion = 1, MinorVersion = 0 };
public static readonly RPC_VERSION SYNTAX_VERSION = new RPC_VERSION() { MajorVersion = 2, MinorVersion = 0 };
public RPC_VERSION(ushort InterfaceVersionMajor, ushort InterfaceVersionMinor)
{
MajorVersion = InterfaceVersionMajor;
MinorVersion = InterfaceVersionMinor;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct RPC_SYNTAX_IDENTIFIER
{
public Guid SyntaxGUID;
public RPC_VERSION SyntaxVersion;
}
[StructLayout(LayoutKind.Sequential)]
private struct RPC_CLIENT_INTERFACE
{
public uint Length;
public RPC_SYNTAX_IDENTIFIER InterfaceId;
public RPC_SYNTAX_IDENTIFIER TransferSyntax;
public IntPtr /*PRPC_DISPATCH_TABLE*/ DispatchTable;
public uint RpcProtseqEndpointCount;
public IntPtr /*PRPC_PROTSEQ_ENDPOINT*/ RpcProtseqEndpoint;
public IntPtr Reserved;
public IntPtr InterpreterInfo;
public uint Flags;
public static readonly Guid IID_SYNTAX = new Guid(0x8A885D04u, 0x1CEB, 0x11C9, 0x9F, 0xE8, 0x08, 0x00, 0x2B,
0x10,
0x48, 0x60);
public RPC_CLIENT_INTERFACE(Guid iid, ushort InterfaceVersionMajor = 1, ushort InterfaceVersionMinor = 0)
{
Length = (uint)Marshal.SizeOf(typeof(RPC_CLIENT_INTERFACE));
InterfaceId = new RPC_SYNTAX_IDENTIFIER() { SyntaxGUID = iid, SyntaxVersion = new RPC_VERSION(InterfaceVersionMajor, InterfaceVersionMinor) };
TransferSyntax = new RPC_SYNTAX_IDENTIFIER() { SyntaxGUID = IID_SYNTAX, SyntaxVersion = RPC_VERSION.SYNTAX_VERSION };
DispatchTable = IntPtr.Zero;
RpcProtseqEndpointCount = 0u;
RpcProtseqEndpoint = IntPtr.Zero;
Reserved = IntPtr.Zero;
InterpreterInfo = IntPtr.Zero;
Flags = 0u;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct MIDL_STUB_DESC
{
public IntPtr /*RPC_CLIENT_INTERFACE*/ RpcInterfaceInformation;
public IntPtr pfnAllocate;
public IntPtr pfnFree;
public IntPtr pAutoBindHandle;
public IntPtr /*NDR_RUNDOWN*/ apfnNdrRundownRoutines;
public IntPtr /*GENERIC_BINDING_ROUTINE_PAIR*/ aGenericBindingRoutinePairs;
public IntPtr /*EXPR_EVAL*/ apfnExprEval;
public IntPtr /*XMIT_ROUTINE_QUINTUPLE*/ aXmitQuintuple;
public IntPtr pFormatTypes;
public int fCheckBounds;
/* Ndr library version. */
public uint Version;
public IntPtr /*MALLOC_FREE_STRUCT*/ pMallocFreeStruct;
public int MIDLVersion;
public IntPtr CommFaultOffsets;
// New fields for version 3.0+
public IntPtr /*USER_MARSHAL_ROUTINE_QUADRUPLE*/ aUserMarshalQuadruple;
// Notify routines - added for NT5, MIDL 5.0
public IntPtr /*NDR_NOTIFY_ROUTINE*/ NotifyRoutineTable;
public IntPtr mFlags;
// International support routines - added for 64bit post NT5
public IntPtr /*NDR_CS_ROUTINES*/ CsRoutineTables;
public IntPtr ProxyServerInfo;
public IntPtr /*NDR_EXPR_DESC*/ pExprInfo;
// Fields up to now present in win2000 release.
public MIDL_STUB_DESC(IntPtr pFormatTypesPtr, IntPtr RpcInterfaceInformationPtr,
IntPtr pfnAllocatePtr, IntPtr pfnFreePtr, IntPtr aGenericBindingRoutinePairsPtr)
{
pFormatTypes = pFormatTypesPtr;
RpcInterfaceInformation = RpcInterfaceInformationPtr;
CommFaultOffsets = IntPtr.Zero;
pfnAllocate = pfnAllocatePtr;
pfnFree = pfnFreePtr;
pAutoBindHandle = IntPtr.Zero;
apfnNdrRundownRoutines = IntPtr.Zero;
aGenericBindingRoutinePairs = aGenericBindingRoutinePairsPtr;
apfnExprEval = IntPtr.Zero;
aXmitQuintuple = IntPtr.Zero;
fCheckBounds = 1;
Version = 0x50002u;
pMallocFreeStruct = IntPtr.Zero;
MIDLVersion = 0x8000253;
aUserMarshalQuadruple = IntPtr.Zero;
NotifyRoutineTable = IntPtr.Zero;
mFlags = new IntPtr(0x00000001);
CsRoutineTables = IntPtr.Zero;
ProxyServerInfo = IntPtr.Zero;
pExprInfo = IntPtr.Zero;
}
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected void InitializeStub(Guid interfaceID, byte[] MIDL_ProcFormatString, byte[] MIDL_TypeFormatString, string pipe, ushort MajorVerson = 1, ushort MinorVersion = 0)
{
this.MIDL_ProcFormatString = MIDL_ProcFormatString;
this.MIDL_TypeFormatString = MIDL_TypeFormatString;
PipeName = pipe;
procString = GCHandle.Alloc(this.MIDL_ProcFormatString, GCHandleType.Pinned);
RPC_CLIENT_INTERFACE clientinterfaceObject = new RPC_CLIENT_INTERFACE(interfaceID, MajorVerson, MinorVersion);
GENERIC_BINDING_ROUTINE_PAIR bindingObject = new GENERIC_BINDING_ROUTINE_PAIR();
// important: keep a reference to avoid CallbakcOnCollectedDelegate Exception
BindDelegate = Bind;
UnbindDelegate = Unbind;
bindingObject.Bind = Marshal.GetFunctionPointerForDelegate((bind)BindDelegate);
bindingObject.Unbind = Marshal.GetFunctionPointerForDelegate((unbind)UnbindDelegate);
faultoffsets = GCHandle.Alloc(new COMM_FAULT_OFFSETS() { CommOffset = -1, FaultOffset = -1 }, GCHandleType.Pinned);
clientinterface = GCHandle.Alloc(clientinterfaceObject, GCHandleType.Pinned);
formatString = GCHandle.Alloc(MIDL_TypeFormatString, GCHandleType.Pinned);
bindinghandle = GCHandle.Alloc(bindingObject, GCHandleType.Pinned);
MIDL_STUB_DESC stubObject = new MIDL_STUB_DESC(formatString.AddrOfPinnedObject(),
clientinterface.AddrOfPinnedObject(),
Marshal.GetFunctionPointerForDelegate(AllocateMemoryDelegate),
Marshal.GetFunctionPointerForDelegate(FreeMemoryDelegate),
bindinghandle.AddrOfPinnedObject());
stub = GCHandle.Alloc(stubObject, GCHandleType.Pinned);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected void freeStub()
{
procString.Free();
faultoffsets.Free();
clientinterface.Free();
formatString.Free();
bindinghandle.Free();
stub.Free();
}
delegate IntPtr allocmemory(int size);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected static IntPtr AllocateMemory(int size)
{
IntPtr memory = Marshal.AllocHGlobal(size);
//Trace.WriteLine("allocating " + memory.ToString());
return memory;
}
delegate void freememory(IntPtr memory);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected static void FreeMemory(IntPtr memory)
{
//Trace.WriteLine("freeing " + memory.ToString());
Marshal.FreeHGlobal(memory);
}
delegate IntPtr bind(IntPtr IntPtrserver);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected IntPtr Bind (IntPtr IntPtrserver)
{
string server = Marshal.PtrToStringUni(IntPtrserver);
IntPtr bindingstring = IntPtr.Zero;
IntPtr binding = IntPtr.Zero;
Int32 status;
Trace.WriteLine("Binding to " + server + " " + PipeName);
status = NativeMethods.RpcStringBindingCompose(null, "ncacn_np", server, PipeName, null, out bindingstring);
if (status != 0)
{
Trace.WriteLine("RpcStringBindingCompose failed with status 0x" + status.ToString("x"));
return IntPtr.Zero;
}
status = NativeMethods.RpcBindingFromStringBinding(Marshal.PtrToStringUni(bindingstring), out binding);
NativeMethods.RpcBindingFree(ref bindingstring);
if (status != 0)
{
Trace.WriteLine("RpcBindingFromStringBinding failed with status 0x" + status.ToString("x"));
return IntPtr.Zero;
}
if (UseNullSession)
{
// note: windows xp doesn't support user or domain = "" => return 0xE
NativeMethods.SEC_WINNT_AUTH_IDENTITY identity = new NativeMethods.SEC_WINNT_AUTH_IDENTITY();
identity.User = "";
identity.UserLength = identity.User.Length * 2;
identity.Domain = "";
identity.DomainLength = identity.Domain.Length * 2;
identity.Password = "";
identity.Flags = 2;
NativeMethods.RPC_SECURITY_QOS qos = new NativeMethods.RPC_SECURITY_QOS();
qos.Version = 1;
qos.ImpersonationType = 3;
GCHandle qoshandle = GCHandle.Alloc(qos, GCHandleType.Pinned);
// 9 = negotiate , 10 = ntlm ssp
status = NativeMethods.RpcBindingSetAuthInfoEx(binding, server, 0, 9, ref identity, 0, ref qos);
qoshandle.Free();
if (status != 0)
{
Trace.WriteLine("RpcBindingSetAuthInfoEx failed with status 0x" + status.ToString("x"));
Unbind(IntPtrserver, binding);
return IntPtr.Zero;
}
}
status = NativeMethods.RpcBindingSetOption(binding, 12, RPCTimeOut);
if (status != 0)
{
Trace.WriteLine("RpcBindingSetOption failed with status 0x" + status.ToString("x"));
}
Trace.WriteLine("binding ok (handle=" + binding + ")");
return binding;
}
delegate void unbind(IntPtr IntPtrserver, IntPtr hBinding);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected static void Unbind(IntPtr IntPtrserver, IntPtr hBinding)
{
string server = Marshal.PtrToStringUni(IntPtrserver);
Trace.WriteLine("unbinding " + server);
NativeMethods.RpcBindingFree(ref hBinding);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected IntPtr GetProcStringHandle(int offset)
{
return Marshal.UnsafeAddrOfPinnedArrayElement(MIDL_ProcFormatString, offset);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected IntPtr GetStubHandle()
{
return stub.AddrOfPinnedObject();
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected IntPtr CallNdrClientCall2x86(int offset, params IntPtr[] args)
{
GCHandle stackhandle = GCHandle.Alloc(args, GCHandleType.Pinned);
IntPtr result;
try
{
result = NativeMethods.NdrClientCall2x86(GetStubHandle(), GetProcStringHandle(offset), stackhandle.AddrOfPinnedObject());
}
finally
{
stackhandle.Free();
}
return result;
}
}
}