Quantcast
Channel: Windows SDK Support Team Blog
Viewing all 126 articles
Browse latest View live

Debugging the PowerShell Debugger

$
0
0

When doing development for PowerShell cmdlets in a managed language such as C#, it can often be convenient to use the PowerShell ISE to test functionality.  Since it has a built-in script debugger, it help with finding some errors.  However, if you need to dig deeper into yourown code and how it’s interacting with PowerShell, you want to debug thePowerShell debugger.  Here’s how to do it:

  1. Attach WinDbg or your other favorite dbghelp based debugger to the PowerShell_ISE.exe instance that you’ll be using. 
  2. Go ahead and load the SOS extension
  3. Execute !DumpDomain in order to see the AppDomains and, more importantly for our purposes, the assemblies loaded in each. 
  4. Find the System.Management.Automation.dll assembly which should look like the below.
    Assembly:          000000c8c1a8e2a0    [C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll]
    ClassLoader:       000000c8c1a84060
    SecurityDescriptor: 000000c8c1a9d900
    Module Name: 00007ffeb93f1000           C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
  5. Note its module address; use that address in the command !DumpModule /d -mt addr.
  6. You’ll see many classes with the text “debugger” in them.  Depending on what you’re wanting to catch, you may want to choose something else like the RemoteDebugger.  For this example, let’s use System.Management.Automation.ScriptDebugger. You’ll want to click on the DML for its method table to output some information about it. 
  7. Take the command that the DML executed, !DumpMT /d addr, and add -MD so that it looks like !DumpMT /d -MD addr
  8. Execute the newly formatted command.  This will output all of the methods defined for the class as well as the method description address for each.  We can use that address to set up breakpoints in WinDbg.  You’ll notice that there are specified functions named for handling commands, jobs, etc defined for the ScriptDebugger class.
  9. For each method on which a breakpoint is desired, execute the command !bpmd -md addrGo ahead and set a breakpoint on the method ProcessCommand. 
  10. Let the application resume execution.
  11. Create a script such as $processes = Get-Process.
  12. Set a breakpoint on that line.
  13. Run the script. 

You’ll notice that a breakpoint has been triggered on the ProcessCommand method. You can now use commands such as !ClrStack to view the managed stack, !DumpStack to see the entire stack, or !DumpStackObjects to see the objects on the stack. 

Congratulations, you’re now debugging the PowerShell debugger!

 Follow us on Twitter, http://www.twitter.com/WindowsSDK.


How to Create and Use Anonymous Pipes in .NET

$
0
0

How to Create and Use Anonymous Pipes in .NET

.NET offers easy support for using named pipes, but what about anonymous pipes?  Can those be done in .NET?  The answer is yes, but it’s tricky to do and only useful in certain situations.  You would need several things in order to accomplish this:

  1. A static place where the pipe or collection of
    pipes would be stored
  2. A method for knowing when a handle has been
    created
  3. A method for getting the handles in another
    process

Assuming we’re not talking about the scenario where Process A always creates Process B where CreateProcess handles the work, the easiest way to implement them would be with a C++/CLI dll. Here’s the steps to make an example implementation in Visual Studio 2013 with comments about what’s happening where in the code:

Create a CLR Class Library project named PipeMaker.

Add a new module definition file to it.

Fill it out with the following contents:

 LIBRARY PipeMaker

    EXPORTS

        AddHandles @1

Overwrite the contents of PipeMaker.h with the following:

 // PipeMaker.h - this is not production quality code

#pragma once

#include <windows.h>
#include <vcclr.h>

//Structure to hold handles
typedef struct _handleHolder
{
    int ProcessId;
    void* ReadHandle;
    void* WriteHandle;
}HandleHolder,*PHandleHolder;

using namespace System;
using namespace System::Collections::Concurrent;
using namespace System::Collections::Generic;
using namespace System::Diagnostics;
using namespace System::IO;
using namespace System::Runtime::InteropServices;

namespace PipeMaker {
    //Delegate for when handles arrive
    public delegate void HandlesArrived(int, IntPtr, IntPtr);
    //Delegate for when pipes arrive
    public delegate void PipesArrived(int pid, FileStream^ readStream, FileStream^ writeStream);

    //Static class that stores handles
    public ref class PipeStore
    {

    public:
        //Read/Write handle tuple stored as a per process id collection
        static ConcurrentDictionary<int, List<Tuple<IntPtr, IntPtr>^>^>^ HandlePairsByProcess;
        //Adds read/write handles for a process
        static void AddHandles(int pid, IntPtr read, IntPtr write)
        {
            if (HandlePairsByProcess == nullptr)
            {
                HandlePairsByProcess = gcnew ConcurrentDictionary<int, List<Tuple<IntPtr, IntPtr>^>^>();
            }
            Tuple<IntPtr, IntPtr>^ t = gcnew Tuple<IntPtr, IntPtr>(read, write);
            if (HandlePairsByProcess->ContainsKey(pid))
            {
                HandlePairsByProcess[pid]->Add(t);
                FireEvent(pid, read, write);
            }
            else
            {
                List<Tuple<IntPtr, IntPtr>^>^ l = gcnew List<Tuple<IntPtr, IntPtr>^>();
                l->Add(t);
                if (HandlePairsByProcess->TryAdd(pid, l))
                {
                    FireEvent(pid, read, write);
                }
                else if (HandlePairsByProcess->ContainsKey(pid))
                {
                    HandlePairsByProcess[pid]->Add(t);
                    FireEvent(pid, read, write);
                }
            }
        }
        //Handles arrived event
        static event HandlesArrived^ HandleHandler;
        //Pipes arrived event
        static event PipesArrived^ PipeHandler;
    private:
        //Fire the events
        static void FireEvent(int pid, IntPtr read, IntPtr write)
        {
            HandleHandler(pid, read, write);
            //Wrap the handles in FileStream objects
            System::IO::FileStream^ fsRead = gcnew FileStream(gcnew Microsoft::Win32::SafeHandles::SafeFileHandle(read, true),FileAccess::Read);
            System::IO::FileStream^ fsWrite = gcnew FileStream(gcnew Microsoft::Win32::SafeHandles::SafeFileHandle(write, true), FileAccess::Write);
            PipeHandler(pid, fsRead, fsWrite);

        }
    };
    //Creates anonymous pipes for cross process communication
    //Works if one process isn't the parent of the other too
 public ref class PipeMaker
 {
    public:
        //Target process id
        PipeMaker(int targetPid)
        {
            InitializeForProcess(targetPid);
        }
        //Target process
        PipeMaker(Process^ targetProcess)
        {
            if (targetProcess != nullptr) InitializeForProcess(targetProcess->Id);
        }
        //Destructor
        ~PipeMaker()
        {
            if (hProcess != IntPtr::Zero)
            {
                CloseHandle((HANDLE)(void*)hProcess);
            }
            if (hTarget != IntPtr::Zero)
            {
                CloseHandle((HANDLE)(void*)hTarget);
            }
        }
        //Returns null if successful
        Exception^ MakeNewPipes()
        {
            SIZE_T structSize;
            HandleHolder holder;
            HandleHolder localHolder;
            void* remAddress;
            SIZE_T bytesWritten;
            __int3264 localProc;
            HMODULE localModule;
            __int3264 remoteModule;
            __int3264 remoteAddress;
            HANDLE remoteThread;
            //Verify the remote module exists
            localHolder.ProcessId = GetProcessId((HANDLE)(void*)hTarget);
            remoteModule = 0;
            Process^ p = Process::GetProcessById(localHolder.ProcessId);
            for each(ProcessModule^ m in p->Modules)
            {
                if (m->ModuleName->EndsWith(L"PipeMaker.dll", StringComparison::OrdinalIgnoreCase))
                {
                    remoteModule = (__int3264)m->BaseAddress.ToPointer();
                    break;
                }
            }
            if (remoteModule == 0) return gcnew Exception("Could not locate remote module");

            //Create the pipe pairs
            if (!CreatePipe(&holder.ReadHandle, &holder.WriteHandle, NULL, NULL)) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
            if (!CreatePipe(&localHolder.ReadHandle, &localHolder.WriteHandle, NULL, NULL)) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));

            //Fill out the remaining local and remote structures
            holder.ProcessId = GetCurrentProcessId();
            structSize = sizeof(holder);
            void* tmpWrite = holder.WriteHandle;

