internal static Span <byte> AssembleCall32(CallDescriptor32 callDescriptor) { var instructions = new List <byte>(); foreach (var argument in callDescriptor.Arguments.Reverse()) { if (argument <= sbyte.MaxValue) { // push argument instructions.AddRange(new byte[] { 0x6A, (byte)argument }); } else { // push argument instructions.Add(0x68); instructions.AddRange(BitConverter.GetBytes(argument)); } } // mov eax, Address instructions.Add(0xB8); instructions.AddRange(BitConverter.GetBytes(callDescriptor.Address.ToInt32())); // call eax instructions.AddRange(new byte[] { 0xFF, 0xD0 }); if (callDescriptor.ReturnAddress != IntPtr.Zero) { // mov ReturnAddress, eax instructions.Add(0xA3); instructions.AddRange(BitConverter.GetBytes(callDescriptor.ReturnAddress.ToInt32())); } // xor eax, eax instructions.AddRange(new byte[] { 0x33, 0xC0 }); // ret instructions.Add(0xC3); return(instructions.ToArray()); }
internal T CallRoutine <T>(IntPtr routineAddress, params dynamic[] arguments) where T : unmanaged { var returnAddress = Process.AllocateMemory(Unsafe.SizeOf <T>()); // Create the shellcode used to call the routine Span <byte> shellcodeBytes; if (Process.GetArchitecture() == Architecture.X86) { var callDescriptor = new CallDescriptor32(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), returnAddress); shellcodeBytes = CallAssembler.AssembleCall32(callDescriptor); } else { var routineDescriptor = new CallDescriptor64(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), returnAddress); shellcodeBytes = CallAssembler.AssembleCall64(routineDescriptor); } try { // Write the shellcode bytes into the process var shellcodeBytesAddress = Process.AllocateMemory(shellcodeBytes.Length, true); try { Process.WriteArray(shellcodeBytesAddress, shellcodeBytes); // Create a thread to execute the shellcode Process.CreateThread(shellcodeBytesAddress); } finally { Process.FreeMemory(shellcodeBytesAddress); } return(Process.ReadStructure <T>(returnAddress)); } finally { Process.FreeMemory(returnAddress); } }
internal void CallRoutine(IntPtr routineAddress, params dynamic[] arguments) { // Create the shellcode used to call the routine Span <byte> shellcodeBytes; if (Process.GetArchitecture() == Architecture.X86) { var callDescriptor = new CallDescriptor32(routineAddress, Array.ConvertAll(arguments, argument => (int)argument), IntPtr.Zero); shellcodeBytes = CallAssembler.AssembleCall32(callDescriptor); } else { var routineDescriptor = new CallDescriptor64(routineAddress, Array.ConvertAll(arguments, argument => (long)argument), IntPtr.Zero); shellcodeBytes = CallAssembler.AssembleCall64(routineDescriptor); } // Write the shellcode bytes into the process var shellcodeBytesAddress = Process.AllocateMemory(shellcodeBytes.Length, true); try { Process.WriteArray(shellcodeBytesAddress, shellcodeBytes); // Create a thread to execute the shellcode Process.CreateThread(shellcodeBytesAddress); } finally { Process.FreeMemory(shellcodeBytesAddress); } }