PInvoke – Random IT Utensils https://blog.adamfurmanek.pl IT, operating systems, maths, and more. Sat, 02 Jan 2021 19:12:42 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 Concurrency Part 10 — Reentrant mutex https://blog.adamfurmanek.pl/2019/11/02/concurrency-part-10/ https://blog.adamfurmanek.pl/2019/11/02/concurrency-part-10/#respond Sat, 02 Nov 2019 09:00:31 +0000 https://blog.adamfurmanek.pl/?p=3157 Continue reading Concurrency Part 10 — Reentrant mutex]]>

This is the tenth part of the Concurrency series. For your convenience you can find other parts in the table of contents in Part 1 – Mutex performance in .NET

We have already seen how to implement custom mutex using memory mapped files and CAS operation. It has one drawback — it is not reentrant. Actually, if we try to take if recursively we will end up with deadlock. Today we will fix it.

Since our mutex protocol requires a delegate to execute while holding mutex (kind of a RAII pattern or try-with-resources approach) we don’t need to worry about taking the mutex and not releasing it. Conceptually, this is not allowed:

mutex.Lock()
mutex.Lock() // again
...
mutex.Release()
// Not releasing again

It is guaranteed that mutex will be released once it’s taken. Well, this is not 100% true as there are AccessViolation exceptions resulting in finally block not being executed but we will ignore this fact. So, we don’t need to take lock for the second time if we can guarantee that we won’t try releasing it.

Let’s see this code:

using System;
using System.Diagnostics;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace MutexUtils
{
    public static class MutexUtils
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        unsafe public static extern long InterlockedCompareExchange64(long* destination, long exchange, long comperand);

        public static unsafe bool DoWithMutex(string name, Action action, int timeoutInSeconds = int.MaxValue, int spinTimeout = 250)
        {
			var myPid = Process.GetCurrentProcess().Id;
			var myTid = AppDomain.GetCurrentThreadId();
			
            // Store <PID><TID> as one field
            long myIdentifier = ((long)myPid << 32) + myTid;

            // Calculate timeout wall clock
            DateTime end = DateTime.UtcNow.AddSeconds(timeoutInSeconds);

            // Open memory mapped file initialized with zeros
            using (var memoryMappedFile = MemoryMappedFile.CreateOrOpen(name, 8))
            using (var viewStream = memoryMappedFile.CreateViewStream(8, 8))
            {
                var pointer = viewStream.SafeMemoryMappedViewHandle.DangerousGetHandle();
				
				try
				{
					var currentLock = Interlocked.Read((long*)pointer);
					if(GetPid(currentLock) == myPid && GetTid(currentLock) == myTid){
						action();
						return true;
					}
				}
				catch(Exception e)
				{
					Console.WriteLine($"Something very bad happened: {e}");
					return false;
				}

                try
                {
                    int holderPid = -1;
                    int holderTid = -1;

                    while (DateTime.UtcNow < end)
                    {
                        // Take lock only if it is not taken
                        var currentLock = InterlockedCompareExchange64((long*)pointer, myIdentifier, 0);

                        if (currentLock == 0)
                        {
                            action();
                            return true;
                        }

                        // Lock is taken, let's see who holds it
                        holderTid = GetTid(currentLock);
                        holderPid = GetPid(currentLock);

                        bool exists = false;
                        try
                        {
                            exists = Process.GetProcessById(holderPid).Threads.OfType<ProcessThread>().Any(t => t.Id == holderTid);
                        }
                        catch
                        {
                        }

                        // If holding thread doesn't exist then the lock is abandoned
                        if (!exists)
                        {
                            // Clear lock only if it is still held by previous owner
                            var currentLock2 = InterlockedCompareExchange64((long*)pointer, 0, currentLock);
                            if (currentLock == currentLock2)
                            {
                               Console.WriteLine($"Mutex {name} was abandoned by pid={holderPid} tid={holderTid}");
                            }
                        }

                        Thread.Sleep(spinTimeout);
                    }

                    Console.WriteLine($"Timeout when waiting on mutex {name} held by pid={holderPid} tid={holderTid}");
                }
                finally
                {
                    // Clear lock only if I'm the one holding it
                    var currentLock = InterlockedCompareExchange64((long*)pointer, 0, myIdentifier);
                    if (currentLock != myIdentifier)
                    {
                        Console.WriteLine($"I tried to release mutex held by someone else, pid={GetPid(currentLock)} tid={GetTid(currentLock)}");
                    }
                }
            }

            return false;
        }

        private static int GetPid(long value)
        {
            return (int)(value >> 32);
        }

        private static int GetTid(long value)
        {
            return (int)(value & 0xFFFFFFFF);
        }
    }
}

We check in line 34 if the current owner of the lock is us — in that case we just execute the action and return early. If something wrong happened (we have exception) then we cannot assume anything about lock owner or executed action so we need to return immediately. The only thing we know for sure is that we didn’t modify the lock. You may be tempted to set a flag that lock is on us and return it in the exception handler — thinking that the exception was thrown by the executed action — but you cannot guarantee that you started executing the action (think about OOM thrown after setting the flag and before calling the handler). You could try enhancing this by using CER but then you constrain yourself a lot.

]]>
https://blog.adamfurmanek.pl/2019/11/02/concurrency-part-10/feed/ 0
Concurrency Part 8 — Tracking mutex owner https://blog.adamfurmanek.pl/2019/10/19/concurrency-part-8/ https://blog.adamfurmanek.pl/2019/10/19/concurrency-part-8/#respond Sat, 19 Oct 2019 08:00:51 +0000 https://blog.adamfurmanek.pl/?p=3148 Continue reading Concurrency Part 8 — Tracking mutex owner]]>

This is the eighth part of the Concurrency series. For your convenience you can find other parts in the table of contents in Part 1 – Mutex performance in .NET

We know how to use global mutexes to synchronize processes. However, there is a big drawback — we don’t know who owns the mutex and we cannot get that information easily. There is https://docs.microsoft.com/en-us/windows/win32/debug/wait-chain-traversal API for reading that information but it is not easy to follow. Can we do better?

One common trick is to use memory mapped files to store the information. Let’s see the code:

using System;
using System.Diagnostics;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace MutexUtils
{
    public static class MutexUtils
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        unsafe public static extern long InterlockedCompareExchange64(long* destination, long exchange, long comperand);

        public static unsafe bool DoWithMutex(string name, Action action, int timeoutInSeconds = int.MaxValue, int spinTimeout = 250)
        {
            // Store <PID><TID> as one field
            long myIdentifier = ((long)Process.GetCurrentProcess().Id << 32) + AppDomain.GetCurrentThreadId();

            // Calculate timeout wall clock
            DateTime end = DateTime.UtcNow.AddSeconds(timeoutInSeconds);

            // Open memory mapped file initialized with zeros
            using (var memoryMappedFile = MemoryMappedFile.CreateOrOpen(name, 8))
            using (var viewStream = memoryMappedFile.CreateViewStream(8, 8))
            {
                var pointer = viewStream.SafeMemoryMappedViewHandle.DangerousGetHandle();

                try
                {
                    int holderPid = -1;
                    int holderTid = -1;

                    while (DateTime.UtcNow < end)
                    {
                        // Take lock only if it is not taken
                        var currentLock = InterlockedCompareExchange64((long*)pointer, myIdentifier, 0);

                        if (currentLock == 0)
                        {
                            action();
                            return true;
                        }

                        // Lock is taken, let's see who holds it
                        holderTid = GetTid(currentLock);
                        holderPid = GetPid(currentLock);

                        bool exists = false;
                        try
                        {
                            exists = Process.GetProcessById(holderPid).Threads.OfType<ProcessThread>().Any(t => t.Id == holderTid);
                        }
                        catch
                        {
                        }

                        // If holding thread doesn't exist then the lock is abandoned
                        if (!exists)
                        {
                            // Clear lock only if it is still held by previous owner
                            var currentLock2 = InterlockedCompareExchange64((long*)pointer, 0, currentLock);
                            if (currentLock == currentLock2)
                            {
                               Console.WriteLine($"Mutex {name} was abandoned by pid={holderPid} tid={holderTid}");
                            }
                        }

                        Thread.Sleep(spinTimeout);
                    }

                    Console.WriteLine($"Timeout when waiting on mutex {name} held by pid={holderPid} tid={holderTid}");
                }
                finally
                {
                    // Clear lock only if I'm the one holding it
                    var currentLock = InterlockedCompareExchange64((long*)pointer, 0, myIdentifier);
                    if (currentLock != myIdentifier)
                    {
                        Console.WriteLine($"I tried to release mutex held by someone else, pid={GetPid(currentLock)} tid={GetTid(currentLock)}");
                    }
                }
            }

            return false;
        }

        private static int GetPid(long value)
        {
            return (int)(value >> 32);
        }

        private static int GetTid(long value)
        {
            return (int)(value & 0xFFFFFFFF);
        }
    }
}

Magic, a lot. Let’s go part by part.

First, we want to store process ID and thread ID somewhere in the lock to be able to read it easily later. In line 18 we encode those in one 64-bit long variable which we can later replace using CAS operation.

In line 21 we just calculate the time when we should stop trying to get lock. This is for timeouts.

Next, we create memory mapped file (lines 24, 25) not backed by any physical file. This is to avoid permission problems — we cannot map the same file in two processes without copy-on-write semantics. We will need separate reader for debugging.

Next, we spin in the loop. Each time we try to take lock (line 37). If current lock value is zero (line 39) then it means that our lock is available and we have just locked it. We execute the action and then return (which is jump to finally).

However, if lock wasn’t available, we now have the owner of the lock (lines 46 and 47). So we need to check if the owner is still alive. We read process and look for thread in line 52.

If it didn’t exist, we try to clear the lock (line 62). We clear it only if it is still held by the same owner. And here is big warning — process ID and thread ID can be recycled so here we may inadvertently release still used mutex!

Then in line 69 we sleep for some timeout and loop again.

Ultimately, in line 77 we try to clear the lock if it is taken by us. We may end up in this line of code if some exception appears so we cannot just blindly release the mutex.

That’s all, you can verify that it should work pretty well. Just be aware of this chance of clearing up some other mutex, you may come up with different identifier if needed.

In theory, this can be solved by using CAS for 128 bits:

public static class MutexUtils
{
	public static void DoWithSemaphore(string name, int semaphoresCount, Action action)
	{
		bool checkedAll = false;
		string fullName;

		for (int index = 0; ; index = (index + 1) % semaphoresCount)
		{
			fullName = name + index;
			if (DoWithMutex(fullName, action, checkedAll ? 20 : 1))
			{
				break;
			}

			if (index == semaphoresCount - 1)
			{
				checkedAll = true;
			}
		}
	}

	[DllImport("kernel32.dll", SetLastError = true)]
	unsafe public static extern bool InterlockedCompareExchange128(long* destination, long exchangeHigh, long exchangeLow, long* comperand);

	public static unsafe bool DoWithMutex(string name, Action action, int timeoutInSeconds = int.MaxValue, int spinTimeout = 250)
	{
		// Store <PID><TID> as one field
		long myIdentifier = ((long)Process.GetCurrentProcess().Id << 32) + AppDomain.GetCurrentThreadId();
		long myTime = DateTime.UtcNow.Ticks;

		// Calculate timeout wall clock
		DateTime end = DateTime.UtcNow.AddSeconds(timeoutInSeconds);

		// Open memory mapped file initialized with zeros
		using (var memoryMappedFile = MemoryMappedFile.CreateOrOpen(name, 8))
		using (var viewStream = memoryMappedFile.CreateViewStream(8, 8))
		{
			var pointer = viewStream.SafeMemoryMappedViewHandle.DangerousGetHandle();
			long* currentLock = stackalloc long[2];
			currentLock[0] = 0;
			currentLock[1] = 0;

			try
			{
				int holderPid = -1;
				int holderTid = -1;

				while (DateTime.UtcNow < end)
				{
					// Take lock only if it is not taken
					var isLockFree = InterlockedCompareExchange128((long*)pointer, myIdentifier, myTime, currentLock);

					if (isLockFree)
					{
						action();
						return true;
					}

					// Lock is taken, let's see who holds it
					holderTid = GetTid(currentLock[0]);
					holderPid = GetPid(currentLock[1]);

					bool exists = false;
					try
					{
						exists = Process.GetProcessById(holderPid).Threads.OfType<ProcessThread>().Any(t => t.Id == holderTid);
					}
					catch
					{
					}

					// If holding thread doesn't exist then the lock is abandoned
					if (!exists)
					{
						// Clear lock only if it is still held by previous owner
						var isLockStillOwnedByTheSameOwner = InterlockedCompareExchange128((long*)pointer, 0, 0, currentLock);
						if (isLockStillOwnedByTheSameOwner)
						{
						   Console.WriteLine($"Mutex {name} was abandoned by pid={holderPid} tid={holderTid}");
						}
					}

					Thread.Sleep(spinTimeout);
				}

				Console.WriteLine($"Timeout when waiting on mutex {name} held by pid={holderPid} tid={holderTid}");
			}
			finally
			{
				// Clear lock only if I'm the one holding it
				currentLock[0] = myIdentifier;
				currentLock[1] = myTime;
				if (!InterlockedCompareExchange128((long*)pointer, 0, 0, currentLock))
				{
					Console.WriteLine($"I tried to release mutex held by someone else, pid={GetPid(currentLock[0])} tid={GetTid(currentLock[1])}");
				}
			}
		}

		return false;
	}

	private static int GetPid(long value)
	{
		return (int)(value >> 32);
	}

