├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml ├── release.yml └── workflows │ ├── build.yml │ ├── changelog.config │ ├── changelog.yml │ ├── dotnet-file.yml │ ├── includes.yml │ ├── publish.yml │ └── triage.yml ├── .gitignore ├── .netconfig ├── Directory.Build.rsp ├── GitInfo.txt ├── Injector.sln ├── _config.yml ├── assets ├── css │ └── style.scss └── img │ ├── content-files.png │ ├── icon-32.png │ ├── icon.png │ └── icon.svg ├── changelog.md ├── license.txt ├── readme.md └── src ├── Bootstrap ├── AssemblyInfo.cpp ├── Bootstrap.vcxproj ├── Bootstrap.vcxproj.filters ├── Injector.cpp ├── Injector.h ├── Stdafx.cpp ├── Stdafx.h └── makefile.def ├── Directory.Build.props ├── Directory.Build.targets ├── Injector ├── App.config ├── Injector.csproj ├── Program.cs ├── build │ ├── Devlooped.Injector.props │ └── Devlooped.Injector.targets ├── msbuild.rsp └── readme.md ├── Sample ├── App.config ├── Program.cs ├── Properties │ └── launchSettings.json └── Sample.csproj ├── icon.png ├── kzu.snk └── nuget.config /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Don't use tabs for indentation. 7 | [*] 8 | indent_style = space 9 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 10 | 11 | # Code files 12 | [*.{cs,csx,vb,vbx}] 13 | indent_size = 4 14 | 15 | # Xml project files 16 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}] 17 | indent_size = 2 18 | 19 | # Xml config files 20 | [*.{ruleset,config,nuspec,resx,vsixmanifest,vsct}] 21 | indent_size = 2 22 | 23 | # YAML files 24 | [*.{yaml,yml}] 25 | indent_size = 2 26 | 27 | # JSON files 28 | [*.json] 29 | indent_size = 2 30 | 31 | # Dotnet code style settings: 32 | [*.{cs,vb}] 33 | # Sort using and Import directives with System.* appearing first 34 | dotnet_sort_system_directives_first = true 35 | # Avoid "this." and "Me." if not necessary 36 | dotnet_style_qualification_for_field = false:suggestion 37 | dotnet_style_qualification_for_property = false:suggestion 38 | dotnet_style_qualification_for_method = false:suggestion 39 | dotnet_style_qualification_for_event = false:suggestion 40 | 41 | # Use language keywords instead of framework type names for type references 42 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 43 | dotnet_style_predefined_type_for_member_access = true:suggestion 44 | 45 | # Suggest more modern language features when available 46 | dotnet_style_object_initializer = true:suggestion 47 | dotnet_style_collection_initializer = true:suggestion 48 | dotnet_style_coalesce_expression = true:suggestion 49 | dotnet_style_null_propagation = true:suggestion 50 | dotnet_style_explicit_tuple_names = true:suggestion 51 | 52 | # CSharp code style settings: 53 | 54 | # IDE0040: Add accessibility modifiers 55 | dotnet_style_require_accessibility_modifiers = omit_if_default:error 56 | 57 | # IDE0040: Add accessibility modifiers 58 | dotnet_diagnostic.IDE0040.severity = error 59 | 60 | [*.cs] 61 | # Top-level files are definitely OK 62 | csharp_using_directive_placement = outside_namespace:silent 63 | csharp_style_namespace_declarations = block_scoped:silent 64 | csharp_prefer_simple_using_statement = true:suggestion 65 | csharp_prefer_braces = true:silent 66 | 67 | # Prefer "var" everywhere 68 | csharp_style_var_for_built_in_types = true:suggestion 69 | csharp_style_var_when_type_is_apparent = true:suggestion 70 | csharp_style_var_elsewhere = true:suggestion 71 | 72 | # Prefer method-like constructs to have an expression-body 73 | csharp_style_expression_bodied_methods = true:none 74 | csharp_style_expression_bodied_constructors = true:none 75 | csharp_style_expression_bodied_operators = true:none 76 | 77 | # Prefer property-like constructs to have an expression-body 78 | csharp_style_expression_bodied_properties = true:none 79 | csharp_style_expression_bodied_indexers = true:none 80 | csharp_style_expression_bodied_accessors = true:none 81 | 82 | # Suggest more modern language features when available 83 | csharp_style_pattern_matching_over_is_with_cast_check = true:error 84 | csharp_style_pattern_matching_over_as_with_null_check = true:error 85 | csharp_style_inlined_variable_declaration = true:suggestion 86 | csharp_style_throw_expression = true:suggestion 87 | csharp_style_conditional_delegate_call = true:suggestion 88 | 89 | # Newline settings 90 | csharp_new_line_before_open_brace = all 91 | csharp_new_line_before_else = true 92 | csharp_new_line_before_catch = true 93 | csharp_new_line_before_finally = true 94 | csharp_new_line_before_members_in_object_initializers = true 95 | csharp_new_line_before_members_in_anonymous_types = true 96 | 97 | # Test settings 98 | [**/*Tests*/**{.cs,.vb}] 99 | # xUnit1013: Public method should be marked as test. Allows using records as test classes 100 | dotnet_diagnostic.xUnit1013.severity = none 101 | 102 | # CS9113: Parameter is unread (usually, ITestOutputHelper) 103 | dotnet_diagnostic.CS9113.severity = none 104 | 105 | # Default severity for analyzer diagnostics with category 'Style' 106 | dotnet_analyzer_diagnostic.category-Style.severity = none 107 | 108 | # VSTHRD200: Use "Async" suffix for async methods 109 | dotnet_diagnostic.VSTHRD200.severity = none 110 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # normalize by default 2 | * text=auto encoding=UTF-8 3 | *.sh text eol=lf 4 | 5 | # These are windows specific files which we may as well ensure are 6 | # always crlf on checkout 7 | *.bat text eol=crlf 8 | *.cmd text eol=crlf 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: nuget 7 | directory: / 8 | schedule: 9 | interval: daily 10 | groups: 11 | Azure: 12 | patterns: 13 | - "Azure*" 14 | - "Microsoft.Azure*" 15 | Identity: 16 | patterns: 17 | - "System.IdentityModel*" 18 | - "Microsoft.IdentityModel*" 19 | System: 20 | patterns: 21 | - "System*" 22 | exclude-patterns: 23 | - "System.IdentityModel*" 24 | Extensions: 25 | patterns: 26 | - "Microsoft.Extensions*" 27 | Web: 28 | patterns: 29 | - "Microsoft.AspNetCore*" 30 | Tests: 31 | patterns: 32 | - "Microsoft.NET.Test*" 33 | - "xunit*" 34 | - "coverlet*" 35 | ThisAssembly: 36 | patterns: 37 | - "ThisAssembly*" 38 | ProtoBuf: 39 | patterns: 40 | - "protobuf-*" 41 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - bydesign 5 | - dependencies 6 | - duplicate 7 | - question 8 | - invalid 9 | - wontfix 10 | - need info 11 | - techdebt 12 | authors: 13 | - devlooped-bot 14 | - dependabot 15 | - github-actions 16 | categories: 17 | - title: ✨ Implemented enhancements 18 | labels: 19 | - enhancement 20 | - title: 🐛 Fixed bugs 21 | labels: 22 | - bug 23 | - title: 📝 Documentation updates 24 | labels: 25 | - docs 26 | - documentation 27 | - title: 🔨 Other 28 | labels: 29 | - '*' 30 | exclude: 31 | labels: 32 | - dependencies 33 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Builds and runs tests in all three supported OSes 2 | # Pushes CI feed if secrets.SLEET_CONNECTION is provided 3 | 4 | name: build 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: [ main, dev, 'feature/*', 'rel/*' ] 9 | paths-ignore: 10 | - changelog.md 11 | - code-of-conduct.md 12 | - security.md 13 | - support.md 14 | pull_request: 15 | types: [opened, synchronize, reopened] 16 | 17 | env: 18 | DOTNET_NOLOGO: true 19 | 20 | jobs: 21 | build: 22 | name: build 23 | runs-on: windows-latest 24 | steps: 25 | - name: 🤘 checkout 26 | uses: actions/checkout@v2 27 | with: 28 | submodules: recursive 29 | fetch-depth: 0 30 | 31 | - name: ✓ ensure format 32 | run: dotnet format --verify-no-changes -v:diag --exclude ~/.nuget 33 | 34 | - name: ≥ msbuild 35 | id: msbuild 36 | uses: microsoft/setup-msbuild@v1.1 37 | 38 | - name: 🙏 build 39 | working-directory: ./src/Injector 40 | run: msbuild -r -t:"build;pack" -p:VersionLabel="$env:GITHUB_REF.$env:GITHUB_RUN_NUMBER" 41 | 42 | - name: 🚀 sleet 43 | env: 44 | SLEET_CONNECTION: ${{ secrets.SLEET_CONNECTION }} 45 | if: env.SLEET_CONNECTION != '' 46 | run: | 47 | dotnet tool install -g --version 4.0.18 sleet 48 | sleet push bin --config none -f --verbose -p "SLEET_FEED_CONTAINER=nuget" -p "SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}" -p "SLEET_FEED_TYPE=azure" || echo "No packages found" 49 | -------------------------------------------------------------------------------- /.github/workflows/changelog.config: -------------------------------------------------------------------------------- 1 | usernames-as-github-logins=true 2 | issues_wo_labels=true 3 | pr_wo_labels=true 4 | exclude-labels=bydesign,dependencies,duplicate,discussion,question,invalid,wontfix,need info,docs 5 | enhancement-label=:sparkles: Implemented enhancements: 6 | bugs-label=:bug: Fixed bugs: 7 | issues-label=:hammer: Other: 8 | pr-label=:twisted_rightwards_arrows: Merged: 9 | unreleased=false 10 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: changelog 2 | on: 3 | workflow_dispatch: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | changelog: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 🤖 defaults 12 | uses: devlooped/actions-bot@v1 13 | with: 14 | name: ${{ secrets.BOT_NAME }} 15 | email: ${{ secrets.BOT_EMAIL }} 16 | gh_token: ${{ secrets.GH_TOKEN }} 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | - name: 🤘 checkout 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | ref: main 24 | token: ${{ env.GH_TOKEN }} 25 | 26 | - name: ⚙ ruby 27 | uses: ruby/setup-ruby@v1 28 | with: 29 | ruby-version: 3.0.3 30 | 31 | - name: ⚙ changelog 32 | run: | 33 | gem install github_changelog_generator 34 | github_changelog_generator --user ${GITHUB_REPOSITORY%/*} --project ${GITHUB_REPOSITORY##*/} --token $GH_TOKEN --o changelog.md --config-file .github/workflows/changelog.config 35 | 36 | - name: 🚀 changelog 37 | run: | 38 | git add changelog.md 39 | (git commit -m "🖉 Update changelog with ${GITHUB_REF#refs/*/}" && git push) || echo "Done" -------------------------------------------------------------------------------- /.github/workflows/dotnet-file.yml: -------------------------------------------------------------------------------- 1 | # Synchronizes .netconfig-configured files with dotnet-file 2 | name: dotnet-file 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | push: 8 | branches: [ 'dotnet-file' ] 9 | 10 | env: 11 | DOTNET_NOLOGO: true 12 | 13 | jobs: 14 | run: 15 | permissions: 16 | contents: write 17 | uses: devlooped/oss/.github/workflows/dotnet-file-core.yml@main 18 | secrets: 19 | BOT_NAME: ${{ secrets.BOT_NAME }} 20 | BOT_EMAIL: ${{ secrets.BOT_EMAIL }} 21 | GH_TOKEN: ${{ secrets.GH_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/includes.yml: -------------------------------------------------------------------------------- 1 | name: +Mᐁ includes 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - 'main' 7 | paths: 8 | - '**.md' 9 | - '!changelog.md' 10 | 11 | jobs: 12 | includes: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write 16 | pull-requests: write 17 | steps: 18 | - name: 🤖 defaults 19 | uses: devlooped/actions-bot@v1 20 | with: 21 | name: ${{ secrets.BOT_NAME }} 22 | email: ${{ secrets.BOT_EMAIL }} 23 | gh_token: ${{ secrets.GH_TOKEN }} 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - name: 🤘 checkout 27 | uses: actions/checkout@v4 28 | with: 29 | token: ${{ env.GH_TOKEN }} 30 | 31 | - name: +Mᐁ includes 32 | uses: devlooped/actions-includes@v1 33 | 34 | - name: ✍ pull request 35 | uses: peter-evans/create-pull-request@v6 36 | with: 37 | add-paths: '**.md' 38 | base: main 39 | branch: markdown-includes 40 | delete-branch: true 41 | labels: docs 42 | author: ${{ env.BOT_AUTHOR }} 43 | committer: ${{ env.BOT_AUTHOR }} 44 | commit-message: +Mᐁ includes 45 | title: +Mᐁ includes 46 | body: +Mᐁ includes 47 | token: ${{ env.GH_TOKEN }} 48 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # Builds a final release version and pushes to nuget.org 2 | # whenever a release is published. 3 | # Requires: secrets.NUGET_API_KEY 4 | 5 | name: publish 6 | on: 7 | release: 8 | types: [published] 9 | 10 | env: 11 | DOTNET_NOLOGO: true 12 | Configuration: Release 13 | 14 | jobs: 15 | publish: 16 | runs-on: windows-latest 17 | steps: 18 | - name: 🤘 checkout 19 | uses: actions/checkout@v2 20 | with: 21 | submodules: recursive 22 | fetch-depth: 0 23 | 24 | - name: ≥ msbuild 25 | id: msbuild 26 | uses: microsoft/setup-msbuild@v1.1 27 | 28 | - name: ✍ version 29 | shell: bash 30 | run: echo "Version=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV 31 | 32 | - name: 🙏 build 33 | working-directory: ./src/Injector 34 | run: msbuild -r -t:"build;pack" 35 | 36 | - name: 🚀 sleet 37 | env: 38 | SLEET_CONNECTION: ${{ secrets.SLEET_CONNECTION }} 39 | if: env.SLEET_CONNECTION != '' 40 | run: | 41 | dotnet tool install -g --version 4.0.18 sleet 42 | sleet push bin --config none -f --verbose -p "SLEET_FEED_CONTAINER=nuget" -p "SLEET_FEED_CONNECTIONSTRING=${{ secrets.SLEET_CONNECTION }}" -p "SLEET_FEED_TYPE=azure" || echo "No packages found" 43 | 44 | - name: 🚀 nuget 45 | if: github.event.release.prerelease == false 46 | run: dotnet nuget push bin\*.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} --skip-duplicate 47 | -------------------------------------------------------------------------------- /.github/workflows/triage.yml: -------------------------------------------------------------------------------- 1 | name: 'triage' 2 | on: 3 | schedule: 4 | - cron: '42 0 * * *' 5 | 6 | workflow_dispatch: 7 | # Manual triggering through the GitHub UI, API, or CLI 8 | inputs: 9 | daysBeforeClose: 10 | description: "Days before closing stale or need info issues" 11 | required: true 12 | default: "30" 13 | daysBeforeStale: 14 | description: "Days before labeling stale" 15 | required: true 16 | default: "180" 17 | daysSinceClose: 18 | description: "Days since close to lock" 19 | required: true 20 | default: "30" 21 | daysSinceUpdate: 22 | description: "Days since update to lock" 23 | required: true 24 | default: "30" 25 | 26 | permissions: 27 | actions: write # For managing the operation state cache 28 | issues: write 29 | contents: read 30 | 31 | jobs: 32 | stale: 33 | # Do not run on forks 34 | if: github.repository_owner == 'devlooped' 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: ⌛ rate 38 | shell: pwsh 39 | if: github.event_name != 'workflow_dispatch' 40 | env: 41 | GH_TOKEN: ${{ secrets.DEVLOOPED_TOKEN }} 42 | run: | 43 | # add random sleep since we run on fixed schedule 44 | $wait = get-random -max 180 45 | echo "Waiting random $wait seconds to start" 46 | sleep $wait 47 | # get currently authenticated user rate limit info 48 | $rate = gh api rate_limit | convertfrom-json | select -expandproperty rate 49 | # if we don't have at least 100 requests left, wait until reset 50 | if ($rate.remaining -lt 100) { 51 | $wait = ($rate.reset - (Get-Date (Get-Date).ToUniversalTime() -UFormat %s)) 52 | echo "Rate limit remaining is $($rate.remaining), waiting for $($wait / 1000) seconds to reset" 53 | sleep $wait 54 | $rate = gh api rate_limit | convertfrom-json | select -expandproperty rate 55 | echo "Rate limit has reset to $($rate.remaining) requests" 56 | } 57 | 58 | - name: ✏️ stale labeler 59 | # pending merge: https://github.com/actions/stale/pull/1176 60 | uses: kzu/stale@c8450312ba97b204bf37545cb249742144d6ca69 61 | with: 62 | ascending: true # Process the oldest issues first 63 | stale-issue-label: 'stale' 64 | stale-issue-message: | 65 | Due to lack of recent activity, this issue has been labeled as 'stale'. 66 | It will be closed if no further activity occurs within ${{ fromJson(inputs.daysBeforeClose || 30 ) }} more days. 67 | Any new comment will remove the label. 68 | close-issue-message: | 69 | This issue will now be closed since it has been labeled 'stale' without activity for ${{ fromJson(inputs.daysBeforeClose || 30 ) }} days. 70 | days-before-stale: ${{ fromJson(inputs.daysBeforeStale || 180) }} 71 | days-before-close: ${{ fromJson(inputs.daysBeforeClose || 30 ) }} 72 | days-before-pr-close: -1 # Do not close PRs labeled as 'stale' 73 | exempt-all-milestones: true 74 | exempt-all-assignees: true 75 | exempt-issue-labels: priority,sponsor,backed 76 | exempt-authors: kzu 77 | 78 | - name: 🤘 checkout actions 79 | uses: actions/checkout@v4 80 | with: 81 | repository: 'microsoft/vscode-github-triage-actions' 82 | ref: v42 83 | 84 | - name: ⚙ install actions 85 | run: npm install --production 86 | 87 | - name: 🔒 issues locker 88 | uses: ./locker 89 | with: 90 | token: ${{ secrets.DEVLOOPED_TOKEN }} 91 | ignoredLabel: priority 92 | daysSinceClose: ${{ fromJson(inputs.daysSinceClose || 30) }} 93 | daysSinceUpdate: ${{ fromJson(inputs.daysSinceUpdate || 30) }} 94 | 95 | - name: 🔒 need info closer 96 | uses: ./needs-more-info-closer 97 | with: 98 | token: ${{ secrets.DEVLOOPED_TOKEN }} 99 | label: 'need info' 100 | closeDays: ${{ fromJson(inputs.daysBeforeClose || 30) }} 101 | closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity.\n\nHappy Coding!" 102 | pingDays: 80 103 | pingComment: "Hey @${assignee}, this issue might need further attention.\n\n@${author}, you can help us out by closing this issue if the problem no longer exists, or adding more information." -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | artifacts 4 | pack 5 | TestResults 6 | results 7 | BenchmarkDotNet.Artifacts 8 | /app 9 | .vs 10 | .vscode 11 | .genaiscript 12 | .idea 13 | local.settings.json 14 | 15 | *.suo 16 | *.sdf 17 | *.userprefs 18 | *.user 19 | *.nupkg 20 | *.metaproj 21 | *.tmp 22 | *.log 23 | *.cache 24 | *.binlog 25 | *.zip 26 | __azurite*.* 27 | __*__ 28 | 29 | .nuget 30 | *.lock.json 31 | *.nuget.props 32 | *.nuget.targets 33 | 34 | node_modules 35 | _site 36 | .jekyll-metadata 37 | .jekyll-cache 38 | .sass-cache 39 | Gemfile.lock 40 | package-lock.json 41 | -------------------------------------------------------------------------------- /.netconfig: -------------------------------------------------------------------------------- 1 | [file] 2 | url = https://github.com/devlooped/oss 3 | [file ".netconfig"] 4 | url = https://github.com/devlooped/oss/blob/main/.netconfig 5 | skip 6 | [file "SponsorLink.sln"] 7 | url = https://github.com/devlooped/oss/blob/main/SponsorLink.sln 8 | skip 9 | [file "readme.md"] 10 | url = https://github.com/devlooped/oss/blob/main/readme.md 11 | skip 12 | [file "src/icon.png"] 13 | url = https://github.com/devlooped/oss/blob/main/src/icon.png 14 | skip 15 | [file ".github/ISSUE_TEMPLATE/config.yml"] 16 | url = https://github.com/devlooped/oss/blob/main/.github/ISSUE_TEMPLATE/config.yml 17 | skip 18 | [file ".github/workflows/release-artifacts.yml"] 19 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/release-artifacts.yml 20 | skip 21 | [file "assets/images/sponsors.svg"] 22 | url = https://github.com/devlooped/oss/blob/main/assets/images/sponsors.svg 23 | skip 24 | [file "assets/images/sponsors.png"] 25 | url = https://github.com/devlooped/oss/blob/main/assets/images/sponsors.png 26 | skip 27 | [file ".editorconfig"] 28 | url = https://github.com/devlooped/oss/blob/main/.editorconfig 29 | sha = e81ab754b366d52d92bd69b24bef1d5b1c610634 30 | etag = 7298c6450967975a8782b5c74f3071e1910fc59686e48f9c9d5cd7c68213cf59 31 | weak 32 | [file ".gitattributes"] 33 | url = https://github.com/devlooped/oss/blob/main/.gitattributes 34 | sha = 5f92a68e302bae675b394ef343114139c075993e 35 | etag = 338ba6d92c8d1774363396739c2be4257bfc58026f4b0fe92cb0ae4460e1eff7 36 | weak 37 | [file ".github/dependabot.yml"] 38 | url = https://github.com/devlooped/oss/blob/main/.github/dependabot.yml 39 | sha = 49661dbf0720cde93eb5569be7523b5912351560 40 | etag = c147ea2f3431ca0338c315c4a45b56ee233c4d30f8d6ab698d0e1980a257fd6a 41 | weak 42 | [file ".github/workflows/build.yml"] 43 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/build.yml 44 | skip 45 | [file ".github/workflows/changelog.yml"] 46 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.yml 47 | sha = 5fb172362c767bef7c36478f1a6bdc264723f8f9 48 | etag = ad1efa56d6024ee1add2bcda81a7e4e38d0e9069473c6ff70374d5ce06af1f5a 49 | weak 50 | [file ".github/workflows/dotnet-file.yml"] 51 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/dotnet-file.yml 52 | sha = 8fa147d4799d73819040736c399d0b1db2c2d86c 53 | etag = 1ca805a23656e99c03f9d478dba8ccef6e571f5de2ac0e9bb7e3c5216c99a694 54 | weak 55 | [file ".github/workflows/publish.yml"] 56 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/publish.yml 57 | skip 58 | [file ".gitignore"] 59 | url = https://github.com/devlooped/oss/blob/main/.gitignore 60 | sha = e0be248fff1d39133345283b8227372b36574b75 61 | etag = c449ec6f76803e1891357ca2b8b4fcb5b2e5deeff8311622fd92ca9fbf1e6575 62 | weak 63 | [file "Directory.Build.rsp"] 64 | url = https://github.com/devlooped/oss/blob/main/Directory.Build.rsp 65 | sha = 0f7f7f7e8a29de9b535676f75fe7c67e629a5e8c 66 | etag = 0ccae83fc51f400bfd7058170bfec7aba11455e24a46a0d7e6a358da6486e255 67 | weak 68 | [file "_config.yml"] 69 | url = https://github.com/devlooped/oss/blob/main/_config.yml 70 | sha = fa83a5161ba52bc5d510ce0ba75ee0b1f8d4bc63 71 | etag = 9139148f845adf503fd3c3c140eb64421fc476a1f9c027fc50825c0efb05f557 72 | weak 73 | [file "assets/css/style.scss"] 74 | url = https://github.com/devlooped/oss/blob/main/assets/css/style.scss 75 | sha = 9db26e2710b084d219d6355339d822f159bf5780 76 | etag = f710d8919abfd5a8d00050b74ba7d0bb05c6d02e40842a3012eb96555c208504 77 | weak 78 | [file "license.txt"] 79 | url = https://github.com/devlooped/oss/blob/main/license.txt 80 | sha = 0683ee777d7d878d4bf013d7deea352685135a05 81 | etag = 2c6335b37e4ae05eea7c01f5d0c9d82b49c488f868a8b5ba7bff7c6ff01f3994 82 | weak 83 | [file "src/Directory.Build.props"] 84 | url = https://github.com/devlooped/oss/blob/main/src/Directory.Build.props 85 | sha = 2fff747a9673b499c99f2da183cdd5263fdc9333 86 | etag = 0fccddf04f282fe98122ab2610dc2972c205a521254559bf013655c6271b0017 87 | weak 88 | [file "src/Directory.Build.targets"] 89 | url = https://github.com/devlooped/oss/blob/main/src/Directory.Build.targets 90 | sha = a8b208093599263b7f2d1fe3854634c588ea5199 91 | etag = 19087699f05396205e6b050d999a43b175bd242f6e8fac86f6df936310178b03 92 | weak 93 | [file "src/kzu.snk"] 94 | url = https://github.com/devlooped/oss/blob/main/src/kzu.snk 95 | sha = 0683ee777d7d878d4bf013d7deea352685135a05 96 | etag = b8d789b5b6bea017cdcc8badcea888ad78de3e34298efca922054e9fb0e7b6b9 97 | weak 98 | [file ".github/workflows/includes.yml"] 99 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/includes.yml 100 | sha = 85829f2510f335f4a411867f3dbaaa116c3ab3de 101 | etag = 086f6b6316cc6ea7089c0dcc6980be519e6ed6e6201e65042ef41b82634ec0ee 102 | weak 103 | [file ".github/release.yml"] 104 | url = https://github.com/devlooped/oss/blob/main/.github/release.yml 105 | sha = 0c23e24704625cf75b2cb1fdc566cef7e20af313 106 | etag = 310df162242c95ed19ed12e3c96a65f77e558b46dced676ad5255eb12caafe75 107 | weak 108 | [file ".github/workflows/changelog.config"] 109 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/changelog.config 110 | sha = 08d83cb510732f861416760d37702f9f55bd7f9e 111 | etag = 556a28914eeeae78ca924b1105726cdaa211af365671831887aec81f5f4301b4 112 | weak 113 | [file ".github/workflows/combine-prs.yml"] 114 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/combine-prs.yml 115 | skip 116 | [file ".github/workflows/dotnet-file-core.yml"] 117 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/dotnet-file-core.yml 118 | skip 119 | [file ".github/workflows/triage.yml"] 120 | url = https://github.com/devlooped/oss/blob/main/.github/workflows/triage.yml 121 | sha = 33000c0c4ab4eb4e0e142fa54515b811a189d55c 122 | etag = 013a47739e348f06891f37c45164478cca149854e6cd5c5158e6f073f852b61a 123 | weak 124 | [file "src/nuget.config"] 125 | url = https://github.com/devlooped/oss/blob/main/src/nuget.config 126 | sha = 032439dbf180fca0539a5bd3a019f18ab3484b76 127 | etag = da7c0104131bd474b52fc9bc9f9bda6470e24ae38d4fb9f5c4f719bc01370ab5 128 | weak 129 | -------------------------------------------------------------------------------- /Directory.Build.rsp: -------------------------------------------------------------------------------- 1 | # See https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files 2 | -nr:false 3 | -m:1 4 | -v:m 5 | -clp:Summary;ForceNoAlign 6 | -------------------------------------------------------------------------------- /GitInfo.txt: -------------------------------------------------------------------------------- 1 | 1.0.2-alpha 2 | -------------------------------------------------------------------------------- /Injector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32407.343 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Injector", "src\Injector\Injector.csproj", "{87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bootstrap", "src\Bootstrap\Bootstrap.vcxproj", "{8072B47B-5611-4BAB-8EF4-CB3125D676A5}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DEEC9CA4-3E15-4B82-B024-F5009DB3092D}" 11 | ProjectSection(SolutionItems) = preProject 12 | .editorconfig = .editorconfig 13 | .github\workflows\build.yml = .github\workflows\build.yml 14 | src\Directory.Build.props = src\Directory.Build.props 15 | src\Directory.Build.targets = src\Directory.Build.targets 16 | .github\workflows\publish.yml = .github\workflows\publish.yml 17 | readme.md = readme.md 18 | EndProjectSection 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "src\Sample\Sample.csproj", "{16A5E068-9E95-4A58-AFD2-B06550E82C3F}" 21 | ProjectSection(ProjectDependencies) = postProject 22 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9} = {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9} 23 | EndProjectSection 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|x64 = Debug|x64 28 | Debug|x86 = Debug|x86 29 | Release|x64 = Release|x64 30 | Release|x86 = Release|x86 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x64.ActiveCfg = Debug|x64 34 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x64.Build.0 = Debug|x64 35 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x86.ActiveCfg = Debug|x86 36 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x86.Build.0 = Debug|x86 37 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x64.ActiveCfg = Release|x64 38 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x64.Build.0 = Release|x64 39 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x86.ActiveCfg = Release|x86 40 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x86.Build.0 = Release|x86 41 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x64.ActiveCfg = Debug|x64 42 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x64.Build.0 = Debug|x64 43 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x86.ActiveCfg = Debug|Win32 44 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x86.Build.0 = Debug|Win32 45 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x64.ActiveCfg = Release|x64 46 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x64.Build.0 = Release|x64 47 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x86.ActiveCfg = Release|Win32 48 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x86.Build.0 = Release|Win32 49 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x64.ActiveCfg = Debug|x64 50 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x64.Build.0 = Debug|x64 51 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x86.ActiveCfg = Debug|x86 52 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x86.Build.0 = Debug|x86 53 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x64.ActiveCfg = Release|x64 54 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x64.Build.0 = Release|x64 55 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x86.ActiveCfg = Release|x86 56 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x86.Build.0 = Release|x86 57 | EndGlobalSection 58 | GlobalSection(SolutionProperties) = preSolution 59 | HideSolutionNode = FALSE 60 | EndGlobalSection 61 | GlobalSection(ExtensibilityGlobals) = postSolution 62 | SolutionGuid = {C34B95A2-3544-4308-81E7-249E03E05A01} 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | 3 | exclude: [ 'src/', '*.sln', 'Gemfile*', '*.rsp' ] -------------------------------------------------------------------------------- /assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "jekyll-theme-slate"; 5 | 6 | .inner { 7 | max-width: 960px; 8 | } 9 | 10 | pre, code { 11 | background-color: unset; 12 | font-size: unset; 13 | } 14 | 15 | code { 16 | font-size: 0.80em; 17 | } 18 | 19 | h1 > img { 20 | border: unset; 21 | box-shadow: unset; 22 | vertical-align: middle; 23 | -moz-box-shadow: unset; 24 | -o-box-shadow: unset; 25 | -ms-box-shadow: unset; 26 | } 27 | -------------------------------------------------------------------------------- /assets/img/content-files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devlooped/Injector/cdc178c3744adc569cb2f9b229e30bc1c236c417/assets/img/content-files.png -------------------------------------------------------------------------------- /assets/img/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devlooped/Injector/cdc178c3744adc569cb2f9b229e30bc1c236c417/assets/img/icon-32.png -------------------------------------------------------------------------------- /assets/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devlooped/Injector/cdc178c3744adc569cb2f9b229e30bc1c236c417/assets/img/icon.png -------------------------------------------------------------------------------- /assets/img/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v1.1.0](https://github.com/devlooped/Injector/tree/v1.1.0) (2022-09-23) 4 | 5 | [Full Changelog](https://github.com/devlooped/Injector/compare/v1.0.1...v1.1.0) 6 | 7 | :twisted_rightwards_arrows: Merged: 8 | 9 | - Allow detecting injection success [\#9](https://github.com/devlooped/Injector/pull/9) (@kzu) 10 | 11 | ## [v1.0.1](https://github.com/devlooped/Injector/tree/v1.0.1) (2022-09-09) 12 | 13 | [Full Changelog](https://github.com/devlooped/Injector/compare/v1.0.0...v1.0.1) 14 | 15 | ## [v1.0.0](https://github.com/devlooped/Injector/tree/v1.0.0) (2022-09-09) 16 | 17 | [Full Changelog](https://github.com/devlooped/Injector/compare/def2f06c210ced05a2858626605e631254e74c5c...v1.0.0) 18 | 19 | :twisted_rightwards_arrows: Merged: 20 | 21 | - +Mᐁ includes [\#6](https://github.com/devlooped/Injector/pull/6) (@devlooped-bot) 22 | - +M▼ includes [\#3](https://github.com/devlooped/Injector/pull/3) (@github-actions[bot]) 23 | 24 | 25 | 26 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 27 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Daniel Cazzulino and Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![Icon](https://raw.githubusercontent.com/devlooped/Injector/main/assets/img/icon-32.png) .NET Injector 2 | ============ 3 | 4 | [![Version](https://img.shields.io/nuget/vpre/Devlooped.Injector.svg)](https://www.nuget.org/packages/Devlooped.Injector) 5 | [![Downloads](https://img.shields.io/nuget/dt/Devlooped.Injector.svg)](https://www.nuget.org/packages/Devlooped.Injector) 6 | [![License](https://img.shields.io/github/license/devlooped/Injector.svg?color=blue)](https://github.com//devlooped/Injector/blob/main/license.txt) 7 | [![Build](https://github.com/devlooped/Injector/workflows/build/badge.svg?branch=main)](https://github.com/devlooped/Injector/actions) 8 | 9 | 10 | Allows injecting .NET code into any Windows process. 11 | 12 | Heavily based on [Cory Plott](http://www.cplotts.com)'s [Snoop](https://github.com/cplotts/snoopwpf). 13 | 14 | The only requirement is that the injected code must be a public static method on a public static 15 | class, such as: 16 | 17 | ```csharp 18 | namespace Sample; 19 | 20 | public static class Startup 21 | { 22 | public static void Start(string arg1, int arg2, bool debug) 23 | { 24 | if (debug) 25 | Debugger.Launch(); 26 | 27 | // do stuff with arg1, arg2, etc. 28 | // note args are typed :) 29 | } 30 | } 31 | ``` 32 | 33 | > NOTE: parameter type conversion is supported and happens via the `TypeConverter` associated with the 34 | parameter type. 35 | 36 | 37 | ## Usage 38 | 39 | There are two main usages for this package: 40 | 41 | * From AnyCPU code: your code is bitness-agnostic and can be injected into 42 | the target process whether it's x86 or x64. 43 | * From x86/x64 code: you are injecting into a target process that has the same 44 | bitness as the calling code. 45 | 46 | ### AnyCPU code 47 | 48 | This is likely the more common scenario. You have .NET code that is AnyCPU and can 49 | therefore be injected regardless of the target process bitness. When referencing this 50 | package, you will get two (content) folders containing a helper `Injector.exe` for each architecture: 51 | 52 | ![Screenshot](https://raw.githubusercontent.com/devlooped/Injector/main/assets/img/content-files.png) 53 | 54 | These files are automatically copied to the output directory under `Injector\[x86|x64]\Injector.exe` 55 | (and are also included when doing `dotnet publish`). This allows you to run the relevant executable 56 | that matches the target process bitness. 57 | 58 | `Injector.exe` usage: 59 | 60 | ``` 61 | > Injector.exe -? 62 | Usage: Injector.exe 63 | 64 | Arguments: 65 | IntPtr of the main window handle of the process to inject, i.e. Process.MainWindowHandle. 66 | The full path to the .NET assembly to load in the remote process. 67 | Full type name of the public static class to invoke in the remote process. 68 | Name of the static method in that class to invoke in the remote process. Must be a 69 | static method, which can also receive arguments, such as 'Start:true:42'. 70 | ``` 71 | 72 | To detect the target process bitness, you can use the following bit of interop: 73 | 74 | ```csharp 75 | static class NativeMethods 76 | { 77 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] 78 | [return: MarshalAs(UnmanagedType.Bool)] 79 | internal static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process); 80 | } 81 | ``` 82 | 83 | And the following code would lookup the target process (in this case, we just get the first instance 84 | of `devenv.exe`, the Visual Studio main process, as an example), and invoke the right executable: 85 | 86 | ```csharp 87 | var targetProcess = System.Diagnostics.Process.GetProcessesByName("devenv.exe")[0]; 88 | 89 | NativeMethods.IsWow64Process(targetProcess.Handle, out var isWow); 90 | var platform = isWow ? "x86" : "x64"; 91 | 92 | Process.Start(Path.Combine("Injector", platform, "Injector.exe"), 93 | // IntPtr of the main window handle of the process to inject 94 | targetProcess.MainWindowHandle + " " + 95 | // The full path to the .NET assembly to load in the remote process 96 | Assembly.GetExecutingAssembly().Location + " " + 97 | // Full type name of the public static class to invoke in the remote process 98 | typeof(Startup).FullName + " " + 99 | // Name of the static method in that class to invoke in the remote process, 100 | // and any parameters. 101 | $"{nameof(Startup.Start)}:hello:42:true"); 102 | ``` 103 | 104 | > NOTE: we can pass typed arguments to the `Startup.Start` method (shown as an example 105 | > at the beginning) and type conversion will be applied automatically. 106 | 107 | 108 | ### Platform-specific code 109 | 110 | When building platform-specific code, the project would typically have (for a console app, for example): 111 | 112 | ```xml 113 | 114 | 115 | Exe 116 | net6.0 117 | x64;x86 118 | 119 | 120 | ``` 121 | 122 | You would then build for either platform via: `dotnet build --arch x64` or `dotnet build --arch x86`. 123 | 124 | In this case, the bitness of the calling code (that intends to inject itself into a remote process) 125 | must match the target process bitness too. Since the bitness of both is the same, you can use the 126 | automatically referenced assembly from your code, rather than invoking the helper `Injector.exe` 127 | as shown in the first case. 128 | 129 | The code will otherwise look similar to the previous case: 130 | 131 | 132 | ```csharp 133 | var targetProcess = System.Diagnostics.Process.GetProcessesByName("devenv.exe")[0]; 134 | 135 | // NOTE: target process bitness must match our own assembly architecture for 136 | // this to succeed. 137 | Devlooped.Injector.Launch( 138 | // IntPtr of the main window handle of the process to inject 139 | targetProcess.MainWindowHandle, 140 | // The full path to the .NET assembly to load in the remote process 141 | Assembly.GetExecutingAssembly().Location, 142 | // Full type name of the public static class to invoke in the remote process 143 | typeof(Startup).FullName, 144 | // Name of the static method in that class to invoke in the remote process, 145 | // and any parameters. 146 | $"{nameof(Startup.Start)}:hello:42:true"); 147 | ``` 148 | 149 | > NOTE: the `Devlooped.Injector` type will NOT be available on AnyCPU projects 150 | 151 | 152 | See [Program.cs](src/Sample/Program.cs) for a complete example. 153 | 154 | 155 | 156 | # Sponsors 157 | 158 | 159 | [![Clarius Org](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/clarius.png "Clarius Org")](https://github.com/clarius) 160 | [![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) 161 | [![Torutek](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/torutek-gh.png "Torutek")](https://github.com/torutek-gh) 162 | [![DRIVE.NET, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/drivenet.png "DRIVE.NET, Inc.")](https://github.com/drivenet) 163 | [![Keith Pickford](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Keflon.png "Keith Pickford")](https://github.com/Keflon) 164 | [![Thomas Bolon](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tbolon.png "Thomas Bolon")](https://github.com/tbolon) 165 | [![Kori Francis](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/kfrancis.png "Kori Francis")](https://github.com/kfrancis) 166 | [![Toni Wenzel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/twenzel.png "Toni Wenzel")](https://github.com/twenzel) 167 | [![Uno Platform](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/unoplatform.png "Uno Platform")](https://github.com/unoplatform) 168 | [![Dan Siegel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/dansiegel.png "Dan Siegel")](https://github.com/dansiegel) 169 | [![Reuben Swartz](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/rbnswartz.png "Reuben Swartz")](https://github.com/rbnswartz) 170 | [![Jacob Foshee](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jfoshee.png "Jacob Foshee")](https://github.com/jfoshee) 171 | [![](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Mrxx99.png "")](https://github.com/Mrxx99) 172 | [![Eric Johnson](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/eajhnsn1.png "Eric Johnson")](https://github.com/eajhnsn1) 173 | [![Ix Technologies B.V.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/IxTechnologies.png "Ix Technologies B.V.")](https://github.com/IxTechnologies) 174 | [![David JENNI](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/davidjenni.png "David JENNI")](https://github.com/davidjenni) 175 | [![Jonathan ](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Jonathan-Hickey.png "Jonathan ")](https://github.com/Jonathan-Hickey) 176 | [![Charley Wu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/akunzai.png "Charley Wu")](https://github.com/akunzai) 177 | [![Jakob Tikjøb Andersen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jakobt.png "Jakob Tikjøb Andersen")](https://github.com/jakobt) 178 | [![Tino Hager](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tinohager.png "Tino Hager")](https://github.com/tinohager) 179 | [![Ken Bonny](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KenBonny.png "Ken Bonny")](https://github.com/KenBonny) 180 | [![Simon Cropp](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/SimonCropp.png "Simon Cropp")](https://github.com/SimonCropp) 181 | [![agileworks-eu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/agileworks-eu.png "agileworks-eu")](https://github.com/agileworks-eu) 182 | [![sorahex](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/sorahex.png "sorahex")](https://github.com/sorahex) 183 | [![Zheyu Shen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/arsdragonfly.png "Zheyu Shen")](https://github.com/arsdragonfly) 184 | [![Vezel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/vezel-dev.png "Vezel")](https://github.com/vezel-dev) 185 | [![ChilliCream](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/ChilliCream.png "ChilliCream")](https://github.com/ChilliCream) 186 | [![4OTC](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/4OTC.png "4OTC")](https://github.com/4OTC) 187 | [![Vincent Limo](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/v-limo.png "Vincent Limo")](https://github.com/v-limo) 188 | [![Jordan S. Jones](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jordansjones.png "Jordan S. Jones")](https://github.com/jordansjones) 189 | [![domischell](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/DominicSchell.png "domischell")](https://github.com/DominicSchell) 190 | [![Joseph Kingry](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jkingry.png "Joseph Kingry")](https://github.com/jkingry) 191 | 192 | 193 | 194 | 195 | [![Sponsor this project](https://raw.githubusercontent.com/devlooped/sponsors/main/sponsor.png "Sponsor this project")](https://github.com/sponsors/devlooped) 196 |   197 | 198 | [Learn more about GitHub Sponsors](https://github.com/sponsors) 199 | 200 | 201 | -------------------------------------------------------------------------------- /src/Bootstrap/AssemblyInfo.cpp: -------------------------------------------------------------------------------- 1 | // (c) Copyright Cory Plotts. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | #include "stdafx.h" 7 | 8 | using namespace System; 9 | using namespace System::Reflection; 10 | using namespace System::Runtime::CompilerServices; 11 | using namespace System::Runtime::InteropServices; 12 | using namespace System::Security::Permissions; 13 | 14 | [assembly:AssemblyTitleAttribute("Bootstrap")]; 15 | [assembly:AssemblyProductAttribute("Bootstrap")]; 16 | [assembly:AssemblyCopyrightAttribute("Copyright (c) Cory Plotts")]; 17 | 18 | [assembly:AssemblyVersionAttribute("1.0.0.0")]; 19 | [assembly:ComVisible(false)]; 20 | [assembly:CLSCompliantAttribute(true)]; 21 | -------------------------------------------------------------------------------- /src/Bootstrap/Bootstrap.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(USERPROFILE)\.nuget\packages\ 5 | 6 | 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Release 22 | x64 23 | 24 | 25 | 26 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5} 27 | v4.7.2 28 | Bootstrap 29 | x86 30 | $(Platform) 31 | ManagedCProj 32 | Bootstrap 33 | bootstrap 34 | $(MSBuildProjectDirectory)\..\kzu.snk 35 | $(MSBuildProjectDirectory)\bin\$(PlatformTarget)\$(Configuration)\ 36 | $(MSBuildProjectDirectory)\obj\$(PlatformTarget)\$(Configuration)\ 37 | v143 38 | 10.0 39 | $(PackFolder)\$(Platform) 40 | false 41 | 42 | 43 | 44 | DynamicLibrary 45 | Unicode 46 | true 47 | true 48 | false 49 | 50 | 51 | DynamicLibrary 52 | Unicode 53 | true 54 | true 55 | false 56 | 57 | 58 | DynamicLibrary 59 | Unicode 60 | true 61 | false 62 | 63 | 64 | DynamicLibrary 65 | Unicode 66 | true 67 | false 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Disabled 91 | WIN32;_DEBUG;%(PreprocessorDefinitions) 92 | MultiThreadedDebugDLL 93 | 94 | 95 | Level3 96 | OldStyle 97 | Async 98 | 99 | 100 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies) 101 | Debug 102 | true 103 | 104 | 105 | MachineX86 106 | 107 | 108 | true 109 | /OPT:REF 110 | 111 | 112 | 113 | 114 | Disabled 115 | WIN64;_DEBUG;%(PreprocessorDefinitions) 116 | MultiThreadedDebugDLL 117 | 118 | 119 | Level3 120 | OldStyle 121 | Async 122 | 123 | 124 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies) 125 | Debug 126 | true 127 | 128 | 129 | 130 | 131 | true 132 | /OPT:REF 133 | 134 | 135 | 136 | 137 | WIN32;NDEBUG;%(PreprocessorDefinitions) 138 | MultiThreadedDLL 139 | 140 | 141 | Level3 142 | None 143 | Async 144 | 145 | 146 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies) 147 | $(OutDir)$(TargetName).dll 148 | makefile.def 149 | false 150 | false 151 | 152 | 153 | MachineX86 154 | 155 | 156 | true 157 | /OPT:REF 158 | 159 | 160 | 161 | 162 | WIN64;NDEBUG;%(PreprocessorDefinitions) 163 | MultiThreadedDLL 164 | 165 | 166 | Level3 167 | None 168 | Async 169 | 170 | 171 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies) 172 | $(OutDir)$(TargetName).dll 173 | makefile.def 174 | false 175 | false 176 | 177 | 178 | 179 | 180 | true 181 | /OPT:REF 182 | 183 | 184 | 185 | 186 | 187 | 188 | Create 189 | Create 190 | Create 191 | Create 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | $(GetTargetPathDependsOn);Build 205 | 206 | 207 | 208 | 209 | 210 | 211 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /src/Bootstrap/Bootstrap.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | Source Files 15 | 16 | 17 | Source Files 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Bootstrap/Injector.cpp: -------------------------------------------------------------------------------- 1 | // (c) Copyright Cory Plotts. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | #include "stdafx.h" 7 | 8 | #include "Injector.h" 9 | #include 10 | 11 | using namespace Devlooped; 12 | 13 | static unsigned int WM_GOBABYGO = ::RegisterWindowMessage(L"Injector_GOBABYGO!"); 14 | static HHOOK _messageHookHandle; 15 | 16 | //----------------------------------------------------------------------------- 17 | //Spying Process functions follow 18 | //----------------------------------------------------------------------------- 19 | bool Injector::Launch(System::IntPtr windowHandle, System::String^ assemblyFile, System::String^ typeFullName, System::String^ methodName) 20 | { 21 | System::String^ assemblyClassAndMethod = assemblyFile + "$" + typeFullName + "$" + methodName; 22 | pin_ptr acmLocal = PtrToStringChars(assemblyClassAndMethod); 23 | 24 | HINSTANCE hinstDLL; 25 | 26 | if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&MessageHookProc, &hinstDLL)) 27 | { 28 | // Don't append the first call, so after each injection attempt, we get a clean log to inspect. 29 | LogMessage("GetModuleHandleEx successful", false); 30 | DWORD processID = 0; 31 | DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID); 32 | 33 | if (processID) 34 | { 35 | LogMessage("Got process id", true); 36 | HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); 37 | if (hProcess) 38 | { 39 | LogMessage("Got process handle", true); 40 | int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t); 41 | void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE); 42 | 43 | if (acmRemote) 44 | { 45 | LogMessage("VirtualAllocEx successful", true); 46 | ::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL); 47 | 48 | _messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, &MessageHookProc, hinstDLL, threadID); 49 | 50 | if (_messageHookHandle) 51 | { 52 | LogMessage("SetWindowsHookEx successful", true); 53 | ::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0); 54 | ::UnhookWindowsHookEx(_messageHookHandle); 55 | return true; 56 | } 57 | 58 | ::VirtualFreeEx(hProcess, acmRemote, 0, MEM_RELEASE); 59 | } 60 | 61 | ::CloseHandle(hProcess); 62 | } 63 | } 64 | else 65 | { 66 | if (windowHandle == IntPtr::Zero) 67 | LogMessage("Invalid window handle received", true); 68 | else 69 | LogMessage("Could not get process from window handle " + windowHandle.ToString(), true); 70 | } 71 | ::FreeLibrary(hinstDLL); 72 | } 73 | 74 | return false; 75 | } 76 | 77 | void Injector::LogMessage(String^ message, bool append) 78 | { 79 | String^ applicationDataPath = Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData); 80 | applicationDataPath += "\\Devlooped\\Injector"; 81 | 82 | if (!System::IO::Directory::Exists(applicationDataPath)) 83 | { 84 | System::IO::Directory::CreateDirectory(applicationDataPath); 85 | } 86 | 87 | String ^ pathname = applicationDataPath + "\\log.txt"; 88 | 89 | if (!append) 90 | { 91 | System::IO::File::Delete(pathname); 92 | } 93 | 94 | System::IO::FileInfo ^ fi = gcnew System::IO::FileInfo(pathname); 95 | 96 | System::IO::StreamWriter ^ sw = fi->AppendText(); 97 | sw->WriteLine(System::DateTime::Now.ToString("yyyy/MM/dd HH:mm:ss") + " : " + message); 98 | sw->Close(); 99 | } 100 | 101 | __declspec(dllexport) 102 | LRESULT __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam) 103 | { 104 | if (nCode == HC_ACTION) 105 | { 106 | CWPSTRUCT* msg = (CWPSTRUCT*)lparam; 107 | if (msg != NULL && msg->message == WM_GOBABYGO) 108 | { 109 | Injector::LogMessage("Got WM_GOBABYGO message", true); 110 | 111 | wchar_t* acmRemote = (wchar_t*)msg->wParam; 112 | 113 | String^ acmLocal = gcnew System::String(acmRemote); 114 | Injector::LogMessage(System::String::Format("acmLocal = {0}", acmLocal), true); 115 | cli::array^ acmSplit = acmLocal->Split('$'); 116 | cli::array^ methodSplit = acmSplit[2]->Split(':'); 117 | 118 | Injector::LogMessage(String::Format("About to load assembly {0}", acmSplit[0]), true); 119 | System::Reflection::Assembly^ assembly = System::Reflection::Assembly::LoadFrom(acmSplit[0]); 120 | if (assembly != nullptr) 121 | { 122 | Injector::LogMessage(String::Format("About to load type {0}", acmSplit[1]), true); 123 | System::Type^ type = assembly->GetType(acmSplit[1]); 124 | if (type != nullptr) 125 | { 126 | Injector::LogMessage(String::Format("Just loaded the type {0}", acmSplit[1]), true); 127 | // Injector::LogMessage(String::Format("Looking for full method and parameters {0}", acmSplit[2]), true); 128 | Injector::LogMessage(String::Format("Looking for method named {0}", methodSplit[0]), true); 129 | 130 | System::Reflection::MethodInfo^ methodInfo = type->GetMethod( 131 | methodSplit[0], 132 | System::Reflection::BindingFlags::Static | System::Reflection::BindingFlags::Public); 133 | 134 | if (methodInfo != nullptr) 135 | { 136 | if (methodSplit->Length > 1) 137 | { 138 | cli::array^ parameters = methodInfo->GetParameters(); 139 | if (methodSplit->Length - 1 != parameters->Length) 140 | { 141 | Injector::LogMessage(System::String::Format("Did not receive the expected {0} parameters to invoke {1}.{2}", parameters->Length, acmSplit[1], methodSplit[0]), true); 142 | } 143 | else 144 | { 145 | Injector::LogMessage(System::String::Format("Converting {0} received method arguments", methodSplit->Length - 1), true); 146 | cli::array^ methodParams = nullptr; 147 | 148 | methodParams = gcnew cli::array(parameters->Length); 149 | for (int i = 0; i < parameters->Length; i++) { 150 | System::Type^ paramType = parameters[i]->ParameterType; 151 | System::ComponentModel::TypeConverter^ converter = System::ComponentModel::TypeDescriptor::GetConverter(paramType); 152 | // NOTE: take into account that the first part of the methodSplit is the method name. 153 | methodParams[i] = converter->ConvertFromString(methodSplit[i + 1]); 154 | } 155 | 156 | Injector::LogMessage(System::String::Format("Invoking {0}.{1}({2})", 157 | acmSplit[1], 158 | methodInfo->Name, 159 | System::String::Join(", ", methodSplit, 1, methodSplit->Length - 1)), true); 160 | methodInfo->Invoke(nullptr, methodParams); 161 | } 162 | } 163 | else 164 | { 165 | Injector::LogMessage(System::String::Format("Invoking {0}.{1}()", acmSplit[1], methodInfo->Name), true); 166 | methodInfo->Invoke(nullptr, nullptr); 167 | } 168 | } 169 | else 170 | { 171 | Injector::LogMessage(System::String::Format("Did not find method named {0} on type {1}", methodSplit[0], acmSplit[1]), true); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | return CallNextHookEx(_messageHookHandle, nCode, wparam, lparam); 178 | } 179 | -------------------------------------------------------------------------------- /src/Bootstrap/Injector.h: -------------------------------------------------------------------------------- 1 | // (c) Copyright Cory Plotts. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | #pragma once 7 | 8 | __declspec(dllexport) 9 | LRESULT __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam); 10 | 11 | using namespace System; 12 | 13 | namespace Devlooped 14 | { 15 | public ref class Injector : System::Object 16 | { 17 | public: 18 | 19 | static bool Launch(System::IntPtr windowHandle, System::String^ assemblyFile, System::String^ typeFullName, System::String^ methodName); 20 | 21 | static void LogMessage(System::String^ message, bool append); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/Bootstrap/Stdafx.cpp: -------------------------------------------------------------------------------- 1 | // (c) Copyright Cory Plotts. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | // stdafx.cpp : source file that includes just the standard includes 7 | // SnoopSpyC.pch will be the pre-compiled header 8 | // stdafx.obj will contain the pre-compiled type information 9 | 10 | #include "stdafx.h" 11 | -------------------------------------------------------------------------------- /src/Bootstrap/Stdafx.h: -------------------------------------------------------------------------------- 1 | // (c) Copyright Cory Plotts. 2 | // This source is subject to the Microsoft Public License (Ms-PL). 3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 4 | // All other rights reserved. 5 | 6 | // stdafx.h : include file for standard system include files, 7 | // or project specific include files that are used frequently, 8 | // but are changed infrequently 9 | 10 | #pragma once 11 | 12 | #define _WIN32_WINNT _WIN32_WINNT_WINXP 13 | 14 | #include "Windows.h" 15 | #include "tchar.h" 16 | -------------------------------------------------------------------------------- /src/Bootstrap/makefile.def: -------------------------------------------------------------------------------- 1 | LIBRARY "bootstrap.dll" 2 | EXPORTS 3 | MessageHookProc @1 4 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | true 14 | 15 | 16 | 17 | 18 | $(CI) 19 | 20 | 21 | 22 | Daniel Cazzulino 23 | Copyright (C) Daniel Cazzulino and Contributors. All rights reserved. 24 | false 25 | MIT 26 | 27 | 28 | icon.png 29 | readme.md 30 | 31 | icon.png 32 | readme.md 33 | 34 | true 35 | true 36 | 37 | $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\bin')) 38 | 39 | 40 | true 41 | true 42 | 43 | 44 | true 45 | 46 | 47 | 48 | Release 49 | Latest 50 | 51 | 52 | false 53 | 54 | embedded 55 | true 56 | enable 57 | 58 | strict 59 | 60 | 61 | $(MSBuildProjectName) 62 | $(MSBuildProjectName.IndexOf('.')) 63 | $(MSBuildProjectName.Substring(0, $(RootNamespaceDot))) 64 | 65 | 66 | $(DefaultItemExcludes);*.binlog;*.zip;*.rsp;*.items;**/TestResults/**/*.* 67 | 68 | true 69 | true 70 | true 71 | true 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | NU5105;$(NoWarn) 81 | 82 | true 83 | 84 | 85 | true 86 | 87 | 88 | LatestMinor 89 | 90 | 91 | 92 | 93 | $(MSBuildThisFileDirectory)kzu.snk 94 | 100 | 002400000480000094000000060200000024000052534131000400000100010051155fd0ee280be78d81cc979423f1129ec5dd28edce9cd94fd679890639cad54c121ebdb606f8659659cd313d3b3db7fa41e2271158dd602bb0039a142717117fa1f63d93a2d288a1c2f920ec05c4858d344a45d48ebd31c1368ab783596b382b611d8c92f9c1b3d338296aa21b12f3bc9f34de87756100c172c52a24bad2db 101 | 00352124762f2aa5 102 | true 103 | 104 | 105 | 106 | 114 | 42.42.42 115 | 116 | 117 | 118 | <_VersionLabel>$(VersionLabel.Replace('refs/heads/', '')) 119 | <_VersionLabel>$(_VersionLabel.Replace('refs/tags/v', '')) 120 | 121 | 122 | <_VersionLabel Condition="$(_VersionLabel.Contains('refs/pull/'))">$(VersionLabel.TrimEnd('.0123456789')) 123 | 124 | <_VersionLabel>$(_VersionLabel.Replace('refs/pull/', 'pr')) 125 | 126 | <_VersionLabel>$(_VersionLabel.Replace('/merge', '')) 127 | 128 | <_VersionLabel>$(_VersionLabel.Replace('/', '-')) 129 | 130 | 131 | $(_VersionLabel) 132 | 133 | $(_VersionLabel) 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 162 | 163 | 1.0.0 164 | $(VersionPrefix)-$(VersionSuffix) 165 | $(VersionPrefix) 166 | 167 | 168 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CI;$(DefineConstants) 6 | 7 | 8 | 9 | 10 | false 11 | false 12 | true 13 | 14 | 15 | 16 | true 17 | true 18 | 19 | 20 | 21 | 31 | false 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 45 | 49 | 50 | 51 | 55 | 56 | 60 | 61 | 62 | 64 | 65 | 1.0.0 66 | $(VersionPrefix)-$(VersionSuffix) 67 | $(VersionPrefix) 68 | 69 | 70 | 71 | 72 | $(PackFolder) 73 | $(PackFolderPath.Replace('\$(TargetFramework)', '')) 74 | $(IntermediateOutputPath)$(PackFolderPath)\ 75 | $(OutputPath)$(PackFolderPath)\ 76 | $(OutputPath) 77 | 78 | 79 | 80 | 81 | pr$(GITHUB_REF.Replace('refs/pull/', '').Replace('/merge', '')) 82 | $(GITHUB_REF.Replace('refs/heads/', '').Replace('refs/tags/', '')) 83 | 84 | $(BUILD_SOURCEBRANCH.Replace('refs/heads/', '').Replace('refs/tags/', '')) 85 | 86 | pr$(APPVEYOR_PULL_REQUEST_NUMBER) 87 | $(APPVEYOR_REPO_TAG_NAME) 88 | $(APPVEYOR_REPO_BRANCH) 89 | 90 | $(TEAMCITY_BUILD_BRANCH) 91 | 92 | pr$(TRAVIS_PULL_REQUEST) 93 | $(TRAVIS_BRANCH) 94 | 95 | pr$(CIRCLE_PR_NUMBER) 96 | $(CIRCLE_TAG) 97 | $(CIRCLE_BRANCH) 98 | 99 | $(CI_COMMIT_TAG) 100 | pr$(CI_MERGE_REQUEST_IID) 101 | pr$(CI_EXTERNAL_PULL_REQUEST_IID) 102 | $(CI_COMMIT_BRANCH) 103 | 104 | pr$(BUDDY_EXECUTION_PULL_REQUEST_NO) 105 | $(BUDDY_EXECUTION_TAG) 106 | $(BUDDY_EXECUTION_BRANCH) 107 | 108 | 109 | 110 | 111 | CoreResGen;$(CoreCompileDependsOn) 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | $(IntermediateOutputPath)\$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\', '.').Replace('/', '.'))%(Filename).g$(DefaultLanguageSourceExtension) 121 | $(Language) 122 | $(RootNamespace) 123 | $(RootNamespace).$([MSBuild]::ValueOrDefault('%(RelativeDir)', '').Replace('\', '.').Replace('/', '.').TrimEnd('.')) 124 | %(Filename) 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 148 | 149 | 150 | 151 | $(PrivateRepositoryUrl) 152 | 153 | 154 | 155 | $(SourceRevisionId) 156 | $(SourceRevisionId.Substring(0, 9)) 157 | 158 | $(RepositorySha) 159 | 160 | 161 | 162 | 163 | <_GitSourceRoot Include="@(SourceRoot -> WithMetadataValue('SourceControl', 'git'))" /> 164 | 165 | 166 | 167 | @(_GitSourceRoot) 168 | 169 | 170 | 171 | 172 | 177 | 178 | $(RepositoryUrl) 179 | $(Description) 180 | $(RepositoryUrl)/blob/main/changelog.md 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/Injector/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Injector/Injector.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | .exe 6 | 7 | net472;netstandard2.0 8 | net472 9 | netstandard2.0 10 | x86;x64 11 | Win32 12 | tools 13 | false 14 | false 15 | 16 | 17 | 18 | false 19 | 20 | Devlooped.Injector 21 | Inject .NET code into any Windows 22 | https://github.com/devlooped/Injector 23 | 24 | 25 | 26 | x86 27 | x86 28 | true 29 | Win32 30 | 31 | 32 | 33 | x64 34 | x64 35 | false 36 | x64 37 | 38 | 39 | 40 | $(PackFolder)\$(Platform) 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {8072b47b-5611-4bab-8ef4-cb3125d676a5} 54 | 55 | VisualStudioVersion=$(VisualStudioVersion); 56 | Configuration=$(Configuration); 57 | Platform=$(BootstrapPlatform); 58 | NuGetPackageRoot=$(NuGetPackageRoot); 59 | PackFolder=$(PackFolder) 60 | 61 | Bootstrap 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/Injector/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Devlooped 4 | { 5 | /// 6 | /// Helper process to allow injection into processes that have different bitness 7 | /// into WPF app processes. 8 | /// 9 | /// VS is 32-bit, so it cannot write to the memory of a 64-bit process, and delegates 10 | /// that to this program instead. 11 | /// 12 | public class Program 13 | { 14 | static int Main(string[] args) 15 | { 16 | if (args.Length != 4) 17 | { 18 | Console.WriteLine("Usage: Injector.exe "); 19 | Console.WriteLine(); 20 | Console.WriteLine("Arguments:"); 21 | Console.WriteLine(" IntPtr of the main window handle of the process to inject, i.e. Process.MainWindowHandle."); 22 | Console.WriteLine(" The full path to the .NET assembly to load in the remote process."); 23 | Console.WriteLine(" Full type name of the public static class to invoke in the remote process."); 24 | Console.WriteLine(" Name of the static method in that class to invoke in the remote process. Must be a "); 25 | Console.WriteLine(" static method, which can also receive arguments, such as 'Start:true:42'."); 26 | return -1; 27 | } 28 | 29 | var mainWindow = new IntPtr(int.Parse(args[0])); 30 | var assemblyFile = args[1].Trim('"'); 31 | var typeName = args[2].Trim('"'); 32 | var methodName = args[3].Trim('"'); 33 | 34 | if (Injector.Launch(mainWindow, assemblyFile, typeName, methodName)) 35 | return 0; 36 | else 37 | return -1; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Injector/build/Devlooped.Injector.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\tools')) 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Injector/build/Devlooped.Injector.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Injector\%(RecursiveDir)%(Filename)%(Extension) 7 | PreserveNewest 8 | true 9 | true 10 | Devlooped.Injector 11 | 12 | 13 | 14 | 15 | $(PlatformTarget) 16 | $(Platform) 17 | 18 | 19 | 20 | 21 | $(WindowsInjectorToolsPath)\$(BootstrapPlatform)\bootstrap.dll 22 | Devlooped.Injector 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Injector/msbuild.rsp: -------------------------------------------------------------------------------- 1 | /v:m /bl -------------------------------------------------------------------------------- /src/Injector/readme.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/Sample/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Threading; 8 | 9 | namespace Sample 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | var exe = args.FirstOrDefault() ?? $"{ThisAssembly.Project.VsInstallRoot}\\devenv.exe"; 16 | 17 | var process = Process.Start(exe); 18 | process.WaitForInputIdle(); 19 | // NOTE: it's important to wait until the window handle is actually created. 20 | // this may take a while if the startup of the target app is lenghty 21 | while (process.MainWindowHandle == IntPtr.Zero) 22 | Thread.Sleep(200); 23 | 24 | // Inspect %LocalAppData%\Windows.Injector\log.txt to troubleshoot 25 | 26 | // Dynamic injection based on the target process bitness 27 | // using the external helper process. 28 | NativeMethods.IsWow64Process(process.Handle, out var isWow); 29 | var platform = isWow ? "x86" : "x64"; 30 | 31 | Process.Start(Path.Combine("Injector", platform, "Injector.exe"), 32 | process.MainWindowHandle + " " + 33 | Assembly.GetExecutingAssembly().Location + " " + 34 | typeof(Startup).FullName + " " + 35 | $"{nameof(Startup.Start)}:hello:42:true"); 36 | 37 | // API-based injection if target process has same bitness as ours 38 | //Bootstrap.Injector.Launch( 39 | // process.MainWindowHandle, 40 | // Assembly.GetExecutingAssembly().Location, 41 | // typeof(Startup).FullName, 42 | // $"{nameof(Startup.Start)}:hello:42:true"); 43 | 44 | Console.ReadLine(); 45 | 46 | if (!process.HasExited) 47 | process.Kill(); 48 | } 49 | } 50 | 51 | public static class Startup 52 | { 53 | // NOTE: parameter type conversion from the {method}:arg1:argN format is done automatically 54 | public static void Start(string arg1, int arg2, bool debug) 55 | { 56 | if (debug) 57 | Debugger.Launch(); 58 | } 59 | } 60 | 61 | static class NativeMethods 62 | { 63 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] 64 | [return: MarshalAs(UnmanagedType.Bool)] 65 | internal static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Sample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Sample": { 4 | "commandName": "Project", 5 | "commandLineArgs": "\"$(VsInstallRoot)\\Common7\\IDE\\devenv.exe\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Sample/Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net472 6 | false 7 | 8 | ..\Injector\bin 9 | x86 10 | x86;x64 11 | 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Injector\x86\%(Filename)%(Extension) 31 | PreserveNewest 32 | 33 | 34 | Injector\x86\%(Filename)%(Extension) 35 | PreserveNewest 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devlooped/Injector/cdc178c3744adc569cb2f9b229e30bc1c236c417/src/icon.png -------------------------------------------------------------------------------- /src/kzu.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devlooped/Injector/cdc178c3744adc569cb2f9b229e30bc1c236c417/src/kzu.snk -------------------------------------------------------------------------------- /src/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------