            //The local read will be the remote write and vice versa
            if (!DuplicateHandle((HANDLE)hProcess, holder.ReadHandle, (HANDLE)(void*)hTarget, &holder.ReadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
            if (!DuplicateHandle((HANDLE)hProcess, localHolder.WriteHandle, (HANDLE)(void*)hTarget, &holder.WriteHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
            localHolder.WriteHandle = tmpWrite;

            //Allocate space remotely
            remAddress = VirtualAllocEx((HANDLE)(void*)hTarget, NULL, structSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            if (remAddress == NULL) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
           
            //Fill in remote structure
            if (!WriteProcessMemory((HANDLE)hTarget, remAddress, &holder, structSize, &bytesWritten)) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
           
            //Call remote method
            localModule = GetModuleHandle(L"PipeMaker.dll"); //hardcoding it to this name...
            localProc = (__int3264)GetProcAddress(localModule, "AddHandles");
            remoteAddress = localProc - (__int3264)localModule + remoteModule; //offset added to remote base
            //There are better ways to do this with more planning in an actual application as CreateRemoteThread is subject to caveats as mentioned in its documentation
            remoteThread = CreateRemoteThread((HANDLE)hTarget, NULL, NULL, (PTHREAD_START_ROUTINE)remoteAddress, remAddress, NULL, NULL);
            if (remoteThread == NULL) return Marshal::GetExceptionForHR(HRESULT_FROM_WIN32(GetLastError()));
            CloseHandle(remoteThread);
           
            //Add it to the local collection
            PipeStore::AddHandles(localHolder.ProcessId, (IntPtr)localHolder.ReadHandle, (IntPtr)localHolder.WriteHandle);
            return nullptr;
            //Note the leaks that occur with the way this is currently written as several things aren't closed when they are no longer in use in other parts of the program and in the situations where we return from this function with an exception without cleaning up what we've already made
        }
    private:
        IntPtr hProcess;
        IntPtr hTarget;
        //Opens the process tokens
        void InitializeForProcess(int targetPid)
        {
            hProcess = (IntPtr)OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId());
            hTarget = (IntPtr)OpenProcess(PROCESS_ALL_ACCESS, false, targetPid);
        }
 };
}

//Export the function that will actually do the remote work
EXTERN_C
{
    DWORD __declspec(dllexport) __stdcall AddHandles(PHandleHolder handles)
    {
        if (handles == NULL)
        {
            return ERROR_BAD_ARGUMENTS;
        }
        PipeMaker::PipeStore::AddHandles(handles->ProcessId, (IntPtr)handles->ReadHandle, (IntPtr)handles->WriteHandle);
    }
}

Create a C# Console Application.

Reference the PipeMaker project.

Replace the contents of Program.cs with the following:

 

using PipeMaker;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace AnonymousPipes
{
    class Program
    {
        static ManualResetEventSlim eventLock = new ManualResetEventSlim(false);
       
        static void Main(string[] args)
        {
            PipeStore.HandleHandler += HandlesArrived;
            PipeStore.PipeHandler += PipesArrived;
            if(args.Length == 0)
            {
                Process p = Process.Start(System.Reflection.Assembly.GetExecutingAssembly( ).Location, "taking up space");
                //Poll to wait until the needed module is loaded; there are much better ways to do this in code that isn't an example for another concept
                bool found = false;
                while(!found)
                {
                    p.Refresh( );
                    foreach(ProcessModule pm in p.Modules)
                    {
                        if(pm.ModuleName.EndsWith("PipeMaker.dll", StringComparison.OrdinalIgnoreCase))
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found) Thread.Sleep(50);
                }
                using (PipeMaker.PipeMaker pm = new PipeMaker.PipeMaker(p))
                {
                    Exception e = pm.MakeNewPipes( );
                    if(e == null)
                    {
                        eventLock.Wait( );
                        string s;
                        do
                        {
                            Console.WriteLine("Enter text to send:");
                            s = Console.ReadLine( );
                            byte[] buffer = Encoding.ASCII.GetBytes(s);
                            List<byte> allbytes = new List<byte>( );
                            allbytes.AddRange(BitConverter.GetBytes(buffer.Length));
                            allbytes.AddRange(buffer);
                            buffer = allbytes.ToArray( );
                            w.Write(buffer, 0, buffer.Length);
                            w.Flush( );
                        }
                        while (!string.IsNullOrEmpty(s));
                    }
                    else
                    {
                        Console.WriteLine("Unable to create pipes: {0}", e.ToString());
                    }
                }
            }
            Console.ReadLine( );
        }

        static FileStream r;
        static FileStream w;

        static void HandlesArrived(int pid, IntPtr read, IntPtr write)
        {

        }
        static void PipesArrived(int pid, FileStream read, FileStream write)
        {
            eventLock.Set( );
            Console.WriteLine("Received pipe connection for Process Id: {0}", pid);
            r = read;
            w = write;
            ThreadPool.QueueUserWorkItem(ContinueRead);
        }

        static void ContinueRead(object o)
        {

            try
            {
                while (true)
                {
                    byte[] sizeBuffer = new byte[4];
                    int read = r.Read(sizeBuffer, 0, 4);
                    if (read < 4) throw new Exception("Didn't read the size accurately");
                    read = BitConverter.ToInt32(sizeBuffer,0);
                    byte[] buffer2 = new byte[read];
                    read = 0;
                    while (read < buffer2.Length)
                    {
                        read += r.Read(buffer2, read, buffer2.Length - read);
                    }
                    Console.WriteLine("Message arrived: {0}", Encoding.ASCII.GetString(buffer2));
                }

            }
            catch(Exception ex)
            {
                Console.WriteLine("Unexpected error reading message: {0}", ex.ToString( ));
            }
        }

    }
}

Set the startup project to be your C# console application.

Debug and you should get something like this:

 

 

Download the example project here: http://1drv.ms/1ERuUMA.

Follow us on Twitter, http://www.twitter.com/WindowsSDK.

Forcing Printer Handle Thread Safety

$
0
0

When working with printer handles in an application obtained from functions such as OpenPrinter and CreateDC,
it is the caller’s responsibility to only access the object from one thread at a time.  This should always be followed
when developing new code. 

If you’re stuck with some code that doesn’t respect this and accesses the object on multiple threads concurrently as
a race condition, there is something that you can try that may help the issue.  There is a registry key that will cause
the spooler subsystem to forcibly restrict access to the object to one thread at a time.  This will have a performance
penalty, so it’s definitely not desirable unless absolutely needed.  In order to make this behavior change, set
the registry key as indicated below and restart the spooler service:

 

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print]
"SynchronousPrintHandleAccessMode"=dword:00000001

 

Follow us on Twitter, http://www.twitter.com/WindowsSDK.

Accessing a CNG private key from an X509Certificate2 class

$
0
0

Currently, The .NET Framework X509Certificate2 class does not support certificates associated with a CNG private key provider.  That is, the X509Certificate.PrivateKey property can only be associated with an RSACryptoServiceProvider, a wrapper around the CryptoAPI provider.

 

If you attempt to acquire the private key of a CNG provider, the result is the following exception:

System.Security.Cryptography.CryptographicException: Invalid provider type specified.

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()

 

If your application is directly accessing the X509Certificate2.PrivateKey property there is a workaround for this known problem. 

The CLR team wrote an extension to the Cryptography classes including an X509Certificate2 property that allows access to a CNG private key.  The extension can be downloaded from CodePlex at http://clrsecurity.codeplex.com/wikipage?title=Security.Cryptography.dll

Once referenced in the project, the X509Certificate2 will contain the GetCngPrivateKey method.

Below is a code sample that demonstrates how an application can use the GetCngPivateKey method.

using System;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Security.Cryptography;
using Security.Cryptography.X509Certificates;
using System.IO;

namespace SecurityTest
{
    class Program
    {
        static byte[] DecryptMessage(byte[] EncryptedData, CngKey BobsKey, byte[] pbAlicePublicKey)
        {
            int IVLength;
            byte[] Message = null;
            CngKey AlicesPublicKey = CngKey.Import(pbAlicePublicKey, CngKeyBlobFormat.EccPublicBlob);
            ECDiffieHellmanCng BobECDH = new ECDiffieHellmanCng(BobsKey);

            byte[] SymmetricKey = BobECDH.DeriveKeyMaterial(AlicesPublicKey);
            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Key = SymmetricKey;
            IVLength = Aes.BlockSize/8;
            byte[] IV = new byte[IVLength];
            for (int n = 0; n < IVLength; n++)
            {
                IV[n] = EncryptedData[n];
            }
            Aes.IV = IV;

            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, Aes.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(EncryptedData, IVLength, EncryptedData.Length - IVLength);
            cs.FlushFinalBlock();
            cs.Close();

            Message = ms.ToArray();

            return Message;
        }

        static byte[] EncryptedMessageForBob(byte[] pbBobsPublicKey, CngAlgorithm Algorithm, out byte[] pbAlicePublicKey)
        {
            byte[] EncryptedBlob = null;
            byte[] bpMessage = Encoding.Unicode.GetBytes("This is an encrypted message from Alice");
            CngKey AliceKey = CngKey.Create(Algorithm);
            CngKey BobsPublicKey = CngKey.Import(pbBobsPublicKey, CngKeyBlobFormat.EccPublicBlob);
            pbAlicePublicKey = AliceKey.Export(CngKeyBlobFormat.EccPublicBlob);

            ECDiffieHellmanCng AliceECDH = new ECDiffieHellmanCng(AliceKey);
            byte[] SymmetricKey = AliceECDH.DeriveKeyMaterial(BobsPublicKey);

            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Key = SymmetricKey;
            Aes.GenerateIV();
           
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, Aes.CreateEncryptor(), CryptoStreamMode.Write);

            ms.Write(Aes.IV, 0, Aes.IV.Length);
            cs.Write(bpMessage, 0, bpMessage.Length);
            cs.FlushFinalBlock();
            cs.Close();

            EncryptedBlob = ms.ToArray();

            return EncryptedBlob;
        }

        static void Main(string[] args)
        {            
            byte[] pbAlicesPublicKey = null;
            X509Store Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            Store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection Certs = Store.Certificates;
        
            Certs = Certs.Find(X509FindType.FindBySubjectName, "CNGCert", false);
            if (Certs.Count > 0)
            {
                X509Certificate2 Cert = Certs[0];
                if (Cert.HasCngKey())
                {
                    // We are Bob in this scenario
                    CngKey Bobkey = Cert.GetCngPrivateKey();

                    // Get an encrypted message from Alice                                                         
                    byte[] EncryptedData = EncryptedMessageForBob(Bobkey.Export(CngKeyBlobFormat.EccPublicBlob), Bobkey.Algorithm, out pbAlicesPublicKey);

                    // Decrypt the message
                    byte[] Message = DecryptMessage(EncryptedData, Bobkey, pbAlicesPublicKey);

                    Console.WriteLine("Message from Alice : {0}", Encoding.Unicode.GetString(Message));
                }
                else
                {
                    // It's a CryptoAPI key
                    RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)Cert.PrivateKey;                                   
                }
            }
        }
    }
}

Unfortunately, if you encounter the exception on in a product such as WCF, CRM or ADFS, the only option is to use a certificate with a CryptoAPI key since these products only know about the PrivateKey property.

Hopefully, a future version of .NET and products that use it will work with CNG keys. 

Follow us on Twitter, www.twitter.com/WindowsSDK.

 

Windows Hotfixes for November 2014

$
0
0

Jeff here from the SDK Team. Here is the list of November 2014 hotfixes, a week late.

2957486                Ls command takes a long time to list shared files in two windows on a Windows-based NFS server

3003689                Exit code improvements for Task Scheduler event log in Windows 8 and Windows Server 2012

2996928                Backup task fails with a time-out error in Windows Server 2012 or Windows Server 2008 R2

3005781                Error occurs when you print an A3 size document in Windows 8.1 or Windows 7

3007593                Stop error occurs when an SIS volume on a Windows Server 2008 R2-based server is accessed by Mac OS X clients

3007196                DSCP value is missing in the SYN-ACK packet during a TCP connection in Windows 7 SP1 or Windows Server 2008 R2 SP1

3001265                "Access Denied" error and all objects and child OUs under OU are deleted in GPMC in Windows 7 or Windows Server 2008 R2

3004070                VSS task schedule is not created as you configure if shadow copy storage is on another share disk in Windows Server 2012

3008193                "Server Failure" error when you query some domain on a Windows Server 2008 R2-based DNS server

3001264                "0x80073B92" error when you perform a Bare Metal Recovery on a Windows 7 or Windows Server 2008 R2-based UEFI computer 

2979127                You can't perform token-based activation in Windows 8.1

2998082                gMSA-based services can't log on after a password change in a Windows Server 2012 R2 domain

3004543                Windows 7 or Windows Server 2008 R2 cannot renew IP address from a Windows Server 2012 R2-based DHCP server

3008288                Handle leak occurs when you execute WMI queries in Windows Server 2008 SP2

2999802                Solid lines instead of dotted lines are printed in Windows 8.1

3001232                Print jobs fail in Windows 7 and Windows Server 2008 R2