	private static int GetTid(long value)
	{
		return (int)(value & 0xFFFFFFFF);
	}
}

However, it doesn’t work on my machine, my kernel32.dll doesn’t support this CAS operation.

And since this is playing with very dangerous primitives, I take no responsibility for any failures in your systems if it doesn’t work. I tested it in my situation and it behaved correctly, though.

]]>
https://blog.adamfurmanek.pl/2019/10/19/concurrency-part-8/feed/ 0
Decreasing pain of stolen focus https://blog.adamfurmanek.pl/2019/08/24/decreasing-pain-of-stolen-focus/ https://blog.adamfurmanek.pl/2019/08/24/decreasing-pain-of-stolen-focus/#respond Sat, 24 Aug 2019 08:00:04 +0000 https://blog.adamfurmanek.pl/?p=3068 Continue reading Decreasing pain of stolen focus]]> One of the most irritating thing in Windows is no way to prevent an application from stealing focus. There are multiple questions on Stack Overflow regarding the issue, there are rumors that Microsoft wanted to do something but they cannot detect it reliably. There are workarounds like ForegroundLockTimeout but ultimately there is no good solution.

I had the the following problem problem — application X was constantly creating new instance of application Y (as desired) which in turn resulted in creating new window stealing focus and appearing on the screen. This is especially irritating when typing or when working using RDP since new window consumes some bandwidth which (especially painful over mobile connection).

Powershell hiding windows

You can use a powershell background script which would restore the focus if it was stole. Here is the code:

Add-Type -AssemblyName System.Windows.Forms
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 

$TypeDef = @"

using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace Api
{
	public class ApiDef
	{
		[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

		[DllImport("user32.dll", SetLastError=true)]
		static extern IntPtr GetForegroundWindow();
		
		private static string ReadText(IntPtr hWnd){
			StringBuilder sb = new StringBuilder(256);
			int res = GetWindowText((IntPtr)hWnd, sb, 256);
			return sb.ToString();
		}

		public static void Activate(){
			var oldWindow = GetForegroundWindow();
			while(true){
				var foreground = GetForegroundWindow();
				var text = ReadText(foreground).ToLower();
				if(text.Contains("whatever title you like")){
					SendKeys.SendWait("%{ESC}");
				}else{
					oldWindow = foreground;
				}
				
				Thread.Sleep(250);
			}
		}

	}
}
"@

Add-Type -TypeDefinition $TypeDef -Language CSharpVersion3 -ReferencedAssemblies @("System.Windows.Forms")

[Api.Apidef]::Activate()

Every 250 milliseconds I get the foreground window and check its title. If it is something which I know steals the focus then I send CTRL + ESC sequence which ultimately switches application back.

I tried doing SetWindowPos or BringWindowToTop orSetForegroundWindow but none of those worked as expected. Finally I decided to go with the hotkey and it looks like this is good enough for me.

VirtuaWin

There is actually much easier solution for doing that. VirtuaWin can create multiple desktops and automatically move windows between them based on rules. Just capture the class or process name you want to move, configure rule and the window will be moved automatically.

Running in different session

You can open new session to the host (using MSTSC or Remote App Terminal Services) and then run application in that session. You won’t see its UI at all, however, it will run normally. You can do that using qwinsta to get session id and then psexec.exe -i session_id app.exe

Creating new desktop

You can create new desktop using Sysinternals Desktops utility. Next, run application stealing focus in new desktop and it will not pop up on other desktops anymore.

I think desktop switcher in Windows 10 may be using the same API. If you are using it then you may look at Windows 10 virtual desktop enhancer to get some more shortcuts.

There is also Dexpot which I was using for many years and it is great. Just watch the license restrictions if you want to use it commercially.

See Pushing the limits and Understanding windows at a deeper level articles about this part of OS.

]]>
https://blog.adamfurmanek.pl/2019/08/24/decreasing-pain-of-stolen-focus/feed/ 0
Custom memory allocation in C# Part 8 — Unsafe list in .NET Core x64 https://blog.adamfurmanek.pl/2018/06/23/custom-memory-allocation-in-c-part-8/ https://blog.adamfurmanek.pl/2018/06/23/custom-memory-allocation-in-c-part-8/#comments Sat, 23 Jun 2018 08:00:29 +0000 https://blog.adamfurmanek.pl/?p=2451 Continue reading Custom memory allocation in C# Part 8 — Unsafe list in .NET Core x64]]>

This is the eighth part of the Custom memory allocation series. For your convenience you can find other parts in the table of contents in Part 1 — Allocating object on a stack

Today we are going to revisit an Unsafe list example using .NET Core. Since I use x64 edition, I need to adjust a code using pointers:

public void Add(T item)
{
	_currentIndex++;

	unsafe
	{
		TypedReference reference = __makeref(item);
		long* itemAddress = (long*) (*(long*) *(long*) &reference - 8);

		for (long i = 1; i < _elementSize; ++i)
		{
			_storage[_currentIndex*_elementSize + i] = *itemAddress;
			itemAddress = itemAddress + 1;
		}

		reference = __makeref(_storage);
		_storage[_currentIndex*_elementSize] = *(long*) *(long*) &reference + _currentIndex*_elementSize*8 + 32;
		_elements[_currentIndex] = GetInternal(_currentIndex);
	}
}

Changes are rather simple — one just needs to replace integers with longs and multiply all the offsets by two.

class Poco
{
	public long Field1;
	public long Field2;
	public long Field3;
	public long Field4;
	public long Field5;
	public long Field6;
	public long Field7;
	public long Field8;
	public long Field9;
	public long Field10;
	public long Field11;
	public long Field12;
	public long Field13;
	public long Field14;
	public long Field15;
	public long Field16;
}

Here I just use long fields to make the code simpler. Of course one can detect the size of the object and work with integers as well.

Here are the results:

Results

Unsafe list is still faster.

]]>
https://blog.adamfurmanek.pl/2018/06/23/custom-memory-allocation-in-c-part-8/feed/ 1
Custom memory allocation in C# Part 7 — Stack allocation once again https://blog.adamfurmanek.pl/2018/06/09/custom-memory-allocation-in-c-part-7/ https://blog.adamfurmanek.pl/2018/06/09/custom-memory-allocation-in-c-part-7/#comments Sat, 09 Jun 2018 08:00:47 +0000 https://blog.adamfurmanek.pl/?p=2446 Continue reading Custom memory allocation in C# Part 7 — Stack allocation once again]]>

This is the seventh part of the Custom memory allocation series. For your convenience you can find other parts in the table of contents in Part 1 — Allocating object on a stack

We know how to allocate object on a stack, however, we did this in .NET Framework. Can we do the same in .NET Core? Let’s see. I am using .NET Core 2.1.103 x64 on W10 Enterprise x64.

Code

Since I am using an 64-bit SDK, I need to change the code. Below is the modified version:

