In our existing application we are using a windows service which has a DLL import to call some functions in native assembly. This has been working fine as long as the service where this native function is called is running as Network Service. It also works when the service runs as LocalSystem.
In order to set customized privileges , we have decided to add support for using a Service account. However simply running the service as a newly created windows user account results in Access Violation error during the Native method call.
Similarly, I tried with a domain account which has administrator permissions on the system to run the service, but still it results in the same problem.
I cannot find any documentation on MSDN where specific permission for user account are listed for DLL Import to work. Can anyone tell me what I might be doing wrong ?
C# Code
[DllImport("lmgr11.dll", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern string GetFeaturelist(short jobType, int flag);
C Code
char* WINAPI GetFeaturelist(int type, int flag)
{
char * featureList;
char ** features, ** tempFeatureList;
int counter = 0;
if (!lm_job)
{
return NULL;
}
features = tempFeatureList = lc_feat_list(lm_job,flag,NULL);
//loop to know the number of features
while(*tempFeatureList != NULL)
{
counter++;
tempFeatureList++;
}
featureList = (char*) CoTaskMemAlloc(counter * 50);
strcpy(featureList,"");
while(*features != NULL)
{
strcat(featureList,*features);
strcat(featureList,"$$&&#&&$$");
features++;
}
lc_log(lm_job, featureList);
return featureList;
}
The problem was that "featurelist" variable in the C code was null, and the below code was not enough to handle it.
while(*features != NULL)
Adding another check using the below code, avoids the crash.
features != NULL
As for the error occurring only when not running as "Network Service", the 3rd Party code (lc_feat_list) depended on an user specific registry entry in HKU, whereas the documentation incorrectly refers to a static registry entry under HKLM, which ultimately caused it to return a null value.
Related
I've recently been working on a very nice Registry Editor.
However, certain Registry keys, pointed out below in Regedit, will not show up in my program, as they raise an error of insufficient privileges when opened, and so are caught by error handling and skipped:
Regedit:
My program:
As you can see, the SECURITY key is missing, and the SAM key is not expandable, even though I am running the program with administrator privileges.
This can obviously be fixed by making fake keys and putting them there, and just displaying an empty default value for them, however that isn't a concrete solution, just a way to make it seem to the user as if the issue is solved.
I was wondering if there is a way to fix the issue in a concrete way, or in other words, to receive registry access to those keys?
All they display is an empty default value any way, including the expandable SAM key - it just has a subkey named 'SAM' with an empty default value as well.
However, to the user, it's much better if the program displays exactly as in Regedit, as it means that it's a fully functional piece of software.
Thanks for the help.
Edit (code included):
public static void TreeViewItemExpanded(TreeViewItem sender)
{
if (sender.Items[0] is string)
{
sender.Items.Clear();
RegistryKey expandedKey = (RegistryKey)sender.Tag;
foreach (string key in expandedKey.GetSubKeyNames().OrderBy(x => x)) try { sender.Items.Add(CreateTreeViewItem(expandedKey.OpenSubKey(key))); } catch { }
}
}
private static TreeViewItem CreateTreeViewItem(RegistryKey key)
{
TreeViewItem treeViewItem = new TreeViewItem() { Header = new RegistryEditor_RegistryStructure_TreeView() { Name = Path.GetFileName(key.ToString()) }, Tag = key };
try { if (key.SubKeyCount > 0) treeViewItem.Items.Add("Loading..."); } catch { }
return treeViewItem;
}
You did not supply sample code to your routine, but I have a suspision that you are using a default registry security descriptor.
You can specify a security descriptor for a registry key when you call the RegCreateKeyEx or RegSetKeySecurity function.
When you call the RegOpenKeyEx function, the system checks the requested access rights against the key's security descriptor. If the user does not have the correct access to the registry key, the open operation fails. If an administrator needs access to the key, the solution is to enable the SE_TAKE_OWNERSHIP_NAME privilege and open the registry key with WRITE_OWNER access.
This information is taken from: MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878(v=vs.85).aspx
In C# You should be using the Registery Permission Class
https://msdn.microsoft.com/en-us/library/system.security.permissions.registrypermission(v=vs.110).aspx
A good example of how to handle Registry Permissions can be found here:
https://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.setaccesscontrol(v=vs.110).aspx
you need enable SE_RESTORE_PRIVILEGE and SE_BACKUP_PRIVILEGE and use RegOpenKeyEx or ZwOpenKeyEx with REG_OPTION_BACKUP_RESTORE flag (but this will be work only begin from Windows 7 and later versions of Windows)
If this flag is set, the function ignores the samDesired parameter and
attempts to open the key with the access required to backup or restore
the key. If the calling thread has the SE_BACKUP_NAME privilege
enabled, the key is opened with the ACCESS_SYSTEM_SECURITY and
KEY_READ access rights. If the calling thread has the SE_RESTORE_NAME
privilege enabled, beginning with Windows Vista, the key is opened
with the ACCESS_SYSTEM_SECURITY, DELETE and KEY_WRITE access rights.
If both privileges are enabled, the key has the combined access rights
for both privileges.
for example
#define LAA(se) {{se},SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT}
#define BEGIN_PRIVILEGES(tp, n) static const struct {ULONG PrivilegeCount;LUID_AND_ATTRIBUTES Privileges[n];} tp = {n,{
#define END_PRIVILEGES }};
ULONG AdjustBackupRestore()
{
HANDLE hToken;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
BEGIN_PRIVILEGES(tp, 2)
LAA(SE_RESTORE_PRIVILEGE),
LAA(SE_BACKUP_PRIVILEGE),
END_PRIVILEGES
AdjustTokenPrivileges(hToken, FALSE, (::PTOKEN_PRIVILEGES)&tp, 0, 0, 0);
ULONG err = GetLastError();
CloseHandle(hToken);
return err;
}
return GetLastError();
}
if (!AdjustBackupRestore())//called once on startup
{
HKEY hKey;
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SECURITY\\SAM", REG_OPTION_BACKUP_RESTORE|REG_OPTION_OPEN_LINK, 0, &hKey))
{
RegCloseKey(hKey);
}
}
however for get full power for registry editor/viewer I be use native api
So I already have a pretty good idea how to set up firewall rules programmatically using the INetFwPolicy2 and INetFwRule COM interface. However, how can I use the COM interop to set up a rule for a specific "Modern App"/"Metro App"/"Store App"?
If I use the Firewall MMC, I can go to:
rule -> Properties -> Programs and Services -> Application Packages
and allow/block specified packages there. But I have no idea how to do this in code. I have found the INetFwRule3 interface which provides LocalAppPackageId property, which is what I assume does all the magic. But the LocalAppPackageId contains an SID of the package rather than its name like microsoft.windows.photos_8wekyb3d8bbwe for example. So how can I block the package I want, when all I know is it's name? I guess I have to get the SID, so how do I find that? Is the SID's scope local (unique per machine), or can I just hard-code the SID once I find it and not bother looking up the SID dynamically?
SID for an app container can be found using the NetworkIsolationEnumAppContainers and ConvertSidToStringSid APIs. This is what Fiddler does in their AppContainer Loopback Exemption Utility (which is how I found the API).
If you care just about SID and nothing else, it's easier to use DeriveAppContainerSidFromAppContainerName/ConvertSidToStringSid combo. You don't even have to use ConvertSidToStringSid, .NET framework already provides the conversion:
private static string SidToString(IntPtr sid)
{
return new SecurityIdentifier(sid).Value;
}
Curiously enough, the DeriveAppContainerSidFromAppContainerName does not check whether the app container exists on the system, it seems to just take whatever input you throw at it and generate the SID from that information alone (like a hash function).
So the complete code:
public static string AppContainerNameToSid(string appContainerName)
{
var sid = IntPtr.Zero;
try
{
if (DeriveAppContainerSidFromAppContainerName(appContainerName, out sid) == 0)
return new SecurityIdentifier(sid).Value;
else
return null;
}
finally
{
if (sid != IntPtr.Zero)
FreeSid(sid);
}
}
[DllImport("userenv.dll", SetLastError = false, CharSet = CharSet.Unicode)]
private static extern int DeriveAppContainerSidFromAppContainerName(string appContainerName, out IntPtr sid);
[DllImport("advapi32.dll", SetLastError = false)]
private static extern IntPtr FreeSid(IntPtr sid);
Blocking internet connection for an UWP app is just like a traditional Desktop software.
Type "advanced security" in Windows 8/10 search then select "Windows Defender Firewall with Advanced Security".
In the newly opened window and in the left panel, go to "Inbound Rules" then in the right panel, select "New Rule..." then tap "Next" when "Program" is selected. Then click on "Browse..." and go to this address:
*C:\Program Files\WindowsApps*
Now find your app's name and enter its folder then select the file with "Application" type.
You'll be able to find the right "Application" type file just in a few seconds.
As an example, the folder name for the "Google" app is this:
GoogleInc.GoogleSearch_2.1.19.0_x64__yfg5n0ztvskxp
And the name of its app "Application" file type is this:
GoogleSearchUniversal
However, after choosing the correct "Application" file type click on "Open" for it.
Then tap "Next" and then choose "Block the connection" then "Next" then marking all types of connections then "Next" then call it and "Finish".
Just like a traditional Desktop software.
Is there any way to get the information about Launching identity of DCOM application programmatically. See the picture attached to understand what i mean.
I tried to use WMI
ManagementObjectSearcher s = new ManagementObjectSearcher(new ManagementScope(#"\\.\root\cimv2"), new ObjectQuery(
"select * from Win32_DCOMApplicationSetting where AppID='{048EB43E-2059-422F-95E0-557DA96038AF}'"))
ManagementObjectCollection dcomSett = s.Get();
var value = dcomSett.Cast<ManagementObject>().ToArray()
[0].Properties["RunAsUser"].Value;
but "RunAsUser" property was empty.
Also tried Interop.COMAdmin
COMAdmin.COMAdminCatalogClass catalog = (COMAdmin.COMAdminCatalogClass)new COMAdmin.COMAdminCatalog();
(COMAdmin.COMAdminCatalogCollection)catalog.GetCollection("Applications")
in this way i managed to get applications which are listed under the "COM+ Applications" node in the "Component Services" snap-in of MMC:
I'm new in COM, DCOM, COM+ stuff and sure that i missed something important.
After a while i found out why i used to get NULL in the first approach (ManagementObject).
You will receive:
NULL if identity is currently set to The launching user
"Interactive User" in case of "The interactive user"
some string with username in case of third option (see the first picture)
But still i need a way to change identity for items like Microsoft PowerPoint Slide under DCOM Config node in MMC.
In the DCOM config, if you are using a specific user for the identity and you want to update the password via code, you need to update it in the Local Security Authority (LSA). This is possible with Windows API calls. MS has some sample code for a utility called dcomperm that does it, and you can see how they implemented in C++. You could make the same calls in C#. See the SetRunAsPassword method here. They are using the method LsaOpenPolicy to get a handle to the policy and calling LsaStorePrivateData to update the password. Then they are adding "login as a batch job" access to the account (but that shouldn't be necessary if you are only changing the password).
This sample code on pinvoke.net looks like it is making the requisite calls, except for the optional part about granting the login as a batch job permission. Note the "key" in the LSA is in the format SCM:{GUID-of-DCOM-object} Example: SCM:{00000000-0000-0000-0000-000000000000}
Oh, and I should mention as an aside that if you wanted to change the RunAs user itself (i.e. the username), you'd need to also update that in the windows registry directly (AFAIK that's the only way to do it). DCOM entries are stored under HKLM\SOFTWARE\Classes\AppID. You can do that with WMI or just use the Registry classes in .NET.
This is very simple , you can get APPId from
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{048EB43E-2059-422F-95E0-557DA96038AF}
using
(RegistryKey dcomPPTIdentity = Registry.LocalMachine.OpenSubKey("Software\\Classes\\AppID\\{048EB43E-2059-422F-95E0-557DA96038AF}"))
{
if (dcomPPTIdentity != null)
{
Registry.SetValue(dcomPPTIdentity.ToString(), "RunAs", "userName");
}
}
I am using COMAdmin DLL successfully. Try something like this:
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = COMAppCollectionInUse.Item[i];
if (application.Name == "Your COM+ application name")
{
application.Value["Identity"] = "nt authority\\localservice"; // for example
}
}
This works for me on my development server. Keep in mind, it is run against the server directly on the server
using COMAdmin;
using System;
namespace ComComponents
{
class Program
{
static void Main(string[] args)
{
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = applications.Item[i];
Console.WriteLine(application.Name);
Console.WriteLine(application.Value["Identity"]);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
I'm try to use Vista TaskDialog Wrapper and Emulator and I'm getting the following exception:
"Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
...in a simple Console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
PSTaskDialog.cTaskDialog.MessageBox(
"MessageBox Title",
"The main instruction text for the message box is shown here.",
"The content text for the message box is shown here and the text willautomatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information
);
}
}
What am I doing wrong?
UPDATE:
Actually, I'm working on an Excel plugin using excel-dna. How can I control what dll Excel loads?
http://exceldna.codeplex.com/discussions/286990#post728888
I haven't been at Office programming in a while, but my guess is that Excel loads both versions of comctl32, so you may need to use the Activation Context API to direct your code to the version that includes TaskDialog. Some ideas for fixing the problem (not solutions as such):
For test purposes, make a temporary enumeration of all modules in the active process - just to check if 6.10 is actually loaded (see below for a simple example of such an enumeration, albeit with a different intent).
Use the Activation Context API to get to the right version. Example of use from C# (for enabling themes by way of comctl32 6.0) here.
Alternatively (I never actually got this to work reliably in a WPF application I worked on), make a dialog abstraction class, which falls back to MessageDlg depending on the version available to you. There may be better ways of doing the check, but...:
FileVersionInfo version = ProcessUtils.GetLoadedModuleVersion("comctl32.dll");
if (version != null && version.FileMajorPart >= 6 && version.FileMinorPart >= 1)
{
// We can use TaskDialog...
}
else
{
// Use old style MessageBox
}
The enumeration of modules:
internal static FileVersionInfo GetLoadedModuleVersion(string name)
{
Process process = Process.GetCurrentProcess();
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name)
{
return module.FileVersionInfo;
}
return null;
}
}
In addition to what all the others are saying: This error will disappear if you set the ForceEmulationMode on PSTaskDialog to true.
I am trying to get process path by pid but I'm getting Win32Exception (access id denied).
The code looks like this:
string path = Process.GetProcessById(pid).MainModule.FileName
I have tried using OpenProcess with GetModuleFileNameEx but OpenProcess is returning 0. I even tried enabling SeDebugPrivilege according to C# – How to enable SeDebugPrivilege but it didn't help.
The above code works for most of the processes but throws error for SynTPHelper.exe (Synaptics Pointing Device Helper) The application is running under the same username as my code. Both, my application and the process run in 64 bit.
Is it possible to retrieve the path without running my application as an administrator?
Edit
Task Manager is able to 'open file location' even though I'm not running it as an administrator.
Finally I managed to solve it. As it turned out there is new function in Vista and above for getting process path and new process access (PROCESS_QUERY_LIMITED_INFORMATION):
QueryFullProcessImageName
Here is the code that works from non-elevated process:
private static string GetExecutablePathAboveVista(UIntPtr dwProcessId)
{
StringBuilder buffer = new StringBuilder(1024);
IntPtr hprocess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION, false, dwProcessId);
if (hprocess != IntPtr.Zero)
{
try
{
int size = buffer.Capacity;
if (QueryFullProcessImageName(hprocess, 0, buff, out size))
{
return buffer.ToString();
}
}
finally
{
CloseHandle(hprocess);
}
}
return string.Empty;
}
Well, it is certainly not unheard of for services to remove access rights so that even an administrator cannot open the process. A service has enough privileges to do so, DRM components like audiodg.exe readily do so. A mouse pad helper doesn't strike me as something that would require such protection. But what the hey, why would anybody ever need to mess with a mouse pad helper?