0

I have a C# (.NET 4) Windows Service running as LocalSystem.

One of its functions is to spawn processes (which also run as LocalSystem). These processes appear on the desktop of a given session (eg SessionID 1 or SessionID 2, winlogon screen, etc).

When processes are created in this way, calling Thread.CurrentThread.CurrentUICulture within the process always returns 'en-US', rather than the culture of the logged in user for the given session.

I need a way to determine the culture of the logged in user. The closest thing I've found is a windows API 'GetProcessPreferredUILanguages' which I was hoping to use to get the language of the 'explorer' process of the given Session, but I'm not clear if this is a viable option.

Any assistance is appreciated. Thanks in advance!

David
  • 101
  • 1
  • 10
  • Completely unrelated to your question, but why do you run processes under the *LocalSystem* account in an interactive user session? This sounds like a rather unfortunate decision. – IInspectable Aug 14 '15 at 14:36
  • Forgive my ignorance, but what would be a better practice? Create an account specifically for this app with specific restricted permissions and run it under that? – Jerreck Aug 14 '15 at 14:43
  • LocalSystem on the desktop? Ouch! – David Heffernan Aug 14 '15 at 14:43
  • LocalSystem is used in a 'controlled fashion' for situations where elevated rights are required. I completely understand there are other ways to achieve this, but we're going off topic. – David Aug 14 '15 at 14:56
  • 1
    @Jerreck: Run the client process under the user's account, that is logged into the user session, like any regular application. If you require elevation, send a request to the service, to perform the action(s) on behalf of the client application. There is no need to inject an unsecurable attack surface into an interactive user session. – IInspectable Aug 14 '15 at 15:05
  • This all sounds excessively far removed from reality. At least tell us how a user account managed to get its own UI culture. – Hans Passant Aug 14 '15 at 15:09
  • In a way, thats actually what I'm doing, there is a UI component that the windows service displays when it receives the elevation request which is the part in scope for discussion. Anyway thanks all for your help. Now just trying to figure out how to convert a LANGID to a culture name – David Aug 14 '15 at 15:10
  • 1
    @David: This is unsecurable. Your UI component is just one DLL injection away from a pwnd machine. You cannot prevent the OS from loading a rogue DLL into your process, when a random other process has set up a global hook. This DLL instantly inherits *LocalSystem* rights. See [ImpersonateLoggedOnUser](https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612.aspx) and [CreateProcessAsUser](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682429.aspx) for the right way to go about this. – IInspectable Aug 15 '15 at 19:26

2 Answers2

3

Haven't ever done this, but I was curious so I did a bit of googling. You might try GetUserDefaultUILanguage().

According to this article in the MSDN:

The current UI culture is a per-thread property. That is, each thread has its own current UI culture. This property is equivalent to retrieving or, starting with the .NET Framework 4.6, setting the CultureInfo object assigned to the System.Threading.Thread.CurrentThread.CurrentUICulture property. When a thread is started, its UI culture is initially determined as follows:

  • By retrieving the culture that is specified by the DefaultThreadCurrentUICulture property in the application domain in which the thread is executing, if the property value is not null.

  • By calling the Windows GetUserDefaultUILanguage function.

Also note this:

This function returns only a language identifier. An application can retrieve the language name using the GetUserPreferredUILanguages function.

Community
  • 1
  • 1
Jerreck
  • 2,930
  • 3
  • 24
  • 42
  • Unfortunately this didn't work. The function GetUserPreferredUILanguages() returns 1033 (en-US) as well. Clearly this is the UI language of the Windows Service, which is being passed down to processes which it spawns. Again, what I need is to identity the language/culture that a given Windows Session (and its logged in user) is running under. – David Aug 14 '15 at 14:13
  • Are you certain the user's culture isn't set to en-US? Also, here's an in-depth answer I just found that gives a lot more detail: http://stackoverflow.com/a/17053067/2344773 – Jerreck Aug 14 '15 at 14:16
  • Absolutely certain. I'm expecting "de-de" (language ID 1031). If I write a stand-alone console app and call Thread.CurrentThread.CurrentUICulture it will return de-DE correctly, but not through a process spawned by the windows service – David Aug 14 '15 at 14:19
  • Reading the article, I think what is happening is it's returning the culture info of NT Authority\SYSTEM (which defaults to English) rather than the culture info of the logged in user (which in my case is German). – David Aug 14 '15 at 14:22
  • So just to update the original question.... We have 2 users in the same session: NT Authority\SYSTEM and user XYZ. How does a process running under context of SYSTEM determine the culture of user XYZ – David Aug 14 '15 at 14:24
  • Ah, I see what you're saying. That would make sense. You would think that you could call GetUserPreferredUILanguages(userID) or something but that method has no overloads. Still trying to figure that one out, however, I did find where you could change the system UI language in this article: https://msdn.microsoft.com/en-us/library/windows/desktop/dd374098(v=vs.85).aspx – Jerreck Aug 14 '15 at 14:39
  • OK think I've figured it out.. calling GetUserDefaultUILanguage() within a WindowsIdentity.Impersonate() block returns the correct culture information.. This can be done from the Windows Service and passed as a parameter to the process being spawned thus allowing it to adjust its culture accordingly. Not very elegant but seems to work.. Jerreck you agree on approach? – David Aug 14 '15 at 15:05
  • Hey if it works, go for it. Based on some comments to your question above it sounds like there are some security and/or design concerns, but it sounds like you're aware of those. – Jerreck Aug 14 '15 at 15:18
2

Calling GetUserDefaultUILanguage() within a WindowsIdentity.Impersonate() block returns the correct culture information

David
  • 101
  • 1
  • 10