2968741                Error 0x80070057 when SQL Server communicates to a web server using stored procedure in Windows 8 or Windows Server 2012

2912095                Lightweight Directory Services auditing Event ID 4662 is missing user information

3007006                Memory usage of the Msdtc.exe process increases on Windows 7 or Windows Server 2008 R2

3004182                Memory leak when transiting web pages that contain the Windows Media Player ActiveX control in Windows

3006207                Windows Journal crashes when you import a Word document that contains pictures in Windows 8 or Windows Server 2012

3001526                The input of Chinese (Traditional) Quick characters is very slow in Windows 7 and Windows Server 2008 R2

3001522                Error when you call an Excel application object on Windows 8 or Windows Server 2012

3002301                A memory leak in nonpaged pool memory occurs when a domain controller is running Windows Server 2008 R2

3002286                Delay in accessing a file server when a Windows 7-based computer connects to the file server

3002288                DFSR service freezes when it calls a method on a Windows-based server

3002297                The SMB Redirector may hang when the SMB protocol is used in Windows 7 SP1 or Windows 8.1

2884176                Large backlogs on Windows Server 2008 R2 SP1-based or Windows Server 2012 R2-based DFSR servers

3002858                "0x0000009F" Stop error when you put the computer in sleep mode or hibernation in Windows 8.1 or Windows Server 2012 R2

2996802                TRIM and UNMAP activities for thin provisioning on one volume block all activities on other volumes

3004383                Outlook clients are disconnected when the RPC Client Access service spikes to 100 percent CPU usage

3002859                Miracast display resolution changes after you shut down and then restart a Windows 8.1-based computer

3002650                Virtual machine live migration is unsuccessful on a server that is running Windows Server 2008 R2

2995478                Wmiprvse.exe memory leak when a program queries disk or partition storage information in Windows Server 2012

2990941                Update to support NVM Express by using native drivers in Windows 7 or Windows Server 2008 R2

2996205                ifAdminStatus variable of 0 in NIC Teaming interface in Windows Server 2012 or Windows Server 2012 R2

3004098                Memory leak occurs when you create or delete CSV snapshots by using a VSS hardware provider in Windows Server 2012

2998530                Disc is ejected unexpectedly when an application is writing to a CD or DVD drive in Windows 7 or Windows Server 2008 R2

2983628                File Server Resource Manager Quota filters are not decremented correctly in Windows Server 2008 SP2

3003385                "Access Violation" error when AzMan processes business rules in Windows 7 SP1 or Windows Server 2008 R2 SP1

3002869                Graphics adapter crashes or timing data is incorrect when you try to analyze the GPU performance of an application

2979933                Sharp increase in CPU usage occurs when a folder is renamed in Windows

3000123                iSCSI SAN server that's running Windows Server 2012 R2 restarts unexpectedly on a high-speed network

Follow us on Twitter, www.twitter.com/WindowsSDK.

/Jeff

 

Powering up Powershell for Remote Desktop Services

$
0
0

Powershell is a powerful tool that lets us perform many tasks and gather incredibly diverse sets of information.  When
Powershell remoting became available, this made it easy to do the same things on a remote system as on the local system. 
For many server and workstations configurations, there is little more which one could ask of a shell with out of the box
functionality.  Fortunately, Powershell is also easily extensible.

Due to the way some Windows APIs work, there are limitations to what information can be accessed from the normal
execution context of a Powershell host.  This is particularly true in the case of the server role formerly known as Terminal
Services, Remote Desktop Services.  If an administrator wants to get information about
what is going on in a user session
of a graphical nature or other such things
that are only visible in that session, they can’t simply just execute a cmdlet to get
it.  With Windows Server 2008, Session 0 Isolation was added to Windows which prevents most UI interactions with
user
sessions from services.  Each
session also gets its own window station and one or more desktops, further segregating UI
information. 

It is possible to get around this issue with a bit of programming and elbow grease and create a Powershell context in another
session which can be used to obtain
the information that the administrator wants. For the solution that I’m going to outline,
we’ll need the following
things:

  • Something to host a Runspace in the desired session
  • Something to redirect input/output from that Runspace to the Runspace we’re using in the Powershell host that we can see;
    this is a two-part requirement as that something needs to exist in both our Runspace and the Runspace in the other session
  • Something to actually put our Runspace host in the desired session

There is a program that has been used by administrators for years prior to the existence of Powershell called PSExec.  It
performs
the creation of new processes and redirects input/output.  It uses a Windows service to execute functions that
need SYSTEM privileges. 
We’ll want to do similar things, and newer Microsoft Technologies make that much easier on us to program. 

Windows Communication Foundation does all the heavy lifting for passing information between processes saving us the
trouble of needing to roll on our own IPC protocol with named pipes, sockets, etc.  Using a NetNamedPipeBinding
 lets us
avoid many of the common firewall issues that could be encountered with
using socket or web based communications. 
Turning PSObjects returned from  invoking commands in a Runspace is done with a single function call with one
parameter each way with the PSSerializer
 class.

Luckily, hosting a Runspace is pretty easy; there’s even an example in the documentation for the class. Code to do that
can fairly easily be made within a .NET executable.  If you look at the example mentioned above,
you’ll see that there are
some things that just wouldn’t
work for our needs.  We don’t need to actually display any output, we need to create a
Runspace that stays constant so that session
state can be maintained, execute commands as we send them from our
Powershell
host, and return the results.  Since we’re using Powershell, it would also be preferable to return the results as
objects
rather than just text; we can do that with the use of the PSSerializer class as mentioned above.

In order to launch a process in the right context with CreateProcessWithTokenW, we’ll need some code to execute as
SYSTEM. Since we’re presumably an administrator on the
server, otherwise none of this should work, we can install
and communicate a
service that runs as SYSTEM in order to meet this need. Running processes as SYSTEM gives them
the ability to do just about anything while erasing the
evidence of what they’re doing if they so choose, so this is
something that
generally should be avoided and when it has to be done, we’ll run as little code as needed in that context. 
We’ll
also want to be sure to create our process with only the security that it needs which we can do by actively restricting
the token or by finding a token that already exists in the
session and using it.

In order to interact with Powershell, we’ll want to make two cmdlets. One cmdlet will be used to creation a new Runspace
in a specified
session.  The other will be used to invoke commands on that Runspace and return the results.

Taking all of the above into consideration, a sensible course of action would be to create the following:

  • An executable that self-hosts a WCF service over a named pipe binding
    that receives commands to invoke on a Runspace and
    returns back the
    results as serialized PSObjects.
  • A service that hosts the executable in the SYSTEM context so it can be
    used to create instances of the executable in the
    desired session(s).
  • A cmdlet that checks for the installation and state of the service,
    remediates it if necessary, connects to it via WCF, asks
    it to return
    information about the executable running in the specified session,

    and then connects to the executable in the specified session via WCF.
  • A cmdlet that invokes arbitrary code in the specified session when
    given the text to run and the session with which to communicate.  It
    then communicates with the executable,
    receives the results of the
    code as serialized PSObjects, deserializes them,
    and writes them as
    PSObjects to the current pipeline.

Assuming we call #3 New-SessionRunspace and #4 Invoke-SessionRunspace,
we could import our module and run the following at an elevated Powershell
prompt to execute some code in session X:

$sr = New-SessionRunspace X

Invoke-SessionRunspace X “[System.Diagnostics.Process]::GetCurrentProcess().SessionId”

 

Here’s an example implementation of this: http://1drv.ms/1vN5BMi (Source and Binaries
included)

Follow us on Twitter, http://www.twitter.com/WindowsSDK.

 

 

The mysteries of WindowsPrincipal.IsInRole

$
0
0

