Using SymSrvStoreFileW from DBGHELP - c#

I am trying to invoke SymSrvStoreFileW from DBGHELP.DLL (after a previous failed attempt at getting SymSrvGetFileIndexInfoW to work). The important functions are defined as follows in MSDN:
BOOL WINAPI SymInitialize(
_In_ HANDLE hProcess,
_In_opt_ PCTSTR UserSearchPath, // null is documented as fine
_In_ BOOL fInvadeProcess // false
);
PCTSTR WINAPI SymSrvStoreFile(
_In_ HANDLE hProcess,
_In_opt_ PCTSTR SrvPath, // e.g. "srv*C:\symbols"
_In_ PCTSTR File, // e.g. "C:\myapp.pdb"
_In_ DWORD Flags // I am using SYMSTOREOPT_RETURNINDEX (0x04)
);
BOOL WINAPI SymCleanup(
_In_ HANDLE hProcess
);
hProcess is a little strange, from the documentation I gather that it really doesn't matter what you pass into it, so long as you remain consistent. I have used both the current process ID and a 'any old value' ID. Neither worked.
I made the following externs:
[DllImport("dbghelp.dll", EntryPoint = "SymInitializeW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
public static extern bool SymInitialize(
IntPtr process,
[param: MarshalAs(UnmanagedType.LPTStr)]
string searchPath,
bool invadeProcess);
[DllImport("dbghelp.dll", EntryPoint = "SymCleanup", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
public static extern bool SymCleanup(IntPtr process);
[DllImport("dbghelp.dll", EntryPoint = "SymSrvStoreFileW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.LPTStr)]
public static extern string SymSrvStoreFile(
IntPtr process,
[param: MarshalAs(UnmanagedType.LPTStr)]
string srvPath,
[param: MarshalAs(UnmanagedType.LPTStr)]
string file,
SymStoreOpt options);
enum SymStoreOpt : uint
{
None = 0x00,
Compress = 0x01,
Overwrite = 0x02,
Pointer = 0x08,
ReturnIndex = 0x04,
PassIfExists = 0x40,
}
And attempted a call:
var processId = IntPtr.Zero;
try
{
// This succeeds.
processId = new IntPtr(Process.GetCurrentProcess().Id);
if (!NativeMethods.SymInitialize(processId, null, false))
{
processId = IntPtr.Zero;
throw new Win32Exception(Marshal.GetLastWin32Error());
}
// This fails.
var storageLocation = NativeMethods.SymSrvStoreFile(processId, "srv*C:\\vssym", "C:\\test\\mscorlib.pdb", SymStoreOpt.ReturnIndex);
if (storageLocation == null)
{
// Errors under various circumstances.
// - The operation completed successfully (but storageLocation is still null)
// - The specified module could not be found
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (processId != IntPtr.Zero)
NativeMethods.SymCleanup(processId);
}
Are there any mistakes with my extern declarations? Alternatively, anyone know how to get the symbol storage location for a PDB/PE (and not only a .Net one)? I have also tried the other SymStoreOpt flags and got nowhere.
At some point (I can't remember what I did) the file appeared in the symbol storage location (even though ReturnIndex was used), but at that point my process would crash (one of those where the debugger doesn't even catch it), running it again would result in "the operation succeeded" with no return value.
EDIT: I tried this in C++ and still get the same behavior - obviously I don't want to go that route because P/Invoke has the advantage of architecture neutrality.

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...

C# OpenProcess returns error 1150

Here is the code I wrote to open a process:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern UIntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(UIntPtr hObject);
private const uint PROCESS_QUERY_INFORMATION = 0x0400;
public static void processInfo() {
uint PID = 3144;
UIntPtr handle = UIntPtr.Zero;
handle = OpenProcess(PROCESS_QUERY_INFORMATION, false, PID);
Console.WriteLine(Marshal.GetLastWin32Error());
Console.WriteLine(handle);
if (!handle.Equals(UIntPtr.Zero)) {
CloseHandle(handle);
}
}
Marshal.GetLastWin32Error() returns error 1150 for any process. From MSDN:
"ERROR_OLD_WIN_VERSION: The specified program requires a newer version
of Windows."
I'm running this code in Windows 2008 R2 in Visual Studio 2015 Community Edition. Target Framework is set to ".NET Framework 4.5.2" in project settings.
Also, it seems that OpenProcess is still able to do its job because the returned handle is not zero. Should I be concerned about this error?
From the documentation:
If the function succeeds, the return value is an open handle to the
specified process.
If the function fails, the return value is NULL. To get extended error
information, call GetLastError.
Note that the only mention of calling GetLastError is if the function fails. That is indicated by the return value. Only check the error code when the function fails, it only has a meaningful value in that situation. Your mistake is that you check the error code unconditionally.
handle = OpenProcess(...);
if (handle == UIntPtr.Zero)
// only now call Marshal.GetLastWin32Error
Note also that it is pointless to assign handle twice. You wrote:
UIntPtr handle = UIntPtr.Zero;
handle = OpenProcess(...);
Surely the compiler warned that this was pointless, that the value assigned to handle was not used. Your code is somewhat akin to:
int i = 1;
i = 2;
I'm sure you'd never do this. Your code should be:
UIntPtr handle = OpenProcess(...);
I do not know what the problem with your code is, but here is a very simple implementation which I have tested working. Keep in mind you must run as administrator.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApp3
{
class Program
{
[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 IntPtr OpenProcess(
ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
static void Main(string[] args)
{
Process proc = Process.GetProcessesByName("ac_client")[0];
var hProc = OpenProcess(ProcessAccessFlags.All, false, proc.Id);
}
}
}

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

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

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;
}
}

Determine if window has close button (Or, why isn't GetTitleBarInfo working?)

I'm trying to determine if a given window has a close button using the GetTitleBarInfo function, as recommended in this SO answer. But when I call the function the return value for rgstate[5] - which should indicate the close button state - is always 0 and I don't understand why. Anyone have any idea what I'm doing wrong here? Alternatively, if any one can suggest another method to get this information, that would be helpful as well. Thanks!
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFO
{
public int cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public int[] rgstate;
}
IntPtr handle = GetForegroundWindow();
TITLEBARINFO titleBarInfo = new TITLEBARINFO();
titleBarInfo.cbSize = Marshal.SizeOf(titleBarInfo);
if (!GetTitleBarInfo(handle, ref titleBarInfo))
throw new Win32Exception(Marshal.GetLastWin32Error());
// titleBarInfo.rgstate[5] is always 0 here. Why?
Edit: Just to be clear, according to MSDN the return value should be a combination of one or more of the values listed here.

Categories

Resources