I created my own parental control app using C# to monitor my kids activity. It logs all the keyboard input and screens in the background silently, with the only gui of taskbar icon. So far, I just let it run in my admin account and everybody share the same account and it works fine. The problem is that as kids grow up, they found a way to kill it from the task manager. So, I need to use a more sophisticated way to protect my app. I thought I could solve this problem easily by creating a separate standard account for each kid and I can setup my app to run as an admin to monitor all their activities. However, I faced a lot of issues.
The keyboard hooks seem to stop working once I switched to a different user account. Is it true? I thought it's global hook - is it just global within the user account?
The screen capturing doesn't work on another user account either. This is my code and
it failed at g.CopyFromScreen with error "the handle is invalid":
RECT rc = Win32.GetWindowRect();
using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rc.Width, rc.Height))
{
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(rc.Location, System.Drawing.Point.Empty, new System.Drawing.Size(rc.Width, rc.Height));
string fileName = Settings.Instance.GetImageFileName();
bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
}
}
Your help is much appreciated.
As long as the kids aren't administrators, you can run the program under their accounts and deny access to the process.
For example (tested):
static void SetAcl() {
var sd = new RawSecurityDescriptor(ControlFlags.None,
new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
null, null, new RawAcl(2, 0));
sd.SetFlags(ControlFlags.DiscretionaryAclPresent | ControlFlags.DiscretionaryAclDefaulted);
var rawSd = new byte[sd.BinaryLength];
sd.GetBinaryForm(rawSd, 0);
if (!NativeMethods.SetKernelObjectSecurity(Process.GetCurrentProcess().Handle, SecurityInfos.DiscretionaryAcl, rawSd))
throw new Win32Exception();
}
static class NativeMethods {
[DllImport("Advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetKernelObjectSecurity(IntPtr target, SecurityInfos info, byte[] descriptor);
}
Related
I have just completed learning Java, now I am working on creating Android apps. But I am not so expert in this field. I have just created an Android app which has some advertisements like banner ad, interstitial ad. I want to give an opportunity to the user to stop those Ads for 24 hours if they watch a video AD. But I'm not familiar with timer task any suggestion will be very appreciating. here is the code that I imagine :
// load from shared preference
SharedPreference spref = getSharedPreference("directory_name", 0);
if(spref.getBoolean("ad_key", false)==true){
// all ads should stop showing
}else{
// ads are showing
}
// help me here in timer task
As ad reward
--> start countadown
--> if(countDown>0){
doneWatchindAd(true);
}else{
doneWatchindAd(false);
}
// store to shared preference
public void doneWatchindAd(bollean cond){
SharedPreference spref = getSharedPreference("directory_name", 0);
SharedPreference.Editor editor = spref.edit();
editor.putBoolean("ad_key", cond);
editor.commit();
}
I implemented an IBackgroundTask on Universal Windows 10 and it works like a charm but the problem is that i want to start the app that is associated to that background task if some action occurs. The code is simple:
public sealed class AdvertisementWatcherTask : IBackgroundTask
{
private IBackgroundTaskInstance backgroundTaskInstance;
public void Run(IBackgroundTaskInstance taskInstance)
{
backgroundTaskInstance = taskInstance;
var details = taskInstance.TriggerDetails as BluetoothLEAdvertisementWatcherTriggerDetails;
if (details != null)
{
//Do things
}
}
}
I've seen that you can create a ToastNotification like that:
Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
Windows.Data.Xml.Dom.XmlNodeList elements = toastXml.GetElementsByTagName("text");
foreach (IXmlNode node in elements)
{
node.InnerText = taskInstance.Task.Name+ " remember to uninstall task if not debugging";
}
ToastNotification notification = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(notification);
The notification toast works good. It creates and prompts a notification and if you click it, the app that created this background task starts. This is the behaviour that I want but I want to start the app without having to click any notification. Is there any way to achieve this? Thank you.
TL;DR: I want to start the app that created the background task at some point of the code.
You can not programmatically launch URI or open app from background task. You can however display a reminder or toast notification to let user open your app.
My service is running under local system permissions, and needs to start an application with administrator permissions in the user session.
What I got is:
WTSGetActiveConsoleSessionID()
WTSQueryUserToken for session ID
CreateProcessAsUser
The problem is I need to run the process (Step 3) as an administrator, without asking the user for the administrator's password.
On Linux systems I would simply do a "su ", but to achieve this on a Windows system?
I've finally found the solution to manage this:
public void launchProcessInUserSession(String process) throws WindowsAPIException {
final DWORD interactiveSessionId = kernel32.WTSGetActiveConsoleSessionId();
final DWORD serviceSessionId = getCurrentSessionId();
final HANDLEByReference pExecutionToken = new HANDLEByReference();
final HANDLE currentProcessToken = getCurrentProcessToken();
try {
final HANDLE interactiveUserToken = getUserToken(interactiveSessionId);
checkAPIError(advapi32.DuplicateTokenEx(currentProcessToken, WinNT.TOKEN_ALL_ACCESS, null, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
WinNT.TOKEN_TYPE.TokenPrimary, pExecutionToken));
} finally {
kernel32.CloseHandle(currentProcessToken);
}
final HANDLE executionToken = pExecutionToken.getValue();
try {
checkAPIError(advapi32.SetTokenInformation(executionToken, TOKEN_INFORMATION_CLASS.TokenSessionId, new IntByReference(interactiveSessionId.intValue()), DWORD.SIZE));
final WinBase.STARTUPINFO si = new WinBase.STARTUPINFO();
final PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
final int dwFlags = WinBase.DETACHED_PROCESS;
checkAPIError(advapi32.CreateProcessAsUser(executionToken, null, process, null, null, false, dwFlags, null, null, si, processInfo));
LOGGER.debug("Execution done. Process ID is {}", processInfo.dwProcessId);
} finally {
kernel32.CloseHandle(executionToken);
}
}
I need to run the process (Step 3) as administrator, without asking the user for the administrator's password.
If it were possible for a low privileged user to execute code as a privileged user, then the system's security model would be broken. If you want to execute code with administrator privileges then you need to supply appropriate credentials, at some point.
Your proposed plan of action has you calling CreateProcessAsUser passing the user token for a low privileged user. This plan, as itemized in the question, cannot succeed. Since the user token you will provide is that of the low privileged user, the process will not be able to perform administrative tasks.
You will need to provide, one way or another, credentials for a user with administrative rights.
I have a windows service that can create an executable in the users windows session, via calling the "CreateProcessAsUser" function. This works fine as long as there is a windows session already there. In the case that there isn't one already I'd like to be able to create one programmatically. Is this is possible? Can't seem to find a function to do it.
This isn't quite the solution for the question I asked, but it was the solution that helped achieve what I was trying to achieve by asking this question, if you see what I mean.
Rather than have having a windows services that creates a server session you can configure windows to automatically logon at boot time. This still means someone could accenditally log off, but cures the main reason for sessions disappearing: the server being rebooted. Use the following steps to activate auto-logon:
Press the Windows key + R on your keyboard to launch the “Run” dialog box.
Type regedit and hit enter to open the Registry Editor
Then browse to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\
Set AutoAdminLogon = 1 (create it if doesn't exist its a string variable)
Set DefaultUserName = your username (create it if doesn't exist its a string variable)
Set DefaultPassword = your password (create it if doesn't exist its a string variable)
Instructions were taken from this post:
http://channel9.msdn.com/Blogs/coolstuff/Tip-Auto-Login-Your-Windows-7-User-Account
You cannot create a new session from a service. Sessions are managed by the OS. New ones get created when users logon interactively.
#Robert, I know this is an old question and that you've already found something that works for you but in my case I was looking for something similar to your original question and I did finally figure it out so I thought I'd share. My solution uses only .NET and a COM reference not the Win32 API mentioned in your title, but I'm guessing that wasn't really a requirement for you.
I've written a simple utility to using the Remote Desktop ActiveX control (COM Reference). If you paste this code into a Class Library you can then call it by simply passing in the server, username, domain, and password and everything is done for you without any other interaction required. Once the method is complete you can then call your "CreateProcessAsUser" Code. I've written this utility in a way so that you could call it every time but initiating an RDP session takes several seconds so for performance sake I'd suggest you write another method to enumerate the sessions and see if your user is logged in and only call this utility when you determine that your user isn't logged in (That's what I did in my actual project). If you feel you need help with that post in the comments and I'll share how I did that but It's not really part of this question so for now I'm leaving it out.
Here's a link back to my question that has a few more requirements/details than this question.
Create Windows Session programmatically from Console or Windows Service
And here's my RDP utility. After you put this code in a class library you can then call it from a console app, winForms app, or from a windows service running on the same machine or from a remote machine.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
namespace Utility.RemoteDesktop
{
public class Client
{
private int LogonErrorCode { get; set; }
public void CreateRdpConnection(string server, string user, string domain, string password)
{
void ProcessTaskThread()
{
var form = new Form();
form.Load += (sender, args) =>
{
var rdpConnection = new AxMSTSCLib.AxMsRdpClient9NotSafeForScripting();
form.Controls.Add(rdpConnection);
rdpConnection.Server = server;
rdpConnection.Domain = domain;
rdpConnection.UserName = user;
rdpConnection.AdvancedSettings9.ClearTextPassword = password;
rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
if (true)
{
rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
}
rdpConnection.Connect();
rdpConnection.Enabled = false;
rdpConnection.Dock = DockStyle.Fill;
Application.Run(form);
};
form.Show();
}
var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
rdpClientThread.SetApartmentState(ApartmentState.STA);
rdpClientThread.Start();
while (rdpClientThread.IsAlive)
{
Task.Delay(500).GetAwaiter().GetResult();
}
}
private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
{
LogonErrorCode = e.lError;
}
private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
{
if (LogonErrorCode == -2)
{
Debug.WriteLine($" ## New Session Detected ##");
Task.Delay(10000).GetAwaiter().GetResult();
}
var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
rdpSession.Disconnect();
}
private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
Environment.Exit(0);
}
}
}
What about the LogonUser function?
http://winapi.freetechsecrets.com/win32/WIN32LogonUser.htm
I'm trying to wrap up my latest app and I want to make it a Free Trial app.
I've done all my checks to see if it is in trial mode or not and now I'm about to launch the MarketPlace so they can buy it. I have a couple of questions...
In this code below, do I have to pass any sort of ID that my app generates so that it knows where to go in the Marketplace? Or is it all done for me in this call?
MarketplaceDetailTask detailTask = new MarketplaceDetailTask();
detailTask.Show();
My second question is in regards to the tombstoning that will happen when this code gets called and what happens after they buy it? Is there some special event that I should be looking for (like a completed event)? From what I understand I need to recheck the license and I'm just wondering what the best practices are for that.
Just as a reference this is the example I'm currently following:
http://msdn.microsoft.com/en-us/library/ff967559%28v=VS.92%29.aspx
Thanks!
1) First Question: if you don't specify the id, WP7 will take the id of the calling app (yours)
2)I have a service in front of the Licence class and when the user goes to the marketplace I reset a field to read again the trial status when ask afterwards (see the buy method below)
public class TrialService : ITrialService
{
private LicenseInformation license;
public bool IsTrial()
{
if (RunAsTrial)
return true;
else
{
if (license == null)
license = new LicenseInformation();
return license.IsTrial();
}
}
public void Buy()
{
license = null;
var launcher = new MarketplaceDetailTask();
launcher.Show();
}
public bool RunAsTrial { get; set; }
}