WindowsPrincipal.IsInRole method is defined as the following in MSDN (http://msdn.microsoft.com/en-us/library/system.security.principal.windowsprincipal.isinrole(v=vs.110).aspx )

"Determines whether the current principal belongs to a specified Windows user group"

A WindowsPrincipal is basically a Windows Token wrapped in a .NET class.  Windows Tokens are generated when a Windows user (Local or Domain) is authenticated by Windows.  The IsInRole() method is similar to the Win32 API, CheckTokenMembership( http://msdn.microsoft.com/en-us/library/windows/desktop/aa376389(v=vs.85).aspx )  The API is used to determine whether the user is a member of the specified Windows Group (via it's Security Identifier, SID).  At the time the token is generated, Windows will create a flattened token.  This basically means that if the user is a member of a group which belongs to another group, you'll see both groups directly associated with the user's token.

The typical issue with IsInRole() is where you expect the user to be a member of the group and it returns FALSE indicating that the user is NOT a member of the group.  This means that the user is definitely not a member of the group.  To determine why this is happening you have to investigate what groups the user is a member of when their token is generated. 

  1. Do you have the correct user?  Maybe you are checking the wrong user.
  2. Is there a Domain Group Scoping Issue?  Maybe the user isn't a member of the Group
  3. Maybe the user isn't a member of the group.  Maybe the System Administrator removed the user or maybe the user was a member of the group through another group.

You are going to need to do some simple investigation to verify that in fact you have the right user and the right group.  There really is no magic going on here.

The Groups the user is a member of are stored in it's token.  They are not stored by the Group name but by their SIDs.  (I gave a hint on this from the CheckTokenMembership API).  This means that IsInRole() must convert the Group Name you are checking in IsInRole() to a SID.  It is quite possible that the SID conversion could fail. (See my previous post on this topic: http://blogs.msdn.com/b/winsdk/archive/2013/12/19/how-to-resolve-a-system-security-principal-identitynotmappedexception.aspx )

For performance reasons, if you use a SID instead, no conversion is necessary, IsInRole() can just compare SIDs.  This is going to be much faster. (http://msdn.microsoft.com/en-us/library/wak3kd03(v=vs.110).aspx )

This is all that you really need to know for IsInRole().

Follow us on Twitter, www.twitter.com/WindowsSDK

How to get notified when going in and out of connected standby from a Windows Service?

$
0
0

Always on Connected Standby (AOAC) was introduced in Windows 8.  Here is the definition from MSDN:

http://msdn.microsoft.com/en-us/library/windows/hardware/dn481238(v=vs.85).aspx

"Starting with Windows 8 and Windows 8.1, connected standby is a new low-power state that features extremely low power consumption while maintaining Internet connectivity. For a PC that implements the connected standby power model, the connected standby power state serves as the primary off mode for the PC—similar to the off mode that a smartphone enters when the user presses the power button. The Windows UI exposes the connected standby power state to the end user as the system "sleep" state."

When going into connected standby Windows Store Applications are suspended as well as Windows Desktop Applications (via the Desktop Activity Moderator through Job Objects).  Windows Services which are located in session 0 are not suspended but instead are throttled.  Windows Desktop Applications can be notified when going into connected standby by registering for a notification.  See the following for more information:

http://msdn.microsoft.com/en-us/library/windows/desktop/hh848040(v=vs.85).aspx

Unfortunately this doesn't apply to Windows Services which are located in session 0 and have no GUI (you can send a message box via WTSSendMessage) and thus have no display.

Connected Standby is synonymous with the display where on an AOAC capable system the display is turned off when going in to connected standby and turned on when leaving this state.

The solution for a service is to monitor on/off notifications for the display.  What you need to do from your service is the following:

  1. Determine if the system is AOAC capable by calling CallNtPowerInformation and looking at the AoAc value of the SYSTEM_POWER_CAPABILITIES struct).
  2. To get monitor on/off notifications you can call:

RegisterPowerSettingNotification
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa373196(v=vs.85).aspx)

And use the GUID_MONITOR_POWER_ON power setting GUID.

Follow us on Twitter, www.twitter.com/WindowsSDK

 


Fix released for Microsoft Fax API on Server 2012 R2 & Windows 8.1

$
0
0

Hi everyone,

 

Writing today to pas along some news on the Fax API on Windows 8.1.   Microsoft support has been receiving some reports lately of a hanging problem in the Fax Server in Windows 8.1 and Server 2012 R2.   Specifically, the reports have been sent when developers are calling the Fax API to send a fax with a Softmodem being on the machine.    For more background on the issue, it has been reported here earlier in the forums:

           http://answers.microsoft.com/en-us/windows/forum/windows8_1-hardware/fax-scan-hangs-sendingreceiving-a-fax-after/994b6579-05f4-4ccf- 9ea6-56b57d7e8c18 

           https://social.technet.microsoft.com/Forums/windows/en-US/7a99e851-cf06-447c-bbd9-785a4c0f79e7/fxst30dll-problem?forum=w8itproappcompat

 

 

The good news is a fix is now available via the latest roll-up released here for Windows 8.1 and Server 2012 R2:

          http://support.microsoft.com/kb/3000850

 

 

After installation of the roll-up, the version of FXST30.dll should be 6.3.9600.17415 which has the updated fix in it now.     Thank you to the community and KeyCentrix for raising this issue to Microsoft.  

 

 

Thanks,

Nathan

 

 

 Follow us on Twitter, www.twitter.com/WindowsSDK

Hotfix List For December 2014 [Not 2015]

$
0
0

Jeff here from the SDK team. Here is a list of this month’s hotfixes, the Yuletide edition.

3016375 You
get a restricted IP address after the wireless interface is re-enabled in Windows 7 or Windows Server 2008 R2

3016350 Windows Photo Viewer cannot print single pages or custom page ranges on Windows 7 SP1 or Windows Server 2008 R2 SP1

3015999 Stop Error 0x27 occurs when you try to move a folder on a network share from one place to another on Windows 7 SP1 or Windows Server 2008 R2 SP1

3014795 A third-party switch extension to the Microsoft VM switch cannot be disabled on Windows Server 2012 R2

3014793 Stop error 0xC2, 0x50, or 0xCC after you restart a computer that's running Windows 7 or Windows Server 2008 R2

3014591 File duration is incorrect in a file that is created by Media Foundation MPEG-4 file sink in Windows

3014300 CredUIPromptForWindowsCredentials API does not select the smart card logon certificate from the pvInAuthBuffer parameter

3013488 Long wait to reset WSUS server when you import CSA files in Windows Server 2012 R2 or Windows Server 2012

3013486 Windows Server 2012 R2-based cluster freezes after you enable data deduplication

3013125 "Unable to connect to the computer" error when you try to manage iSCSI virtual disks in Windows Server 2012

3013108 RDS License Manager shows no issued free or temporary client access licenses in Windows Server 2012 R2

3013102 "Command not found" error when you run a command in the C shell for SUA in Windows 7 or Windows Server 2008 R2

3012982 Update to enable Schannel crypto APIs to be called from a DPC-level driver in Windows 8.1 and Windows Server 2012 R2

3012714 "0x80070016 ERROR_BAD_COMMAND" error when Hyper-V replication stops in Windows Server 2012

3012696 An IPP printer stops responding after you cancel a print job from PowerPoint in Windows 7 or Windows Server 2008 R2

3012325 Windows APN database entries update for DIGI, Vodafone, and Telekom mobile operators in Windows 8.1 and Windows 8

3009736 MP4 file cannot be played on a non-Windows-based device if it was created in Windows 7 or Windows Server 2008 R2

3009621 VMware virtual machines freeze when they shut down or restart in Windows 7 or Windows Server 2008 R2

3009350 Excel freezes when you import an .xml file in Windows 7 or Windows Server 2008 R2

3009197 "0x0000009F" Stop errors when you restart the computer in Windows 7

3009016 Network adapter is displayed on the taskbar and in the VAN UI in Windows 8.1

3008558 Servers restart unexpectedly when the Lsass.exe process crashes in Windows Server 2008 R2 or Windows 7

3007054 PIN-protected printing option always shows when you print a document within a Windows Store application in Windows

3006139 Chinese IME toggle hotkey cannot be disabled in Windows 7 or Windows Server 2008 R2

3006114 Update to support vertical forms of punctuation for SimSun font in Windows 8 or Windows Server 2012

3006112 Surrogate pair characters in fallback font are displayed as squares in Windows 7 or Windows Server 2008 R2

3003385 "Access Violation" error when AzMan processes business rules in Windows

3001267 You cannot connect to a network printer by using the CNAME for the print server in a Windows Server 2012 R2 DNS environment

3000461 A wireless, high-quality print job to a WSD port is automatically canceled on a Windows 8.1 computer

2999802 Solid lines instead of dotted lines are printed in Windows

2993229 Copy-on-write method for a snapshot CSV volume doesn't occur for a two-node cluster in Windows Server 2012 R2

2978137 Update lets OEMs prevent specific non-video AVStream devices from being used on Windows 8.1 devices

2974005 Stop error 0x0000007E in Windows 7 or Windows Server 2008 R2

2965917 A computer freezes during startup after filter drivers are installed in Windows 7 or Windows Server 2008 R2

2961042 Printer server goes offline when you wake up the computer at another network location in Windows

2957701 The FSRM UI stops responding when there are many storage reports to monitor on a server that is running Windows Server 2012 R2

2957699 Confusing message from Work Folders in Action Center when you change or disconnect the network in Windows 8.1

2914743 You receive Stop error 0xD1 in Windows Server 2012 R2 or Windows 8

2896881 Long logon time when you use the AddPrinterConnection VBScript command to map printers for users during logon process in Windows

2535094 Server stops responding when you lock or unlock files on a network by using the SMB2 protocol in Windows

2500511 Windows crashes when you try to run the "sysprep /generalize" command after you run the "mountvol /n" command in Windows 7 or in Windows Server 2008 R2

Until next year,

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

DNSQuery() Sample To Loop Through Multiple IP Addresses

$
0
0

Jeff from the Windows SDK team here.

I had a customer that wanted to just find the IP address that is registered in DNS, i.e., they wanted to get back the single public IP
address and not any of the other multihomed IP addresses.

Most APIs use the DNS Resolver Cache and return all of the all of the local addresses when you query the local machine name.

DNSQuery() has dozens of flags including DNS_QUERY_WIRE_ONLY, DNS_QUERY_BYPASS_CACHE,
DNS_QUERY_NO_HOSTS_FILE that looked promising. Now I just needed a way to test
it; I couldn’t find a sample that actually looped through the results. There is an old KB article with
sample code that calls DNSQuery() but it doesn’t account for multiple returned addresses.

So I thought I would write a blog with a sample of DNSQuery(); this is that blog.

#pragma comment(lib,"Iphlpapi.lib")
#pragma comment(lib,"dnsapi.lib")
#pragma comment(lib,"ws2_32.lib") 

#include "windows.h"
#include "stdio.h"
#include "windns.h" 

int wmain(int argc, WCHAR** argv)
{
       DNS_STATUS dnsStatus;
       IN_ADDR ipaddr;
       PDNS_RECORD ppQueryResultsSet, p;
       PIP4_ARRAY pSrvList = NULL;
       char temp[MAX_PATH];
       int iRecord = 0; 

       if (argc == 1 || argc > 3)
       {
              wprintf(L"Usage: %s hostname [IP addr of DNS server] \n\n", argv[0]);
              return -2;
       } 

       wprintf(L"Querying for host: %s\n", argv[1]); 

       if (argc == 3) // Get the IP address of the DNS server to query
       {
              pSrvList = (PIP4_ARRAY)LocalAlloc(LPTR, sizeof(IP4_ARRAY));
              if (!pSrvList)
              {
                     wprintf(L"PIP4_ARRAY allocation failed \n");
                     return -3;
              }                    

              sprintf_s(temp,MAX_PATH,"%S", argv[2]);  // Convert to ASCII
              pSrvList->AddrArray[0] = inet_addr(temp); //DNS (ASCII) to  IP address
              pSrvList->AddrCount = 1; 

              wprintf(L"Querying DNS Server: %s\n", argv[2]);
       }     

        dnsStatus = DnsQuery(argv[1], 
                           DNS_TYPE_A,
                           DNS_QUERY_WIRE_ONLY  
                          pSrvList, // Documented as reserved, but can take a PIP4_ARRAY for the DNS server
                           &ppQueryResultsSet,
                           NULL ); // Reserved

       if (dnsStatus)
       {

              wprintf(L"\nDNSQuery failed and returned %d, GLE = %d\n\n", dnsStatus, GetLastError()); 
              return -1;
       } 

       p = ppQueryResultsSet; 

       while (p) // Loop through the returned addresses
       {            

             iRecord++;
              wprintf(L"\nRecord #%d\n", iRecord);

               ipaddr.S_un.S_addr = (p->Data.A.IpAddress);
              wprintf(L"The IP address of %s is %S \n", p->pName, inet_ntoa(ipaddr));
              wprintf(L"TTL: %d (secs)\n",p->dwTtl);        

               p = p->pNext;       
       }

       if (pSrvList) LocalFree(pSrvList);

        DnsRecordListFree(ppQueryResultsSet, DnsFreeRecordList);

}

It turns out the flag that I needed was DNS_QUERY_WIRE_ONLY, this sent the query on the wire and bypassed the local cache.

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

 

 

Example impact of Microsoft Accounts on Windows APIs in Windows 8/8.1

$
0
0

Windows 8 introduced the ability for a user to logon to their desktop with their Microsoft Account.  This is an email address and password that you can use to sign on to any Microsoft site and services such as Outlook.com, OneDrive and Office 365.  More information on this is in the following BLOG post:

http://blogs.msdn.com/b/b8/archive/2011/09/26/signing-in-to-windows-8-with-a-windows-live-id.aspx

When you logon with your Microsoft Account, you'll noticed that you are actually logged on with a local account created by Windows.  If you dump the token of the Microsoft Account.  You'll notice the following new Security Identifiers (SIDs):

  • S-1-11-96-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ
  • S-1-5-64-32

A SID is made up of a revision level, an authority and a bunch of relative identifiers (RIDs) or subauthority values.  The standard notation for a SID is the following:

S-R-I-S

You can also reference SID components at the following link:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa379597(v=vs.85).aspx

Typically the values are defined in Winnt.h

Going back to the SIDs in the token, we can break them down and identify them.

The first SID (S-1-11-96-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ-ZZZ) represents your Microsoft Account.  This is a user SID (the type of SID).  If you convert the SID to a readable name.  It will convert to:

MicrosoftAccount\yourid@domain.com

The Authority ID, 11 isn't defined in Winnt.h and neither is the first rid which is 96 but we have a good idea what represents the SID.

The second SID (S-1-5-64-32) is a group SID and represents the following Group:

NT AUTHORITY\Microsoft Account Authentication

The authority ID (5) is fairly common in Windows:

#define SECURITY_NT_AUTHORITY           {0,0,0,0,0,5}

The first RID is 64 which is:

#define SECURITY_PACKAGE_BASE_RID       (0x00000040L)

The 2nd RID is 32 which is:

#define SECURITY_BUILTIN_DOMAIN_RID     (0x00000020L)

I will have future posts on Microsoft Accounts as I encounter more interesting things with applications running as the Microsoft Account user.

Now, let me discuss the impact of Microsoft Accounts on a specific Microsoft Technology.  In this case, it was with a Network Provider DLL.  Basically, you can create a DLL in Windows that enables it to interact with other kinds of network.  Take a look a the following link for more info:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa378776(v=vs.85).aspx

For example, you can create a Network Provider DLL which will be invoked when a user logs on.  During this time, you can deal with this event like synchronizing the user's password.  Well, in the case of a Network Provider DLL, it will not be invoked during a logon because the logon isn't a Domain Logon.  Windows internally checks to see if the logon was a Kerberos Interactive Logon.

This is just an example of how new functionality introduced in Windows can impact existing APIs and technologies.  In this case, if you have written a Network Provider DLL and a Microsoft Account user logs on, your DLL will not be invoked.

 

Follow us on Twitter, www.twitter.com/WindowsSDK

 

 

 

Using multiple monitors programmatically from an RDP Active X control.

$
0
0

In Windows VISTA, Span mode was introduced.  This allowed a Remote Desktop session to span across all monitors on the client as long as the monitors were arranged to form a rectangle.  In Windows 7, this functionality was improved so it didn't have to form a rectangle. Here are some examples where you could span and couldn't span. For a detailed explanation, see the following:

http://blogs.msdn.com/b/rds/archive/2009/07/01/using-multiple-monitors-in-remote-desktop-session.aspx

Using multiple monitors (or spanning) from mstsc.exe is fairly straight forward.  You can do this from the command line or directly in mstsc.exe or from a custom .RDP file.
Programatically, you access a remote desktop server via the Remote Desktop Active X control. The control can be hosted on a Web Site or in an application.  In an application, you can use the following code snippet:


axMsRdpCLient8NotSafeForScripting.Server = "XX.XX.XX.XX";
axMsRdpCLient8NotSafeForScripting.UserName = @"Computer\administrator";
axMsRdpCLient8NotSafeForScripting.AdvancedSettings6.ClearTextPassword = @"Password";
axMsRdpCLient8NotSafeForScripting.AdvancedSettings9.EnableCredSspSupport = true;
axMsRdpCLient8NotSafeForScripting.FullScreenTitle = "test";
axMsRdpCLient8NotSafeForScripting.FullScreen = true;
axMsRdpCLient8NotSafeForScripting.AdvancedSettings.ContainerHandledFullScreen = 1;

IMsRdpClientNonScriptable5 test = (IMsRdpClientNonScriptable5)axMsRdpCLient8NotSafeForScripting.GetOcx();

test.UseMultimon = true;
            
axMsRdpCLient8NotSafeForScripting.Connect();

 

Here is the MSDN link for the UseMultiMon property:

http://msdn.microsoft.com/en-us/library/ff817569(v=vs.85).aspx

One thing your'll notice is that the property is only exposed in the following interface, IMsRdpClientNonScriptable5 which is why you see the GetOcx() call.

http://msdn.microsoft.com/en-us/library/ee620998(v=vs.85).aspx

You'll also notice that the latest interface is IMsRdpClientNonScriptable8.  (The interface is updated when the RDP protocol is updated which happens with each release of Windows)

Finally, you'll notice that this property is only available for the non scriptable interface.  You can't take advantage of this from a web page.

 

Follow us on Twitter, www.twitter.com/WindowsSDK

WLAN Programming How-To Tips and Tricks Including Using It in C#

$
0
0

 Questions concerning the wireless local area network APIs have been coming up a lot recently often in the context of using them from C#.  You'll find an example C# WinForms application that allows you to see the almost all of the wireless network APIs in action at the end of this post.  The WLAN APIs facilitate the enumeration, configuration, and management of WiFi on Windows Operating Systems.  Here are just a fraction of things that the WLAN APIs allow a developer to do programmatically:

  • Connect to a wireless network
  • Disconnect from a wireless network
  • Modify the behavior of the automatic wireless configuration module
  • Start or stop a locally hosted wireless network
  • Connect to or disconnect from a WiFi Direct device
  • Query the properties of any of the above
  • Read, Modify, and Create profiles that control the settings for a wireless network
  • Create temporary profiles that can be used without making them available for display to the end user

The WLAN APIs follow the same general pattern of proper use for regular WiFi, WiFi Direct, and hosted wireless networks shown here:

  1. A handle/session is opened using WlanOpenHandle.
  2. Operations are performed as desired for the specific technology or technologies.
  3. The opened handle/session is closed using WlanCloseHandle.

The rest of this post is going to focus on the APIs for wireless networks.  If you're interested in hearing more about the other technologies, please let me know in the comments section at the bottom of the page.  Wireless networks are interacted with using a specific interface which typically ultimately represents a piece of hardware such as a wireless networking card.  A collection of wireless network interfaces is obtained through the use of the WlanEnumInterfaces function.  Most subsequent operations, such as managing profiles, connect or disconnecting from networks, etc. are performed against one of the specific interfaces.  The one real exception is change monitoring.  Change monitoring takes places for everything at the session/handle level.  All of this functionality lends itself to wrap pretty easily into managed objects.  You'll find the specific implementation details of what is below in the example code, but here's a basic summary of how things would roughly shape out as objects taken from the implementation of the example code:

  • WlanNative - Class that encapsulates the session/handle, provides access to a collection of WlanNativeInterface objects, controls whether or not to be listening for changes, and provides an event that can be subscribed to in order to receive change notifications
  • WlanNativeInterface - Class that encapsulates a specific wireless interface

    Methods: Scan for available wireless networks, connect to a wireless network using an existing or temporary profile, disconnect from a wireless network, retrieve a profile, change a profile, change EAP or customer user data outside of a direct profile change, how the system profile edit dialog for a profile (there are a few other things that could be retrieved here as well)

    Properties: Collection of wireless profiles as WlanNativeProfile objects, Collection of available wireless networks as WlanNativeNetwork objects, Interface Guid, Description, Autoconfiguration setting, background scan enabled, collection of physical radio state objects (not shown in this summary), collection of basic service sets objects (not shown in this summary), Interface state, currently used profile, current authentication algorithm, current cipher algorithm, Collection of supported authentication algorithms associated with their supported cipher algorithms as objects (not shown in this summary - one for infrastructureor adhoc), channel number, OneX enabled or disabled, Security enabled or disabled, Media streaming mode enabled or disabled, operation mode, safe mode support, certified for safe mode, and received signal strength (there are a few other things that could be retrieved here as well)
  • WlanNativeProfile - Class that encapsulates a specific wireless profile

    Methods: All of the editing/deleting methods available for WlanNativeInterface that apply to the profile

    Properties: Profile Name, UserProfile, GroupPolicyProfile
  • WlanNativeNetwork - Class that represents a specific wireless network

    Properties:  Connectable, Collection of Basic Service Set IDs, Name, SSID, BSS Type, Why it's not connectable if it's not, Signal strength, default authentication algorithm, default cipher algorithm, Collection of physical types, Security enabled

Here are a few concepts worth remembering that I've seen come up multiple times:

  • Be sure to set profiles, EAP data, etc. with the all users flag set if you want the change to show up for other users.  If you're not running in the same context as the user, e.g. a different session or user with code executing as a service, you need to do this in order for the changes to be used by the user.
  • EAP and custom user data can be set in a profile directly.  This is often more efficient than keeping up with them separately.
  • Scanning for networks returns immediately and isn't additive most of the time; wait for the change event to indicate scanning is finished if you need all the networks
  • Verify that profile settings are compatible with the interface by looking at the authorization types and their associated cipher algorithms by querying the interface
  • Functions that take a parameter for the contents of a temporary profile want a string containing XML not a filename whose contents contains XML
  • Use WlanFreeMemory properly to prevent memory leaks
  • Use WlanUIEditProfile to let an end user edit a profile with the standard Windows dialog


Here are a couple screenshots of the example program:

 

Hotfix List for January 2015 [Short]


RDP and CredMan

$
0
0

One common question asked by our customer is how to programmatically store credentials for connecting to both a Remote Desktop Gateway and Remote Desktop Servers?

End Users will notice that the credentials to access these servers are available in the Credential Manager Application via the Control Panel.

Programmatically, an application can write credentials to the Credential Manager via the Credential Manager (CredMan) APIs.

The way the Credential Manager works is that credentials are associated with a "Target Name".

The information you would need to store is the following for a remote desktop gateway server where GATEWAYSERVER is the name of the Remote Desktop Gateway Server. RDSERVER is the name of the Remote Desktop Server.

//
// RD Gateway Server: SERVER
// USER:              DOMAIN\USER
// PASSWORD:          PASSWORD
//

Here is some example code:

PCREDENTIAL_TARGET_INFORMATION pcti;

CredGetTargetInfo(L"GATEWAYSERVER", 0, &pcti))

