C# Random Exception when Getting / Setting Registry ACL "SeSecurityPrivilege" - c#

I've been getting a completely random exception, I can run the same set of code 1000 times (each "run" is a full end-end of the program and thus starts as its own process from commandline and then exists) and get it fail once, or even 150 times. And I mean I can run it back-back over and over and it will fail completely randomly.
System.Security.AccessControl.PrivilegeNotHeldException: The process does not possess the 'SeSecurityPrivilege' privilege which is required for this operation.
at System.Security.AccessControl.Win32.GetSecurityInfo(ResourceType resourceType, String name, SafeHandle handle, AccessControlSections accessControlSections, RawSecurityDescriptor& resultSd)
at System.Security.AccessControl.NativeObjectSecurity.CreateInternal(ResourceType resourceType, Boolean isContainer, String name, SafeHandle handle, AccessControlSections includeSections, Boolean createByName, ExceptionFromErrorCode exceptionFromErrorCode, Object exceptionContext)
at System.Security.AccessControl.RegistrySecurity..ctor(SafeRegistryHandle hKey, String name, AccessControlSections includeSections)
at Microsoft.Win32.RegistryKey.GetAccessControl(AccessControlSections includeSections)
I can't get it to fail when debugging so am having issues trying to see why it randomly decides to fail. As its failing inside the (RegistryKey).GetAccessControl(AccessControlSections.All) method, I'm stumped as to what I should try next.
Also, I'm looping through multiple keys, and if it decides to fail with this permission exception on one, they all fail for that process.
I'm running from command line (as admin, UACed in), starting the process and then it exists. From that same command line I start the process again, and it will randomly fail.
I am loading user hives and making sure that the registry rights are elevated, and it works except for this random bug.
Also, the issue occurs on multiple machines (always running locally, not remote), both under system (psexec) and administrator accounts.

I don't think that the System account has the SeSecurityPrivilege enabled, or an admin for that matter.
Instead of (RegistryKey).GetAccessControl(AccessControlSections.All), try: (RegistryKey).GetAccessControl(AccessControlSections.Access)
Does that still give you the error? You won't be able to get the SACL with Access though.
EDIT: I grabbed some code from pinvoke for adjusting the privileges in an access token, you'll need admin rights to do it; I modified it for the SeSecurityPrivilege, you should be able to use (RegistryKey).GetAccessControl(AccessControlSections.All) now without any errors once "SetPriv();" is called. I was able to verify that it is working by using Process Hacker 2 and checking the token before and after, it is enabling SeSecuirtyPrivilege:
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const string SeSecurity = "SeSecurityPrivilege";
private bool SetPriv()
{
try
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, SeSecurity, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex)
{
throw;
return false;
}
}

Related

How to get the target location of a Junction if the target directory does not exist?

I have a junction from A -> B.
B does not exist, but I want to read from A the target of the junction (B).
However I can't make this work (filename = A):
// directoryHandle.isInvalid == true
var directoryHandle = CreateFile(filename, EFileAccess.GenericRead, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);
StringBuilder path = new StringBuilder(1024);
// path is empty string
var res = GetFinalPathNameByHandle(directoryHandle, path, path.Capacity, 0);
GetFinalPathNameByHandle returns the location of the junction if B exists. But if B does not exist, I receive an invalid file handle so that the call to GetFinalPathNameByHandle also fails.
Question: How do I get the target of a junction if the target directory does not exist?
Here are the method definitions:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern int GetFinalPathNameByHandle([In] SafeFileHandle hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder path, int bufLen, int flags);
Ask the junction directly.
To determine the type, use FindFirstFile (or GetFileInformationByHandleEx(FileAttributeTagInfo) if you already have a handle). The FILE_ATTRIBUTE_REPARSE_POINT bit must be set in the file attributes and the tag must be IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMLINK.
If all checks pass, call CreateFile with the FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS flags. Now call DeviceIoControl(FSCTL_GET_REPARSE_POINT) to read the REPARSE_DATA_BUFFER (allocate MAXIMUM_REPARSE_DATA_BUFFER_SIZE bytes for it). Look at the tag type to find PathBuffer and SubstituteNameOffset+SubstituteNameLength to find where in the buffer the path is.
You can find C# example code on Codeproject...

