I am currently programming a windows-firewallmanager for a company.
Problem is, that I can only delete an entry by name and not by an INetFwRule object or something.
There are entries, that have the same name two times where one is for TCP and the other one for UDP and we might want to delete only one of them.
I could delete both and create one of them afterwards again, but I would not like to use that workaround.
Does anyone have an easy solution to this?
You can only delete rules by name using the INetFwRules interface which seems to be a badly designed API because different rules can have the same name. A workaround is to filter the rules not only by name by also by the other properties that specifies the rule you want to delete. When you have found the rule to delete you can then rename the rule to a unique name using the INetFwRule interface.
You can then delete the rule using this unique temporary name.
Based on #"Martin Liversage" suggesting, here is a working C++ example tested with C# interop.
"AddAppFirewallRule" will only add the firewall rule if it doesn't exist.
"RemoveAppFirewallRule" will remove all firewall rules that match the exe path.
C/C++
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include <netfw.h>
#include <atlcomcli.h>
#include "Exports.h"
HRESULT WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2)
{
return CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), (void**)ppNetFwPolicy2);
}
extern "C"
{
MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, wchar_t* exePath, wchar_t* name, wchar_t* groupName, wchar_t* desc, wchar_t* ports, int tcp, int udp)
{
// declare locals
int result = 0;
HRESULT addRuleResult;
BSTR ruleName = SysAllocString(name);
BSTR ruleGroup = SysAllocString(groupName);
BSTR ruleDesc = SysAllocString(desc);
BSTR ruleExe = SysAllocString(exePath);
BSTR rulePorts = nullptr;
if (ports != nullptr) rulePorts = SysAllocString(ports);
INetFwPolicy2* policy = nullptr;
INetFwRules* rules = nullptr;
INetFwRule* rule = nullptr;
long profilesBitMask = 0;
HRESULT iterateResult = 0;
IUnknown* rulesCollection = nullptr;
IEnumVARIANT* variant = nullptr;
CComVariant var = {};
ULONG fetched = 0;
bool found = false;
// init
if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
if (FAILED(policy->get_Rules(&rules))) goto Cleanup;
//if (FAILED(policy->get_CurrentProfileTypes(&profilesBitMask))) goto Cleanup;
if (privateNetworks) profilesBitMask |= NET_FW_PROFILE2_PRIVATE;
if (publicNetworks) profilesBitMask |= NET_FW_PROFILE2_PUBLIC;
if (domainNetworks) profilesBitMask |= NET_FW_PROFILE2_DOMAIN;
if (FAILED(CoCreateInstance(__uuidof(NetFwRule), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&rule))) goto Cleanup;
// setup rule
rule->put_Name(ruleName);
rule->put_Description(ruleDesc);
rule->put_ApplicationName(ruleExe);
if (tcp && udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_ANY);
else if (tcp) rule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
else if (udp) rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
if (rulePorts != nullptr) rule->put_LocalPorts(rulePorts);
rule->put_Direction(NET_FW_RULE_DIR_MAX);
rule->put_Grouping(ruleGroup);
rule->put_Profiles(profilesBitMask);
rule->put_Action(NET_FW_ACTION_ALLOW);
rule->put_Enabled(VARIANT_TRUE);
// get rules enumerator
if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;
// enumerate rules to check if it already exists
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
{
BSTR ruleEXEPath = nullptr;
INetFwRule* existingRule = nullptr;
long exitingRuleProfileBitMask = 0;
if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&existingRule)))) goto Cleanup;
if (FAILED(existingRule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
if (FAILED(existingRule->get_Profiles(&exitingRuleProfileBitMask))) goto Cleanup;
if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0 && exitingRuleProfileBitMask == profilesBitMask)// check if exe paths match
{
BSTR existingRuleName = nullptr;
if (SUCCEEDED(existingRule->get_Name(&existingRuleName)))
{
if (existingRuleName != nullptr)
{
if (wcscmp(ruleName, existingRuleName) == 0) found = true;
SysFreeString(existingRuleName);
}
}
}
// cleanup iteration
if (existingRule != nullptr)
{
existingRule->Release();
existingRule = nullptr;
}
if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);
// exit loop if found
if (found) break;
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
}
// add rule if it doesn't already exist
if (!found)
{
addRuleResult = rules->Add(rule);
if (FAILED(addRuleResult)) goto Cleanup;
}
result = 1;// success
// cleanup resources
Cleanup:;
if (variant != nullptr) variant->Release();
if (rulesCollection != nullptr) rulesCollection->Release();
if (ruleName != nullptr) SysFreeString(ruleName);
if (ruleGroup != nullptr) SysFreeString(ruleGroup);
if (ruleDesc != nullptr) SysFreeString(ruleDesc);
if (ruleExe != nullptr) SysFreeString(ruleExe);
if (rulePorts != nullptr) SysFreeString(rulePorts);
if (rule != nullptr) rule->Release();
if (rules != nullptr) rules->Release();
if (policy != nullptr) policy->Release();
return result;
}
MyFrameworkOSNative_EXPORT int MyFrameworkOSNative_RemoveAppFirewallRule(wchar_t* exePath)
{
// declare locals
int result = 0;
INetFwPolicy2* policy = nullptr;
INetFwRules* rules = nullptr;
INetFwRule* rule = nullptr;
long profilesBitMask = 0;
HRESULT iterateResult = 0;
IUnknown* rulesCollection = nullptr;
IEnumVARIANT* variant = nullptr;
CComVariant var = {};
ULONG fetched = 0;
bool found = false;
// init
if (FAILED(WFCOMInitialize(&policy))) goto Cleanup;
if (FAILED(policy->get_Rules(&rules))) goto Cleanup;
// get rules enumerator
if (FAILED(rules->get__NewEnum(&rulesCollection))) goto Cleanup;
if (FAILED(rulesCollection->QueryInterface(__uuidof(IEnumVARIANT), (void**)&variant))) goto Cleanup;
// enumerate rules
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
while (SUCCEEDED(iterateResult) && iterateResult != S_FALSE)
{
BSTR ruleEXEPath = nullptr;
if (FAILED((V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&rule)))) goto Cleanup;
if (FAILED(rule->get_ApplicationName(&ruleEXEPath))) goto Cleanup;
if (ruleEXEPath != nullptr && wcscmp(ruleEXEPath, exePath) == 0)// check if exe paths match
{
found = true;
SysFreeString(ruleEXEPath);
BSTR ruleName = nullptr;
if (FAILED(rule->get_Name(&ruleName)))
{
if (ruleName != nullptr) SysFreeString(ruleName);
goto Cleanup;
}
if (FAILED(rules->Remove(ruleName)))
{
if (ruleName != nullptr) SysFreeString(ruleName);
goto Cleanup;
}
if (ruleName != nullptr) SysFreeString(ruleName);
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
continue;// continue to scan for more rules with same criteria
}
// cleanup iteration
if (rule != nullptr)
{
rule->Release();
rule = nullptr;
}
if (ruleEXEPath != nullptr) SysFreeString(ruleEXEPath);
// get next item in collection
var.Clear();
iterateResult = variant->Next(1, &var, &fetched);
}
if (!found) goto Cleanup;
result = 1;// success
// cleanup resources
Cleanup:;
if (variant != nullptr) variant->Release();
if (rulesCollection != nullptr) rulesCollection->Release();
if (rule != nullptr) rule->Release();
if (rules != nullptr) rules->Release();
if (policy != nullptr) policy->Release();
return result;
}
}
C#
[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int VMyFrameworkOSNative_AddAppFirewallRule(int privateNetworks, int publicNetworks, int domainNetworks, char* exePath, char* name, char* groupName, char* desc, char* ports, int tcp, int udp);
[DllImport("MyFramework.OS.Native.dll")]
private static unsafe extern int MyFrameworkOSNative_RemoveAppFirewallRule(char* exePath);
public static unsafe bool AddAppFirewallRule(bool privateNetworks, bool publicNetworks, bool domainNetworks, string exePath, string ruleName, string ruleDesc, int port = -1, bool tcp = true, bool udp = true)
{
// ensure COM is init
Ole32.CoInitialize(IntPtr.Zero);
// invoke native method
string portValue = port.ToString();
fixed (char* exePathPtr = exePath)
fixed (char* ruleNamePtr = ruleName)
fixed (char* ruleDescPtr = ruleDesc)
fixed (char* portValuePtr = portValue)
{
return MyFrameworkOSNative_AddAppFirewallRule
(
privateNetworks ? 1 : 0,
publicNetworks ? 1 : 0,
domainNetworks ? 1 : 0,
exePathPtr,
ruleNamePtr, ruleNamePtr,
ruleDescPtr,
port > 0 ? portValuePtr : null,
tcp ? 1 : 0, udp ? 1 : 0
) != 0;
}
}
public static unsafe bool RemoveAppFirewallRule(string exePath)
{
// ensure COM is init
Ole32.CoInitialize(IntPtr.Zero);
// invoke native method
fixed (char* exePathPtr = exePath)
{
return VMyFrameworkOSNative_RemoveAppFirewallRule(exePathPtr) != 0;
}
}
UnitTests
[Fact]
public void AddAppFirewallRule()
{
using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
{
Assert.True(NetworkUtils.AddAppFirewallRule(true, true, false, #"<Path-To-Exe>", "TestRule", "Test Rule Desc"));
}
}
[Fact]
public void RemoveAppFirewallRule()
{
using (var lib = new LibHandle("MyFramework.OS.Native.dll"))
{
Assert.True(NetworkUtils.RemoveAppFirewallRule(#"<Path-To-Exe>"));
}
}
public static void RemoveFirewallRules(string RuleName = "BreakermindCom")
{
try
{
Type tNetFwPolicy2 = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(tNetFwPolicy2);
var currentProfiles = fwPolicy2.CurrentProfileTypes;
// Lista rules
// List<INetFwRule> RuleList = new List<INetFwRule>();
foreach (INetFwRule rule in fwPolicy2.Rules)
{
// Add rule to list
// RuleList.Add(rule);
// Console.WriteLine(rule.Name);
if (rule.Name.IndexOf(RuleName) != -1)
{
// Now add the rule
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Remove(rule.Name);
Console.WriteLine(rule.Name + " has been deleted from Firewall Policy");
}
}
}
catch (Exception r)
{
Console.WriteLine("Error delete rule from firewall");
}}
Look at this
Related
I am relatively new to C++, and have copied some code from a live stream to get started with embedding C# mono into my game engine.
I have created a C# script:
using System;
namespace Neutron {
public class Main {
public float FloatVar { get; set; }
public Main() {
Console.WriteLine("Main constructor");
}
public void PrintMessage() {
Console.WriteLine("Hello World from C#!");
}
public void PrintCustomMessage(string message) {
Console.WriteLine($"C# says: {message}");
}
}
}
and built it to
../Sandbox/Sandbox/bin/Debug/Sandbox.dll (which i have verified within the c++ program that I am embedding it into)
when i call mono_runtime_object_init passing the MonoObject* created from calling mono_object_new (I have verified that it doesnt return a nullptr)
The following error occurs:
* Assertion at object.c:116, condition `is_ok (error)' not met, function:mono_runtime_object_init, (null) assembly:/usr/lib/mono/4.5/mscorlib.dll type:TypeInitializationException member:(null)
Followed by a long stack trace.
Here are my relavent files:
ScriptingEngine.cpp (See the InitMono function towards the bottom)
//
// Created by aw1lt on 05/12/22.
//
#include "ScriptingEngine.h"
#include "Logger.h"
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <fstream>
namespace Neutron {
struct ScriptEngineData {
MonoDomain* RootDomain = nullptr;
MonoDomain* AppDomain = nullptr;
MonoAssembly* CoreAssembly = nullptr;
};
char* ReadBytes(const std::string& filepath, uint32_t* outSize) {
std::ifstream stream(filepath, std::ios::binary | std::ios::ate);
if (!stream) {
// Failed to open the file
return nullptr;
}
std::streampos end = stream.tellg();
stream.seekg(0, std::ios::beg);
uint32_t size = end - stream.tellg();
if (size == 0) {
// File is empty
return nullptr;
}
char* buffer = new char[size];
stream.read((char*)buffer, size);
stream.close();
*outSize = size;
return buffer;
}
MonoAssembly* LoadCSharpAssembly(const std::string& assemblyPath) {
uint32_t fileSize = 0;
char* fileData = ReadBytes(assemblyPath, &fileSize);
// NOTE: We can't use this image for anything other than loading the assembly because this image doesn't have a reference to the assembly
MonoImageOpenStatus status;
MonoImage* image = mono_image_open_from_data_full(fileData, fileSize, 1, &status, 0);
if (status != MONO_IMAGE_OK) {
const char* errorMessage = mono_image_strerror(status);
Logger::Crit(errorMessage);
return nullptr;
}
MonoAssembly* assembly = mono_assembly_load_from_full(image, assemblyPath.c_str(), &status, 0);
mono_image_close(image);
// Don't forget to free the file data
delete[] fileData;
return assembly;
}
void PrintAssemblyTypes(MonoAssembly* assembly) {
MonoImage* image = mono_assembly_get_image(assembly);
const MonoTableInfo* typeDefinitionsTable = mono_image_get_table_info(image, MONO_TABLE_TYPEDEF);
int32_t numTypes = mono_table_info_get_rows(typeDefinitionsTable);
for (int32_t i = 0; i < numTypes; i++) {
uint32_t cols[MONO_TYPEDEF_SIZE];
mono_metadata_decode_row(typeDefinitionsTable, i, cols, MONO_TYPEDEF_SIZE);
const char* nameSpace = mono_metadata_string_heap(image, cols[MONO_TYPEDEF_NAMESPACE]);
const char* name = mono_metadata_string_heap(image, cols[MONO_TYPEDEF_NAME]);
Logger::Log(std::string(nameSpace) + "." + name);
}
}
static ScriptEngineData* s_Data;
void ScriptingEngine::Init() {
s_Data = new ScriptEngineData();
InitMono();
}
void ScriptingEngine::Shutdown() {
delete s_Data;
}
void ScriptingEngine::InitMono(std::string path) {
MonoDomain* rootDomain = mono_jit_init("NeutronJITRuntime");
Logger::Assert(rootDomain != nullptr);
//system(("cat " + path).c_str());
// Store the root domain pointer
s_Data->RootDomain = rootDomain;
// Create an App Domain
s_Data->AppDomain = mono_domain_create_appdomain("NeutronScriptRuntime", nullptr);
mono_domain_set(s_Data->AppDomain, true);
s_Data->CoreAssembly = LoadCSharpAssembly(path);
Logger::Assert(s_Data->CoreAssembly != nullptr);
MonoImage* assemblyImage = mono_assembly_get_image(s_Data->CoreAssembly);
MonoClass* monoClass = mono_class_from_name(assemblyImage, "Neutron", "Main");
Logger::Assert(monoClass != nullptr);
PrintAssemblyTypes(s_Data->CoreAssembly);
MonoObject* instance = mono_object_new(s_Data->AppDomain, monoClass);
Logger::Assert(instance != nullptr);
mono_runtime_object_init(instance); // << ERROR HAPPENS HERE
}
void ScriptingEngine::ShutdownMono() {
}
} // Neutron
my header file, ScriptingEngine.h
//
// Created by aw1lt on 05/12/22.
//
#ifndef NEUTRONENGINE_SCRIPTINGENGINE_H
#define NEUTRONENGINE_SCRIPTINGENGINE_H
#include <string>
namespace Neutron {
class ScriptingEngine {
public:
static void Init();
static void Shutdown();
private:
static void InitMono(std::string path = "../Sandbox/Sandbox/bin/Debug/Sandbox.dll");
static void ShutdownMono();
};
} // Neutron
#endif //NEUTRONENGINE_SCRIPTINGENGINE_H
I also tried the answers on this page.
Thank you, and sorry if this answer is a mess.
A software I am writing is about to take an action that requires the current logged in user is actually the one taking the action. So I want to have windows just ask for the current user's password or biometrics or whatever before the action is allowed to continue.
I used an interop for UserConsentVerifier from another post (Code Below).
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Security.Credentials.UI;
namespace UWPInterop
{
//MIDL_INTERFACE("39E050C3-4E74-441A-8DC0-B81104DF949C")
//IUserConsentVerifierInterop : public IInspectable
//{
//public:
// virtual HRESULT STDMETHODCALLTYPE RequestVerificationForWindowAsync(
// /* [in] */ HWND appWindow,
// /* [in] */ HSTRING message,
// /* [in] */ REFIID riid,
// /* [iid_is][retval][out] */ void** asyncOperation) = 0;
//};
[System.Runtime.InteropServices.Guid("39E050C3-4E74-441A-8DC0-B81104DF949C")]
[System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIInspectable)]
public interface IUserConsentVerifierInterop
{
IAsyncOperation<UserConsentVerificationResult> RequestVerificationForWindowAsync(IntPtr appWindow, [MarshalAs(UnmanagedType.HString)] string Message, [In] ref Guid riid);
}
//Helper to initialize UserConsentVerifier
public static class UserConsentVerifierInterop
{
public static IAsyncOperation<UserConsentVerificationResult> RequestVerificationForWindowAsync(IntPtr hWnd, string Message)
{
IUserConsentVerifierInterop userConsentVerifierInterop = (IUserConsentVerifierInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(UserConsentVerifier));
Guid guid = typeof(IAsyncOperation<UserConsentVerificationResult>).GUID;
return userConsentVerifierInterop.RequestVerificationForWindowAsync(hWnd, Message, ref guid);
}
}
}
This works fine if a Windows Hello is setup. It returns DeviceNotPresent when its not or similar errors. Trying to find an alternative where the windows password is provided instead. This code works but I'm not entirely happy with the fact I am using a password in the app's memory. (C++/CLR)
bool ValidateUser(String ^caption, String ^message)
{
bool result = false;
String^ userName = WindowsIdentity::GetCurrent()->Name;
std::wstring strUsername = marshal_as<std::wstring>(userName);
std::wstring strCaption = marshal_as<std::wstring>(caption);
std::wstring strMessage = marshal_as<std::wstring>(message);
CREDUI_INFOW info;
ZeroMemory(&info, sizeof(info));
info.cbSize = sizeof(info);
info.pszMessageText = strMessage.c_str();
info.pszCaptionText = strCaption.c_str();
ULONG authPackage = 0;
LPVOID pOut;
ULONG bufSize;
DWORD inBuffer = 0;
std::vector<uint8_t> credBuffer;
if (!CredPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, (LPWSTR)strUsername.c_str(), L"", NULL, &inBuffer)
&& ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
{
credBuffer.resize(inBuffer);
if (!CredPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, (LPWSTR)strUsername.c_str(), L"", credBuffer.data(), &inBuffer))
{
return false;
}
}
DWORD dwResult = CredUIPromptForWindowsCredentialsW(&info, 0, &authPackage, credBuffer.data(), inBuffer, &pOut, &bufSize, NULL, CREDUIWIN_GENERIC | CREDUIWIN_IN_CRED_ONLY);
if (dwResult == ERROR_SUCCESS)
{
DWORD dwUserLength = 0;
DWORD dwDomainLength = 0;
DWORD dwPasswordLength = 0;
try
{
if (!::CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, pOut, bufSize, nullptr, &dwUserLength, nullptr, &dwDomainLength, nullptr, &dwPasswordLength)
&& ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
{
std::vector<wchar_t> bufferUser(dwUserLength);
std::vector<wchar_t> bufferDomain(dwDomainLength);
std::vector<wchar_t> bufferPassword(dwPasswordLength);
if (::CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, pOut, bufSize, bufferUser.data(), &dwUserLength, bufferDomain.data(), &dwDomainLength, bufferPassword.data(), &dwPasswordLength))
{
HANDLE hToken;
std::wstring strUsername = bufferUser.data();
std::wstring strDomain;
if (bufferDomain.size() == 0)
{
std::wstring::size_type pos = strUsername.find(L'\\');
if (pos != std::wstring::npos)
{
strDomain = strUsername.substr(0, pos);
strUsername = strUsername.substr(pos + 1, strUsername.size() - pos - 1);
}
}
else
{
strDomain = bufferDomain.data();
}
try
{
if (::LogonUserW(strUsername.c_str(), strDomain.c_str(), bufferPassword.data(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
result = true;
}
catch (...) // Catch so memory can be cleared
{
}
ClearBuffer(bufferUser.data(), dwUserLength);
ClearBuffer(bufferDomain.data(), dwDomainLength);
ClearBuffer(bufferPassword.data(), dwPasswordLength);
}
}
}
catch(...) // Catch so memory can be cleared
{
}
ClearBuffer(pOut, bufSize);
CoTaskMemFree(pOut);
}
return result;
}
Is there a way to use CredUIPromptForWindowsCredentialsW without unpacking the buffer it returns to verify the login?
I researched a lot about my problem and found many questions relative to [how to pass string from c# to c dll] :
Passing strings from C# to C++ DLL and back -- minimal example
https://www.codeproject.com/Articles/1189085/%2FArticles%2F1189085%2FPassing-strings-between-managed-and-unmanaged-code
But none of them couldn't help me. Any way I prefer to ask my question :
Briefly explanation :
My c function working properly in c# just when I interchange the GetProcessIntegrityLevel parameters (both in c dll and also in c# import-dll) from :
BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel);
To this one :
BOOL GetProcessIntegrityLevel(LPSTR szIntegrityLevel, DWORD dwPID);
In 1st state my program working properly and changes the LPSTR szIntegrityLevel But in 2nd, It doesn't work and LPSTR szIntegrityLevel is always empty with any pid.
I created a c dll library in which I declared the following c function that get Integrity Level of a process through a pid :
#define MAX_INTEGRITY_LEVEL_LENGTH 30
extern "C"
{
__declspec(dllexport) BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel);
}
C function implementation :
BOOL GetProcessIntegrityLevel(DWORD dwPID, LPSTR szIntegrityLevel)
{
BOOL bFlag = FALSE; // Return flag
HANDLE hToken = INVALID_HANDLE_VALUE; // Token handle
HANDLE hProcess = NULL; // Process handle
BOOL bProcToken = FALSE; // OpenProcessToken() result
BOOL bTokenInfo = FALSE; // GetTokenInformation() result
DWORD dwLengthNeeded = 0; // Token information length
DWORD dwError = ERROR_SUCCESS; // GetTokenInformation() last error
DWORD dwIntegrityLevel = 0; // Integrity level
PTOKEN_MANDATORY_LABEL pTIL = NULL; // Use as token information
// Open the process
hProcess = OpenProcess(MAXIMUM_ALLOWED | PROCESS_QUERY_LIMITED_INFORMATION,
FALSE, dwPID);
if (hProcess != NULL)
{
// Open process token
bProcToken = OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (bProcToken == TRUE)
{
// Get token information
bTokenInfo = GetTokenInformation(hToken, TokenIntegrityLevel,
NULL, 0, &dwLengthNeeded);
if (bTokenInfo == FALSE)
{
dwError = GetLastError();
if (dwError == ERROR_INSUFFICIENT_BUFFER)
{
pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwLengthNeeded);
if (pTIL != NULL)
{
// Get token information
bTokenInfo = GetTokenInformation(hToken, TokenIntegrityLevel,
pTIL, dwLengthNeeded, &dwLengthNeeded);
if (bTokenInfo == TRUE)
{
// Get integrity level
dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
if (dwIntegrityLevel <= SECURITY_MANDATORY_LOW_RID)
{
// Low Integrity
StrCpyA(szIntegrityLevel, "Low");
}
else if ((dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID) &&
(dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID))
{
// Medium Integrity
StrCpyA(szIntegrityLevel, "Medium");
}
else if ((dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) &&
(dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID))
{
// High Integrity
StrCpyA(szIntegrityLevel, "High");
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID)
{
// System Integrity
StrCpyA(szIntegrityLevel, "System");
}
else if (dwIntegrityLevel == SECURITY_MANDATORY_UNTRUSTED_RID)
{
// Untrusted integrity
StrCpyA(szIntegrityLevel, "Untrusted");
}
else
{
StrCpyA(szIntegrityLevel, "UnKnown");
}
bFlag = TRUE;
}
LocalFree(pTIL);
}
}
}
// Close token handle
CloseHandle(hToken);
}
// Close the process handle
CloseHandle(hProcess);
}
return bFlag;
}
So, I import GetProcessIntegrityLevel() from my c dll in c# as following :
// Define function pointers for using of c dll functions
[DllImport("ProcessesPropDll.dll",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
// Get integrity level
static extern bool GetProcessIntegrityLevel(ulong dwPID, StringBuilder szIntegrityLevel);
And call the function in c# like this :
// Integrity level
StringBuilder integrityLevel = new StringBuilder(200);
if(GetProcessIntegrityLevel(11684, integrityLevel) == true)
{
MessageBox.Show(integrityLevel.ToString());
}
In this state when i run the program, the GetProcessIntegrityLevel() returns true but integrityLevel is always empty in messagebox for any pid!!!!
‌Surprisingly, when I interchange the parameters in my c function and also in c#, It does work :
__declspec(dllexport) BOOL GetProcessIntegrityLevel(LPSTR szIntegrityLevel, DWORD dwPID);
This is very strange for me. Also I tried with MarshalAs(UnmanagedType.LPStr)] but give me the same result.
In C# ulong is a 64 bit type. The PID parameter is DWORD which is a 32 bit parameter.
Change your C# parameter declaration from ulong to uint to fix the problem.
thank you for any amount of time spent trying to answer this.
I'm trying to create a DLL that open's a window from within the DLL. I'm running the created DLL with C#. The DLL is created in VSC, and the C# code compiled with VSC#.
The window is intalized with a call to Initalize(const char* title) or Initalize(string title) in C#. Regardless of how I try to do it, the created window is created, run's, but it's title is'nt the passed string. I've tryed using const wchar_t*, LPCSTR, LPCWSTR, System.String, [MarshalAs(UnmanagedType.LPStr)], [MarshalAs(UnmanagedType.LPWStr)]. I've tryed copying the passed string into a dynamically allocated array, allocated with new/delete and malloc/free.
I'd think it was a pointer error, but what get's me the most is that printf("passed string: %s", title) in my C++ code prints the correct title into the console, but my window looks like:
My C++ code is:
// GameInterface.cpp : Defines the exported functions for the DLL application.
//
#include "GameInterface.h"
#include <Windows.h>
// OpenGL was origionally implimented into here, and removed to be asked on StackOverflow.
LRESULT WINAPI DLLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HINSTANCE hInstance = NULL;
ATOM wclAtom = NULL;
HWND hWnd = NULL;
HDC hDC = NULL;
HGLRC hRC = NULL;
bool running = false;
#if _DEBUG
#include <stdio.h>
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
#if _DEBUG
printf("GameInterface.dll::DllMain()\n");
#endif
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
hInstance = hModule;
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
Shutdown();
break;
}
return TRUE;
}
GAMEINTERFACE_API int Initalize(const char* title)
{
if (hWnd != NULL)
return 0;
#if _DEBUG
printf("GameInterface.dll::Initalize(\"%s\")\n", title);
#endif
int length = strlen(title);
char* name = new char[length+1];
strcpy(name, title);
WNDCLASSEXA wcl;
wcl.cbSize = sizeof(WNDCLASSEXA);
wcl.style = CS_OWNDC;
wcl.lpfnWndProc = DLLWindowProc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hInstance = hInstance;
wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
wcl.lpszMenuName = NULL;
wcl.lpszClassName = name;
wcl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wclAtom = RegisterClassExA(&wcl);
#if _DEBUG
printf(" Registering Class\n");
#endif
if (!wclAtom)
{
#if _DEBUG
printf(" Error: Could not Register Class.\nExiting with error: %i\n", GetLastError() );
#endif
return 1;
}
#if _DEBUG
printf(" Creating Window\n");
#endif
hWnd = CreateWindowExA(0,
(LPCSTR)wclAtom,
(LPCSTR)name,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
512, 512,
NULL, NULL,
hInstance, NULL);
if (hWnd == NULL)
{
#if _DEBUG
printf(" Error: Window could not be created.\nExiting with error: %i\n", GetLastError() );
#endif
return 2;
}
#if _DEBUG
printf(" Displaying Window\n");
#endif
// to reduce size removed the code to initalize an OpenGL 3.1 context
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
running = true;
delete [] name;
#if _DEBUG
printf("Returning from GameInterface.dll::Initalize(const char*) with errors: %i\n", GetLastError() );
#endif
return 0;
}
GAMEINTERFACE_API void Shutdown()
{
if (running = false)
return;
#if _DEBUG
printf("GameInterface.dll::Shutdown()\n");
#endif
running = false;
wglMakeCurrent(NULL, NULL);
if (hRC != NULL) wglDeleteContext(hRC);
if (hDC != NULL) ReleaseDC(hWnd, hDC);
hRC = NULL;
hDC = NULL;
DestroyWindow(hWnd);
UnregisterClassA( (LPCSTR)wclAtom, hInstance);
wclAtom = NULL;
hWnd = NULL;
running = false;
}
GAMEINTERFACE_API int Update()
{
if ( (running == false) && (hWnd == NULL) )
return 1;
MSG msg;
if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (running == false)
return 1;
return 0;
}
GAMEINTERFACE_API void DrawFrame()
{
// Contained some OpenGL code that has now been removed.
}
LRESULT WINAPI DLLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
running = false;
break;
// handle other messages.
default: // anything we dont handle.
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0; // just in case
}
// GameInterface.h : Outlines the exported functions for the DLL application.
//
#pragma once
#ifdef GAMEINTERFACE_EXPORTS
#define GAMEINTERFACE_API __declspec(dllexport)
#else
#define GAMEINTERFACE_API __declspec(dllimport)
#endif
extern "C"
{
GAMEINTERFACE_API int Initalize(const char* title);
GAMEINTERFACE_API void Shutdown();
GAMEINTERFACE_API int Update();
GAMEINTERFACE_API void DrawFrame();
};
And the C# code:
// GameInterface.cs
//
using System;
using System.Runtime.InteropServices;
class GameInterface
{
const string GameInterfaceFile = "GameInterface_d.dll";
[DllImport(GameInterfaceFile)] public extern static int Initalize(string title);
[DllImport(GameInterfaceFile)] public extern static void Shutdown();
[DllImport(GameInterfaceFile)] public extern static int Update();
[DllImport(GameInterfaceFile)] public extern static void DrawFrame();
};
// Program.cs
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class Program
{
public static void Main()
{
string title = "OpenGL Window Title";
if (GameInterface.Initalize(title) != 0)
return;
while ( GameInterface.Update() == 0 )
{
// game logic.
GameInterface.DrawFrame();
}
GameInterface.Shutdown();
}
}
I'm stumped, have been for a while now.
Are you defining UNICODE and _UNICODE in your C++ build? You need to be, for the C# to talk to it like that.
In the Visual Studio properties for your C++ project, under General, set Character Set to Use Unicode Character Set. Double-check that /D "UNICODE" and /D "_UNICODE" appear on the C/C++ / Command Line page.
(The opposite approach is to declare your exports as ANSI, but that's a poorer solution. You should be supporting Unicode.)
This could be because the code is expecting ANSI.
What happens if you try this:
[DllImport(GameInterfaceFile, CharSet=CharSet.Ansi)] public extern static int Initalize(string title)
I have a WPF application with two PasswordBoxes, one for the password and another for the password to be entered a second time for confirmation purposes. I was wanting to use PasswordBox.SecurePassword to get the SecureString of the password, but I need to be able to compare the contents of the two PasswordBoxes to ensure equality before I accept the password. However, two identical SecureStrings are not considered equal:
var secString1 = new SecureString();
var secString2 = new SecureString();
foreach (char c in "testing")
{
secString1.AppendChar(c);
secString2.AppendChar(c);
}
Assert.AreEqual(secString1, secString2); // This fails
I was thinking comparing the Password property of the PasswordBoxes would defeat the point of accessing only SecurePassword because I'd be reading the plain-text password. What should I do to compare the two passwords without sacrificing security?
Edit: based on this question, I'm checking out this blog post about "using the Marshal class to convert the SecureString to ANSI or Unicode or a BSTR", then maybe I can compare those.
This doesn't have unsafe blocks and won't display the password in plaintext:
public static bool IsEqualTo(this SecureString ss1, SecureString ss2)
{
IntPtr bstr1 = IntPtr.Zero;
IntPtr bstr2 = IntPtr.Zero;
try
{
bstr1 = Marshal.SecureStringToBSTR(ss1);
bstr2 = Marshal.SecureStringToBSTR(ss2);
int length1 = Marshal.ReadInt32(bstr1, -4);
int length2 = Marshal.ReadInt32(bstr2, -4);
if (length1 == length2)
{
for (int x = 0; x < length1; ++x)
{
byte b1 = Marshal.ReadByte(bstr1, x);
byte b2 = Marshal.ReadByte(bstr2, x);
if (b1 != b2) return false;
}
}
else return false;
return true;
}
finally
{
if (bstr2 != IntPtr.Zero) Marshal.ZeroFreeBSTR(bstr2);
if (bstr1 != IntPtr.Zero) Marshal.ZeroFreeBSTR(bstr1);
}
}
Edit: Fixed the leak as recommended by Alex J.
It looks like you could use this to compare the two SecureStrings.
It uses unsafe code to iterate through the strings:
bool SecureStringEqual(SecureString s1, SecureString s2)
{
if (s1 == null)
{
throw new ArgumentNullException("s1");
}
if (s2 == null)
{
throw new ArgumentNullException("s2");
}
if (s1.Length != s2.Length)
{
return false;
}
IntPtr bstr1 = IntPtr.Zero;
IntPtr bstr2 = IntPtr.Zero;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
bstr1 = Marshal.SecureStringToBSTR(s1);
bstr2 = Marshal.SecureStringToBSTR(s2);
unsafe
{
for (Char* ptr1 = (Char*)bstr1.ToPointer(), ptr2 = (Char*)bstr2.ToPointer();
*ptr1 != 0 && *ptr2 != 0;
++ptr1, ++ptr2)
{
if (*ptr1 != *ptr2)
{
return false;
}
}
}
return true;
}
finally
{
if (bstr1 != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(bstr1);
}
if (bstr2 != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(bstr2);
}
}
}
I have modified it below to work without unsafe code (note however you are able to see the string in plain text when debugging):
Boolean SecureStringEqual(SecureString secureString1, SecureString secureString2)
{
if (secureString1 == null)
{
throw new ArgumentNullException("s1");
}
if (secureString2 == null)
{
throw new ArgumentNullException("s2");
}
if (secureString1.Length != secureString2.Length)
{
return false;
}
IntPtr ss_bstr1_ptr = IntPtr.Zero;
IntPtr ss_bstr2_ptr = IntPtr.Zero;
try
{
ss_bstr1_ptr = Marshal.SecureStringToBSTR(secureString1);
ss_bstr2_ptr = Marshal.SecureStringToBSTR(secureString2);
String str1 = Marshal.PtrToStringBSTR(ss_bstr1_ptr);
String str2 = Marshal.PtrToStringBSTR(ss_bstr2_ptr);
return str1.Equals(str2);
}
finally
{
if (ss_bstr1_ptr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(ss_bstr1_ptr);
}
if (ss_bstr2_ptr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(ss_bstr2_ptr);
}
}
}
Translating #NikolaNovák answer to plain PowerShell:
param(
[Parameter(mandatory=$true,position=0)][SecureString]$ss1,
[Parameter(mandatory=$true,position=1)][SecureString]$ss2
)
function IsEqualTo{
param(
[Parameter(mandatory=$true,position=0)][SecureString]$ss1,
[Parameter(mandatory=$true,position=1)][SecureString]$ss2
)
begin{
[IntPtr] $bstr1 = [IntPtr]::Zero;
[IntPtr] $bstr2 = [IntPtr]::Zero;
[bool]$answer=$true;
}
process{
try{
$bstr1 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ss1);
$bstr2 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ss2);
[int]$length1 = [System.Runtime.InteropServices.Marshal]::ReadInt32($bstr1, -4);
[int]$length2 = [System.Runtime.InteropServices.Marshal]::ReadInt32($bstr2, -4);
if ($length1 -eq $length2){
for ([int]$x -eq 0; $x -lt $length1; ++$x){
[byte]$b1 = [System.Runtime.InteropServices.Marshal]::ReadByte($bstr1, $x);
[byte]$b2 = [System.Runtime.InteropServices.Marshal]::ReadByte($bstr2, $x);
if ($b1 -ne $b2){
$answer=$false;
}
}
}
else{ $answer=$false;}
}
catch{
}
finally
{
if ($bstr2 -ne [IntPtr]::Zero){ [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr2)};
if ($bstr1 -ne [IntPtr]::Zero){ [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr1)};
}
}
END{
return $answer
}
}
IsEqualTo -ss1 $ss1 -ss2 $ss2
If the code is running on Windows Vista or higher, here is a version that's based on the CompareStringOrdinal Windows function, so there's no plain text, all buffers stay unmanaged. Bonus is it supports case-insensitive comparison.
public static bool EqualsOrdinal(this SecureString text1, SecureString text2, bool ignoreCase = false)
{
if (text1 == text2)
return true;
if (text1 == null)
return text2 == null;
if (text2 == null)
return false;
if (text1.Length != text2.Length)
return false;
var b1 = IntPtr.Zero;
var b2 = IntPtr.Zero;
try
{
b1 = Marshal.SecureStringToBSTR(text1);
b2 = Marshal.SecureStringToBSTR(text2);
return CompareStringOrdinal(b1, text1.Length, b2, text2.Length, ignoreCase) == CSTR_EQUAL;
}
finally
{
if (b1 != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(b1);
}
if (b2 != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(b2);
}
}
}
public static bool EqualsOrdinal(this SecureString text1, string text2, bool ignoreCase = false)
{
if (text1 == null)
return text2 == null;
if (text2 == null)
return false;
if (text1.Length != text2.Length)
return false;
var b = IntPtr.Zero;
try
{
b = Marshal.SecureStringToBSTR(text1);
return CompareStringOrdinal(b, text1.Length, text2, text2.Length, ignoreCase) == CSTR_EQUAL;
}
finally
{
if (b != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(b);
}
}
}
private const int CSTR_EQUAL = 2;
[DllImport("kernel32")]
private static extern int CompareStringOrdinal(IntPtr lpString1, int cchCount1, IntPtr lpString2, int cchCount2, bool bIgnoreCase);
[DllImport("kernel32")]
private static extern int CompareStringOrdinal(IntPtr lpString1, int cchCount1, [MarshalAs(UnmanagedType.LPWStr)] string lpString2, int cchCount2, bool bIgnoreCase);
You could take a different approach. I hit the same problem in my code, the comparison of a password and a confirmation, both of type SecureString. I realised that the end goal was that the new password needs to be stored in the database as a base-64 string. So what I did was simply pass the confirmation string through the same code as if I were going to write it to the database. Then, when I have two base-64 strings, I compare them at that point, which is a simple string comparison.
It does take a bit more plumbing to communicate any failure all the way back to the UI layer, but the end result seemed acceptable. This code hopefully is enough to give the basic idea.
private string CalculateHash( SecureString securePasswordString, string saltString )
{
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode( securePasswordString );
byte[] passwordBytes = Encoding.UTF8.GetBytes( Marshal.PtrToStringUni( unmanagedString ) );
byte[] saltBytes = Encoding.UTF8.GetBytes( saltString );
byte[] passwordPlusSaltBytes = new byte[ passwordBytes.Length + saltBytes.Length ];
Buffer.BlockCopy( passwordBytes, 0, passwordPlusSaltBytes, 0, passwordBytes.Length );
Buffer.BlockCopy( saltBytes, 0, passwordPlusSaltBytes, passwordBytes.Length, saltBytes.Length );
HashAlgorithm algorithm = new SHA256Managed();
return Convert.ToBase64String( algorithm.ComputeHash( passwordPlusSaltBytes ) );
}
finally
{
if( unmanagedString != IntPtr.Zero )
Marshal.ZeroFreeGlobalAllocUnicode( unmanagedString );
}
}
string passwordSalt = "INSERT YOUR CHOSEN METHOD FOR CONSTRUCTING A PASSWORD SALT HERE";
string passwordHashed = CalculateHash( securePasswordString, passwordSalt );
string confirmPasswordHashed = CalculateHash( secureConfirmPasswordString, passwordSalt );
if( passwordHashed == confirmPasswordHashed )
{
// Both matched so go ahead and persist the new password.
}
else
{
// Strings don't match, so communicate the failure back to the UI.
}
I am a bit of a newbie at security programming, so I welcome any suggestions for improvement.