CREDENTIAL                    cred;
TCHAR                        *password     = _T("GATEWAYPASSWORD");

ZeroMemory( &cred, sizeof(CREDENTIAL) );
cred.Persist            = CRED_PERSIST_LOCAL_MACHINE;
cred.Flags              = 0;
cred.Type               = CRED_TYPE_DOMAIN_PASSWORD;
cred.TargetName         = _T("GATEWAYSERVER");
cred.UserName           = _T("DOMAIN\\administrator");
cred.CredentialBlob     = (BYTE *) password;
cred.CredentialBlobSize = ( lstrlen( password ) + 1 ) * sizeof(TCHAR);

CredWriteDomainCredentials(pcti, &cred, 0);
CredFree((PVOID)pcti);

//
// RD Server
//

ZeroMemory( &cred, sizeof(CREDENTIAL) );
cred.Persist            = CRED_PERSIST_LOCAL_MACHINE;
cred.Flags              = 0;
cred.Type               = CRED_TYPE_DOMAIN_PASSWORD;
cred.TargetName         = _T("TERMSRV/RDSERVER");
cred.UserName           = _T("DOMAIN\\administrator");
cred.CredentialBlob     = (BYTE *) password;
cred.CredentialBlobSize = ( lstrlen( password ) + 1 ) * sizeof(TCHAR);