OpenFileById getting System.AccessViolationException when running as a user (Running as admin works)

I have some code which retrieves the 128bit NTFS Ids from files at specific paths. Then I attempted to retrieve the file path using this ID. The code works as long as when retrieving the paths I run as admin. This is not going to be possible in production. Unfortunately I am unable to call Marshal.GetLastWin32Error() because the System.AccessViolationException causes the application to completely crash. Below is the code to retrieve the paths.
public const int NO_PERMISSION = 0;
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
[InAttribute()] System.IntPtr hTemplateFile
);
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle OpenFileById(
IntPtr hVolumeHint,
FILE_ID_DESCRIPTOR lpFileId,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwFlagsAndAttributes
);
public enum _FILE_ID_TYPE
{
FileIdType = 0,
ObjectIdType,
ExtendedFileIdType,
MaximumFileIdType
}
[StructLayout(LayoutKind.Explicit)]
public struct FILE_ID_128
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
[FieldOffset(0)]
public byte[] Identifier;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_ID_DESCRIPTOR
{
public uint dwSize;
public _FILE_ID_TYPE Type;
public FILE_ID_128 ExtendedFileId;
}
public static string GetObjectPathFromId(string pathToSection, string hexId)
{
// We need a file handle to the drive we are looking in
using (SafeFileHandle handle = Methods.CreateFile(
pathToSection,
Constants.NO_PERMISSION,
Constants.NO_PERMISSION,
IntPtr.Zero,
Constants.OPEN_EXISTING,
0x02000000 | 0x00000080,
IntPtr.Zero))
{
// Build descriptor
FILE_ID_DESCRIPTOR descriptor = new FILE_ID_DESCRIPTOR();
descriptor.dwSize = (uint)Marshal.SizeOf(descriptor);
descriptor.Type = _FILE_ID_TYPE.ExtendedFileIdType;
descriptor.ExtendedFileId.Identifier = StringToByteArrayFastest(hexId);
using (SafeFileHandle actualFile = OpenFileById(handle.DangerousGetHandle(), descriptor,
Constants.NO_PERMISSION, Constants.NO_PERMISSION,
IntPtr.Zero, 0))
{
if (actualFile.IsInvalid)
return "";
// Buffer for the path, this should be way big enough
int sizeOfBuffer = 1024;
// Allocate a buffer
IntPtr pointer = Marshal.AllocHGlobal(sizeOfBuffer);
uint size = (uint)sizeOfBuffer;
uint returnValue = GetFinalPathNameByHandleW(actualFile.DangerousGetHandle(), pointer, size, 0);
// Copy it into a managed array
byte[] outPut = new byte[sizeOfBuffer];
Marshal.Copy(pointer, outPut, 0, (int)returnValue);
// Decode it
var str = Encoding.Unicode.GetString(outPut);
// Will be an empty string if the call fails
return str;
}
}
}
Again I want to specify - this code works perfectly when running as admin. The files are owned by the user, the user is able to delete, rename and move the files without any additional permissions.
Any help would be greatly appreciated thanks!
Edit1:
I implemented the answer found here How to handle AccessViolationException to successfully catch the exception. However even after doing this Marshal.GetLastWin32Error() returns 0. If anyone has any idea of how I can debug this type of issue please let me know.
Also it's still functioning when I run as admin, just not as a user.
Edit2:
Not sure if it's relevant - library with this code is building for .NET Standard 2.0 - Application using this library code is building for .NET Framework 4.6.2

C# Pinvoke invalid file handle

