{"id":18603050,"url":"https://github.com/devlooped/injector","last_synced_at":"2025-04-10T19:31:27.952Z","repository":{"id":37964720,"uuid":"482905052","full_name":"devlooped/Injector","owner":"devlooped","description":"Allows injecting .NET code into another Windows process","archived":false,"fork":false,"pushed_at":"2024-05-26T01:07:20.000Z","size":154,"stargazers_count":12,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-28T11:57:55.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devlooped.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"devlooped"}},"created_at":"2022-04-18T15:51:39.000Z","updated_at":"2024-05-30T07:02:16.524Z","dependencies_parsed_at":"2024-05-30T07:02:07.896Z","dependency_job_id":"f963d5e0-65a2-4273-ab63-413884537f69","html_url":"https://github.com/devlooped/Injector","commit_stats":{"total_commits":113,"total_committers":5,"mean_commits":22.6,"dds":0.1415929203539823,"last_synced_commit":"8637af527f395237a3629c930761d6ac599ceb76"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FInjector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FInjector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FInjector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FInjector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devlooped","download_url":"https://codeload.github.com/devlooped/Injector/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248281401,"owners_count":21077423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T02:13:22.168Z","updated_at":"2025-04-10T19:31:22.934Z","avatar_url":"https://github.com/devlooped.png","language":"C++","funding_links":["https://github.com/sponsors/devlooped","https://github.com/sponsors"],"categories":[],"sub_categories":[],"readme":"![Icon](https://raw.githubusercontent.com/devlooped/Injector/main/assets/img/icon-32.png) .NET Injector\n============\n\n[![Version](https://img.shields.io/nuget/vpre/Devlooped.Injector.svg)](https://www.nuget.org/packages/Devlooped.Injector)\n[![Downloads](https://img.shields.io/nuget/dt/Devlooped.Injector.svg)](https://www.nuget.org/packages/Devlooped.Injector)\n[![License](https://img.shields.io/github/license/devlooped/Injector.svg?color=blue)](https://github.com//devlooped/Injector/blob/main/license.txt)\n[![Build](https://github.com/devlooped/Injector/workflows/build/badge.svg?branch=main)](https://github.com/devlooped/Injector/actions)\n\n\u003c!-- #content --\u003e\nAllows injecting .NET code into any Windows process.\n\nHeavily based on [Cory Plott](http://www.cplotts.com)'s [Snoop](https://github.com/cplotts/snoopwpf).\n\nThe only requirement is that the injected code must be a public static method on a public static \nclass, such as:\n\n```csharp\nnamespace Sample;\n\npublic static class Startup\n{\n    public static void Start(string arg1, int arg2, bool debug)\n    {\n        if (debug)\n            Debugger.Launch();\n\n        // do stuff with arg1, arg2, etc.\n        // note args are typed :)\n    }\n}\n```\n\n\u003e NOTE: parameter type conversion is supported and happens via the `TypeConverter` associated with the \nparameter type.\n\n\n## Usage\n\nThere are two main usages for this package:\n\n* From AnyCPU code: your code is bitness-agnostic and can be injected into \n  the target process whether it's x86 or x64.\n* From x86/x64 code: you are injecting into a target process that has the same \n  bitness as the calling code. \n\n### AnyCPU code\n\nThis is likely the more common scenario. You have .NET code that is AnyCPU and can \ntherefore be injected regardless of the target process bitness. When referencing this \npackage, you will get two (content) folders containing a helper `Injector.exe` for each architecture:\n\n![Screenshot](https://raw.githubusercontent.com/devlooped/Injector/main/assets/img/content-files.png)\n\nThese files are automatically copied to the output directory under `Injector\\[x86|x64]\\Injector.exe` \n(and are also included when doing `dotnet publish`). This allows you to run the relevant executable \nthat matches the target process bitness. \n\n`Injector.exe` usage:\n\n```\n\u003e Injector.exe -?\nUsage: Injector.exe \u003cmainWindowHandle\u003e \u003cassemblyFile\u003e \u003ctypeName\u003e \u003cmethodName\u003e\n\nArguments:\n  \u003cprocessMainWindowHandle\u003e   IntPtr of the main window handle of the process to inject, i.e. Process.MainWindowHandle.\n  \u003cassemblyFile\u003e              The full path to the .NET assembly to load in the remote process.\n  \u003ctypeName\u003e                  Full type name of the public static class to invoke in the remote process.\n  \u003cmethodName\u003e                Name of the static method in that class to invoke in the remote process. Must be a\n                              static method, which can also receive arguments, such as 'Start:true:42'.\n```\n\nTo detect the target process bitness, you can use the following bit of interop:\n\n```csharp\nstatic class NativeMethods\n{\n    [DllImport(\"kernel32.dll\", SetLastError = true, CallingConvention = CallingConvention.Winapi)]\n    [return: MarshalAs(UnmanagedType.Bool)]\n    internal static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process);\n}\n```\n\nAnd the following code would lookup the target process (in this case, we just get the first instance \nof `devenv.exe`, the Visual Studio main process, as an example), and invoke the right executable:\n\n```csharp\nvar targetProcess = System.Diagnostics.Process.GetProcessesByName(\"devenv.exe\")[0];\n\nNativeMethods.IsWow64Process(targetProcess.Handle, out var isWow);\nvar platform = isWow ? \"x86\" : \"x64\";\n\nProcess.Start(Path.Combine(\"Injector\", platform, \"Injector.exe\"),\n    // IntPtr of the main window handle of the process to inject\n    targetProcess.MainWindowHandle + \" \" +\n    // The full path to the .NET assembly to load in the remote process\n    Assembly.GetExecutingAssembly().Location + \" \" +\n    // Full type name of the public static class to invoke in the remote process\n    typeof(Startup).FullName + \" \" +\n    // Name of the static method in that class to invoke in the remote process, \n    // and any parameters.\n    $\"{nameof(Startup.Start)}:hello:42:true\");\n```\n\n\u003e NOTE: we can pass typed arguments to the `Startup.Start` method (shown as an example \n\u003e at the beginning) and type conversion will be applied automatically.\n\n\n### Platform-specific code\n\nWhen building platform-specific code, the project would typically have (for a console app, for example):\n\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\t\u003cPropertyGroup\u003e\n\t\t\u003cOutputType\u003eExe\u003c/OutputType\u003e\n\t\t\u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n\t\t\u003cPlatforms\u003ex64;x86\u003c/Platforms\u003e\n\t\u003c/PropertyGroup\u003e\n\u003c/Project\u003e\n```\n\nYou would then build for either platform via: `dotnet build --arch x64` or `dotnet build --arch x86`.  \n\nIn this case, the bitness of the calling code (that intends to inject itself into a remote process) \nmust match the target process bitness too. Since the bitness of both is the same, you can use the \nautomatically referenced assembly from your code, rather than invoking the helper `Injector.exe` \nas shown in the first case.\n\nThe code will otherwise look similar to the previous case:\n\n\n```csharp\nvar targetProcess = System.Diagnostics.Process.GetProcessesByName(\"devenv.exe\")[0];\n\n// NOTE: target process bitness must match our own assembly architecture for \n// this to succeed.\nDevlooped.Injector.Launch(\n    // IntPtr of the main window handle of the process to inject\n    targetProcess.MainWindowHandle,\n    // The full path to the .NET assembly to load in the remote process\n    Assembly.GetExecutingAssembly().Location,\n    // Full type name of the public static class to invoke in the remote process\n    typeof(Startup).FullName,\n    // Name of the static method in that class to invoke in the remote process, \n    // and any parameters.\n    $\"{nameof(Startup.Start)}:hello:42:true\");\n```\n\n\u003e NOTE: the `Devlooped.Injector` type will NOT be available on AnyCPU projects\n\n\nSee [Program.cs](src/Sample/Program.cs) for a complete example.\n\n\n\u003c!-- include https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n# Sponsors \n\n\u003c!-- sponsors.md --\u003e\n[![Clarius Org](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/clarius.png \"Clarius Org\")](https://github.com/clarius)\n[![Kirill Osenkov](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KirillOsenkov.png \"Kirill Osenkov\")](https://github.com/KirillOsenkov)\n[![MFB Technologies, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MFB-Technologies-Inc.png \"MFB Technologies, Inc.\")](https://github.com/MFB-Technologies-Inc)\n[![Stephen Shaw](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/decriptor.png \"Stephen Shaw\")](https://github.com/decriptor)\n[![Torutek](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/torutek-gh.png \"Torutek\")](https://github.com/torutek-gh)\n[![DRIVE.NET, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/drivenet.png \"DRIVE.NET, Inc.\")](https://github.com/drivenet)\n[![Ashley Medway](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/AshleyMedway.png \"Ashley Medway\")](https://github.com/AshleyMedway)\n[![Keith Pickford](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Keflon.png \"Keith Pickford\")](https://github.com/Keflon)\n[![Thomas Bolon](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tbolon.png \"Thomas Bolon\")](https://github.com/tbolon)\n[![Kori Francis](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/kfrancis.png \"Kori Francis\")](https://github.com/kfrancis)\n[![Toni Wenzel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/twenzel.png \"Toni Wenzel\")](https://github.com/twenzel)\n[![Giorgi Dalakishvili](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Giorgi.png \"Giorgi Dalakishvili\")](https://github.com/Giorgi)\n[![Uno Platform](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/unoplatform.png \"Uno Platform\")](https://github.com/unoplatform)\n[![Dan Siegel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/dansiegel.png \"Dan Siegel\")](https://github.com/dansiegel)\n[![Reuben Swartz](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/rbnswartz.png \"Reuben Swartz\")](https://github.com/rbnswartz)\n[![Jacob Foshee](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jfoshee.png \"Jacob Foshee\")](https://github.com/jfoshee)\n[![](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Mrxx99.png \"\")](https://github.com/Mrxx99)\n[![Eric Johnson](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/eajhnsn1.png \"Eric Johnson\")](https://github.com/eajhnsn1)\n[![Ix Technologies B.V.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/IxTechnologies.png \"Ix Technologies B.V.\")](https://github.com/IxTechnologies)\n[![David JENNI](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/davidjenni.png \"David JENNI\")](https://github.com/davidjenni)\n[![Jonathan ](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Jonathan-Hickey.png \"Jonathan \")](https://github.com/Jonathan-Hickey)\n[![Oleg Kyrylchuk](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/okyrylchuk.png \"Oleg Kyrylchuk\")](https://github.com/okyrylchuk)\n[![Charley Wu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/akunzai.png \"Charley Wu\")](https://github.com/akunzai)\n[![Jakob Tikjøb Andersen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jakobt.png \"Jakob Tikjøb Andersen\")](https://github.com/jakobt)\n[![Seann Alexander](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/seanalexander.png \"Seann Alexander\")](https://github.com/seanalexander)\n[![Tino Hager](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tinohager.png \"Tino Hager\")](https://github.com/tinohager)\n[![Mark Seemann](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/ploeh.png \"Mark Seemann\")](https://github.com/ploeh)\n[![Ken Bonny](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KenBonny.png \"Ken Bonny\")](https://github.com/KenBonny)\n[![Simon Cropp](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/SimonCropp.png \"Simon Cropp\")](https://github.com/SimonCropp)\n[![agileworks-eu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/agileworks-eu.png \"agileworks-eu\")](https://github.com/agileworks-eu)\n[![sorahex](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/sorahex.png \"sorahex\")](https://github.com/sorahex)\n[![Zheyu Shen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/arsdragonfly.png \"Zheyu Shen\")](https://github.com/arsdragonfly)\n[![Vezel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/vezel-dev.png \"Vezel\")](https://github.com/vezel-dev)\n[![ChilliCream](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/ChilliCream.png \"ChilliCream\")](https://github.com/ChilliCream)\n[![4OTC](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/4OTC.png \"4OTC\")](https://github.com/4OTC)\n\n\n\u003c!-- sponsors.md --\u003e\n\n[![Sponsor this project](https://raw.githubusercontent.com/devlooped/sponsors/main/sponsor.png \"Sponsor this project\")](https://github.com/sponsors/devlooped)\n\u0026nbsp;\n\n[Learn more about GitHub Sponsors](https://github.com/sponsors)\n\n\u003c!-- https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Finjector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevlooped%2Finjector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Finjector/lists"}