/// <summary> /// Injects instructions at the specified location, overwriting following instructions. This will nop-fill. /// </summary> /// <param name="address">The injection address.</param> /// <param name="assembly">The assembly code to disassemble and inject into the code cave.</param> /// <returns>The address of the code cave.</returns> public UInt64 InjectCode(UInt64 address, String assembly) { this.PrintDebugTag(); assembly = this.ResolveKeywords(assembly); Int32 assemblySize = this.GetAssemblySize(assembly, address); Byte[] originalBytes = this.CollectOriginalBytes(address, assemblySize); if (originalBytes == null) { throw new Exception("Could not gather original bytes"); } // Determine number of no-ops to fill dangling bytes String noOps = (originalBytes.Length - assemblySize > 0 ? "db " : String.Empty) + String.Join(" ", Enumerable.Repeat("0x90,", originalBytes.Length - assemblySize)).TrimEnd(','); Byte[] injectionBytes = this.GetAssemblyBytes(assembly + "\n" + noOps, address); EngineCore.GetInstance().VirtualMemory.WriteBytes(address.ToIntPtr(), injectionBytes); CodeCave codeCave = new CodeCave(address, 0, originalBytes); this.CodeCaves.Add(codeCave); return(address); }
/// <summary> /// Creates a code cave that jumps from a given entry address and executes the given assembly. This will nop-fill. /// If the injected assmebly code fits in one instruction, no cave will be created. /// </summary> /// <param name="address">The injection address.</param> /// <param name="assembly">The assembly code to disassemble and inject into the code cave.</param> /// <returns>The address of the code cave. Returns zero if no allocation was necessary.</returns> public UInt64 CreateCodeCave(UInt64 address, String assembly) { this.PrintDebugTag(); assembly = this.ResolveKeywords(assembly); // Determine size of our injected code Int32 assemblySize = this.GetAssemblySize(assembly, address); // Determine the minimum number of bytes that need to be replaced Int32 minimumReplacementSize = Math.Min(assemblySize, MemoryCore.JumpSize); // Gather the original bytes Byte[] originalBytes = this.CollectOriginalBytes(address, minimumReplacementSize); // Handle case where allocation is not needed if (assemblySize <= originalBytes.Length) { // Determine number of no-ops to fill dangling bytes String noOps = assemblySize - originalBytes.Length > 0 ? "db " + String.Join(" ", Enumerable.Repeat("0x90,", assemblySize - originalBytes.Length)).TrimEnd(',') : String.Empty; Byte[] injectionBytes = this.GetAssemblyBytes(assembly + Environment.NewLine + noOps, address); this.Write(address, injectionBytes); CodeCave codeCave = new CodeCave(address, 0, originalBytes); this.CodeCaves.Add(codeCave); return(address); } else { // Determine number of no-ops to fill dangling bytes String noOps = originalBytes.Length - minimumReplacementSize > 0 ? "db " + String.Join(" ", Enumerable.Repeat("0x90,", originalBytes.Length - minimumReplacementSize)).TrimEnd(',') : String.Empty; // Add code cave jump return automatically UInt64 returnAddress = this.GetCaveExitAddress(address); // Place jump to return address assembly = assembly.Trim() + Environment.NewLine + "jmp " + Conversions.ToHex(returnAddress, formatAsAddress: false, includePrefix: true); assemblySize = this.GetAssemblySize(assembly, address); // Allocate memory UInt64 remoteAllocation; if (EngineCore.GetInstance().Processes.IsOpenedProcess32Bit()) { remoteAllocation = this.Allocate(assemblySize); } else { remoteAllocation = this.Allocate(assemblySize, address); } // Write injected code to new page Byte[] injectionBytes = this.GetAssemblyBytes(assembly, remoteAllocation); this.Write(remoteAllocation, injectionBytes); // Write in the jump to the code cave String codeCaveJump = ("jmp " + Conversions.ToHex(remoteAllocation, formatAsAddress: false, includePrefix: true) + Environment.NewLine + noOps).Trim(); Byte[] jumpBytes = this.GetAssemblyBytes(codeCaveJump, address); this.Write(address, jumpBytes); // Save this code cave for later deallocation CodeCave codeCave = new CodeCave(address, remoteAllocation, originalBytes); this.CodeCaves.Add(codeCave); return(remoteAllocation); } }