// This application stores managed object on stack
// Windbg internals:
/*
Load SOS:
.loadby sos coreclr

Select proper thread:
~0s

Present all values:
!clrstack -i -a

Tested with .NET Core 2.1.103 x64 on W10 Enterprise x64
*/

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Makeref_core
{
    class Poco
    {
        public int Field;

        public void WriteField()
        {
            Console.WriteLine(Field);
        }

        public override string ToString()
        {
            return Field.ToString();
        }

        ~Poco()
        {
            Console.WriteLine("Cleaning: " + Field);
        }
    }

    class Program
    {
        static void Main()
        {
            #region Copy

            Poco heapPoco = new Poco
            {
                Field = 5
            };
            Poco originalPoco = heapPoco;

            unsafe
            {
                var space = stackalloc ulong[10];
                for (int i = 0; i < 10; ++i)
                {
                    space[i] = 0xBADF00D;
                }

                TypedReference typedReference = __makeref(heapPoco);
                ulong* pocoAddress = (ulong*)(*(ulong*)*(ulong*)&typedReference - 8);

                Console.WriteLine($"Got address of an EE method: {((ulong)(pocoAddress + 1)).ToString("X")} Value: {(*(pocoAddress + 1)).ToString("X")}");
                Console.ReadLine();


                for (int i = 0; i < 3; ++i)
                {
                    Console.WriteLine($"Address {((ulong)pocoAddress).ToString("X")} Value {(*pocoAddress).ToString("X")}");
                    space[i] = *pocoAddress;
                    pocoAddress = pocoAddress + 1;
                }

                Console.WriteLine("Rewritten values");
                Console.ReadLine();

                *(ulong*)*(ulong*)&typedReference = (ulong)&space[1];

                Console.WriteLine($"Set reference to the stack: {((ulong)&space[1]).ToString("X")}");
                Console.ReadLine();

                Poco stackPoco = __refvalue(typedReference, Poco);
                //Poco stackPoco = heapPoco; - This is the same
                #endregion

                #region Write
                Console.WriteLine("Got poco on stack. Displaying values:");
                Console.Write("Heap: ");
                originalPoco.WriteField();
                Console.Write("Stack: ");
                stackPoco.WriteField();
                Console.WriteLine();

                Console.WriteLine("Modifying values using references. Displaying values:");
                originalPoco.Field = 555;
                stackPoco.Field = 444;
                Console.Write("Heap: ");
                originalPoco.WriteField();
                Console.Write("Stack: ");
                stackPoco.WriteField();
                Console.WriteLine();

                Console.WriteLine("Modifying values using array on a stack. Displaying values:");
                space[2] = 333;
                Console.Write("Heap: ");
                originalPoco.WriteField();
                Console.Write("Stack: ");
                stackPoco.WriteField();
                Console.ReadLine();

                Console.WriteLine("Calling virtual method:");
                Console.WriteLine("Heap: " + originalPoco.ToString());
                Console.WriteLine("Stack: " + stackPoco.ToString());
                Console.ReadLine();

                Console.WriteLine("Displaying object types:");
                Console.WriteLine(originalPoco.GetType());
                Console.WriteLine(stackPoco.GetType());
                Console.ReadLine();

                Console.WriteLine("Displaying GC generations:");
                Console.WriteLine(GC.GetGeneration(originalPoco));
                Console.WriteLine(GC.GetGeneration(stackPoco));
                Console.ReadLine();

                Console.WriteLine("Threading:");
                Console.WriteLine($"Taking lock in base: {DateTime.Now}");

                lock (stackPoco)
                {
                    Console.WriteLine($"Lock in base aquired: {DateTime.Now}");

                    Task.Run(() =>
                    {
                        Console.WriteLine($"Taking lock in child: {DateTime.Now}");
                        lock (stackPoco)
                        {
                            Console.WriteLine($"Lock in child aquired: {DateTime.Now}");
                        }
                        Console.WriteLine($"Lock in child released: {DateTime.Now}");
                    });

                    Thread.Sleep(2000);
                }

                Console.WriteLine($"Lock in base released: {DateTime.Now}");
                Console.ReadLine();

                //GC.ReRegisterForFinalize(stackPoco);// - bad idea

                Console.WriteLine("End");
            }
            #endregion
        }
    }
}

It is basically the same code as in Part 1, however, instead of casting pointers to int I use ulong type. ALso, the syncblock is now 8 bytes before the metadata.

WinDBG

Let’s see the WinDBG session. We start the application, wait for first ReadLine and attach the debugger:

