├── .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 |
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 |  .NET Injector
2 | ============
3 |
4 | [](https://www.nuget.org/packages/Devlooped.Injector)
5 | [](https://www.nuget.org/packages/Devlooped.Injector)
6 | [](https://github.com//devlooped/Injector/blob/main/license.txt)
7 | [](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 | 
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 | [](https://github.com/clarius)
160 | [](https://github.com/MFB-Technologies-Inc)
161 | [](https://github.com/torutek-gh)
162 | [](https://github.com/drivenet)
163 | [](https://github.com/Keflon)
164 | [](https://github.com/tbolon)
165 | [](https://github.com/kfrancis)
166 | [](https://github.com/twenzel)
167 | [](https://github.com/unoplatform)
168 | [](https://github.com/dansiegel)
169 | [](https://github.com/rbnswartz)
170 | [](https://github.com/jfoshee)
171 | [](https://github.com/Mrxx99)
172 | [](https://github.com/eajhnsn1)
173 | [](https://github.com/IxTechnologies)
174 | [](https://github.com/davidjenni)
175 | [](https://github.com/Jonathan-Hickey)
176 | [](https://github.com/akunzai)
177 | [](https://github.com/jakobt)
178 | [](https://github.com/tinohager)
179 | [](https://github.com/KenBonny)
180 | [](https://github.com/SimonCropp)
181 | [](https://github.com/agileworks-eu)
182 | [](https://github.com/sorahex)
183 | [](https://github.com/arsdragonfly)
184 | [](https://github.com/vezel-dev)
185 | [](https://github.com/ChilliCream)
186 | [](https://github.com/4OTC)
187 | [](https://github.com/v-limo)
188 | [](https://github.com/jordansjones)
189 | [](https://github.com/DominicSchell)
190 | [](https://github.com/jkingry)
191 |
192 |
193 |
194 |
195 | [](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 |
--------------------------------------------------------------------------------