CredWrite(&cred, 0);

For references to CredWrite on MSDN, see the following:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v=vs.85).aspx

and for CredWriteDomainCredentials:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa375189(v=vs.85).aspx

Let me know if you have any questions and follow us on Twitter, www.twitter.com/WindowsSDK

C# and Fastcall - How to make them work together without C++/CLI (Shellcode!)

$
0
0

I recently ran into a situation where code had to meet the following requirements:

  1. C# language only
  2. No dependence on VC++ runtimes
  3. Support COM Interop with no ole32
  4. Support delegates for Fastcall calling convention callback functions

 

The first three were no big deal in and of themselves.  The fourth, however, introduced a big problem.  The CLR natively supports several different types of calling conventions for functions and delegates for native interop.  It defaults to stdcall which is what the Windows API typically uses.  If I needed to make a delegate use cdecl instead, I could simply place a tag above the delegate like this:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]   

public delegate void ExampleDelegate(); 

The CallingConvention enumeration has five members: Winapi, Cdecl, StdCall, ThisCall, and FastCall.  I'm not going to go over the differences between them since odds are if you're writing code in C# you don't care other than knowing which one you should be using.  If you enter the FastCall value in Visual Studio, you'll probably notice the comment that goes along with it: "This calling convention is not supported."  For the other four, you could simply use Marshal.GetFunctionPointerForDelegate and do interop with no issues.  But this won't work for Fastcall.  If you try to use it anyway, it will compile, it will run, and it will probably cause bad results.  What typically happens is that your delegate is called but none of the parameters are what you expect them to be; if you used IntPtr instead of referenced Structure types, that won't cause a crash in and of itself.  However, since the function calling your delegate expects the stack to be in a certain state, it is highly likely to create a access violation which will result in the .NET exception "Attempted to read or write protected memory." 

Normally, the easy way around this is to use C++/CLI, create a native function to use a delegate, and use it to call a managed function in a convention that the Common Runtime Language can understand.  Here's a simple example of doing that for the ExampleDelegate shown above:

 

#include"stdafx.h"

usingnamespace System;

#pragmaunmanaged

typedefvoid(__stdcall *PExampleDelegateManaged)();

PExampleDelegateManaged managedDelegate;

void __fastcall ExampleDelegateNativeFunction()

{

managedDelegate();

}

#pragmamanaged

[System::Runtime::InteropServices::UnmanagedFunctionPointerAttribute(System::Runtime::InteropServices::CallingConvention::StdCall)]

delegate void ExampleDelegateManaged();

voidExampleDelegateManagedFunction()

Console::WriteLine("Yay this works just fine");

}

intmain(array<System::String ^> ^args)

//You'd want the delegate below to be a member of a class or otherwise pinned to something so that the GC wouldn't clean it up when it could still be called

//and obviously this probably wouldn't be in your main function:-)

ExampleDelegateManaged^ managedDelegatePinnedHereToAvoidGarbageCollection = gcnewExampleDelegateManaged(ExampleDelegateManagedFunction);

IntPtr funcPointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(managedDelegatePinnedHereToAvoidGarbageCollection);

managedDelegate = (PExampleDelegateManaged)(void*)funcPointer;

//other code here 

return 0;

}

While that's not overly complicated to do, it wouldn't work with the requirements that had to be met, so another way to do it needed to be developed.  The solution that I came up with was to use "shellcode" which is the term I'm going to use since it's the best way that I know of to describe native code that executes at an arbitrary point in memory without needing any modules or linked libraries to execute successfully.  Normally writing shellcode isn't something that a programmer has to do very often unless they're doing "security research", but it can occasionally be useful in legitimate programming as well.  Since we're going to be using such code on purpose in our process, not having to worry about removing null bytes makes it not too difficult to do.  So here's what needs to be done in visual studio to make this happen in C without writing assembly(though the same thing can be done with other compilers and operating systems too!):

  1. Create a New Project with the VC++ language.
  2. Choose Win32 Console Application, name it, hit ok, and click Finish.
  3. Right-click the project and go to its properties page.
  4. In the C/C++ -> Optimization section, set Optimization to Disabled.
  5. In the C/C++ -> Code Generation section, set Runtime Library to Multi-Threaded DLL and set  Security Check to Disabled.
  6. In the C/C++ -> Output Files section, set Assembler Output to Assembly, Machine Code, and Source.

Now that that is done, we have a framework to make the code we need.  In my case, one of the callbacks that I had to wrap took four arguments: a pointer, an integer, a pointer, and a pointer.  In order to make code to wrap it, I simply coded the following in the file that the Visual Studio created for me with a main method already in it:

#include"stdafx.h"

extern "C" {

#pragma runtime_checks( "", off ) //Security and cookie checks create dependencies that we can't have in order to make this code truly independent

typedef void(__stdcall *PStdCallPrototype)(void* Argument1, int Argument2, void* Argument3, void* Argument4);

//You don't want it to be inlined if you call it in main, so tell the compiler not to inline it

__declspec(noinline) void__fastcall FastCallPrototypeCalledFixedAddress(void* Argument1, intArgument2, void* Argument3, void* Argument4)

//We'll use fixed addresses for where this gets called as it will make it easier to replace with a real address later in C#

PStdCallPrototype protoFunction;

#ifdef_WIN64
protoFunction= (PStdCallPrototype)0xF0F0F0F0F0F0F0F0;

#else

protoFunction = (PStdCallPrototype)0xF0F0F0F0;

#endif

protoFunction(Argument1, Argument2, Argument3, Argument4);

}

#pragma runtime_checks( "", restore )

}

int_tmain(intargc, _TCHAR* argv[])

//Use four very easy to identify parameters

void* Argument1 = (void*)1;

int Argument2 = 2;

void* Argument3 = (void*)3;

void* Argument4 = (void*)4; 

//Call the wrapper so you can step through it if you want to see it in action

FastCallPrototypeCalledFixedAddress(Argument1, Argument2, Argument3, Argument4); 

return 0;

}

Once you build that, it'll create a file that has the raw machine bytes in it.  I needed my code to work in both x86 and x64 scenarios since my C# code compiled to Any CPU, so I had to make a second file for x64.  To do that, go to Build->Configuration Manager, click on the Platform dropdown for the project, select New, then choose x64 (you can leave the create solutions platform checkbox checked or uncheck it - it doesn't matter for this small use case) and click ok.  Close the configuration manager, go back to the project properties, and repeat the above configuration options if necessary.  Then build the project again.  Now there are both x86 and x64 raw machine bytes available.  Now that we have raw machine code, we need a way to execute it.  I put the following simple class together that does the following:

  1. Takes a delegate, the raw machine bytes, and the original address using in the raw machine bytes (0xF0F0F0F0 / 0xF0F0F0F0F0F0F0F0 in the above)
  2. Uses VirtualAlloc to create PAGE_EXECUTE_READWRITE memory in the process.  That allows it to copy code to that area and then execute it.
  3. Pins the supplied delegate and creates an IntPtr to that pinned delegate using Marshal.GetFunctionPointerForDelegate
  4. Replaces the original address with the address represented by the IntPtr
  5. Exposes an IntPtr property pointing to the wrapped delegate that can be supplied as the delegate procedure for a fastcall callback

It looks like this: 

class UnmanagedCodeSupplier : IDisposable

