x86 – Random IT Utensils https://blog.adamfurmanek.pl IT, operating systems, maths, and more. Sat, 02 Jan 2021 19:11:48 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.2 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
.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 1 — Registry https://blog.adamfurmanek.pl/2016/03/26/dll-injection-part-1/ https://blog.adamfurmanek.pl/2016/03/26/dll-injection-part-1/#comments Fri, 25 Mar 2016 23:00:26 +0000 https://blog.adamfurmanek.pl/?p=1602 Continue reading DLL Injection Part 1 — Registry]]>

This is the first part of the DLL Injection series. For your convenience you can find other parts using the links below :
Part 1 — Registry
Part 2 — Hooks
Part 3 — Creating remote thread
Part 4 — Injecting managed DLL
Part 5 — Hacking Minesweeper
Part 6 — Injecting managed code into specific App Domain
Part 7 — Injecting Java code

If you are interested in the topic see the talk page

Hello. In this post I start a new series in which we will see some methods of injecting DLLs. Today we start with an introduction and a few simple methods.

Introduction

Why would you want to inject DLL? Usually DLL injection is used for running custom code within the address space of another process. There are multiple applications which do that:

  • ConEmu uses this technique to hijack console windows
  • EMET loads its custom DLL to enhance application security
  • Sophos injects its libraries to protect system
  • ForceBindIP loadss its DLLs to modify sockets behavior

Usually we want to inject our library to modify behavior of some system APIs, simplify reading and writing memory, add plugins, or to control another application.

Requirements

In order to execute our code within different process we need to consider some basics.

First, we are not going to hack a machine. We assume that we control the system (however, we might not have an administrator privileges) and we are able to freely save files, run applications, and execute code we like.

We do not want to modify existing application’s source code, especially we do not want to recompile it. We want to start application normally and then inject our code.

We need to remember about virtual memory. Every application runs in its own memory address space and, from its point of view, the memory is linear. The process doesn’t care about physical mapping of memory frames, however, we need to be aware of this process.

We want the process to be clean and reliable.

Virtual Address Space

Every process run in its own address space and memory is divided into partitions. On x86 architecture there are four of them:

  • NULL-Pointer assignment
  • User-Mode
  • 64KB Off-Limits
  • Kernel-Mode

Below are ranges of these partitions:

    \begin{gather*} \label{tab:sets} \begin{tabular}{|c|c|c|} \hline Partition & 32-Bit Windows & 32-Bit Windows with 3 GB User-Mode\\ \hline NULL-Pointer & 0x00000000 - 0x0000FFFF & 0x00000000 - 0x0000FFFF\\ \hline User-Mode & 0x00010000 - 0x7FFEFFFF & 0x00010000 - 0xBFFEFFFF \\ \hline 64-KB Off-Limits & 0x7FFF0000 - 0x7FFFFFFF & 0xBFFFF0000 - 0xBFFFFFFF \\ \hline Kernel-Mode & 0x80000000 - 0xFFFFFFFF & 0xC0000000 - 0xFFFFFFFF  \\ \hline \end{tabular} \end{gather*}

Ranges for x64:

    \begin{gather*} \label{tab:sets} \begin{tabular}{|c|c|} \hline Partition &  64-Bit Windows \\ \hline NULL-Pointer &  0x00000000'00000000 - 0x00000000'0000FFFF\\ \hline User-Mode &  0x00000000'00010000 - 0x000007FF'FFFEFFFF\\ \hline 64-KB Off-Limits &  0x000007FF'FFFF0000 - 0x000007FF'FFFFFFFF\\ \hline Kernel-Mode &  0x00000800'00000000 - 0xFFFFFFFF'FFFFFFFF \\ \hline \end{tabular} \end{gather*}

As we can see, process thinks that its memory is linear. It is up to the operating system how the actual frames of memory are stored — they can be in RAM, paged to disk, mapped to files etc.

In order to load and execute code from library, process needs to load the library into its address space. Every binary (executable or library) has its preferred address meaning where the binary would like to be loaded. It is important because if we load binary to different place we need to rebase the binary. We also need to remember that the same library can be loaded into different address in different processes. There is also a mechanism for randomizing address space layout.

So when we load our code we need to be very careful. We cannot just reference memory by addresses blindly because they can differ between processes.

Global Loader Lock

During execution of LoadLibrary your application holds a lock. Because of this there are things which should not be done when loading library. This means that even if we are able to load our library, we cannot execute every code during initialization and we need to take another actions. We will see some details in next parts of this series.

Search order

When process wants to load a library, the following places are searched for matching file:

  1. The directory containing the executable image file
  2. The Windows system directory returned by GetWindowsDirectory function
  3. The 16-bit system directory (System subfolder under the Windows directory)
  4. The Windows directory returned by GetSystemDirectory
  5. The process’ current directory
  6. The directories listed in the PATH environment variable

We can change order of last two steps in registry.

This gives us first method of injecting our code into another process: we simply replace the DLL file stored on the disk with our library, which should export methods with the same signatures as the original library.

Registry

There is an easy way to inject DLL into a process which loads User32.dll. During initialization User32.dll looks into the registry and checks if HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs is set to 1. If it is so, then library loads all DLLs listed in HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs. So we can just add our DLL in the registry and have it loaded into every process which loads User32.dll. Good news is: most of Windows applications loads this library so it is fairly common.

Of course there are shortcomings of this method. First, we need to have an administrator privileges in order to modify the registry. What’s more, our library is loaded into every process loading system library, so we need to make sure that we are executing code in a correct process. Finally, we cannot control the moment of library injection and we are unable to load our library into already running process.

Injecting into spawned process

There is another way using registry. If we add library to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDLLs key, our library will be loaded into every process that calls the Win32 API functions like CreateProcess. Shortcomings are almost the same as in the previous method.

Summary

In the next part we will see another method based on system hooks.

]]>
https://blog.adamfurmanek.pl/2016/03/26/dll-injection-part-1/feed/ 6