0:003> .loadby sos coreclr
0:003> ~0s
ntdll!NtReadFile+0x14:
00007fff`e6545464 c3              ret
0:000> !clrstack -a -i
Loaded C:\tmp\mscordbi.dll\5A81EF0016d000\mscordbi.dll
Loaded C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\mscordaccore.dll



Dumping managed stack and managed variables using ICorDebug.
=============================================================================
Child SP         IP               Call Site
000000d38d57d858 00007fffe6545464 [NativeStackFrame]
000000d38d57d8e0 00007fff3f07214f 000000d38d57d910 (null) [Managed to Unmanaged transition: 000000d38d57d910]
000000d38d57d9a0 00007fffb2e28f65 [DEFAULT] I4 System.ConsolePal+WindowsConsoleStream.ReadFileNative(I,SZArray UI1,I4,I4,Boolean,ByRef I4,Boolean) (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Console.dll)

PARAMETERS:
  + (Error 0x80131304 retrieving parameter 'hFile')
  + (Error 0x80131304 retrieving parameter 'bytes')
  + (Error 0x80131304 retrieving parameter 'offset')
  + (Error 0x80131304 retrieving parameter 'count')
  + (Error 0x80131304 retrieving parameter 'isPipe')
  + (Error 0x80131304 retrieving parameter 'bytesRead')
  + (Error 0x80131304 retrieving parameter 'useFileAPIs')

LOCALS:
  + (Error 0x80004005 retrieving local variable 'readSuccess')
  + (Error 0x80004005 retrieving local variable 'errorCode')
  + (Error 0x80004005 retrieving local variable 'p')
  + (Error 0x80004005 retrieving local variable 'local_3')
  + (Error 0x80004005 retrieving local variable 'charsRead')

000000d38d57da00 00007fffb2e28db3 [DEFAULT] [hasThis] I4 System.ConsolePal+WindowsConsoleStream.Read(SZArray UI1,I4,I4) (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Console.dll)

PARAMETERS:
  + (Error 0x80131304 retrieving parameter 'this')
  + (Error 0x80131304 retrieving parameter 'buffer')
  + (Error 0x80131304 retrieving parameter 'offset')
  + (Error 0x80131304 retrieving parameter 'count')

LOCALS:
  + (Error 0x80004005 retrieving local variable 'bytesRead')
  + (Error 0x80004005 retrieving local variable 'errCode')

000000d38d57da70 00007fffa3ccdc6d [DEFAULT] [hasThis] I4 System.IO.StreamReader.ReadBuffer() (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Runtime.Extensions.dll)

PARAMETERS:
  + System.IO.StreamReader this @ 0x22b678659f0

LOCALS:
  + (Error 0x80004005 retrieving local variable 'len')
  + (Error 0x80004005 retrieving local variable 'local_1')

000000d38d57dac0 00007fffa3cce04a [DEFAULT] [hasThis] String System.IO.StreamReader.ReadLine() (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Runtime.Extensions.dll)

PARAMETERS:
  + System.IO.StreamReader this @ 0x22b678659f0

LOCALS:
  + (Error 0x80004005 retrieving local variable 'sb')
  + (Error 0x80004005 retrieving local variable 'i')
  + (Error 0x80004005 retrieving local variable 'ch')
  + (Error 0x80004005 retrieving local variable 's')

000000d38d57db10 00007fffb2e2d517 [DEFAULT] [hasThis] String System.IO.SyncTextReader.ReadLine() (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Console.dll)

PARAMETERS:
  + System.IO.SyncTextReader this @ 0x22b678663b0

LOCALS:
  + (Error 0x80004005 retrieving local variable 'local_0')
  + (Error 0x80004005 retrieving local variable 'local_1')
  + (Error 0x80004005 retrieving local variable 'local_2')

000000d38d57db60 00007fffb2e252fa [DEFAULT] String System.Console.ReadLine() (C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.6\System.Console.dll)

PARAMETERS: (none)

LOCALS: (none)

000000d38d57db90 00007fff3f0709b8 [DEFAULT] Void Makeref_core.Program.Main() (C:\Users\user\Desktop\msp_windowsinternals\Makeref_core\bin\Debug\netcoreapp2.0\Makeref_core.dl)

PARAMETERS: (none)

LOCALS:
  + Makeref_core.Poco heapPoco @ 0x22b67863840
  + Makeref_core.Poco originalPoco @ 0x22b67863840
  + Makeref_core.Program+c__DisplayClass0_0 CS$8__locals0 @ 0x22b67863858
  + unsigned long* space  = 195948557
  + typedbyref typedReference @ 0x22b67863840
  + unsigned long* pocoAddress  = 0
  + int i  = 10
  + (Error 0x80004005 retrieving local variable 'local_7')
  + (Error 0x80004005 retrieving local variable 'local_8')
  + int i  = 0
  + (Error 0x80004005 retrieving local variable 'local_10')
  + (Error 0x80004005 retrieving local variable 'local_11')
  + (Error 0x80004005 retrieving local variable 'local_12')

000000d38d57de00 00007fff9eb735f3 [NativeStackFrame]
Stack walk complete.
=============================================================================

Nothing special here, let’s examine the stack:

0:000> dd 000000d38d57db90 
000000d3`8d57db90  67865760 0000022b 00000000 00000000
000000d3`8d57dba0  6786575c 0000022b 8d57d970 000000d3
000000d3`8d57dbb0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbc0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbd0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbe0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbf0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dc00  8d57dbe0 000000d3 9ea4eeeb 00007fff

We can see the 0badf00d markers. Let’s continue the application, and after one step check the stack again:

0:003> dd 000000d38d57db90 
000000d3`8d57db90  67865760 0000022b 00000000 00000000
000000d3`8d57dba0  6786575c 0000022b 8d57d970 000000d3
000000d3`8d57dbb0  00000000 00000000 3ef15e20 00007fff
000000d3`8d57dbc0  00000005 00000000 0badf00d 00000000
000000d3`8d57dbd0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbe0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dbf0  0badf00d 00000000 0badf00d 00000000
000000d3`8d57dc00  8d57dbe0 000000d3 9ea4eeeb 00007fff

Yes, this looks correct. Let’s verify with the object metadata directly:

0:003> !do 0x22b67863840
Name:        Makeref_core.Poco
MethodTable: 00007fff3ef15e20
EEClass:     00007fff3f062110
Size:        24(0x18) bytes
File:        C:\Users\user\Desktop\msp_windowsinternals\Makeref_core\bin\Debug\netcoreapp2.0\Makeref_core.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007fff978b6648  4000001        8         System.Int32  1 instance                5 Field

The MethodTable part is correct so the whole object is copied to the stack correctly. We can verify this differently:

0:003> !do 000000d3`8d57dbb8
Name:        Makeref_core.Poco
MethodTable: 00007fff3ef15e20
EEClass:     00007fff3f062110
Size:        24(0x18) bytes
File:        C:\Users\user\Desktop\msp_windowsinternals\Makeref_core\bin\Debug\netcoreapp2.0\Makeref_core.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007fff978b6648  4000001        8         System.Int32  1 instance                5 Field

So we dump the object directly from the stack and it works.

Summary

There was no TypedReference in .NET Core for a long time. Right now it is available so we can toy with memory and check what has been changed.

]]>
https://blog.adamfurmanek.pl/2018/06/09/custom-memory-allocation-in-c-part-7/feed/ 1
Concurrency Part 4 – .NET with P/Invoke https://blog.adamfurmanek.pl/2018/05/19/concurrency-part-4/ https://blog.adamfurmanek.pl/2018/05/19/concurrency-part-4/#comments Sat, 19 May 2018 08:00:55 +0000 https://blog.adamfurmanek.pl/?p=2432 Continue reading Concurrency Part 4 – .NET with P/Invoke]]>

This is the fourth part of the Concurrency series. For your convenience you can find other parts in the table of contents in Part 1 – Mutex performance in .NET

We have already seen a mutex in C# but last time it happened that Java JNI is faster. Let’s compare it with P/Invoke.

Code

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MutexPInvoke
{
    class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

        [DllImport("kernel32.dll")]
        public static extern bool ReleaseMutex(IntPtr hMutex);

        static void Main(string[] args)
        {
            IntPtr mutex = CreateMutex(IntPtr.Zero, false, "mutex_pinvoke");

            Stopwatch watch = new Stopwatch();

            while (true)
            {
                watch.Restart();
                for (int i = 0; i < 100000; ++i)
                {
                    WaitForSingleObject(mutex, 0xFFFFFFFF);
                    ReleaseMutex(mutex);
                }
                watch.Stop();
                Console.WriteLine(watch.ElapsedMilliseconds);
            }
        }
    }
}

As always, nothing special. Let’s see the results.

Results

    \[ \begin{array}{cc} Number\ of\ processes & Time [ms] \\ 1 & 110\\ 2 & 620\\ 3 & 1011\\ 4 & 1346\\ 5 & 1728\\ 6 & 2072\\ 7 & 2456\\ 8 & 2803\\ 9 & 3254\\ 10 & 3627\\ \end{array} \]

Well, slightly better than in pure C#, however, still worse than JNI. It’s time to go down.

]]>
https://blog.adamfurmanek.pl/2018/05/19/concurrency-part-4/feed/ 1
.NET Inside Out Part 8 — Handling Stack Overflow Exception in C# with VEH https://blog.adamfurmanek.pl/2018/04/07/handling-stack-overflow-exception-in-c-with-veh/ https://blog.adamfurmanek.pl/2018/04/07/handling-stack-overflow-exception-in-c-with-veh/#comments Sat, 07 Apr 2018 08:00:34 +0000 https://blog.adamfurmanek.pl/?p=2404 Continue reading .NET Inside Out Part 8 — Handling Stack Overflow Exception in C# with VEH]]>

This is the eighth part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#

If you are interested in the topic see the talk page

Today we are going to swallow Stack Overflow Exception in C# using Vectored Exception Handling. Let’s begin.

Why?

As specified in exception’s documentation, you are not allowed to catch Stack Overflow Exception (SOE) in .NET 2.0+. Why would you even try to do that? Well, normally you should detect and avoid it but imagine that you are writing a testing framework. If some of the tested code has a bug and results in SOE your runner will fail instead of showing nice message with stacktrace. You could in theory change this by reworking shim loading CLR but today we will do it using VEH.

I hope you read the Allocating object on a stack and Generating Func from a bunch of bytes posts because I use those tricks a lot.

How?

VEH is like an external exception handler, similar to Application_Error method. When something goes wrong you are notified with exception details. It is a Windows mechanism so don’t count on nice object which you can utilize from C#, you need to work with pointers and low level stuff. There can be multiple VEH handlers and each of them can indicate either to continue execution or continue search. Continuing execution means restoring thread to the state at the exception (or to any different state by changing CPU registers) and carrying on. Continuing search means executing next VEH handler, SEH handler or unhandled exception handler.

We are going to register new VEH handler, remember the point where we start calling method causing SOE (it is like adding catch in the code), catching the exception and redirecting the CPU to known location. Let’s go.

Implementation

We start with this faulty method:

public static void DoWork()
{
	try
	{
		Console.WriteLine("Preparing to throw");
		// Either try to divide by zero
		//int a = 5;
		//int b = 0;
		//Console.WriteLine(a / b);

		// Or generate SOE
		//DoWork();
	}
	catch(Exception e)
	{
		Console.WriteLine("I am in normal catch block with exception: " + e);
	}
}

You can uncomment any part you like. Dividing by zero should be caught by C# exception handler, however, SO should be ignored and crash your process. Ideally, if we get division by zero, C# handler should run, otherwise (if it is a SOE), our VEH handler should be in play.

We need the following helper methods:

P/Invoke to register VEH:

// Method for registering VEH handler
[DllImport("Kernel32.dll", SetLastError = true)]
static extern int AddVectoredExceptionHandler(uint first, IntPtr addres);

Methods to get addresses of machine codes:

private static byte[] GetAddress(string name)
{
	var address = BitConverter.GetBytes((int)GetRawAddress(name)).ToArray();
	return address;
}

private static IntPtr GetRawAddress(string name)
{
	var methodHandle = typeof(Program).GetMethod(name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).MethodHandle;
	RuntimeHelpers.PrepareMethod(methodHandle);
	var methodAddress = methodHandle.GetFunctionPointer();
	Console.WriteLine("Address: " + methodAddress.ToString("X"));
	return methodAddress;
}

Some space to hold registers to restore:

// Space to hold return context
public static int[] EipEspEbpEsiEdiEbxHolder = new [] { 0xBADF00D, 0xBADBEEF, 0xBADF00D, 0xBADBEEF, 0xBADF00D, 0xBADBEEF };

// Get field address (actually, first usable integer of the array, after metadata)
private static int GetEipEspEbpEsiEdiEbxHolder()
{
	unsafe
	{
		TypedReference typedReference = __makeref(EipEspEbpEsiEdiEbxHolder);
		int* fieldAddress = (int*)*(int*)*(int*)&typedReference;
		Console.WriteLine("Holder address: " + ((int)fieldAddress).ToString("X"));
		return (int)fieldAddress + 8;
	}
}

First, easy part — exception handler:

// Exception info is passed in esp+8 which is fourth parameter according to fastcall calling convention
// Having signature correctly like (int, int, int, IntPtr) spils stack because of calling convention - .NET will remove 2 integers from it
// We need to fix ret 8 to ret 4 at the end
public static int CatchingVeh(int a, int b, int c, IntPtr pExceptionInfo)
{
	//#define EXCEPTION_EXECUTE_HANDLER      1
	//#define EXCEPTION_CONTINUE_SEARCH      0
	//#define EXCEPTION_CONTINUE_EXECUTION (-1)

	Console.WriteLine("Catching VEH!");

	uint exceptionCode = (uint)Marshal.ReadInt32(Marshal.ReadIntPtr(pExceptionInfo));
	Console.WriteLine("Exception code: " + exceptionCode.ToString("X"));
	if(exceptionCode != 0xC00000FD)
	{
		// Not Stack Overflow Exception
		// Return CONTINUE_SEARCH
		return 0;
	}

	// We restore registers here using ExceptionInfo structure

	Console.WriteLine("Info: " + pExceptionInfo.ToString("X"));
	IntPtr pContextRecord = Marshal.ReadIntPtr(pExceptionInfo + 4);
	Console.WriteLine("Context: " + pContextRecord.ToString("X"));
	
	Marshal.WriteIntPtr(pContextRecord + 0xB8, (IntPtr)EipEspEbpEsiEdiEbxHolder[0]);
	Marshal.WriteIntPtr(pContextRecord + 0xC4, (IntPtr)EipEspEbpEsiEdiEbxHolder[1]);
	Marshal.WriteIntPtr(pContextRecord + 0xB4, (IntPtr)EipEspEbpEsiEdiEbxHolder[2]);
	Marshal.WriteIntPtr(pContextRecord + 0xA0, (IntPtr)EipEspEbpEsiEdiEbxHolder[3]);
	Marshal.WriteIntPtr(pContextRecord + 0x9C, (IntPtr)EipEspEbpEsiEdiEbxHolder[4]);
	Marshal.WriteIntPtr(pContextRecord + 0xA4, (IntPtr)EipEspEbpEsiEdiEbxHolder[5]);

	Console.WriteLine("Going back to Eip: " + EipEspEbpEsiEdiEbxHolder[0].ToString("X"));
	Console.ReadLine();

	// Return CONTINUE_EXECUTION
	return -1;
}

Lots of magic here!

First, method CatchingVeh is an actual VEH handler. It has very weird signature – it is because of VEH handler signature. Basically, the pointer to exception structure is passed via the stack, however, C# calling convention would access it via fourth parameter so we need to ad dummy parameters. Otherwise we would need to access the exception via asm code which is tedious so let’s make a different hack (see later).

We first get exception code. You can easily traverse structures on your own using pointers so there is nothing special here. We compare exception code with value 0xC00000FD which is a Stack Overflow Exception code. If the code is different, we just continue searching for different handler, eventually going to ordinary C# catch handler.

Next we start toying with CPU. ExceptionInfo has a pointer to ContextRecord structure which holds CPU registers at the time of throwing the exception. If we indicate that we want to continue execution, those registers will be restored from this structure. So we can modify EIP here and effectively jump to some other place. We jump to our catch handler (or in this sample just to line right after calling the faulty method). We also restore other registers so we are in the same state as before calling faulty method. So: we change EIP to do jump. We change ESP and EBP to effectively drop frames from the stack. We restore ESI, EDI and EBX to be in the same state and to adhere to calling convention.

This was easy, now comes the tricky part. We need to fill EipEspEbpEsiEdiEbxHolder with register values before calling the faulty method. And for this we need to use asembler language.

public static void Veh()
{
	var doWorkAddress = GetAddress(nameof(Program.DoWork));
	var catchingAddress = GetRawAddress(nameof(Program.CatchingVeh));
	
	// Fix ret 8 to ret 4 for CatchingVeh function
	IntPtr current = catchingAddress;
	while (true)
	{
		if(Marshal.ReadByte(current) == 0xC2 && Marshal.ReadByte(current + 1) == 0x8 && Marshal.ReadByte(current + 2) == 0)
		{
			Marshal.WriteByte(current + 1, 0x4);
			break;
		}
		current += 1;
	}

	// Register VEH handler
	AddVectoredExceptionHandler(1, catchingAddress);
	
	var holderAddress = GetEipEspEbpEsiEdiEbxHolder();

	Action<int> function = FuncGenerator.Generate<Action<int>, ActionInt>(
		new byte[0]
		// --------------------------------------------
		// Storing stack and instruction address
		// call helper for EIP
		.Concat(new byte[]{
			0xE8, 0x1C, 0x00, 0x00, 0x00  // call 28
		})
		// save EIP, ESP, EBP, ESI, EDI to temp array
		.Concat(new byte[]{
			0x83, 0xC0, 0x1B, // add eax,0x1B (27 bytes)
			0x89, 0x02, // mov    DWORD PTR [edx],eax
			0x89, 0x62, 0x04, // mov    DWORD PTR [edx+0x4],esp
			0x89, 0x6A, 0x08, // mov    DWORD PTR [edx+0x8],ebp
			0x89, 0x72, 0x0C, // mov    DWORD PTR [edx+0xc],esi
			0x89, 0x7A, 0x10, // mov    DWORD PTR [edx+0x10],edi
			0x89, 0x5A, 0x14, // mov    DWORD PTR [edx+0x14],ebx
		})
		// --------------------------------------------

		// --------------------------------------------
		// Calling DoWork method
		.Concat(new byte[]{
			0xB8, // mov eax
		})
		.Concat(doWorkAddress)
		.Concat(new byte[]
		{
			0xFF, 0xD0 // call eax
		})
		// --------------------------------------------

		// --------------------------------------------
		// Returning
		.Concat(new byte[]
		{
			0xC3 //retn
		})
		// --------------------------------------------


		// --------------------------------------------
		// Helper function for getting EIP as it is inaccessible directly on x86_32
		.Concat(new byte[]{
			0x8B, 0x04, 0x24, // mov eax,DWORD PTR [esp]
			0xC3 //retn
		})

		.ToArray()
	);

	Console.WriteLine("Calling with VEH");
	Console.ReadLine();
	function(holderAddress);
	Console.WriteLine("I'm done");
}

Even more magic here…

First, we get addresses of methods we use.

Next, we need to fix CatchingVeh function. If you disassembled it you would see that it uses ret 8 instruction at the end which drops two integers from the stack. To adhere to calling convention we must drop exactly one integer so we need to manually modify the code to use ret 4

Next, we register VEH handler and get address of array holding registers. We need to have machine address because we are going to fill it from asm. We pass this address via delegate parameters (see invocation at the end) so it lands in edx register (recall that ecx is a this parameter).

And then we begin our magic. We want to get the eip register but we cannot read it directly so we use a trick. At the end of machine code we have a helper function. When we call it, return address is pushed on the stack so we can read it from there and return via eax.

So we call this method at the beginning and when we are back we have the eip value in eax register. We just need to calculate the actual address after the method call (yes, we just count the bytes by hand). Next, we store other registers which we can easily access.

Finally, we just do absolute call via eax register and return. That’s it.

Summary

We can now handle the SOE easily using the VEH. We could do some more magic to analyze the reason behind the exception, capture the stack trace etc, but this is an exercise for you. And don’t forget to remove the VEH handler!

]]>
https://blog.adamfurmanek.pl/2018/04/07/handling-stack-overflow-exception-in-c-with-veh/feed/ 3
DLL Injection Part 6 — Injecting managed code into specific App Domain https://blog.adamfurmanek.pl/2017/04/22/dll-injection-part-6/ https://blog.adamfurmanek.pl/2017/04/22/dll-injection-part-6/#comments Sat, 22 Apr 2017 08:00:01 +0000 https://blog.adamfurmanek.pl/?p=2119 Continue reading DLL Injection Part 6 — Injecting managed code into specific App Domain]]>

This is the sixth part of the DLL Injection series. For your convenience you can find other parts in the table of contents in Part 1 – Registry

In Part 4 we saw how to inject managed DLL and execute some code in default App Domain. Today we will inject some code into different app domains. Actually, this is not tied to DLL injection (because we might want to do this in our application as well).

Listing App Domains

If you check reflection mechanism you will see that it is possible to list all type members (fields, methods, properties), all assembly types, all assemblies of app domain, but there is no simple way to list of app domains of a process. So how do we do it?

We know that .NET exe file can be executed as an ordinary Windows application. This is because it is in fact ordinary application. What it does at start is initializing .NET platform host and loading actual .NET code. We can use this host to list domains. This code does it (.NET 4, it requires COM reference to mscoree.tlb):

public static class CLRUtil
{
	public static IEnumerable<_AppDomain> EnumAppDomains()
	{
		// Obtain ICLRMetaHost interface
		object objHost;
		int hr = CLRCreateInstance(ref CLSID_CLRMetaHost, ref IID_CLRMetaHost, out objHost);
		if (hr < 0) throw new COMException("Cannot create meta host", hr);
		var host = (ICLRMetaHost)objHost;

		// Obtain ICLRRuntimeInfo interface
		var vers = Environment.Version;
		var versString = string.Format("v{0}.{1}.{2}", vers.Major, vers.Minor, vers.Build);
		var objRuntime = host.GetRuntime(versString, ref IID_CLRRuntimeInfo);
		var runtime = (ICLRRuntimeInfo)objRuntime;
		bool started;
		uint flags;
		runtime.IsStarted(out started, out flags);
		if (!started) throw new COMException("CLR not started??");

		// Obtain legacy ICorRuntimeHost interface and iterate appdomains
		var V2Host = (ICorRuntimeHost)runtime.GetInterface(ref CLSID_CorRuntimeHost, ref IID_CorRuntimeHost);
		IntPtr hDomainEnum;
		V2Host.EnumDomains(out hDomainEnum);
		for (;;)
		{
			_AppDomain domain = null;
			V2Host.NextDomain(hDomainEnum, out domain);
			if (domain == null) break;
			yield return domain;
		}
		V2Host.CloseEnum(hDomainEnum);
	}
}

If we don’t want to reference mscoree.tlb, we can use the following code:

public static class CLRUtil
	public static IList<AppDomain> EnumAppDomains()
	{
	    IList<AppDomain> _IList = new List<AppDomain>();
	    IntPtr enumHandle = IntPtr.Zero;
	    ICorRuntimeHost host = new CorRuntimeHost();
	    try
	    {
	        host.EnumDomains(out enumHandle);
	        object domain = null;
	        while (true)
	        {
	            host.NextDomain(enumHandle, out domain);
	            if (domain == null) break;
	            AppDomain appDomain = (AppDomain)domain;
	            _IList.Add(appDomain);
	        }
	        return _IList;
	    }
	    catch (Exception e)
	    {
	        Console.WriteLine(e.ToString());
	        return null;
	    }
	    finally
	    {
	        host.CloseEnum(enumHandle);
	        Marshal.ReleaseComObject(host);
	    }
	}

	private static Guid CLSID_CLRMetaHost = new Guid(0x9280188d, 0xe8e, 0x4867, 0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde);
	private static Guid IID_CLRMetaHost = new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16);
	private static Guid IID_CLRRuntimeInfo = new Guid(0xBD39D1D2, 0xBA2F, 0x486a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91);
	private static Guid CLSID_CorRuntimeHost = new Guid(0xcb2f6723, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e);
	private static Guid IID_CorRuntimeHost = new Guid(0xcb2f6722, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e);

	[DllImport("mscoree.dll")]
	private static extern int CLRCreateInstance(ref Guid clsid, ref Guid iid,
		[MarshalAs(UnmanagedType.Interface)] out object ptr);

	[ComImport, Guid("D332DB9E-B9B3-4125-8207-A14884F53216"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	private interface ICLRMetaHost
	{
		[return: MarshalAs(UnmanagedType.Interface)]
		object GetRuntime(string version, ref Guid iid);
		// Rest omitted
	}

	[ComImport, Guid("BD39D1D2-BA2F-486a-89B0-B4B0CB466891"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	private interface ICLRRuntimeInfo
	{
		void GetVersionString(char[] buffer, int bufferLength);
		void GetRuntimeDirectory(char[] buffer, int bufferLength);
		bool IsLoaded(IntPtr hProcess);
		void LoadErrorString(uint id, char[] buffer, int bufferLength, int lcid);
		void LoadLibrary(string path, out IntPtr hMdodule);
		void GetProcAddress(string name, out IntPtr addr);
		[return: MarshalAs(UnmanagedType.Interface)]
		object GetInterface(ref Guid clsid, ref Guid iid);
		bool IsLoadable();
		void SetDefaultStartupFlags(uint flags, string configFile);
		void GetDefaultStartupFlags(out uint flags, char[] configFile, int configFileLength);
		void BindAsLegacyV2Runtime();
		void IsStarted(out bool started, out uint flags);
	}

	[ComImport, Guid("CB2F6722-AB3A-11d2-9C40-00C04FA30A3E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	private interface ICorRuntimeHost
	{
		void CreateLogicalThreadState();
		void DeleteLogicalThreadState();
		void SwitchinLogicalThreadState(IntPtr cookie);
		void SwitchoutLogicalThreadState(out IntPtr cookie);
		void LocksHeldByLogicalThread(out int count);
		void MapFile(IntPtr hFile, out IntPtr address);
		void GetConfiguration(out IntPtr config);
		void Start();
		void Stop();
		void CreateDomain(string name, object identity, out _AppDomain domain);
		void GetDefaultDomain(out _AppDomain domain);
		void EnumDomains(out IntPtr hEnum);
		void NextDomain(IntPtr hEnum, out _AppDomain domain);
		void CloseEnum(IntPtr hEnum);
		// rest omitted
	}
}

And this allows us to list all domains.

Injecting code

In order to execute code in different app domain, we need to create object there. The simplest way is to do it like this:

foreach (var d in CLRUtil.EnumAppDomains())
{
	Log("AppDomain " + d.FriendlyName);
	try
	{
		var o = d.CreateInstance(@"MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "MyAssembly.Class1");
		Log("Object in remote app domain created");
	}
	catch (Exception exception)
	{
		Log(exception.Message);
	}
}

and now in constructor of Class1 we can do anything we want because we are already in target app domain.

]]>
https://blog.adamfurmanek.pl/2017/04/22/dll-injection-part-6/feed/ 1
DLL Injection Part 5 — Hacking Minesweeper https://blog.adamfurmanek.pl/2016/10/15/dll-injection-part-5/ https://blog.adamfurmanek.pl/2016/10/15/dll-injection-part-5/#comments Sat, 15 Oct 2016 08:00:52 +0000 https://blog.adamfurmanek.pl/?p=1842 Continue reading DLL Injection Part 5 — Hacking Minesweeper]]>

This is the fifth part of the DLL Injection series. For your convenience you can find other parts in the table of contents in Part 1 – Registry

In previous posts of this series we saw how to inject DLLs in different ways. Today we are going to write simple DLL to hack Windows XP Minesweeper!

This post is based on Playing with Minesweeper post which described how to hack the game using WinDBG. We are going to do exactly the same, but with DLL injection.

Code

You can find detailed description somewhere else, so today I will just move on to the code:

#include "stdafx.h"
#include < cstdio >
#include < windows.h >
#include < string >

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:{
							char *PEB = NULL;
							__asm
							{
								mov eax, fs:[0x30]
								mov PEB, eax
							}

							

							char *target = (char*)((*(int*)((int)PEB + 8)) + 0x36FA);
							char buffer[] = { (char)0xC6, (char)0x00, (char)0x8A };
							// eb poi(@$peb + 0x8) + 0x36fa c6 00 8a - shows mines
							// eb poi(@$peb + 0x8) + 0x36fa c6 00 8e - flags mines

							SIZE_T written;
							WriteProcessMemory(GetCurrentProcess(), target, &buffer, 3, &written);
							break;
	}
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

We are basically doing exactly the same thing as we would do in WinDBG. Interesting part is how to access Process Environment Block using asm snippet, but it is not something you would do in production.

In order to get it working, you need to inject the DLL at start of application, so you probably would like to use registry injection — remember that injection via registry injects library to all processes! As this is just for demonstration purposes, there is little to no error handling.

However, there is one little surprise in the application, but you need to run it in order to find out what’s going on.

]]>
https://blog.adamfurmanek.pl/2016/10/15/dll-injection-part-5/feed/ 1