{

private Delegate delegateInstance;

private IntPtr delegatePointer;

private IntPtr newFunctionAddress;

public IntPtr WrappedDelegateFunction { get { return newFunctionAddress; } }

public UnmanagedCodeSupplier(Delegate actualDelegate, byte[] codeBytes, UIntPtr addressToReplace)

{

newFunctionAddress = VirtualAlloc(IntPtr.Zero, newIntPtr(codeBytes.Length), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

if (newFunctionAddress == IntPtr.Zero)

{

Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

}

List<byte> newcode = newList<byte>();

List<byte> currentcodequeued = newList<byte>();

delegateInstance = actualDelegate;

delegatePointer = Marshal.GetFunctionPointerForDelegate(delegateInstance);       

//Get the original address to replace as bytes

byte[] cBytes = IntPtr.Size == sizeof(int) ? BitConverter.GetBytes(addressToReplace.ToUInt32()) : BitConverter.GetBytes(addressToReplace.ToUInt64()); //Account for the size difference

//Get the new bytes to use

byte[] nBytes = IntPtr.Size == sizeof(int) ? BitConverter.GetBytes(delegatePointer.ToInt32()) : BitConverter.GetBytes(delegatePointer.ToInt64()); //Account for the size difference

int currentMatchNumber = 0; bool matched = false;

//Loop through the code, find the matching address, replace it with the address from the delegate

for (int i = 0; i < codeBytes.Length; i++)

{

if (matched) {

newcode.Add(codeBytes[i]);

}

elseif (codeBytes[i] == cBytes[currentMatchNumber]) {

currentMatchNumber++;

if (currentMatchNumber == cBytes.Length) {//Add the real address instead of the fake

newcode.AddRange(nBytes);

currentcodequeued.Clear();

matched = true;

}              

else {

currentcodequeued.Add(codeBytes[i]);

}

else {

if (currentcodequeued.Count > 0) {

newcode.AddRange(currentcodequeued);

currentcodequeued.Clear();

}

newcode.Add(codeBytes[i]);

}

}

if (!matched)

{

Dispose();

//cleanup - this happens to be implemented in such a way that just calling dispose can be used

throw new ArgumentException("Invalid addressToReplace specified for the specified codeBytes");

}

//Now just copy that executable code over to where it should be

Marshal.Copy(newcode.ToArray(), 0, newFunctionAddress, codeBytes.Length);

}

#region Native Interop

const uint MEM_COMMIT = 0x1000;

const uint MEM_RESERVE = 0x2000;

const uint MEM_RELEASE = 0x8000;

const uint PAGE_EXECUTE_READWRITE = 0x40;

[DllImport("kernel32", SetLastError = true)]

static extern IntPtr VirtualAlloc(IntPtr startAddress, IntPtr size, uint allocationType, uint protectionType);

[DllImport("kernel32", SetLastError = true)]

static extern IntPtr VirtualFree(IntPtr address, IntPtr size, uint freeType);

#endregion

~UnmanagedCodeSupplier()

 {

Dispose(false);

}

public void Dispose()

{

Dispose(true);

GC.SuppressFinalize(this);

}

private void Dispose(bool calledDispose)

 {

if (calledDispose)

{

//Do managed cleanup

delegateInstance =null;

}

//Do native cleanup

if (newFunctionAddress != IntPtr.Zero)

{

VirtualFree(newFunctionAddress, IntPtr.Zero, MEM_RELEASE);

newFunctionAddress = IntPtr.Zero;

}

}

}

I then opened up my raw machine code files and put them in my code as static byte arrays like this:

 

static byte[] x86CodeForFastcallWrapperForExecutionDelegate = new byte[] {
    0x55,   //push  ebp
    0x8b, 0xec,  // mov  ebp, esp
    0x83, 0xec, 0x4c, // sub  esp, 76   ; 0000004cH
    0x53,   //push  ebx
    0x56,   //push  esi
    0x57,   //push  edi
    0x89, 0x55, 0xf8,  //mov  DWORD PTR _Argument2$[ebp], edx
    0x89, 0x4d, 0xfc,  //mov  DWORD PTR _Argument1$[ebp], ecx
    0xc7, 0x45, 0xf4, 0xf0, 0xf0, 0xf0, 0xf0,   //mov  DWORD PTR _protoFunction$[ebp], -252645136 ; f0f0f0f0H
    0x8b, 0x45, 0x0c,  //mov  eax, DWORD PTR _Argument4$[ebp]
    0x50,  // push  eax
    0x8b, 0x4d, 0x08, // mov  ecx, DWORD PTR _Argument3$[ebp]
    0x51,  // push  ecx
    0x8b, 0x55, 0xf8, // mov  edx, DWORD PTR _Argument2$[ebp]
    0x52,  // push  edx
    0x8b, 0x45, 0xfc, // mov  eax, DWORD PTR _Argument1$[ebp]
    0x50,  // push  eax
    0xff, 0x55, 0xf4, // call  DWORD PTR _protoFunction$[ebp]
    0x5f,  // pop  edi
    0x5e,  // pop  esi
    0x5b,  // pop  ebx
    0x8b, 0xe5,  // mov  esp, ebp
    0x5d,  // pop  ebp
    0xc2, 0x08, 0x00 // ret  8
};
static byte[] x64CodeForFastcallWrapperForExecutionDelegate = new byte[] {
    0x4c, 0x89, 0x4c, 0x24, 0x20, // mov  QWORD PTR [rsp+32], r9
    0x4c, 0x89, 0x44, 0x24, 0x18, // mov  QWORD PTR [rsp+24], r8
    0x89, 0x54, 0x24, 0x10, // mov  DWORD PTR [rsp+16], edx
    0x48, 0x89, 0x4c, 0x24, 0x08, // mov  QWORD PTR [rsp+8], rcx
    0x48, 0x83, 0xec, 0x38, // sub  rsp, 56   ; 00000038H
    0x48, 0xb8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,//  mov  rax, -1085102592571150096 ; f0f0f0f0f0f0f0f0H
    0x48, 0x89, 0x44, 0x24, 0x20, // mov  QWORD PTR protoFunction$[rsp], rax
    0x4c, 0x8b, 0x4c, 0x24, 0x58, // mov  r9, QWORD PTR Argument4$[rsp]
    0x4c, 0x8b, 0x44, 0x24, 0x50, // mov  r8, QWORD PTR Argument3$[rsp]
    0x8b, 0x54, 0x24, 0x48,  //mov  edx, DWORD PTR Argument2$[rsp]
    0x48, 0x8b, 0x4c, 0x24, 0x40,//  mov  rcx, QWORD PTR Argument1$[rsp]
    0xff, 0x54, 0x24, 0x20,  //call  QWORD PTR protoFunction$[rsp]
    0x48, 0x83, 0xc4, 0x38,  //add  rsp, 56   ; 00000038H
    0xc3  // ret  0
};

And finally used it all in my code like this:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]

private delegate void PStdCallDelegateVersion(IntPtr context, TTCallbackType type, IntPtr arg1, IntPtr arg2);

private UnmanagedCodeSupplier callbackProvider;

private MyClass()

{

callbackProvider = new UnmanagedCodeSupplier((PStdCallDelegateVersion)ttExecutionCallback, IntPtr.Size == sizeof(int) ? x86CodeForFastcallWrapperForExecutionDelegate : x64CodeForFastcallWrapperForExecutionDelegate, IntPtr.Size == sizeof(int) ? new UIntPtr(0xF0F0F0F0) : new UIntPtr(0xF0F0F0F0F0F0F0F0));

privatevoid ttExecutionCallback(IntPtr cntxt, TTCallbackType type, IntPtr arg1, IntPtr arg2) { ... }

 

So while it's far from the simplest thing in the world to do this, it's not that bad, and it certainly made for an interesting afternoon of problem solving.  Once you have a template like this together, it's easy and relatively quick to do for additional function prototypes.

Follow us on Twitter, www.twitter.com/WindowsSDK.

Reducing the time to perform a CRL check on isolated networks

$
0
0

 

 

Hi everyone,

 

Writing today to pass along a solution to reduce the time for performing certificate revocation list processing (CRL checking).   This topic has been covered in other blogs in length in ways to lock down servers to prevent outgoing calls for CRL processing and delays.  Here are a few for example:

http://blogs.msdn.com/b/chaun/archive/2014/05/01/best-practices-for-crl-checking-on-sharepoint-servers.aspx

http://blogs.technet.com/b/exchange/archive/2010/05/14/3409948.aspx

 

One additional option that we have been recommending is using the Public Key Policies on the machine to reduce the timeout when machines are blocking all outgoing traffic either through a proxy server or firewall.   For system administrators, this can be reduced from the default of 15 seconds to a smaller number for example, 1 second.   The settings are shown below inside of the MMC console snap-in:

 

CRL_FINAL

 

 

The walkthrough on how to get to the dialog is also listed here on TechNet:

      https://technet.microsoft.com/en-us/library/cc771429.aspx

 

 

So before giving up hope with enabling the firewall or doing other changes to disable CRL altogether, consider just reducing the timeout setting as an option.  

 

 

Thank you,

Nathan

 

---------------------------------------------------------------------------------------------------------

Follow us on Twitter, www.twitter.com/WindowsSDK.

Hotfixes for February 2015

$
0
0

 

Here are the Windows hotfixes for February 2015.

3031420  "100060" time-out error when you drain VM roles for CAU during VM live migration on Windows Server 2012 R2 compute nodes

3031417  Deduplication fixes for optimization job schedule and resiliency to hardware failures in Windows Server 2012 R2

3027577  "0x0000007F" Stop error when you run both data encryption and antivirus software in Windows 7 or Windows Server 2008 R2

3027174  Insufficient MBCS file name support on the FTP client in Windows Server 2012 and Windows 8

3027127  "Round Robin with Subset" load balancing policy is lost after computer restarts in Windows 7 or Windows Server 2008 R2

3027115  Custom values for various MPIO timers in Windows Server 2012 R2 may not be honored

3027113  Can't save a dump file when the system crashes and the Round Robin MPIO policy is used in Windows Server 2012

3027110  Hyper-V hosts freeze in black screen if cluster nodes shut down unexpectedly in Windows 8.1 or Windows Server 2012 R2

3027108  "0x0000003B" Stop error when you mount a virtual hard disk driver in Windows on a computer that has 4K sector disks

3026773  VSS snapshot disappears after system starts in Windows 7 or Windows Server 2008 R2

3026771  "0x0000007E" Stop error after you perform a VSS backup job in Windows 7 or Windows Server 2008 R2

3026738  RemoteApp window is too large or too small when you use RDP to run a RemoteApp application in Windows Server 2012 R2

3026679   Network interface IP address is not updated when you resume a computer from sleep in Windows 7 or Windows Server 2008 R2

3026286  Internal sites cannot be accessed through VPN in Windows 7 SP1 or Windows Server 2008 SP1

3025426  RRAS phonebook and registry key go out of sync on an S2S VPN in Windows 8.1 or Windows Server 2012 R2

3025101  "Not support" error when you click Open with Explorer on SharePoint in Windows 7 or Windows Server 2008 R2

3025097  "Invalid device" error when you try to rename a file on a Network File System client that is running Windows 8.1 or Windows Server 2012 R2

3025087  Lsass.exe process and Windows Server 2012 R2-based domain controller crashes when the server runs under low memory

3025080 Operation fails when you try to save an Office file through Web Application Proxy in Windows Server 2012 R2

3025078  You are not prompted for username again when you use an incorrect username to log on to Windows Server 2012 R2

3024681  Program icons are missing from network tiles in the Windows Modern UI

3024331  "XACT_E_CONNECTION_DOWN" error on SQL Server instances after you restart MS DTC in Windows 8 or Windows server 2012

3024260 OK and Cancel buttons are missing from the Local Devices and Resources dialog box in the Norwegian language pack

3023894   Cluster fixes for deadlock and resource time-out issues in Windows Server 2012 R2 Update 1

3023569  Windows Process Activation Service crashes with an access violation in Windows 7 SP1 or Windows Server 2008 R2 SP1

3023557  WSAEINVAL error when many applications make WCF calls to connect to web in Windows 7 SP1 or Windows Server 2008 R2 SP1

3023161  Remote session disconnects when you are connected to a server by remote desktop in Windows 7 or Windows Server 2008 R2

3022780  DNS server does not respond with IP address to a CNAME query for a delegated zone in Windows Server 2008 R2

3022773  Dnscache service no longer sends update packets to the DNS server

3022333  Hotfix to avoid a deadlock situation on a CSV file system volume on Windows Server 2012 R2

3022332  "Windows has detected an IP address conflict" error in Windows Server 2012 R2 or Windows Server 2008 R2 NLB nodes

3022235  USB SD card reader loses capability to detect media change in Windows

3021169  Computer freezes when updating network driver or installing network filter driver in Windows 7 or Windows Server 2008 R2

3021064  "0x0000003B" Stop error and losing remote session on remote server in Windows 7 or Windows Server 2008 R2

3021052  Monitor that uses the WMI service stops working for the cluster service in Windows Server 2012

3020813 You are prompted for authentication when you run a web application in Windows Server 2012 R2 AD FS

3020773  Time-out failures after initial deployment of Device Registration service in Windows Server 2012 R2

3020398  Shared screen flashes when an attendee joins or leaves a multiparty session in an application in Windows 7

3020396  Sysprep.exe process crashes when you use the SCVMM tool to create a VM template of a Windows Server 2012 image

3019282  Print Spooler service crashes when you print documents on a network shared printer in Windows

3019276  You cannot selectively restore files from a data deduplication backup in Windows Server 2012 R2 or Windows Server 2012

3019274  L3 cache size is reported incorrectly from Windows Management Instrumentation interface in Windows

3019272  It takes a long time to log on to a domain-joined computer that runs Windows 8.1 or Windows Server 2012 R2

3019224  "Not able to connect to printer" error when you try to connect to a printer on a computer that is running Windows 7 or Windows Server 2008 R2

3018886  You are prompted for a username and password two times when you access Windows Server 2012 R2 AD FS server from intranet

3018775 "STATUS_NONE_MAPPED" error returns by Windows Server 2012 R2 DC when resolving SIDs from SIDHistory of a migrated object

3018489  "No host bus adapter is present" error when querying SAS cable issues in Windows Server 2012

3016331  Virtual machines restart unexpectedly when Resource Host Monitor is stopped in Windows Server 2008 R2

3015693  "0x000000AB" Stop error in Windows Server 2012-based RDS server when you log off from a Remote Desktop session

3015354  Update of multimedia class device drivers fails after you upgrade Windows

3014176  Windows does not change the client certificates in subsequent HTTP requests after the initial connection

3013808  "0x00000024" Stop error caused by the Ntfs.sys file in Windows Vista SP2 or Windows Server 2008 SP2

3013174  "No Computer Found" error on front panel of USB scanner when you scan documents in Windows 7 or Windows Server 2008 R2

3012660  "The update is not applicable to your computer" error when you install update 2853587 in Windows 7 SP1 with AD LDS

3007058  "Print to file" feature does not work through a Windows-based printer server that uses a version 4 printer driver

3006137  Hotfix changes the currency symbol of Lithuania from the Lithuanian litas (Lt) to the euro (€) in Windows

3005788  Printing preferences window appears behind a RemoteApp window in Windows 7 or Windows Server 2008 R2

3004545  You cannot access virtual machines that are hosted on Azure hosting services through a VPN connection in Windows

3004544  You are repeatedly prompted for credentials when you access intranet sources by using certification-based SSO in Windows

3002286  Delay in accessing a file server when a Windows 7-based computer connects to the file server

2972254  Hyper-V virtual machines cannot be connected to sometimes when TCP connections reconnect in Windows

2616886  Group membership is emptied on a Windows Server 2008 R2-based or Windows Server 2008-based RODC

/Jeff

Follow us on Twitter, www.twitter.com/WindowsSDK.

Accidental Denial of Service through Inefficient Program Design Part 1 – Watching WMI Events for Object Creation (e.g. Win32_Process)

$
0
0
 

There are few things that are more annoying as a user than to have the performance of a computer which they’re using grind to a halt.  This series will outline program design flaws that I’ve run across, explain what they are, how they impact the system, example scenarios where the impact will be exacerbated, and safer alternatives to accomplish the same programming goal.  In part one of this series, we’ll be exploring:

Watching WMI Events for Object Creation (e.g. Win32_Process)

 

What It Is

WMI stands for Windows Management Infrastructure(2012+) or Windows Management Instrumentation(2008R2 and before).  It is a management infrastructure that allows for local and remote management data collection and operations execution.  It’s a great framework to have around to be used when you need to find out some information and want to be able to do so without writing much if any code.  If you’re at a Powershell prompt or still writing vbscripts like its the 90s, it’s a great option for many one-off tasks.

How It Impacts the System

The framework itself has fairly high overhead compared to native function calls which is required to be able to support the ability to make specific queries.  Since it’s a generic framework, the variance in the amount of resources it requires to do something depends predominantly on the Provider and Class, so one needs to treat its class as its own impact entity when considering its implications on the system.  In other words, the query “Select * From Win32_Product” may take a considerably different amount of resources and time to execute compared to the query “Select * From Win32_Registry”.  When performing an event query, the amount of resources can be multiplied substantially due to the way that some event providers work.

Since the WMI framework is so vast, we’ll be focusing the rest of part one on the Win32_Process class.  This is a commonly used class for performing event queries most often to be notified of process creation.  For example, here’s some C# code that I’ve seen used before to be notified of when a Notepad process has been created:

var scope = new ManagementScope( string.Format("\\\\{0}\\root\\cimv2", machineName) , null); 
scope.Connect(); 
var wmiStartQuery = new WqlEventQuery("__InstanceCreationEvent", 
new TimeSpan(0, 0, 1), 
"TargetInstance ISA \"Win32_Process\" AND " + 
"TargetInstance.Name=\"Notepad.exe\" "); 
var StartWatcher = new ManagementEventWatcher(scope, wmiStartQuery); 
StartWatcher.EventArrived += StartWatcher_EventArrived; 
StartWatcher.Start();

Let’s take a step back here and look at what is actually happening.  The root\cimv2 namespace is being connected to on the machine “machineName.”  WqlEventQuery is being instantiated to report events of class “__InstanceCreationEvent”, send status within one second, and constrain events reported to come from the class Win32_Process and have a Name property equal to “Notepad.exe.”  The ManagementEventWatcher uses the WMI connection on the machine to perform that query and calls the EventArrived event whenever data is available.  Looking at the explanation for the second parameter in the documentation linked above, we see:

This value is used in cases where there is no explicit event provider for the query requested and WMI is required to poll for the condition. This interval is the maximum amount of time that can pass before notification of an event must be delivered.

So let’s translate this into what basically actually happens on “machinename” in order to facilitate this translated into C# (accurate enough to show impact of what’s generally happening anyway since obviously WMI doesn’t use WMI to obtain process information:-)):

Stopwatch sw = new Stopwatch(); 
var scope = new ManagementScope( 
string.Format("\\\\{0}\\root\\cimv2", machineName) , null); 
scope.Connect(); 
var processQuery = new SelectQuery( "SELECT * FROM Win32_Process WHERE " + 
"Name=\"Notepad.exe\" "); 
var searcher = new ManagementObjectSearcher(scope, processQuery); 
ManagementObjectCollection baseCollection; 
ManagementObjectCollection nextCollection; 
sw.Restart(); 
baseCollection = searcher.Get(); 
do { 
TimeSpan timeLeft = TimeSpan.FromSeconds(1).Subtract(sw.Elapsed); 
if(timeLeft.TotalMilliseconds > 0) Thread.Sleep(timeLeft); 
nextCollection = searcher.Get(); 
sw.Restart(); 
foreach(ManagementObject moNext in nextCollection) { 
bool matched = false; 
uint procId = (uint)moNext["ProcessId"]; 
foreach(ManagementObject moBase in baseCollection) { 
if((uint)moBase["ProcessId"] == procId) { 
matched = true; break; 
} 
} 
if(!matched) { 
//Report that the process was created here! 
} 
} 
baseCollection = nextCollection; 
} 
while (isRunning);

It’s pretty easy to see how that is inefficient.  Sure, if you write the C# code shown originally, your callback will only fire when the criteria is met, but on the machine where you are monitoring in the WMI Service Host, an inefficient operation is taking place on a continual basis.  If you use a shorter timeout, this querying has to take place even more frequently.  If you use a longer timeout, there is potentially longer delay between when the process is created and when you are notified of its creation.

Example Scenario of Exacerbation

Consider the following scenario:

  • Application A needs to be launched whenever Application B is running
  • Application B could potentially be ran on a server with Remote Desktop Services by users in specific sessions
  • Application C is launched in each session when the session is started so that it can launch Application A in the proper context in that session whenever Application B is launched
  • Multiple users log on to the same server with a Remote Desktop Services session

In this case, multiple event queries could end up running simultaneously.  Even if they are the same query text, WMI isn’t going to combine them into a single query with multiple subscribers since each user will be connected to WMI with a different RPC context.

On a system with 8 vCPUs, 32 GB of RAM, and SSD storage for the OS Drive and Pagefile, I observed the following by measuring the impact of having X users perform the example event query with 133 base processes running and 7 processes added per signed in user (I was only adding one process per user, but there are dependencies for running a session as well):

Users Performing Event QueryTimeout (seconds)% CPU Used by WMI as shown in Task Manager over Two Minutes
215.8% – 7.0%
6113.7%-14.5%
15149.6%-50.8%

As you can see, as more and more users get on, more and more CPU is being eaten up just to maintain this event query, and application response times will suffer more and more.   Eventually, with enough users, it would become a nightmare to interact with an application on the machine since there would be so many context switches and contention for CPU time.

Safer Alternatives

In this case, while it’s still far from an optimal programming practice, increasing the timeout value can massively mitigate the impact.  Running the same test as above except changing the timeout value to 30 seconds, with 15 users the average % CPU impact was shown to be 0% and less than 5 seconds of total CPU time was used by WMI in two minutes (with 8 cores that means it used between .25% and .31% of available CPU in that time period).  If an application doesn’t need to know right away, a longer timeout is something easy to change to make this methodology much more palatable.  If a process doesn’t live very long, the chances of it failing to be caught does go up the longer the polling interval is.

Either in conjunction with the above or on its own, performing a single event query from a service and using that service to launch applications in the correct context is also a huge improvement in resource utilization in a Remote Desktop Services scenario.

When running on a local machine, using WMI is just adding overhead from a resource standpoint versus calling the native APIs yourself, so switching the logic to native code will also provide some benefit.  Using the Process Status API, Tool Help Library, or NtQuerySystemInformation with the SystemProcessInformation parameter will get a user mode application a collection of every process running on the local machine for supported versions of the Windows Server family of operating systems at the time of this point.

Ideally, polling would be avoided altogether and there is of course a mechanism to do that as well.  One can use a driver to replace Application A in the scenario above and use either PsSetCreateProcessNotifyRoutine or PsSetCreateProcessNotifyRoutineEx to register a function for Windows to call each time a new process is created (a la procmon and sysmon).

Enabling the Audit Process Creation policy will cause an event to be logged to the security event log whenever a process starts.  Once that is happening, you can get notified of when said event log is written to using EvtSubscribe or even the managed class System.Diagnostics.Eventing.Reader.EventLogWatcher.

System Monitor also has an event that will get trigged when a counter is added to a collection, so monitoring the Process counters will allow you to get notified that a process has been created.  This does add the overhead of COM and a UI as well, so its impact can add up on Remote Desktop Services too.

Perhaps the best thing to do for this particular scenario would be to eschew a programmatic process watching solution altogether.  If you know that you need an application launched alongside another, it makes sense to use a shortcut to a batch file, script file, or executable file to launch both applications.

Follow us on Twitter, www.twitter.com/WindowsSDK.

Viewing all 126 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>