I'm having a problem with kernal32 Pinvoke functions as they keeps throwing an INVALID_FILE_HANDLE. The program reads the first sector of the current hard disk. I can't see what is wrong with the following code.
class Program
{
const uint GENERIC_READ = 0x80000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint OPEN_EXISTING = 0x00000003;
const uint FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle CreateFile(string Disk, uint Access, uint ShareMode, IntPtr SecurityAttributes, uint CreationDisposition, uint Flags, IntPtr TemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetFilePointer([In] SafeFileHandle Handle, [In] int DistanceToMove, [Out] out int DistanceToMoveHigh, [In] int MoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
unsafe public static extern int ReadFile(SafeFileHandle Handle, [Out] byte[] Buffer, int NumberOfBytesToRead, out int NumberOfBytesRead, IntPtr Overlapped);
unsafe public static void Main(string[] args)
{
string Drive = #"\\.\C";
int SectorSize = 512;
int Sector = 0;
int BytesRead, DistanceToMoveHigh;
byte[] Buffer = new byte[SectorSize];
SafeFileHandle Handle = CreateFile(Drive, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, IntPtr.Zero);
SetFilePointer(Handle, Sector * SectorSize, out DistanceToMoveHigh, 0);
ReadFile(Handle, Buffer, SectorSize, out BytesRead, IntPtr.Zero);
Console.WriteLine(Marshal.GetLastWin32Error()); // It gives 6 which translates to an INVALID_FILE_HANDLE error
Console.ReadKey();
}
}
Your call to CreateFile fails. Of course you cannot know that because you omitted any error checking. Read the documentation. Errors for all three functions that you call are signaled by the return value. Which you ignore.
Your call to CreateFile returns INVALID_HANDLE_VALUE. You need to test for that. When you encounter that, and only then, call GetLastWin32Error. Likely ERROR_ACCESS_DENIED will be returned then.
Passing FILE_FLAG_DELETE_ON_CLOSE is a mistake. Remove that flag.
I believe that the share flags must be FILE_SHARE_READ | FILE_SHARE_WRITE.
The file name must be #"\\.\C:" with a trailing colon.
And you will need the process to be executed elevated.
You use GetLastWin32Error in a wrong way.
The method that fails here is CreateFile and it returns an INVALID_HANDLE_VALUE (indicating that it failed). To determine what went wrong you have to call GetLastWin32Error directly after CreateFile.
When you call it after trying to read, the error is of course ERROR_INVALID_HANDLE (6) as you passed an invalid handle to ReadFile.
If you call GetLastWin32Error directly after the failing CreateFile you get error 2:
The system cannot find the file specified.
That is because the the drive name misses a :
string Drive = #"\\.\C:"; // <- add colon :
I tried with that drive name, but then got the error 32:
The process cannot access the file because it is being used by another process.
I keep trying to figure out how that can be handled...

C# Monitor ECX register every time breakpoint is fired

How do I monitor current ECX register in C# at given ASM opcode?
Say, I have a:
FF8.exe+69DD8 - push ecx
Using any ready debugger I can do a breakpoint at given opcode and watch registers.
But I need to make an automation software to:
Catch every time 'push ecx' is called and add it to table with the time it was called to know how often is it called.
It's something like cut-scene with different sounds being played, and we need to know what's the time the sounds are played, one after another
Why I can't use ready softwares for this?
Because when I breakpoint 'push ecx', (note: ecx register) and then step over I lose whole timing. I need to do a table with detailed times in which this opcode is accesed.
After four years I am getting back to respond to my own question- Yes, we have to create our own debugger.
It's as simple as calling P/Invoke:
[DllImport("kernel32.dll")]
public static extern bool DebugActiveProcess(int dwProcessId);
Get process id (pId) and call DebugActiveProcess:
Process[] processes = Process.GetProcessesByName(args[0]);
bool bAttached = pinvokes.DebugActiveProcess(processes[0].Id);
Create new struct of DEBUG_EVENT - it would contain all the data about breakpoint
Wait for debug event in a while loop:
WaitForDebugEvent(ref debug, 0xFFFFFFFF);
The breakpoint 0xCC opcode will trigger the EXCEPTION_BREAKPOINT. You now have the threadId associated with given exception. You have to now get the thread context by GetThreadContext- the CONTEXT structure will now contain CPU registers including ECX. You just need to add p/invoke for GetThreadContext and structure for CONTEXT. Full structure and an example can be seen here: http://www.pinvoke.net/default.aspx/kernel32/GetThreadContext.html
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
The process code will break on every debugging event even on DLL_LOAD. To set a breakpoint at given address you have to actually write an INT 3 opcode. To do that you have to open process in R/W and inject 0xCC to process memory. Use OpenProcess p/invoke and WriteProcessMemory p/invoke:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);
public static IntPtr OpenProcess(Process proc, ProcessAccessFlags flags)
{
return OpenProcess(flags, false, proc.Id);
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[MarshalAs(UnmanagedType.AsAny)] object lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesWritten);
Now we have everything required to open, write opcode and break when any thread arrive on that position:
IntPtr procHwnd = pinvokes.OpenProcess(processes[0], pinvokes.ProcessAccessFlags.All);
WriteProcessMemory(procHwnd, new IntPtr(0x469DD8), new byte[] { 0xCC }, 1, out IntPtr lpnum);
the lpAddress should be absolute virtual address- that means that in the question there's FF8.exe+69DD8, so we need to get IMAGE_BASE for selected module which in this case is "FF8.exe" and then add 0x69DD8 to that IMAGE_BASE. Naturally every 32-bit non ASLR processes have IMAGE_BASE set at 0x400000. For ASLR activated processes you have to get process modules and get the BaseAddress like this:
foreach(var mod in processes[0].Modules)
{
if ((mod as ProcessModule).ModuleName == args[3])
{
image_base = (mod as ProcessModule).BaseAddress;
break;
}
}
where args[3] == "FF8.exe"- this should return 0x400000 for non-ASLR processes on 32bit

Using SetCommTimeouts on parallel port fails

SetCommTimeouts and GetCommTimeouts are the function in kernel32 to set and get timeout when communicate with devices.
Now GetCommTimeouts works for me, but SetCommTimeouts returns error code 87 which indicates parameter error.
Now my question is whether this SetCommTimeouts works when it talks to a parallel port?
If so what can do I to fix it?
[DllImport("kernel32.dll")]
private static extern bool SetCommTimeouts(IntPtr hFile, ref LPCOMMTIMEOUTS lpCommTimeouts);
[DllImport("kernel32.dll ")]
private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
[StructLayout(LayoutKind.Sequential)]
private struct LPCOMMTIMEOUTS
{
public UInt32 ReadIntervalTimeout;
public UInt32 ReadTotalTimeoutMultiplier;
public UInt32 ReadTotalTimeoutConstant;
public UInt32 WriteTotalTimeoutMultiplier;
public UInt32 WriteTotalTimeoutConstant;
}
private const uint GENERIC_WRITE = 0x40000000;
private const int OPEN_EXISTING = 3;
PHandler = CreateFile("LPT1", GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
IntPtr hnd = new System.IntPtr(PHandler);
LPCOMMTIMEOUTS lpcto = new LPCOMMTIMEOUTS();
Boolean bb = SetCommTimeouts(hnd, ref lpcto);
Console.WriteLine(bb); // get false here
Your declaration for CreateFile() is quite wrong and can never work in 64-bit mode. Since you don't do any of the required error checking and just keep plowing on, the next call that will fail is your SetCommTimeouts() call. It will complain about getting a bad handle value. Make it look like this instead:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFile(
string FileName,
FileAccess DesiredAccess,
FileShare ShareMode,
IntPtr SecurityAttributes,
FileMode CreationDisposition,
FileAttributes FlagsAndAttributes,
IntPtr TemplateFile);
Proper error handling looks like this:
IntPtr hnd = CreateFile("LPT1", FileAccess.Write, FileShare.None, IntPtr.Zero,
FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
if (hnd == (IntPtr)-1) throw new System.ComponentModel.Win32Exception();
Additional failure modes are your machine not having a LPT1 port, parallel ports went the way of the dodo a long time ago. And the parallel port driver you have installed not supporting timeouts, it is normally only used for serial ports. Ask the vendor from which you obtained the parallel port hardware for support if necessary.

Categories

Resources