├── .editorconfig
├── .gitattributes
├── .gitignore
├── LICENSE
├── NativeSharp.sln
├── NativeSharp
├── Additions
│ ├── ExportTableInfo.cs
│ ├── Injector.cs
│ ├── MemoryIO.cs
│ ├── MemoryManagement.cs
│ ├── ModuleInfo.cs
│ ├── ProcessInfo.cs
│ └── ProcessUtils.cs
├── NativeEnvironment.cs
├── NativeMethods.cs
├── NativeModule.cs
├── NativeProcess.cs
├── NativeSharp.csproj
└── System
│ └── Array2.cs
├── README.md
└── appveyor.yml
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | end_of_line = crlf
7 | indent_style = tab
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | # C# files
12 | [*.cs]
13 |
14 | #### .NET Coding Conventions ####
15 |
16 | # Organize usings
17 | dotnet_separate_import_directive_groups = false
18 | dotnet_sort_system_directives_first = true
19 |
20 | # this. and Me. preferences
21 | dotnet_style_qualification_for_event = false:suggestion
22 | dotnet_style_qualification_for_field = false:suggestion
23 | dotnet_style_qualification_for_method = false:suggestion
24 | dotnet_style_qualification_for_property = false:suggestion
25 |
26 | # Language keywords vs BCL types preferences
27 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
28 | dotnet_style_predefined_type_for_member_access = true:suggestion
29 |
30 | # Parentheses preferences
31 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
32 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
33 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
34 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
35 |
36 | # Modifier preferences
37 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
38 |
39 | # Expression-level preferences
40 | dotnet_style_coalesce_expression = true:suggestion
41 | dotnet_style_collection_initializer = true:suggestion
42 | dotnet_style_explicit_tuple_names = true:suggestion
43 | dotnet_style_null_propagation = true:suggestion
44 | dotnet_style_object_initializer = true:suggestion
45 | dotnet_style_prefer_auto_properties = false:suggestion
46 | dotnet_style_prefer_compound_assignment = true:suggestion
47 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent
48 | dotnet_style_prefer_conditional_expression_over_return = true:silent
49 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
50 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
51 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
52 | dotnet_style_prefer_simplified_interpolation = true:suggestion
53 |
54 | # Field preferences
55 | dotnet_style_readonly_field = true:suggestion
56 |
57 | # Parameter preferences
58 | dotnet_code_quality_unused_parameters = all:suggestion
59 |
60 | #### C# Coding Conventions ####
61 |
62 | # var preferences
63 | csharp_style_var_elsewhere = true:suggestion
64 | csharp_style_var_for_built_in_types = false:suggestion
65 | csharp_style_var_when_type_is_apparent = true:suggestion
66 |
67 | # Expression-bodied members
68 | csharp_style_expression_bodied_accessors = true:suggestion
69 | csharp_style_expression_bodied_constructors = false:suggestion
70 | csharp_style_expression_bodied_indexers = true:suggestion
71 | csharp_style_expression_bodied_lambdas = true:suggestion
72 | csharp_style_expression_bodied_local_functions = false:suggestion
73 | csharp_style_expression_bodied_methods = false:suggestion
74 | csharp_style_expression_bodied_operators = false:suggestion
75 | csharp_style_expression_bodied_properties = true:suggestion
76 |
77 | # Pattern matching preferences
78 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
79 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
80 | csharp_style_prefer_switch_expression = true:suggestion
81 |
82 | # Null-checking preferences
83 | csharp_style_conditional_delegate_call = true:suggestion
84 |
85 | # Modifier preferences
86 | csharp_prefer_static_local_function = true:suggestion
87 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
88 |
89 | # Code-block preferences
90 | csharp_prefer_braces = false:silent
91 | csharp_prefer_simple_using_statement = true:suggestion
92 |
93 | # Expression-level preferences
94 | csharp_prefer_simple_default_expression = true:suggestion
95 | csharp_style_deconstructed_variable_declaration = true:suggestion
96 | csharp_style_inlined_variable_declaration = true:suggestion
97 | csharp_style_pattern_local_over_anonymous_function = true:suggestion
98 | csharp_style_prefer_index_operator = true:suggestion
99 | csharp_style_prefer_range_operator = true:suggestion
100 | csharp_style_throw_expression = true:suggestion
101 | csharp_style_unused_value_assignment_preference = unused_local_variable:silent
102 | csharp_style_unused_value_expression_statement_preference = unused_local_variable:silent
103 |
104 | # 'using' directive preferences
105 | csharp_using_directive_placement = outside_namespace:suggestion
106 |
107 | #### C# Formatting Rules ####
108 |
109 | # New line preferences
110 | csharp_new_line_before_catch = true
111 | csharp_new_line_before_else = true
112 | csharp_new_line_before_finally = true
113 | csharp_new_line_before_members_in_anonymous_types = true
114 | csharp_new_line_before_members_in_object_initializers = true
115 | csharp_new_line_before_open_brace = none
116 | csharp_new_line_between_query_expression_clauses = false
117 |
118 | # Indentation preferences
119 | csharp_indent_block_contents = true
120 | csharp_indent_braces = false
121 | csharp_indent_case_contents = true
122 | csharp_indent_case_contents_when_block = false
123 | csharp_indent_labels = one_less_than_current
124 | csharp_indent_switch_labels = false
125 |
126 | # Space preferences
127 | csharp_space_after_cast = false
128 | csharp_space_after_colon_in_inheritance_clause = true
129 | csharp_space_after_comma = true
130 | csharp_space_after_dot = false
131 | csharp_space_after_keywords_in_control_flow_statements = true
132 | csharp_space_after_semicolon_in_for_statement = true
133 | csharp_space_around_binary_operators = before_and_after
134 | csharp_space_around_declaration_statements = false
135 | csharp_space_before_colon_in_inheritance_clause = true
136 | csharp_space_before_comma = false
137 | csharp_space_before_dot = false
138 | csharp_space_before_open_square_brackets = false
139 | csharp_space_before_semicolon_in_for_statement = false
140 | csharp_space_between_empty_square_brackets = false
141 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
142 | csharp_space_between_method_call_name_and_opening_parenthesis = false
143 | csharp_space_between_method_call_parameter_list_parentheses = false
144 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
145 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
146 | csharp_space_between_method_declaration_parameter_list_parentheses = false
147 | csharp_space_between_parentheses = false
148 | csharp_space_between_square_brackets = false
149 |
150 | # Wrapping preferences
151 | csharp_preserve_single_line_blocks = true
152 | csharp_preserve_single_line_statements = true
153 |
154 | #### Naming styles ####
155 |
156 | # Naming rules
157 |
158 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
159 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
160 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
161 |
162 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
163 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types
164 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
165 |
166 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
167 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
168 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
169 |
170 | # Symbol specifications
171 |
172 | dotnet_naming_symbols.interface.applicable_kinds = interface
173 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
174 | dotnet_naming_symbols.interface.required_modifiers =
175 |
176 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
177 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
178 | dotnet_naming_symbols.types.required_modifiers =
179 |
180 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
181 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
182 | dotnet_naming_symbols.non_field_members.required_modifiers =
183 |
184 | # Naming styles
185 |
186 | dotnet_naming_style.pascal_case.required_prefix =
187 | dotnet_naming_style.pascal_case.required_suffix =
188 | dotnet_naming_style.pascal_case.word_separator =
189 | dotnet_naming_style.pascal_case.capitalization = pascal_case
190 |
191 | dotnet_naming_style.begins_with_i.required_prefix = I
192 | dotnet_naming_style.begins_with_i.required_suffix =
193 | dotnet_naming_style.begins_with_i.word_separator =
194 | dotnet_naming_style.begins_with_i.capitalization = pascal_case
195 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 |
235 | # RIA/Silverlight projects
236 | Generated_Code/
237 |
238 | # Backup & report files from converting an old project file
239 | # to a newer Visual Studio version. Backup files are not needed,
240 | # because we have git ;-)
241 | _UpgradeReport_Files/
242 | Backup*/
243 | UpgradeLog*.XML
244 | UpgradeLog*.htm
245 | ServiceFabricBackup/
246 | *.rptproj.bak
247 |
248 | # SQL Server files
249 | *.mdf
250 | *.ldf
251 | *.ndf
252 |
253 | # Business Intelligence projects
254 | *.rdl.data
255 | *.bim.layout
256 | *.bim_*.settings
257 | *.rptproj.rsuser
258 | *- Backup*.rdl
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush personal settings
299 | .cr/personal
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 | # Local History for Visual Studio
337 | .localhistory/
338 |
339 | # BeatPulse healthcheck temp database
340 | healthchecksdb
341 |
342 | # wwh1004
343 | launchSettings.json
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 文煌
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 |
--------------------------------------------------------------------------------
/NativeSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29519.181
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeSharp", "NativeSharp\NativeSharp.csproj", "{2CD47F09-B324-4B20-8C8B-38FC4A037E37}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {2CD47F09-B324-4B20-8C8B-38FC4A037E37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {2CD47F09-B324-4B20-8C8B-38FC4A037E37}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {2CD47F09-B324-4B20-8C8B-38FC4A037E37}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {2CD47F09-B324-4B20-8C8B-38FC4A037E37}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {1B2D6C3C-7D11-4E95-91FA-8A1888F531EB}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/ExportTableInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using static NativeSharp.NativeMethods;
5 |
6 | namespace NativeSharp {
7 | ///
8 | /// 导出函数信息
9 | ///
10 | public sealed unsafe class ExportFunctionInfo {
11 | ///
12 | /// 表示一个空的实例
13 | ///
14 | public readonly static ExportFunctionInfo Empty = new ExportFunctionInfo(null, string.Empty, 0);
15 |
16 | private readonly void* _address;
17 | private readonly string _name;
18 | private readonly ushort _ordinal;
19 |
20 | ///
21 | /// 地址
22 | ///
23 | public void* Address => _address;
24 |
25 | ///
26 | /// 名称
27 | ///
28 | public string Name => _name;
29 |
30 | ///
31 | /// 序号
32 | ///
33 | public ushort Ordinal => _ordinal;
34 |
35 | ///
36 | /// 构造器
37 | ///
38 | /// 地址
39 | /// 名称
40 | /// 序号
41 | public ExportFunctionInfo(void* address, string name, ushort ordinal) {
42 | _address = address;
43 | _name = name ?? string.Empty;
44 | _ordinal = ordinal;
45 | }
46 | }
47 |
48 | unsafe partial class NativeModule {
49 | ///
50 | /// 通过函数名获取导出函数地址
51 | ///
52 | /// 函数名
53 | ///
54 | public void* GetFunctionAddress(string functionName) {
55 | _process.QuickDemand(ProcessAccess.MemoryRead | ProcessAccess.QueryInformation);
56 | return GetFunctionAddressInternal(_process.Handle, _handle, functionName);
57 | }
58 |
59 | internal static void* GetFunctionAddressInternal(void* processHandle, string moduleName, string functionName) {
60 | void* moduleHandle = NativeProcess.GetModuleHandleInternal(processHandle, false, moduleName);
61 | if (moduleHandle == null)
62 | return null;
63 | return GetFunctionAddressInternal(processHandle, moduleHandle, functionName);
64 | }
65 |
66 | internal static void* GetFunctionAddressInternal(void* processHandle, void* moduleHandle, string functionName) {
67 | if (!SafeGetExportTableInfo((IntPtr)processHandle, (IntPtr)moduleHandle, out var ied, out uint[] nameOffsets))
68 | return null;
69 | for (uint i = 0; i < ied.NumberOfNames; i++) {
70 | if (!NativeProcess.ReadStringInternal(processHandle, (byte*)moduleHandle + nameOffsets[i], out string name, false, Encoding.ASCII) || name != functionName)
71 | continue;
72 | if (!NativeProcess.ReadUInt16Internal(processHandle, (byte*)moduleHandle + ied.AddressOfNameOrdinals + (i * 2), out ushort ordinal))
73 | continue;
74 | if (!NativeProcess.ReadUInt32Internal(processHandle, (byte*)moduleHandle + ied.AddressOfFunctions + (ordinal * 4), out uint addressOffset))
75 | continue;
76 | return (byte*)moduleHandle + addressOffset;
77 | }
78 | return null;
79 | }
80 |
81 | ///
82 | /// 获取所有导出函数信息
83 | ///
84 | ///
85 | public IEnumerable EnumerateFunctionInfos() {
86 | _process.QuickDemand(ProcessAccess.MemoryRead | ProcessAccess.QueryInformation);
87 | return EnumerateFunctionInfosInternal((IntPtr)_process.Handle, (IntPtr)_handle);
88 | }
89 |
90 | internal static IEnumerable EnumerateFunctionInfosInternal(IntPtr processHandle, IntPtr moduleHandle) {
91 | if (!SafeGetExportTableInfo(processHandle, moduleHandle, out var ied, out uint[] nameOffsets))
92 | yield break;
93 | for (uint i = 0; i < ied.NumberOfNames; i++) {
94 | if (SafeGetExportFunctionInfo(processHandle, moduleHandle, ied, nameOffsets, i, out var functionInfo))
95 | yield return functionInfo;
96 | else
97 | yield break;
98 | }
99 | }
100 |
101 | private static bool SafeGetExportTableInfo(IntPtr processHandle, IntPtr moduleHandle, out IMAGE_EXPORT_DIRECTORY ied, out uint[] nameOffsets) {
102 | ied = default;
103 | nameOffsets = Array2.Empty();
104 | if (!NativeProcess.ReadUInt32Internal((void*)processHandle, (byte*)moduleHandle + 0x3C, out uint ntHeaderOffset))
105 | return false;
106 | if (!NativeProcess.Is64BitProcessInternal((void*)processHandle, out bool is64Bit))
107 | return false;
108 | uint iedRVA;
109 | if (is64Bit) {
110 | if (!NativeProcess.ReadUInt32Internal((void*)processHandle, (byte*)moduleHandle + ntHeaderOffset + 0x88, out iedRVA))
111 | return false;
112 | }
113 | else {
114 | if (!NativeProcess.ReadUInt32Internal((void*)processHandle, (byte*)moduleHandle + ntHeaderOffset + 0x78, out iedRVA))
115 | return false;
116 | }
117 | fixed (void* p = &ied) {
118 | if (!NativeProcess.ReadInternal((void*)processHandle, (byte*)moduleHandle + iedRVA, p, IMAGE_EXPORT_DIRECTORY.UnmanagedSize))
119 | return false;
120 | }
121 | if (ied.NumberOfNames == 0)
122 | return true;
123 | nameOffsets = new uint[ied.NumberOfNames];
124 | fixed (void* p = nameOffsets) {
125 | if (!NativeProcess.ReadInternal((void*)processHandle, (byte*)moduleHandle + ied.AddressOfNames, p, ied.NumberOfNames * 4))
126 | return false;
127 | }
128 | return true;
129 | }
130 |
131 | private static bool SafeGetExportFunctionInfo(IntPtr processHandle, IntPtr moduleHandle, IMAGE_EXPORT_DIRECTORY ied, uint[] nameOffsets, uint i, out ExportFunctionInfo functionInfo) {
132 | functionInfo = ExportFunctionInfo.Empty;
133 | if (!NativeProcess.ReadStringInternal((void*)processHandle, (byte*)moduleHandle + nameOffsets[i], out string functionName, false, Encoding.ASCII))
134 | return false;
135 | if (!NativeProcess.ReadUInt16Internal((void*)processHandle, (byte*)moduleHandle + ied.AddressOfNameOrdinals + (i * 2), out ushort ordinal))
136 | return false;
137 | if (!NativeProcess.ReadUInt32Internal((void*)processHandle, (byte*)moduleHandle + ied.AddressOfFunctions + (ordinal * 4), out uint addressOffset))
138 | return false;
139 | functionInfo = new ExportFunctionInfo((byte*)moduleHandle + addressOffset, functionName, ordinal);
140 | return true;
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/Injector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using static NativeSharp.NativeMethods;
5 |
6 | namespace NativeSharp {
7 | ///
8 | /// 注入时使用的CLR版本
9 | ///
10 | public enum InjectionClrVersion {
11 | ///
12 | /// 自动选择,由要注入的程序集本身决定
13 | ///
14 | Auto,
15 |
16 | ///
17 | /// v2.0.50727
18 | ///
19 | V2,
20 |
21 | ///
22 | /// v4.0.30319
23 | ///
24 | V4
25 | }
26 |
27 | unsafe partial class NativeProcess {
28 | ///
29 | /// 注入托管DLL
30 | ///
31 | /// 要注入程序集的路径
32 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB)
33 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)
34 | /// 参数,可传入
35 | ///
36 | public bool InjectManaged(string assemblyPath, string typeName, string methodName, string argument) {
37 | return InjectManaged(assemblyPath, typeName, methodName, argument, InjectionClrVersion.Auto);
38 | }
39 |
40 | ///
41 | /// 注入托管DLL
42 | ///
43 | /// 要注入程序集的路径
44 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB)
45 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)
46 | /// 参数,可传入
47 | /// 使用的CLR版本
48 | ///
49 | public bool InjectManaged(string assemblyPath, string typeName, string methodName, string argument, InjectionClrVersion clrVersion) {
50 | if (string.IsNullOrEmpty(assemblyPath))
51 | throw new ArgumentNullException(nameof(assemblyPath));
52 | if (!File.Exists(assemblyPath))
53 | throw new FileNotFoundException();
54 | if (string.IsNullOrEmpty(typeName))
55 | throw new ArgumentNullException(nameof(typeName));
56 | if (string.IsNullOrEmpty(methodName))
57 | throw new ArgumentNullException(nameof(methodName));
58 |
59 | QuickDemand(ProcessAccess.CreateThread | ProcessAccess.MemoryOperation | ProcessAccess.MemoryRead | ProcessAccess.MemoryWrite | ProcessAccess.QueryInformation | ProcessAccess.Synchronize);
60 | return Injector.InjectManagedInternal(_handle, assemblyPath, typeName, methodName, argument, clrVersion, out _, false);
61 | }
62 |
63 | ///
64 | /// 注入托管DLL,并获取被调用方法的返回值(警告:被调用方法返回后才能获取到返回值,方法将一直等待到被调用方法返回。如果仅注入程序集而不需要获取返回值,请使用重载版本)
65 | ///
66 | /// 要注入程序集的路径
67 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB)
68 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)
69 | /// 参数,可传入
70 | /// 被调用方法返回的整数值
71 | ///
72 | public bool InjectManaged(string assemblyPath, string typeName, string methodName, string argument, out int returnValue) {
73 | return InjectManaged(assemblyPath, typeName, methodName, argument, InjectionClrVersion.Auto, out returnValue);
74 | }
75 |
76 | ///
77 | /// 注入托管DLL,并获取被调用方法的返回值(警告:被调用方法返回后才能获取到返回值,方法将一直等待到被调用方法返回。如果仅注入程序集而不需要获取返回值,请使用重载版本)
78 | ///
79 | /// 要注入程序集的路径
80 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB)
81 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)
82 | /// 参数,可传入
83 | /// 使用的CLR版本
84 | /// 被调用方法返回的整数值
85 | ///
86 | public bool InjectManaged(string assemblyPath, string typeName, string methodName, string argument, InjectionClrVersion clrVersion, out int returnValue) {
87 | if (string.IsNullOrEmpty(assemblyPath))
88 | throw new ArgumentNullException(nameof(assemblyPath));
89 | if (!File.Exists(assemblyPath))
90 | throw new FileNotFoundException();
91 | if (string.IsNullOrEmpty(typeName))
92 | throw new ArgumentNullException(nameof(typeName));
93 | if (string.IsNullOrEmpty(methodName))
94 | throw new ArgumentNullException(nameof(methodName));
95 |
96 | QuickDemand(ProcessAccess.CreateThread | ProcessAccess.MemoryOperation | ProcessAccess.MemoryRead | ProcessAccess.MemoryWrite | ProcessAccess.QueryInformation | ProcessAccess.Synchronize);
97 | return Injector.InjectManagedInternal(_handle, assemblyPath, typeName, methodName, argument, clrVersion, out returnValue, true);
98 | }
99 |
100 | ///
101 | /// 注入非托管DLL
102 | ///
103 | /// 要注入DLL的路径
104 | ///
105 | public bool InjectUnmanaged(string dllPath) {
106 | if (string.IsNullOrEmpty(dllPath))
107 | throw new ArgumentNullException(nameof(dllPath));
108 |
109 | QuickDemand(ProcessAccess.CreateThread | ProcessAccess.MemoryOperation | ProcessAccess.MemoryRead | ProcessAccess.MemoryWrite | ProcessAccess.QueryInformation | ProcessAccess.Synchronize);
110 | return Injector.InjectUnmanagedInternal(_handle, dllPath);
111 | }
112 | }
113 |
114 | internal static unsafe class Injector {
115 | private const string CLR_V2 = "v2.0.50727";
116 | private const string CLR_V4 = "v4.0.30319";
117 | private const int AssemblyPathOffset = 0x200;
118 | private const int TypeNameOffset = 0x800;
119 | private const int MethodNameOffset = 0x980;
120 | private const int ReturnValueOffset = 0xA00;
121 | private const int CLRVersionOffset = 0xA10;
122 | private const int CLSID_CLRMetaHostOffset = 0xA60;
123 | private const int IID_ICLRMetaHostOffset = 0xA70;
124 | private const int IID_ICLRRuntimeInfoOffset = 0xA80;
125 | private const int CLSID_CLRRuntimeHostOffset = 0xA90;
126 | private const int IID_ICLRRuntimeHostOffset = 0xAA0;
127 | private const int ArgumentOffset = 0xB00;
128 | private readonly static byte[] CLSID_CLRMetaHost = new Guid(0x9280188D, 0x0E8E, 0x4867, 0xB3, 0x0C, 0x7F, 0xA8, 0x38, 0x84, 0xE8, 0xDE).ToByteArray();
129 | private readonly static byte[] IID_ICLRMetaHost = new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16).ToByteArray();
130 | private readonly static byte[] IID_ICLRRuntimeInfo = new Guid(0xBD39D1D2, 0xBA2F, 0x486A, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91).ToByteArray();
131 | private readonly static byte[] CLSID_CLRRuntimeHost = new Guid(0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray();
132 | private readonly static byte[] IID_ICLRRuntimeHost = new Guid(0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray();
133 |
134 | private struct SectionHeader {
135 | public uint VirtualSize;
136 |
137 | public uint VirtualAddress;
138 |
139 | public uint RawSize;
140 |
141 | public uint RawAddress;
142 |
143 | public SectionHeader(uint virtualSize, uint virtualAddress, uint rawSize, uint rawAddress) {
144 | VirtualSize = virtualSize;
145 | VirtualAddress = virtualAddress;
146 | RawSize = rawSize;
147 | RawAddress = rawAddress;
148 | }
149 | }
150 |
151 | internal static bool InjectManagedInternal(void* processHandle, string assemblyPath, string typeName, string methodName, string argument, InjectionClrVersion clrVersion, out int returnValue, bool wait) {
152 | returnValue = 0;
153 | assemblyPath = Path.GetFullPath(assemblyPath);
154 | // 获取绝对路径
155 | IsAssembly(assemblyPath, out bool isAssembly, out var clrVersionTemp);
156 | if (clrVersion == InjectionClrVersion.Auto)
157 | clrVersion = clrVersionTemp;
158 | if (!isAssembly)
159 | throw new NotSupportedException("Not a valid .NET assembly.");
160 | if (!InjectUnmanagedInternal(processHandle, Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), @"System32\mscoree.dll")))
161 | return false;
162 | // 加载对应进程位数的mscoree.dll
163 | void* pEnvironment = WriteMachineCode(processHandle, clrVersion, assemblyPath, typeName, methodName, argument);
164 | // 获取远程进程中启动CLR的函数指针
165 | if (pEnvironment == null)
166 | return false;
167 | void* threadHandle = CreateRemoteThread(processHandle, null, 0, pEnvironment, (byte*)pEnvironment + ReturnValueOffset, 0, null);
168 | if (threadHandle == null)
169 | return false;
170 | if (wait) {
171 | WaitForSingleObject(threadHandle, INFINITE);
172 | // 等待线程结束
173 | if (!GetExitCodeThread(threadHandle, out uint exitCode))
174 | return false;
175 | if (!NativeProcess.ReadInt32Internal(processHandle, (byte*)pEnvironment + ReturnValueOffset, out returnValue))
176 | return false;
177 | // 获取程序集中被调用方法的返回值
178 | if (!NativeProcess.FreeMemoryInternal(processHandle, pEnvironment))
179 | return false;
180 | return exitCode == 0;
181 | }
182 | return true;
183 | }
184 |
185 | internal static bool InjectUnmanagedInternal(void* processHandle, string dllPath) {
186 | void* pLoadLibrary = NativeModule.GetFunctionAddressInternal(processHandle, "kernel32.dll", "LoadLibraryW");
187 | // 获取LoadLibrary的函数地址
188 | void* pDllPath = NativeProcess.AllocMemoryInternal(processHandle, ((uint)dllPath.Length * 2) + 2, MemoryProtection.ExecuteRead);
189 | if (pDllPath == null)
190 | return false;
191 | try {
192 | if (!NativeProcess.WriteStringInternal(processHandle, pDllPath, dllPath, Encoding.Unicode))
193 | return false;
194 | void* threadHandle = CreateRemoteThread(processHandle, null, 0, pLoadLibrary, pDllPath, 0, null);
195 | if (threadHandle == null)
196 | return false;
197 | WaitForSingleObject(threadHandle, INFINITE);
198 | // 等待线程结束
199 | GetExitCodeThread(threadHandle, out uint exitCode);
200 | return exitCode != 0;
201 | // LoadLibrary返回值不为0则调用成功,否则失败
202 | }
203 | finally {
204 | NativeProcess.FreeMemoryInternal(processHandle, pDllPath);
205 | }
206 | }
207 |
208 | private static void* WriteMachineCode(void* processHandle, InjectionClrVersion clrVersion, string assemblyPath, string typeName, string methodName, string argument) {
209 | if (!NativeProcess.Is64BitProcessInternal(processHandle, out bool is64Bit))
210 | return null;
211 | string clrVersionString = clrVersion switch
212 | {
213 | InjectionClrVersion.V2 => CLR_V2,
214 | InjectionClrVersion.V4 => CLR_V4,
215 | _ => throw new ArgumentOutOfRangeException(nameof(clrVersion)),
216 | };
217 | byte[] machineCode = GetMachineCodeTemplate(clrVersionString, assemblyPath, typeName, methodName, argument);
218 | void* pEnvironment = NativeProcess.AllocMemoryInternal(processHandle, 0x1000 + (argument is null ? 0 : ((uint)argument.Length * 2) + 2), MemoryProtection.ExecuteReadWrite);
219 | if (pEnvironment == null)
220 | return null;
221 | try {
222 | fixed (byte* p = machineCode)
223 | switch (clrVersion) {
224 | case InjectionClrVersion.V2:
225 | void* pCorBindToRuntimeEx = NativeModule.GetFunctionAddressInternal(processHandle, "mscoree.dll", "CorBindToRuntimeEx");
226 | if (pCorBindToRuntimeEx == null)
227 | return null;
228 | if (is64Bit)
229 | WriteMachineCode64v2(p, (ulong)pEnvironment, (ulong)pCorBindToRuntimeEx);
230 | else
231 | WriteMachineCode32v2(p, (uint)pEnvironment, (uint)pCorBindToRuntimeEx);
232 | break;
233 | case InjectionClrVersion.V4:
234 | void* pCLRCreateInstance = NativeModule.GetFunctionAddressInternal(processHandle, "mscoree.dll", "CLRCreateInstance");
235 | if (pCLRCreateInstance == null)
236 | return null;
237 | if (is64Bit)
238 | WriteMachineCode64v4(p, (ulong)pEnvironment, (ulong)pCLRCreateInstance);
239 | else
240 | WriteMachineCode32v4(p, (uint)pEnvironment, (uint)pCLRCreateInstance);
241 | break;
242 | }
243 | if (!NativeProcess.WriteBytesInternal(processHandle, pEnvironment, machineCode))
244 | return null;
245 | }
246 | catch {
247 | NativeProcess.FreeMemoryInternal(processHandle, pEnvironment);
248 | return null;
249 | }
250 | return pEnvironment;
251 | }
252 |
253 | private static byte[] GetMachineCodeTemplate(string clrVersion, string assemblyPath, string typeName, string methodName, string argument) {
254 | using var stream = new MemoryStream(0x1000 + (argument is null ? 0 : argument.Length * 2));
255 | byte[] buffer = Encoding.Unicode.GetBytes(assemblyPath);
256 | stream.Position = AssemblyPathOffset;
257 | stream.Write(buffer, 0, buffer.Length);
258 | // assemblyPath
259 | buffer = Encoding.Unicode.GetBytes(typeName);
260 | stream.Position = TypeNameOffset;
261 | stream.Write(buffer, 0, buffer.Length);
262 | // typeName
263 | buffer = Encoding.Unicode.GetBytes(methodName);
264 | stream.Position = MethodNameOffset;
265 | stream.Write(buffer, 0, buffer.Length);
266 | // methodName
267 | buffer = argument is null ? Array2.Empty() : Encoding.Unicode.GetBytes(argument);
268 | stream.Position = ArgumentOffset;
269 | stream.Write(buffer, 0, buffer.Length);
270 | // argument
271 | buffer = Encoding.Unicode.GetBytes(clrVersion);
272 | stream.Position = CLRVersionOffset;
273 | stream.Write(buffer, 0, buffer.Length);
274 | // clrVersion
275 | stream.Position = CLSID_CLRMetaHostOffset;
276 | stream.Write(CLSID_CLRMetaHost, 0, CLSID_CLRMetaHost.Length);
277 | stream.Position = IID_ICLRMetaHostOffset;
278 | stream.Write(IID_ICLRMetaHost, 0, IID_ICLRMetaHost.Length);
279 | stream.Position = IID_ICLRRuntimeInfoOffset;
280 | stream.Write(IID_ICLRRuntimeInfo, 0, IID_ICLRRuntimeInfo.Length);
281 | stream.Position = CLSID_CLRRuntimeHostOffset;
282 | stream.Write(CLSID_CLRRuntimeHost, 0, CLSID_CLRRuntimeHost.Length);
283 | stream.Position = IID_ICLRRuntimeHostOffset;
284 | stream.Write(IID_ICLRRuntimeHost, 0, IID_ICLRRuntimeHost.Length);
285 | stream.SetLength(stream.Capacity);
286 | return stream.ToArray();
287 | }
288 |
289 | private static void WriteMachineCode32v2(byte* p, uint pFunction, uint pCorBindToRuntimeEx) {
290 | // HRESULT WINAPI LoadCLR2(DWORD *pReturnValue)
291 | #region {
292 | p[0] = 0x55;
293 | p += 1;
294 | // push ebp
295 | p[0] = 0x89;
296 | p[1] = 0xE5;
297 | p += 2;
298 | // mov ebp,esp
299 | p[0] = 0x83;
300 | p[1] = 0xEC;
301 | p[2] = 0x44;
302 | p += 3;
303 | // sub esp,byte +0x44
304 | p[0] = 0x53;
305 | p += 1;
306 | // push ebx
307 | p[0] = 0x56;
308 | p += 1;
309 | // push esi
310 | p[0] = 0x57;
311 | p += 1;
312 | // push edi
313 | p[0] = 0xC7;
314 | p[1] = 0x45;
315 | p[2] = 0xFC;
316 | p[3] = 0x00;
317 | p[4] = 0x00;
318 | p[5] = 0x00;
319 | p[6] = 0x00;
320 | p += 7;
321 | #endregion
322 | #region ICLRRuntimeHost *pRuntimeHost = nullptr;
323 | // mov dword [ebp-0x4],0x0
324 | p[0] = 0x8D;
325 | p[1] = 0x45;
326 | p[2] = 0xFC;
327 | p += 3;
328 | #endregion
329 | #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
330 | // lea eax,[ebp-0x4]
331 | p[0] = 0x50;
332 | p += 1;
333 | // push eax
334 | p[0] = 0x68;
335 | *(uint*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
336 | p += 5;
337 | // push dword PIID_ICLRRuntimeHost
338 | p[0] = 0x68;
339 | *(uint*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
340 | p += 5;
341 | // push dword pCLSID_CLRRuntimeHost
342 | p[0] = 0x6A;
343 | p[1] = 0x00;
344 | p += 2;
345 | // push byte +0x0
346 | p[0] = 0x6A;
347 | p[1] = 0x00;
348 | p += 2;
349 | // push byte +0x0
350 | p[0] = 0x68;
351 | *(uint*)(p + 1) = pFunction + CLRVersionOffset;
352 | p += 5;
353 | // push dword pCLRVersion
354 | p[0] = 0xB9;
355 | *(uint*)(p + 1) = pCorBindToRuntimeEx;
356 | p += 5;
357 | // mov ecx,pCorBindToRuntimeEx
358 | p[0] = 0xFF;
359 | p[1] = 0xD1;
360 | p += 2;
361 | // call ecx
362 | #endregion
363 | #region pRuntimeHost->Start();
364 | p[0] = 0x8B;
365 | p[1] = 0x45;
366 | p[2] = 0xFC;
367 | p += 3;
368 | // mov eax,[ebp-0x4]
369 | p[0] = 0x8B;
370 | p[1] = 0x08;
371 | p += 2;
372 | // mov ecx,[eax]
373 | p[0] = 0x8B;
374 | p[1] = 0x55;
375 | p[2] = 0xFC;
376 | p += 3;
377 | // mov edx,[ebp-0x4]
378 | p[0] = 0x52;
379 | p += 1;
380 | // push edx
381 | p[0] = 0x8B;
382 | p[1] = 0x41;
383 | p[2] = 0x0C;
384 | p += 3;
385 | // mov eax,[ecx+0xc]
386 | p[0] = 0xFF;
387 | p[1] = 0xD0;
388 | p += 2;
389 | // call eax
390 | #endregion
391 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
392 | p[0] = 0x8B;
393 | p[1] = 0x45;
394 | p[2] = 0x08;
395 | p += 3;
396 | // mov eax,[ebp+0x8]
397 | p[0] = 0x50;
398 | p += 1;
399 | // push eax
400 | p[0] = 0x68;
401 | *(uint*)(p + 1) = pFunction + ArgumentOffset;
402 | p += 5;
403 | // push dword pArgument
404 | p[0] = 0x68;
405 | *(uint*)(p + 1) = pFunction + MethodNameOffset;
406 | p += 5;
407 | // push dword pMethodName
408 | p[0] = 0x68;
409 | *(uint*)(p + 1) = pFunction + TypeNameOffset;
410 | p += 5;
411 | // push dword pTypeName
412 | p[0] = 0x68;
413 | *(uint*)(p + 1) = pFunction + AssemblyPathOffset;
414 | p += 5;
415 | // push dword pAssemblyPath
416 | p[0] = 0x8B;
417 | p[1] = 0x4D;
418 | p[2] = 0xFC;
419 | p += 3;
420 | // mov ecx,[ebp-0x4]
421 | p[0] = 0x8B;
422 | p[1] = 0x11;
423 | p += 2;
424 | // mov edx,[ecx]
425 | p[0] = 0x8B;
426 | p[1] = 0x45;
427 | p[2] = 0xFC;
428 | p += 3;
429 | // mov eax,[ebp-0x4]
430 | p[0] = 0x50;
431 | p += 1;
432 | // push eax
433 | p[0] = 0x8B;
434 | p[1] = 0x4A;
435 | p[2] = 0x2C;
436 | p += 3;
437 | // mov ecx,[edx+0x2c]
438 | p[0] = 0xFF;
439 | p[1] = 0xD1;
440 | p += 2;
441 | // call ecx
442 | #endregion
443 | #region }
444 | p[0] = 0x5F;
445 | p += 1;
446 | // pop edi
447 | p[0] = 0x5E;
448 | p += 1;
449 | // pop esi
450 | p[0] = 0x5B;
451 | p += 1;
452 | // pop ebx
453 | p[0] = 0x89;
454 | p[1] = 0xEC;
455 | p += 2;
456 | // mov esp,ebp
457 | p[0] = 0x5D;
458 | p += 1;
459 | // pop ebp
460 | p[0] = 0xC2;
461 | p[1] = 0x04;
462 | p[2] = 0x00;
463 | // ret 0x4
464 | #endregion
465 | }
466 |
467 | private static void WriteMachineCode32v4(byte* p, uint pFunction, uint pCLRCreateInstance) {
468 | // HRESULT WINAPI LoadCLR4(DWORD *pReturnValue)
469 | #region {
470 | p[0] = 0x55;
471 | p += 1;
472 | // push ebp
473 | p[0] = 0x89;
474 | p[1] = 0xE5;
475 | p += 2;
476 | // mov ebp,esp
477 | p[0] = 0x83;
478 | p[1] = 0xEC;
479 | p[2] = 0x4C;
480 | p += 3;
481 | // sub esp,byte +0x4c
482 | p[0] = 0x53;
483 | p += 1;
484 | // push ebx
485 | p[0] = 0x56;
486 | p += 1;
487 | // push esi
488 | p[0] = 0x57;
489 | p += 1;
490 | // push edi
491 | #endregion
492 | #region ICLRMetaHost *pMetaHost = nullptr;
493 | p[0] = 0xC7;
494 | p[1] = 0x45;
495 | p[2] = 0xFC;
496 | p[3] = 0x00;
497 | p[4] = 0x00;
498 | p[5] = 0x00;
499 | p[6] = 0x00;
500 | p += 7;
501 | // mov dword [ebp-0x4],0x0
502 | #endregion
503 | #region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
504 | p[0] = 0xC7;
505 | p[1] = 0x45;
506 | p[2] = 0xF8;
507 | p[3] = 0x00;
508 | p[4] = 0x00;
509 | p[5] = 0x00;
510 | p[6] = 0x00;
511 | p += 7;
512 | // mov dword [ebp-0x8],0x0
513 | #endregion
514 | #region ICLRRuntimeHost *pRuntimeHost = nullptr;
515 | p[0] = 0xC7;
516 | p[1] = 0x45;
517 | p[2] = 0xF4;
518 | p[3] = 0x00;
519 | p[4] = 0x00;
520 | p[5] = 0x00;
521 | p[6] = 0x00;
522 | p += 7;
523 | // mov dword [ebp-0xc],0x0
524 | #endregion
525 | #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
526 | p[0] = 0x8D;
527 | p[1] = 0x45;
528 | p[2] = 0xFC;
529 | p += 3;
530 | // lea eax,[ebp-0x4]
531 | p[0] = 0x50;
532 | p += 1;
533 | // push eax
534 | p[0] = 0x68;
535 | *(uint*)(p + 1) = pFunction + IID_ICLRMetaHostOffset;
536 | p += 5;
537 | // push dword pIID_ICLRMetaHost
538 | p[0] = 0x68;
539 | *(uint*)(p + 1) = pFunction + CLSID_CLRMetaHostOffset;
540 | p += 5;
541 | // push dword pCLSID_CLRMetaHost
542 | p[0] = 0xB9;
543 | *(uint*)(p + 1) = pCLRCreateInstance;
544 | p += 5;
545 | // mov ecx,pCLRCreateInstance
546 | p[0] = 0xFF;
547 | p[1] = 0xD1;
548 | p += 2;
549 | // call ecx
550 | #endregion
551 | #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
552 | p[0] = 0x8D;
553 | p[1] = 0x45;
554 | p[2] = 0xF8;
555 | p += 3;
556 | // lea eax,[ebp-0x8]
557 | p[0] = 0x50;
558 | p += 1;
559 | // push eax
560 | p[0] = 0x68;
561 | *(uint*)(p + 1) = pFunction + IID_ICLRRuntimeInfoOffset;
562 | p += 5;
563 | // push dword pIID_ICLRRuntimeInfo
564 | p[0] = 0x68;
565 | *(uint*)(p + 1) = pFunction + CLRVersionOffset;
566 | p += 5;
567 | // push dword pCLRVersion
568 | p[0] = 0x8B;
569 | p[1] = 0x4D;
570 | p[2] = 0xFC;
571 | p += 3;
572 | // mov ecx,[ebp-0x4]
573 | p[0] = 0x8B;
574 | p[1] = 0x11;
575 | p += 2;
576 | // mov edx,[ecx]
577 | p[0] = 0x8B;
578 | p[1] = 0x45;
579 | p[2] = 0xFC;
580 | p += 3;
581 | // mov eax,[ebp-0x4]
582 | p[0] = 0x50;
583 | p += 1;
584 | // push eax
585 | p[0] = 0x8B;
586 | p[1] = 0x4A;
587 | p[2] = 0x0C;
588 | p += 3;
589 | // mov ecx,[edx+0xc]
590 | p[0] = 0xFF;
591 | p[1] = 0xD1;
592 | p += 2;
593 | // call ecx
594 | #endregion
595 | #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
596 | p[0] = 0x8D;
597 | p[1] = 0x45;
598 | p[2] = 0xF4;
599 | p += 3;
600 | // lea eax,[ebp-0xc]
601 | p[0] = 0x50;
602 | p += 1;
603 | // push eax
604 | p[0] = 0x68;
605 | *(uint*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
606 | p += 5;
607 | // push dword pIID_ICLRRuntimeHost
608 | p[0] = 0x68;
609 | *(uint*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
610 | p += 5;
611 | // push dword pCLSID_CLRRuntimeHost
612 | p[0] = 0x8B;
613 | p[1] = 0x4D;
614 | p[2] = 0xF8;
615 | p += 3;
616 | // mov ecx,[ebp-0x8]
617 | p[0] = 0x8B;
618 | p[1] = 0x11;
619 | p += 2;
620 | // mov edx,[ecx]
621 | p[0] = 0x8B;
622 | p[1] = 0x45;
623 | p[2] = 0xF8;
624 | p += 3;
625 | // mov eax,[ebp-0x8]
626 | p[0] = 0x50;
627 | p += 1;
628 | // push eax
629 | p[0] = 0x8B;
630 | p[1] = 0x4A;
631 | p[2] = 0x24;
632 | p += 3;
633 | // mov ecx,[edx+0x24]
634 | p[0] = 0xFF;
635 | p[1] = 0xD1;
636 | p += 2;
637 | // call ecx
638 | #endregion
639 | #region pRuntimeHost->Start();
640 | p[0] = 0x8B;
641 | p[1] = 0x45;
642 | p[2] = 0xF4;
643 | p += 3;
644 | // mov eax,[ebp-0xc]
645 | p[0] = 0x8B;
646 | p[1] = 0x08;
647 | p += 2;
648 | // mov ecx,[eax]
649 | p[0] = 0x8B;
650 | p[1] = 0x55;
651 | p[2] = 0xF4;
652 | p += 3;
653 | // mov edx,[ebp-0xc]
654 | p[0] = 0x52;
655 | p += 1;
656 | // push edx
657 | p[0] = 0x8B;
658 | p[1] = 0x41;
659 | p[2] = 0x0C;
660 | p += 3;
661 | // mov eax,[ecx+0xc]
662 | p[0] = 0xFF;
663 | p[1] = 0xD0;
664 | p += 2;
665 | // call eax
666 | #endregion
667 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
668 | p[0] = 0x8B;
669 | p[1] = 0x45;
670 | p[2] = 0x08;
671 | p += 3;
672 | // mov eax,[ebp+0x8]
673 | p[0] = 0x50;
674 | p += 1;
675 | // push eax
676 | p[0] = 0x68;
677 | *(uint*)(p + 1) = pFunction + ArgumentOffset;
678 | p += 5;
679 | // push dword pArgument
680 | p[0] = 0x68;
681 | *(uint*)(p + 1) = pFunction + MethodNameOffset;
682 | p += 5;
683 | // push dword pMethodName
684 | p[0] = 0x68;
685 | *(uint*)(p + 1) = pFunction + TypeNameOffset;
686 | p += 5;
687 | // push dword pTypeName
688 | p[0] = 0x68;
689 | *(uint*)(p + 1) = pFunction + AssemblyPathOffset;
690 | p += 5;
691 | // push dword pAssemblyPath
692 | p[0] = 0x8B;
693 | p[1] = 0x4D;
694 | p[2] = 0xF4;
695 | p += 3;
696 | // mov ecx,[ebp-0xc]
697 | p[0] = 0x8B;
698 | p[1] = 0x11;
699 | p += 2;
700 | // mov edx,[ecx]
701 | p[0] = 0x8B;
702 | p[1] = 0x45;
703 | p[2] = 0xF4;
704 | p += 3;
705 | // mov eax,[ebp-0xc]
706 | p[0] = 0x50;
707 | p += 1;
708 | // push eax
709 | p[0] = 0x8B;
710 | p[1] = 0x4A;
711 | p[2] = 0x2C;
712 | p += 3;
713 | // mov ecx,[edx+0x2c]
714 | p[0] = 0xFF;
715 | p[1] = 0xD1;
716 | p += 2;
717 | // call ecx
718 | #endregion
719 | #region }
720 | p[0] = 0x5F;
721 | p += 1;
722 | // pop edi
723 | p[0] = 0x5E;
724 | p += 1;
725 | // pop esi
726 | p[0] = 0x5B;
727 | p += 1;
728 | // pop ebx
729 | p[0] = 0x89;
730 | p[1] = 0xEC;
731 | p += 2;
732 | // mov esp,ebp
733 | p[0] = 0x5D;
734 | p += 1;
735 | // pop ebp
736 | p[0] = 0xC2;
737 | p[1] = 0x04;
738 | p[2] = 0x00;
739 | // ret 0x4
740 | #endregion
741 | }
742 |
743 | private static void WriteMachineCode64v2(byte* p, ulong pFunction, ulong pCorBindToRuntimeEx) {
744 | // HRESULT WINAPI LoadCLR2(DWORD *pReturnValue)
745 | #region {
746 | p[0] = 0x48;
747 | p[1] = 0x89;
748 | p[2] = 0x4C;
749 | p[3] = 0x24;
750 | p[4] = 0x08;
751 | p += 5;
752 | // mov [rsp+0x8],rcx
753 | p[0] = 0x55;
754 | p += 1;
755 | // push rbp
756 | p[0] = 0x48;
757 | p[1] = 0x81;
758 | p[2] = 0xEC;
759 | p[3] = 0x80;
760 | p[4] = 0x00;
761 | p[5] = 0x00;
762 | p[6] = 0x00;
763 | p += 7;
764 | // sub rsp,0x80
765 | p[0] = 0x48;
766 | p[1] = 0x8D;
767 | p[2] = 0x6C;
768 | p[3] = 0x24;
769 | p[4] = 0x30;
770 | p += 5;
771 | // lea rbp,[rsp+0x30]
772 | #endregion
773 | #region ICLRRuntimeHost *pRuntimeHost = nullptr;
774 | p[0] = 0x48;
775 | p[1] = 0xC7;
776 | p[2] = 0x45;
777 | p[3] = 0x00;
778 | p[4] = 0x00;
779 | p[5] = 0x00;
780 | p[6] = 0x00;
781 | p[7] = 0x00;
782 | p += 8;
783 | // mov qword [rbp+0x0],0x0
784 | #endregion
785 | #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
786 | p[0] = 0x48;
787 | p[1] = 0x8D;
788 | p[2] = 0x45;
789 | p[3] = 0x00;
790 | p += 4;
791 | // lea rax,[rbp+0x0]
792 | p[0] = 0x48;
793 | p[1] = 0x89;
794 | p[2] = 0x44;
795 | p[3] = 0x24;
796 | p[4] = 0x28;
797 | p += 5;
798 | // mov [rsp+0x28],rax
799 | p[0] = 0x48;
800 | p[1] = 0xB8;
801 | *(ulong*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
802 | p += 10;
803 | // mov rax,pIID_ICLRRuntimeHost
804 | p[0] = 0x48;
805 | p[1] = 0x89;
806 | p[2] = 0x44;
807 | p[3] = 0x24;
808 | p[4] = 0x20;
809 | p += 5;
810 | // mov [rsp+0x20],rax
811 | p[0] = 0x49;
812 | p[1] = 0xB9;
813 | *(ulong*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
814 | p += 10;
815 | // mov r9,pCLSID_CLRRuntimeHost
816 | p[0] = 0x45;
817 | p[1] = 0x31;
818 | p[2] = 0xC0;
819 | p += 3;
820 | // xor r8d,r8d
821 | p[0] = 0x31;
822 | p[1] = 0xD2;
823 | p += 2;
824 | // xor edx,edx
825 | p[0] = 0x48;
826 | p[1] = 0xB9;
827 | *(ulong*)(p + 2) = pFunction + CLRVersionOffset;
828 | p += 10;
829 | // mov rcx,pCLRVersion
830 | p[0] = 0x49;
831 | p[1] = 0xBF;
832 | *(ulong*)(p + 2) = pCorBindToRuntimeEx;
833 | p += 10;
834 | // mov r15,pCorBindToRuntimeEx
835 | p[0] = 0x41;
836 | p[1] = 0xFF;
837 | p[2] = 0xD7;
838 | p += 3;
839 | // call r15
840 | #endregion
841 | #region pRuntimeHost->Start();
842 | p[0] = 0x48;
843 | p[1] = 0x8B;
844 | p[2] = 0x45;
845 | p[3] = 0x00;
846 | p += 4;
847 | // mov rax,[rbp+0x0]
848 | p[0] = 0x48;
849 | p[1] = 0x8B;
850 | p[2] = 0x00;
851 | p += 3;
852 | // mov rax,[rax]
853 | p[0] = 0x48;
854 | p[1] = 0x8B;
855 | p[2] = 0x4D;
856 | p[3] = 0x00;
857 | p += 4;
858 | // mov rcx,[rbp+0x0]
859 | p[0] = 0xFF;
860 | p[1] = 0x50;
861 | p[2] = 0x18;
862 | p += 3;
863 | // call [rax+0x18]
864 | #endregion
865 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
866 | p[0] = 0x48;
867 | p[1] = 0x8B;
868 | p[2] = 0x45;
869 | p[3] = 0x00;
870 | p += 4;
871 | // mov rax,[rbp+0x0]
872 | p[0] = 0x48;
873 | p[1] = 0x8B;
874 | p[2] = 0x00;
875 | p += 3;
876 | // mov rax,[rax]
877 | p[0] = 0x48;
878 | p[1] = 0x8B;
879 | p[2] = 0x4D;
880 | p[3] = 0x60;
881 | p += 4;
882 | // mov rcx,[rbp+0x60]
883 | p[0] = 0x48;
884 | p[1] = 0x89;
885 | p[2] = 0x4C;
886 | p[3] = 0x24;
887 | p[4] = 0x28;
888 | p += 5;
889 | // mov [rsp+0x28],rcx
890 | p[0] = 0x48;
891 | p[1] = 0xB9;
892 | *(ulong*)(p + 2) = pFunction + ArgumentOffset;
893 | p += 10;
894 | // mov rcx,pArgument
895 | p[0] = 0x48;
896 | p[1] = 0x89;
897 | p[2] = 0x4C;
898 | p[3] = 0x24;
899 | p[4] = 0x20;
900 | p += 5;
901 | // mov [rsp+0x20],rcx
902 | p[0] = 0x49;
903 | p[1] = 0xB9;
904 | *(ulong*)(p + 2) = pFunction + MethodNameOffset;
905 | p += 10;
906 | // mov r9,pMethodName
907 | p[0] = 0x49;
908 | p[1] = 0xB8;
909 | *(ulong*)(p + 2) = pFunction + TypeNameOffset;
910 | p += 10;
911 | // mov r8,pTypeName
912 | p[0] = 0x48;
913 | p[1] = 0xBA;
914 | *(ulong*)(p + 2) = pFunction + AssemblyPathOffset;
915 | p += 10;
916 | // mov rdx,pAssemblyPath
917 | p[0] = 0x48;
918 | p[1] = 0x8B;
919 | p[2] = 0x4D;
920 | p[3] = 0x00;
921 | p += 4;
922 | // mov rcx,[rbp+0x0]
923 | p[0] = 0xFF;
924 | p[1] = 0x50;
925 | p[2] = 0x58;
926 | p += 3;
927 | // call [rax+0x58]
928 | #endregion
929 | #region }
930 | p[0] = 0x48;
931 | p[1] = 0x8D;
932 | p[2] = 0x65;
933 | p[3] = 0x50;
934 | p += 4;
935 | // lea rsp,[rbp+0x50]
936 | p[0] = 0x5D;
937 | p += 1;
938 | // pop rbp
939 | p[0] = 0xC3;
940 | // ret
941 | #endregion
942 | }
943 |
944 | private static void WriteMachineCode64v4(byte* p, ulong pFunction, ulong pCLRCreateInstance) {
945 | // HRESULT WINAPI LoadCLR4(DWORD *pReturnValue)
946 | #region {
947 | p[0] = 0x48;
948 | p[1] = 0x89;
949 | p[2] = 0x4C;
950 | p[3] = 0x24;
951 | p[4] = 0x08;
952 | p += 5;
953 | // mov [rsp+0x8],rcx
954 | p[0] = 0x55;
955 | p += 1;
956 | // push rbp
957 | p[0] = 0x48;
958 | p[1] = 0x81;
959 | p[2] = 0xEC;
960 | p[3] = 0x90;
961 | p[4] = 0x00;
962 | p[5] = 0x00;
963 | p[6] = 0x00;
964 | p += 7;
965 | // sub rsp,0x90
966 | p[0] = 0x48;
967 | p[1] = 0x8D;
968 | p[2] = 0x6C;
969 | p[3] = 0x24;
970 | p[4] = 0x30;
971 | p += 5;
972 | // lea rbp,[rsp+0x30]
973 | #endregion
974 | #region ICLRMetaHost *pMetaHost = nullptr;
975 | p[0] = 0x48;
976 | p[1] = 0xC7;
977 | p[2] = 0x45;
978 | p[3] = 0x00;
979 | p[4] = 0x00;
980 | p[5] = 0x00;
981 | p[6] = 0x00;
982 | p[7] = 0x00;
983 | p += 8;
984 | // mov qword [rbp+0x0],0x0
985 | #endregion
986 | #region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
987 | p[0] = 0x48;
988 | p[1] = 0xC7;
989 | p[2] = 0x45;
990 | p[3] = 0x08;
991 | p[4] = 0x00;
992 | p[5] = 0x00;
993 | p[6] = 0x00;
994 | p[7] = 0x00;
995 | p += 8;
996 | // mov qword [rbp+0x8],0x0
997 | #endregion
998 | #region ICLRRuntimeHost *pRuntimeHost = nullptr;
999 | p[0] = 0x48;
1000 | p[1] = 0xC7;
1001 | p[2] = 0x45;
1002 | p[3] = 0x10;
1003 | p[4] = 0x00;
1004 | p[5] = 0x00;
1005 | p[6] = 0x00;
1006 | p[7] = 0x00;
1007 | p += 8;
1008 | // mov qword [rbp+0x10],0x0
1009 | #endregion
1010 | #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
1011 | p[0] = 0x4C;
1012 | p[1] = 0x8D;
1013 | p[2] = 0x45;
1014 | p[3] = 0x00;
1015 | p += 4;
1016 | // lea r8,[rbp+0x0]
1017 | p[0] = 0x48;
1018 | p[1] = 0xBA;
1019 | *(ulong*)(p + 2) = pFunction + IID_ICLRMetaHostOffset;
1020 | p += 10;
1021 | // mov rdx,pIID_ICLRMetaHost
1022 | p[0] = 0x48;
1023 | p[1] = 0xB9;
1024 | *(ulong*)(p + 2) = pFunction + CLSID_CLRMetaHostOffset;
1025 | p += 10;
1026 | // mov rcx,pCLSID_CLRMetaHost
1027 | p[0] = 0x49;
1028 | p[1] = 0xBF;
1029 | *(ulong*)(p + 2) = pCLRCreateInstance;
1030 | p += 10;
1031 | // mov r15,pCLRCreateInstance
1032 | p[0] = 0x41;
1033 | p[1] = 0xFF;
1034 | p[2] = 0xD7;
1035 | p += 3;
1036 | // call r15
1037 | #endregion
1038 | #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
1039 | p[0] = 0x48;
1040 | p[1] = 0x8B;
1041 | p[2] = 0x45;
1042 | p[3] = 0x00;
1043 | p += 4;
1044 | // mov rax,[rbp+0x0]
1045 | p[0] = 0x48;
1046 | p[1] = 0x8B;
1047 | p[2] = 0x00;
1048 | p += 3;
1049 | // mov rax,[rax]
1050 | p[0] = 0x4C;
1051 | p[1] = 0x8D;
1052 | p[2] = 0x4D;
1053 | p[3] = 0x08;
1054 | p += 4;
1055 | // lea r9,[rbp+0x8]
1056 | p[0] = 0x49;
1057 | p[1] = 0xB8;
1058 | *(ulong*)(p + 2) = pFunction + IID_ICLRRuntimeInfoOffset;
1059 | p += 10;
1060 | // mov r8,pIID_ICLRRuntimeInfo
1061 | p[0] = 0x48;
1062 | p[1] = 0xBA;
1063 | *(ulong*)(p + 2) = pFunction + CLRVersionOffset;
1064 | p += 10;
1065 | // mov rdx,pCLRVersion
1066 | p[0] = 0x48;
1067 | p[1] = 0x8B;
1068 | p[2] = 0x4D;
1069 | p[3] = 0x00;
1070 | p += 4;
1071 | // mov rcx,[rbp+0x0]
1072 | p[0] = 0xFF;
1073 | p[1] = 0x50;
1074 | p[2] = 0x18;
1075 | p += 3;
1076 | // call [rax+0x18]
1077 | #endregion
1078 | #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
1079 | p[0] = 0x48;
1080 | p[1] = 0x8B;
1081 | p[2] = 0x45;
1082 | p[3] = 0x08;
1083 | p += 4;
1084 | // mov rax,[rbp+0x8]
1085 | p[0] = 0x48;
1086 | p[1] = 0x8B;
1087 | p[2] = 0x00;
1088 | p += 3;
1089 | // mov rax,[rax]
1090 | p[0] = 0x4C;
1091 | p[1] = 0x8D;
1092 | p[2] = 0x4D;
1093 | p[3] = 0x10;
1094 | p += 4;
1095 | // lea r9,[rbp+0x10]
1096 | p[0] = 0x49;
1097 | p[1] = 0xB8;
1098 | *(ulong*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
1099 | p += 10;
1100 | // mov r8,pIID_ICLRRuntimeHost
1101 | p[0] = 0x48;
1102 | p[1] = 0xBA;
1103 | *(ulong*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
1104 | p += 10;
1105 | // mov rdx,pCLSID_CLRRuntimeHost
1106 | p[0] = 0x48;
1107 | p[1] = 0x8B;
1108 | p[2] = 0x4D;
1109 | p[3] = 0x08;
1110 | p += 4;
1111 | // mov rcx,[rbp+0x8]
1112 | p[0] = 0xFF;
1113 | p[1] = 0x50;
1114 | p[2] = 0x48;
1115 | p += 3;
1116 | // call [rax+0x48]
1117 | #endregion
1118 | #region pRuntimeHost->Start();
1119 | p[0] = 0x48;
1120 | p[1] = 0x8B;
1121 | p[2] = 0x45;
1122 | p[3] = 0x10;
1123 | p += 4;
1124 | // mov rax,[rbp+0x10]
1125 | p[0] = 0x48;
1126 | p[1] = 0x8B;
1127 | p[2] = 0x00;
1128 | p += 3;
1129 | // mov rax,[rax]
1130 | p[0] = 0x48;
1131 | p[1] = 0x8B;
1132 | p[2] = 0x4D;
1133 | p[3] = 0x10;
1134 | p += 4;
1135 | // mov rcx,[rbp+0x10]
1136 | p[0] = 0xFF;
1137 | p[1] = 0x50;
1138 | p[2] = 0x18;
1139 | p += 3;
1140 | // call [rax+0x18]
1141 | #endregion
1142 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
1143 | p[0] = 0x48;
1144 | p[1] = 0x8B;
1145 | p[2] = 0x45;
1146 | p[3] = 0x10;
1147 | p += 4;
1148 | // mov rax,[rbp+0x10]
1149 | p[0] = 0x48;
1150 | p[1] = 0x8B;
1151 | p[2] = 0x00;
1152 | p += 3;
1153 | // mov rax,[rax]
1154 | p[0] = 0x48;
1155 | p[1] = 0x8B;
1156 | p[2] = 0x4D;
1157 | p[3] = 0x70;
1158 | p += 4;
1159 | // mov rcx,[rbp+0x70]
1160 | p[0] = 0x48;
1161 | p[1] = 0x89;
1162 | p[2] = 0x4C;
1163 | p[3] = 0x24;
1164 | p[4] = 0x28;
1165 | p += 5;
1166 | // mov [rsp+0x28],rcx
1167 | p[0] = 0x48;
1168 | p[1] = 0xB9;
1169 | *(ulong*)(p + 2) = pFunction + ArgumentOffset;
1170 | p += 10;
1171 | // mov rcx,pArgument
1172 | p[0] = 0x48;
1173 | p[1] = 0x89;
1174 | p[2] = 0x4C;
1175 | p[3] = 0x24;
1176 | p[4] = 0x20;
1177 | p += 5;
1178 | // mov [rsp+0x20],rcx
1179 | p[0] = 0x49;
1180 | p[1] = 0xB9;
1181 | *(ulong*)(p + 2) = pFunction + MethodNameOffset;
1182 | p += 10;
1183 | // mov r9,pMethodName
1184 | p[0] = 0x49;
1185 | p[1] = 0xB8;
1186 | *(ulong*)(p + 2) = pFunction + TypeNameOffset;
1187 | p += 10;
1188 | // mov r8,pTypeName
1189 | p[0] = 0x48;
1190 | p[1] = 0xBA;
1191 | *(ulong*)(p + 2) = pFunction + AssemblyPathOffset;
1192 | p += 10;
1193 | // mov rdx,pAssemblyPath
1194 | p[0] = 0x48;
1195 | p[1] = 0x8B;
1196 | p[2] = 0x4D;
1197 | p[3] = 0x10;
1198 | p += 4;
1199 | // mov rcx,[rbp+0x10]
1200 | p[0] = 0xFF;
1201 | p[1] = 0x50;
1202 | p[2] = 0x58;
1203 | p += 3;
1204 | // call [rax+0x58]
1205 | #endregion
1206 | #region }
1207 | p[0] = 0x48;
1208 | p[1] = 0x8D;
1209 | p[2] = 0x65;
1210 | p[3] = 0x60;
1211 | p += 4;
1212 | // lea rsp,[rbp+0x60]
1213 | p[0] = 0x5D;
1214 | p += 1;
1215 | // pop rbp
1216 | p[0] = 0xC3;
1217 | // ret
1218 | #endregion
1219 | }
1220 |
1221 | private static void IsAssembly(string path, out bool isAssembly, out InjectionClrVersion clrVersion) {
1222 | try {
1223 | using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
1224 | using var reader = new BinaryReader(stream);
1225 | clrVersion = GetVersionString(reader) switch
1226 | {
1227 | CLR_V2 => InjectionClrVersion.V2,
1228 | CLR_V4 => InjectionClrVersion.V4,
1229 | _ => default,
1230 | };
1231 | isAssembly = true;
1232 | }
1233 | catch {
1234 | clrVersion = default;
1235 | isAssembly = false;
1236 | }
1237 | }
1238 |
1239 | private static string GetVersionString(BinaryReader binaryReader) {
1240 | GetPEInfo(binaryReader, out uint peOffset, out bool is64Bit);
1241 | binaryReader.BaseStream.Position = peOffset + (is64Bit ? 0xF8 : 0xE8);
1242 | uint rva = binaryReader.ReadUInt32();
1243 | // .Net Metadata Directory RVA
1244 | if (rva == 0)
1245 | throw new BadImageFormatException("File isn't a valid .NET assembly.");
1246 | var sectionHeaders = GetSectionHeaders(binaryReader);
1247 | var sectionHeader = GetSectionHeader(rva, sectionHeaders);
1248 | binaryReader.BaseStream.Position = sectionHeader.RawAddress + rva - sectionHeader.VirtualAddress + 0x8;
1249 | // .Net Metadata Directory FileOffset
1250 | rva = binaryReader.ReadUInt32();
1251 | // .Net Metadata RVA
1252 | if (rva == 0)
1253 | throw new BadImageFormatException("File isn't a valid .NET assembly.");
1254 | sectionHeader = GetSectionHeader(rva, sectionHeaders);
1255 | binaryReader.BaseStream.Position = sectionHeader.RawAddress + rva - sectionHeader.VirtualAddress + 0xC;
1256 | // .Net Metadata FileOffset
1257 | return Encoding.UTF8.GetString(binaryReader.ReadBytes(binaryReader.ReadInt32() - 2));
1258 | }
1259 |
1260 | private static void GetPEInfo(BinaryReader binaryReader, out uint peOffset, out bool is64Bit) {
1261 | binaryReader.BaseStream.Position = 0x3C;
1262 | peOffset = binaryReader.ReadUInt32();
1263 | binaryReader.BaseStream.Position = peOffset + 0x4;
1264 | ushort machine = binaryReader.ReadUInt16();
1265 | if (machine != 0x14C && machine != 0x8664)
1266 | throw new BadImageFormatException("Invalid \"Machine\" in FileHeader.");
1267 | is64Bit = machine == 0x8664;
1268 | }
1269 |
1270 | private static SectionHeader[] GetSectionHeaders(BinaryReader binaryReader) {
1271 | GetPEInfo(binaryReader, out uint ntHeaderOffset, out bool is64Bit);
1272 | ushort numberOfSections = binaryReader.ReadUInt16();
1273 | binaryReader.BaseStream.Position = ntHeaderOffset + (is64Bit ? 0x108 : 0xF8);
1274 | var sectionHeaders = new SectionHeader[numberOfSections];
1275 | for (int i = 0; i < numberOfSections; i++) {
1276 | binaryReader.BaseStream.Position += 0x8;
1277 | sectionHeaders[i] = new SectionHeader(binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32());
1278 | binaryReader.BaseStream.Position += 0x10;
1279 | }
1280 | return sectionHeaders;
1281 | }
1282 |
1283 | private static SectionHeader GetSectionHeader(uint rva, SectionHeader[] sectionHeaders) {
1284 | foreach (var sectionHeader in sectionHeaders) {
1285 | if (rva >= sectionHeader.VirtualAddress && rva < sectionHeader.VirtualAddress + Math.Max(sectionHeader.VirtualSize, sectionHeader.RawSize))
1286 | return sectionHeader;
1287 | }
1288 | throw new BadImageFormatException("Can't get section from specific RVA.");
1289 | }
1290 | }
1291 | }
1292 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/MemoryIO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using static NativeSharp.NativeMethods;
6 |
7 | namespace NativeSharp {
8 | ///
9 | /// 指针
10 | ///
11 | public unsafe sealed class Pointer {
12 | private string _moduleName;
13 | private void* _baseAddress;
14 | private readonly List _offsets;
15 |
16 | ///
17 | /// 模块名。若 为 ,下次使用当前指针实例获取地址时, 将被设置为 对应的句柄(模块基址)
18 | ///
19 | public string ModuleName {
20 | get => _moduleName;
21 | set => _moduleName = value;
22 | }
23 |
24 | ///
25 | /// 基址
26 | ///
27 | public void* BaseAddress {
28 | get => _baseAddress;
29 | set => _baseAddress = value;
30 | }
31 |
32 | ///
33 | /// 多级偏移
34 | ///
35 | public IList Offsets => _offsets;
36 |
37 | ///
38 | /// 构造器
39 | ///
40 | public Pointer() {
41 | _moduleName = string.Empty;
42 | _offsets = new List();
43 | }
44 |
45 | ///
46 | /// 构造器
47 | ///
48 | /// 模块名
49 | /// 多级偏移
50 | public Pointer(string moduleName, params uint[] offsets) {
51 | _moduleName = moduleName;
52 | _offsets = new List(offsets);
53 | }
54 |
55 | ///
56 | /// 构造器
57 | ///
58 | /// 基址
59 | /// 偏移
60 | public Pointer(void* baseAddress, params uint[] offsets) {
61 | _moduleName = string.Empty;
62 | _baseAddress = baseAddress;
63 | _offsets = new List(offsets);
64 | }
65 |
66 | ///
67 | /// 构造器
68 | ///
69 | /// 指针
70 | public Pointer(Pointer pointer) {
71 | _moduleName = pointer._moduleName;
72 | _baseAddress = pointer._baseAddress;
73 | _offsets = new List(pointer._offsets);
74 | }
75 | }
76 |
77 | unsafe partial class NativeProcess {
78 | #region pointer
79 | ///
80 | /// 获取指针指向的地址
81 | ///
82 | /// 指针
83 | ///
84 | public void* ToAddress(Pointer pointer) {
85 | if (pointer is null)
86 | throw new ArgumentNullException(nameof(pointer));
87 |
88 | QuickDemand(ProcessAccess.MemoryRead);
89 | ThrowWin32ExceptionIfFalse(ToAddressInternal(_handle, pointer, out void* address));
90 | return address;
91 | }
92 |
93 | ///
94 | /// 获取指针指向的地址
95 | ///
96 | /// 指针
97 | ///
98 | ///
99 | public bool TryToAddress(Pointer pointer, out void* address) {
100 | address = default;
101 | if (pointer is null)
102 | return false;
103 |
104 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
105 | return false;
106 | return ToAddressInternal(_handle, pointer, out address);
107 | }
108 | #endregion
109 |
110 | #region read
111 | ///
112 | /// 读取内存
113 | ///
114 | /// 地址
115 | ///
116 | public byte ReadByte(void* address) {
117 | QuickDemand(ProcessAccess.MemoryRead);
118 | ThrowWin32ExceptionIfFalse(ReadByteInternal(_handle, address, out byte value));
119 | return value;
120 | }
121 |
122 | ///
123 | /// 读取内存
124 | ///
125 | /// 地址
126 | ///
127 | public short ReadInt16(void* address) {
128 | QuickDemand(ProcessAccess.MemoryRead);
129 | ThrowWin32ExceptionIfFalse(ReadInt16Internal(_handle, address, out short value));
130 | return value;
131 | }
132 |
133 | ///
134 | /// 读取内存
135 | ///
136 | /// 地址
137 | ///
138 | public ushort ReadUInt16(void* address) {
139 | QuickDemand(ProcessAccess.MemoryRead);
140 | ThrowWin32ExceptionIfFalse(ReadUInt16Internal(_handle, address, out ushort value));
141 | return value;
142 | }
143 |
144 | ///
145 | /// 读取内存
146 | ///
147 | /// 地址
148 | ///
149 | public int ReadInt32(void* address) {
150 | QuickDemand(ProcessAccess.MemoryRead);
151 | ThrowWin32ExceptionIfFalse(ReadInt32Internal(_handle, address, out int value));
152 | return value;
153 | }
154 |
155 | ///
156 | /// 读取内存
157 | ///
158 | /// 地址
159 | ///
160 | public uint ReadUInt32(void* address) {
161 | QuickDemand(ProcessAccess.MemoryRead);
162 | ThrowWin32ExceptionIfFalse(ReadUInt32Internal(_handle, address, out uint value));
163 | return value;
164 | }
165 |
166 | ///
167 | /// 读取内存
168 | ///
169 | /// 地址
170 | ///
171 | public long ReadInt64(void* address) {
172 | QuickDemand(ProcessAccess.MemoryRead);
173 | ThrowWin32ExceptionIfFalse(ReadInt64Internal(_handle, address, out long value));
174 | return value;
175 | }
176 |
177 | ///
178 | /// 读取内存
179 | ///
180 | /// 地址
181 | ///
182 | public ulong ReadUInt64(void* address) {
183 | QuickDemand(ProcessAccess.MemoryRead);
184 | ThrowWin32ExceptionIfFalse(ReadUInt64Internal(_handle, address, out ulong value));
185 | return value;
186 | }
187 |
188 | ///
189 | /// 读取内存
190 | ///
191 | /// 地址
192 | ///
193 | public IntPtr ReadIntPtr(void* address) {
194 | QuickDemand(ProcessAccess.MemoryRead);
195 | ThrowWin32ExceptionIfFalse(ReadIntPtrInternal(_handle, address, out var value));
196 | return value;
197 | }
198 |
199 | ///
200 | /// 读取内存
201 | ///
202 | /// 地址
203 | ///
204 | public UIntPtr ReadUIntPtr(void* address) {
205 | QuickDemand(ProcessAccess.MemoryRead);
206 | ThrowWin32ExceptionIfFalse(ReadUIntPtrInternal(_handle, address, out var value));
207 | return value;
208 | }
209 |
210 | ///
211 | /// 读取内存
212 | ///
213 | /// 地址
214 | ///
215 | public float ReadSingle(void* address) {
216 | QuickDemand(ProcessAccess.MemoryRead);
217 | ThrowWin32ExceptionIfFalse(ReadSingleInternal(_handle, address, out float value));
218 | return value;
219 | }
220 |
221 | ///
222 | /// 读取内存
223 | ///
224 | /// 地址
225 | ///
226 | public double ReadDouble(void* address) {
227 | QuickDemand(ProcessAccess.MemoryRead);
228 | ThrowWin32ExceptionIfFalse(ReadDoubleInternal(_handle, address, out double value));
229 | return value;
230 | }
231 |
232 | ///
233 | /// 读取内存
234 | ///
235 | /// 地址
236 | /// 值
237 | public void ReadBytes(void* address, byte[] value) {
238 | if (value is null)
239 | throw new ArgumentNullException(nameof(value));
240 |
241 | ReadBytes(address, value, 0, (uint)value.Length);
242 | }
243 |
244 | ///
245 | /// 读取内存
246 | ///
247 | /// 地址
248 | /// 值
249 | /// 从 的指定偏移处开始
250 | /// 长度
251 | public void ReadBytes(void* address, byte[] value, uint startIndex, uint length) {
252 | if (value is null)
253 | throw new ArgumentNullException(nameof(value));
254 | if (startIndex > value.Length)
255 | throw new ArgumentOutOfRangeException(nameof(startIndex));
256 | if (startIndex + length > value.Length)
257 | throw new ArgumentOutOfRangeException(nameof(length));
258 |
259 | QuickDemand(ProcessAccess.MemoryRead);
260 | ThrowWin32ExceptionIfFalse(ReadBytesInternal(_handle, address, value, startIndex, length));
261 | }
262 |
263 | ///
264 | /// 读取内存
265 | ///
266 | /// 地址
267 | /// 字符串是否以2个\0结尾
268 | /// 内存中字符串的编码
269 | ///
270 | public string ReadString(void* address, bool isEndWithDoubleZero, Encoding fromEncoding) {
271 | if (fromEncoding is null)
272 | throw new ArgumentNullException(nameof(fromEncoding));
273 |
274 | QuickDemand(ProcessAccess.MemoryRead);
275 | ThrowWin32ExceptionIfFalse(ReadStringInternal(_handle, address, out string value, isEndWithDoubleZero, fromEncoding));
276 | return value;
277 | }
278 |
279 | ///
280 | /// 读取内存
281 | ///
282 | /// 地址
283 | /// 值
284 | ///
285 | public bool TryReadByte(void* address, out byte value) {
286 | value = default;
287 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
288 | return false;
289 | return ReadByteInternal(_handle, address, out value);
290 | }
291 |
292 | ///
293 | /// 读取内存
294 | ///
295 | /// 地址
296 | /// 值
297 | ///
298 | public bool TryReadInt16(void* address, out short value) {
299 | value = default;
300 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
301 | return false;
302 | return ReadInt16Internal(_handle, address, out value);
303 | }
304 |
305 | ///
306 | /// 读取内存
307 | ///
308 | /// 地址
309 | /// 值
310 | ///
311 | public bool TryReadUInt16(void* address, out ushort value) {
312 | value = default;
313 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
314 | return false;
315 | return ReadUInt16Internal(_handle, address, out value);
316 | }
317 |
318 | ///
319 | /// 读取内存
320 | ///
321 | /// 地址
322 | /// 值
323 | ///
324 | public bool TryReadInt32(void* address, out int value) {
325 | value = default;
326 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
327 | return false;
328 | return ReadInt32Internal(_handle, address, out value);
329 | }
330 |
331 | ///
332 | /// 读取内存
333 | ///
334 | /// 地址
335 | /// 值
336 | ///
337 | public bool TryReadUInt32(void* address, out uint value) {
338 | value = default;
339 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
340 | return false;
341 | return ReadUInt32Internal(_handle, address, out value);
342 | }
343 |
344 | ///
345 | /// 读取内存
346 | ///
347 | /// 地址
348 | /// 值
349 | ///
350 | public bool TryReadInt64(void* address, out long value) {
351 | value = default;
352 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
353 | return false;
354 | return ReadInt64Internal(_handle, address, out value);
355 | }
356 |
357 | ///
358 | /// 读取内存
359 | ///
360 | /// 地址
361 | /// 值
362 | ///
363 | public bool TryReadUInt64(void* address, out ulong value) {
364 | value = default;
365 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
366 | return false;
367 | return ReadUInt64Internal(_handle, address, out value);
368 | }
369 |
370 | ///
371 | /// 读取内存
372 | ///
373 | /// 地址
374 | /// 值
375 | ///
376 | public bool TryReadIntPtr(void* address, out IntPtr value) {
377 | value = default;
378 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
379 | return false;
380 | return ReadIntPtrInternal(_handle, address, out value);
381 | }
382 |
383 | ///
384 | /// 读取内存
385 | ///
386 | /// 地址
387 | /// 值
388 | ///
389 | public bool TryReadUIntPtr(void* address, out UIntPtr value) {
390 | value = default;
391 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
392 | return false;
393 | return ReadUIntPtrInternal(_handle, address, out value);
394 | }
395 |
396 | ///
397 | /// 读取内存
398 | ///
399 | /// 地址
400 | /// 值
401 | ///
402 | public bool TryReadSingle(void* address, out float value) {
403 | value = default;
404 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
405 | return false;
406 | return ReadSingleInternal(_handle, address, out value);
407 | }
408 |
409 | ///
410 | /// 读取内存
411 | ///
412 | /// 地址
413 | /// 值
414 | ///
415 | public bool TryReadDouble(void* address, out double value) {
416 | value = default;
417 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
418 | return false;
419 | return ReadDoubleInternal(_handle, address, out value);
420 | }
421 |
422 | ///
423 | /// 读取内存
424 | ///
425 | /// 地址
426 | /// 值
427 | ///
428 | public bool TryReadBytes(void* address, byte[] value) {
429 | if (value is null)
430 | return false;
431 |
432 | return TryReadBytes(address, value, 0, (uint)value.Length);
433 | }
434 |
435 | ///
436 | /// 读取内存
437 | ///
438 | /// 地址
439 | /// 值
440 | /// 从 的指定偏移处开始
441 | /// 长度
442 | ///
443 | public bool TryReadBytes(void* address, byte[] value, uint startIndex, uint length) {
444 | if (value is null)
445 | return false;
446 | if (startIndex > value.Length)
447 | return false;
448 | if (startIndex + length > value.Length)
449 | return false;
450 |
451 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
452 | return false;
453 | return ReadBytesInternal(_handle, address, value, startIndex, length);
454 | }
455 |
456 | ///
457 | /// 读取内存
458 | ///
459 | /// 地址
460 | /// 值
461 | /// 字符串是否以2个\0结尾
462 | /// 内存中字符串的编码
463 | ///
464 | public bool TryReadString(void* address, out string value, bool isEndWithDoubleZero, Encoding fromEncoding) {
465 | value = string.Empty;
466 | if (fromEncoding is null)
467 | return false;
468 |
469 | if (!QuickDemandNoThrow(ProcessAccess.MemoryRead))
470 | return false;
471 | return ReadStringInternal(_handle, address, out value, isEndWithDoubleZero, fromEncoding);
472 | }
473 | #endregion
474 |
475 | #region write
476 | ///
477 | /// 写入内存
478 | ///
479 | /// 地址
480 | /// 值
481 | public void WriteByte(void* address, byte value) {
482 | QuickDemand(ProcessAccess.MemoryWrite);
483 | ThrowWin32ExceptionIfFalse(WriteByteInternal(_handle, address, value));
484 | }
485 |
486 | ///
487 | /// 写入内存
488 | ///
489 | /// 地址
490 | /// 值
491 | public void WriteInt16(void* address, short value) {
492 | QuickDemand(ProcessAccess.MemoryWrite);
493 | ThrowWin32ExceptionIfFalse(WriteInt16Internal(_handle, address, value));
494 | }
495 |
496 | ///
497 | /// 写入内存
498 | ///
499 | /// 地址
500 | /// 值
501 | public void WriteUInt16(void* address, ushort value) {
502 | QuickDemand(ProcessAccess.MemoryWrite);
503 | ThrowWin32ExceptionIfFalse(WriteUInt16Internal(_handle, address, value));
504 | }
505 |
506 | ///
507 | /// 写入内存
508 | ///
509 | /// 地址
510 | /// 值
511 | public void WriteInt32(void* address, int value) {
512 | QuickDemand(ProcessAccess.MemoryWrite);
513 | ThrowWin32ExceptionIfFalse(WriteInt32Internal(_handle, address, value));
514 | }
515 |
516 | ///
517 | /// 写入内存
518 | ///
519 | /// 地址
520 | /// 值
521 | public void WriteUInt32(void* address, uint value) {
522 | QuickDemand(ProcessAccess.MemoryWrite);
523 | ThrowWin32ExceptionIfFalse(WriteUInt32Internal(_handle, address, value));
524 | }
525 |
526 | ///
527 | /// 写入内存
528 | ///
529 | /// 地址
530 | /// 值
531 | public void WriteInt64(void* address, long value) {
532 | QuickDemand(ProcessAccess.MemoryWrite);
533 | ThrowWin32ExceptionIfFalse(WriteInt64Internal(_handle, address, value));
534 | }
535 |
536 | ///
537 | /// 写入内存
538 | ///
539 | /// 地址
540 | /// 值
541 | public void WriteUInt64(void* address, ulong value) {
542 | QuickDemand(ProcessAccess.MemoryWrite);
543 | ThrowWin32ExceptionIfFalse(WriteUInt64Internal(_handle, address, value));
544 | }
545 |
546 | ///
547 | /// 写入内存
548 | ///
549 | /// 地址
550 | /// 值
551 | public void WriteIntPtr(void* address, IntPtr value) {
552 | QuickDemand(ProcessAccess.MemoryWrite);
553 | ThrowWin32ExceptionIfFalse(WriteIntPtrInternal(_handle, address, value));
554 | }
555 |
556 | ///
557 | /// 写入内存
558 | ///
559 | /// 地址
560 | /// 值
561 | public void WriteUIntPtr(void* address, UIntPtr value) {
562 | QuickDemand(ProcessAccess.MemoryWrite);
563 | ThrowWin32ExceptionIfFalse(WriteUIntPtrInternal(_handle, address, value));
564 | }
565 |
566 | ///
567 | /// 写入内存
568 | ///
569 | /// 地址
570 | /// 值
571 | public void WriteSingle(void* address, float value) {
572 | QuickDemand(ProcessAccess.MemoryWrite);
573 | ThrowWin32ExceptionIfFalse(WriteSingleInternal(_handle, address, value));
574 | }
575 |
576 | ///
577 | /// 写入内存
578 | ///
579 | /// 地址
580 | /// 值
581 | public void WriteDouble(void* address, double value) {
582 | QuickDemand(ProcessAccess.MemoryWrite);
583 | ThrowWin32ExceptionIfFalse(WriteDoubleInternal(_handle, address, value));
584 | }
585 |
586 | ///
587 | /// 写入内存
588 | ///
589 | /// 地址
590 | /// 值
591 | public void WriteBytes(void* address, byte[] value) {
592 | if (value is null)
593 | throw new ArgumentNullException(nameof(value));
594 |
595 | WriteBytes(address, value, 0, (uint)value.Length);
596 | }
597 |
598 | ///
599 | /// 写入内存
600 | ///
601 | /// 地址
602 | /// 值
603 | /// 从 的指定偏移处开始
604 | /// 长度
605 | public void WriteBytes(void* address, byte[] value, uint startIndex, uint length) {
606 | if (value is null)
607 | throw new ArgumentNullException(nameof(value));
608 | if (startIndex > value.Length)
609 | throw new ArgumentOutOfRangeException(nameof(startIndex));
610 | if (startIndex + length > value.Length)
611 | throw new ArgumentOutOfRangeException(nameof(length));
612 |
613 | QuickDemand(ProcessAccess.MemoryWrite);
614 | ThrowWin32ExceptionIfFalse(WriteBytesInternal(_handle, address, value, startIndex, length));
615 | }
616 |
617 | ///
618 | /// 写入内存
619 | ///
620 | /// 地址
621 | /// 值
622 | /// 内存中字符串的编码
623 | public void WriteString(void* address, string value, Encoding toEncoding) {
624 | if (value is null)
625 | throw new ArgumentNullException(nameof(value));
626 | if (toEncoding is null)
627 | throw new ArgumentNullException(nameof(toEncoding));
628 |
629 | QuickDemand(ProcessAccess.MemoryWrite);
630 | ThrowWin32ExceptionIfFalse(WriteStringInternal(_handle, address, value, toEncoding));
631 | }
632 |
633 | ///
634 | /// 写入内存
635 | ///
636 | /// 地址
637 | /// 值
638 | ///
639 | public bool TryWriteByte(void* address, byte value) {
640 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
641 | return false;
642 | return WriteByteInternal(_handle, address, value);
643 | }
644 |
645 | ///
646 | /// 写入内存
647 | ///
648 | /// 地址
649 | /// 值
650 | ///
651 | public bool TryWriteInt16(void* address, short value) {
652 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
653 | return false;
654 | return WriteInt16Internal(_handle, address, value);
655 | }
656 |
657 | ///
658 | /// 写入内存
659 | ///
660 | /// 地址
661 | /// 值
662 | ///
663 | public bool TryWriteUInt16(void* address, ushort value) {
664 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
665 | return false;
666 | return WriteUInt16Internal(_handle, address, value);
667 | }
668 |
669 | ///
670 | /// 写入内存
671 | ///
672 | /// 地址
673 | /// 值
674 | ///
675 | public bool TryWriteInt32(void* address, int value) {
676 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
677 | return false;
678 | return WriteInt32Internal(_handle, address, value);
679 | }
680 |
681 | ///
682 | /// 写入内存
683 | ///
684 | /// 地址
685 | /// 值
686 | ///
687 | public bool TryWriteUInt32(void* address, uint value) {
688 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
689 | return false;
690 | return WriteUInt32Internal(_handle, address, value);
691 | }
692 |
693 | ///
694 | /// 写入内存
695 | ///
696 | /// 地址
697 | /// 值
698 | ///
699 | public bool TryWriteInt64(void* address, long value) {
700 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
701 | return false;
702 | return WriteInt64Internal(_handle, address, value);
703 | }
704 |
705 | ///
706 | /// 写入内存
707 | ///
708 | /// 地址
709 | /// 值
710 | ///
711 | public bool TryWriteUInt64(void* address, ulong value) {
712 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
713 | return false;
714 | return WriteUInt64Internal(_handle, address, value);
715 | }
716 |
717 | ///
718 | /// 写入内存
719 | ///
720 | /// 地址
721 | /// 值
722 | ///
723 | public bool TryWriteIntPtr(void* address, IntPtr value) {
724 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
725 | return false;
726 | return WriteIntPtrInternal(_handle, address, value);
727 | }
728 |
729 | ///
730 | /// 写入内存
731 | ///
732 | /// 地址
733 | /// 值
734 | ///
735 | public bool TryWriteUIntPtr(void* address, UIntPtr value) {
736 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
737 | return false;
738 | return WriteUIntPtrInternal(_handle, address, value);
739 | }
740 |
741 | ///
742 | /// 写入内存
743 | ///
744 | /// 地址
745 | /// 值
746 | ///
747 | public bool TryWriteSingle(void* address, float value) {
748 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
749 | return false;
750 | return WriteSingleInternal(_handle, address, value);
751 | }
752 |
753 | ///
754 | /// 写入内存
755 | ///
756 | /// 地址
757 | /// 值
758 | ///
759 | public bool TryWriteDouble(void* address, double value) {
760 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
761 | return false;
762 | return WriteDoubleInternal(_handle, address, value);
763 | }
764 |
765 | ///
766 | /// 写入内存
767 | ///
768 | /// 地址
769 | /// 值
770 | ///
771 | public bool TryWriteBytes(void* address, byte[] value) {
772 | if (value is null)
773 | return false;
774 |
775 | return TryWriteBytes(address, value, 0, (uint)value.Length);
776 | }
777 |
778 | ///
779 | /// 写入内存
780 | ///
781 | /// 地址
782 | /// 值
783 | /// 从 的指定偏移处开始
784 | /// 长度
785 | ///
786 | public bool TryWriteBytes(void* address, byte[] value, uint startIndex, uint length) {
787 | if (value is null)
788 | return false;
789 | if (startIndex > value.Length)
790 | return false;
791 | if (startIndex + length > value.Length)
792 | return false;
793 |
794 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
795 | return false;
796 | return WriteBytesInternal(_handle, address, value, startIndex, length);
797 | }
798 |
799 | ///
800 | /// 写入内存
801 | ///
802 | /// 地址
803 | /// 值
804 | /// 内存中字符串的编码
805 | ///
806 | public bool TryWriteString(void* address, string value, Encoding toEncoding) {
807 | if (value is null)
808 | return false;
809 | if (toEncoding is null)
810 | return false;
811 |
812 | if (!QuickDemandNoThrow(ProcessAccess.MemoryWrite))
813 | return false;
814 | return WriteStringInternal(_handle, address, value, toEncoding);
815 | }
816 | #endregion
817 |
818 | #region pointer impl
819 | internal static bool ToAddressInternal(void* processHandle, Pointer pointer, out void* address) {
820 | if (!Is64BitProcessInternal(processHandle, out bool is64Bit)) {
821 | address = default;
822 | return false;
823 | }
824 | return is64Bit ? ToAddressPrivate64(processHandle, pointer, out address) : ToAddressPrivate32(processHandle, pointer, out address);
825 | }
826 |
827 | private static bool ToAddressPrivate32(void* processHandle, Pointer pointer, out void* address) {
828 | address = default;
829 | if (pointer.BaseAddress == null) {
830 | if (string.IsNullOrEmpty(pointer.ModuleName))
831 | throw new ArgumentNullException(nameof(Pointer.ModuleName));
832 | pointer.BaseAddress = GetModuleHandleInternal(processHandle, false, pointer.ModuleName);
833 | }
834 | if (pointer.BaseAddress == null)
835 | throw new ArgumentNullException(nameof(Pointer.BaseAddress));
836 | uint newAddress = (uint)pointer.BaseAddress;
837 | var offsets = pointer.Offsets;
838 | if (offsets.Count > 0) {
839 | for (int i = 0; i < offsets.Count - 1; i++) {
840 | newAddress += offsets[i];
841 | if (!ReadUInt32Internal(processHandle, (void*)newAddress, out newAddress))
842 | return false;
843 | }
844 | newAddress += offsets[offsets.Count - 1];
845 | }
846 | address = (void*)newAddress;
847 | return true;
848 | }
849 |
850 | private static bool ToAddressPrivate64(void* processHandle, Pointer pointer, out void* address) {
851 | address = default;
852 | if (pointer.BaseAddress == null) {
853 | if (string.IsNullOrEmpty(pointer.ModuleName))
854 | throw new ArgumentNullException(nameof(Pointer.ModuleName));
855 | pointer.BaseAddress = GetModuleHandleInternal(processHandle, false, pointer.ModuleName);
856 | }
857 | if (pointer.BaseAddress == null)
858 | throw new ArgumentNullException(nameof(Pointer.BaseAddress));
859 | ulong newAddress = (ulong)pointer.BaseAddress;
860 | var offsets = pointer.Offsets;
861 | if (offsets.Count > 0) {
862 | for (int i = 0; i < offsets.Count - 1; i++) {
863 | newAddress += offsets[i];
864 | if (!ReadUInt64Internal(processHandle, (void*)newAddress, out newAddress))
865 | return false;
866 | }
867 | newAddress += offsets[offsets.Count - 1];
868 | }
869 | address = (void*)newAddress;
870 | return true;
871 | }
872 | #endregion
873 |
874 | #region read impl
875 | internal static bool ReadByteInternal(void* processHandle, void* address, out byte value) {
876 | fixed (void* p = &value)
877 | return ReadInternal(processHandle, address, p, 1);
878 | }
879 |
880 | internal static bool ReadInt16Internal(void* processHandle, void* address, out short value) {
881 | fixed (void* p = &value)
882 | return ReadInternal(processHandle, address, p, 2);
883 | }
884 |
885 | internal static bool ReadUInt16Internal(void* processHandle, void* address, out ushort value) {
886 | fixed (void* p = &value)
887 | return ReadInternal(processHandle, address, p, 2);
888 | }
889 |
890 | internal static bool ReadInt32Internal(void* processHandle, void* address, out int value) {
891 | fixed (void* p = &value)
892 | return ReadInternal(processHandle, address, p, 4);
893 | }
894 |
895 | internal static bool ReadUInt32Internal(void* processHandle, void* address, out uint value) {
896 | fixed (void* p = &value)
897 | return ReadInternal(processHandle, address, p, 4);
898 | }
899 |
900 | internal static bool ReadInt64Internal(void* processHandle, void* address, out long value) {
901 | fixed (void* p = &value)
902 | return ReadInternal(processHandle, address, p, 8);
903 | }
904 |
905 | internal static bool ReadUInt64Internal(void* processHandle, void* address, out ulong value) {
906 | fixed (void* p = &value)
907 | return ReadInternal(processHandle, address, p, 8);
908 | }
909 |
910 | internal static bool ReadIntPtrInternal(void* processHandle, void* address, out IntPtr value) {
911 | fixed (void* p = &value)
912 | return ReadInternal(processHandle, address, p, (uint)IntPtr.Size);
913 | }
914 |
915 | internal static bool ReadUIntPtrInternal(void* processHandle, void* address, out UIntPtr value) {
916 | fixed (void* p = &value)
917 | return ReadInternal(processHandle, address, p, (uint)UIntPtr.Size);
918 | }
919 |
920 | internal static bool ReadSingleInternal(void* processHandle, void* address, out float value) {
921 | fixed (void* p = &value)
922 | return ReadInternal(processHandle, address, p, 4);
923 | }
924 |
925 | internal static bool ReadDoubleInternal(void* processHandle, void* address, out double value) {
926 | fixed (void* p = &value)
927 | return ReadInternal(processHandle, address, p, 8);
928 | }
929 |
930 | internal static bool ReadBytesInternal(void* processHandle, void* address, byte[] value) {
931 | return ReadBytesInternal(processHandle, address, value, 0, (uint)value.Length);
932 | }
933 |
934 | internal static bool ReadBytesInternal(void* processHandle, void* address, byte[] value, uint startIndex, uint length) {
935 | fixed (void* p = &value[startIndex])
936 | return ReadInternal(processHandle, address, p, length);
937 | }
938 |
939 | internal static bool ReadStringInternal(void* processHandle, void* address, out string value, bool isEndWithDoubleZero, Encoding fromEncoding) {
940 | // TODO: 在出现时一些特殊字符可能导致字符串被过早截取!
941 | const uint BASE_BUFFER_SIZE = 0x100;
942 |
943 | uint dummy;
944 | if (!ReadInternal(processHandle, address, &dummy, isEndWithDoubleZero ? 2u : 1)) {
945 | value = string.Empty;
946 | return false;
947 | }
948 | using var stream = new MemoryStream((int)BASE_BUFFER_SIZE);
949 | uint bufferSize = BASE_BUFFER_SIZE;
950 | byte[]? bytes = null;
951 | bool isLastZero = false;
952 | do {
953 | byte[] buffer = new byte[bufferSize];
954 | ReadBytesInternal(processHandle, address, buffer);
955 | long oldPostion = stream.Position == 0 ? 0 : stream.Position - (isEndWithDoubleZero ? 2 : 1);
956 | stream.Write(buffer, 0, buffer.Length);
957 | int length = (int)(stream.Length - oldPostion);
958 | stream.Position = oldPostion;
959 | for (int i = 0; i < length; i++) {
960 | bool isZero = stream.ReadByte() == 0;
961 | if ((isEndWithDoubleZero && !isLastZero) || !isZero) {
962 | isLastZero = isZero;
963 | continue;
964 | }
965 | bytes = new byte[stream.Position];
966 | stream.Position = 0;
967 | stream.Read(bytes, 0, bytes.Length);
968 | break;
969 | }
970 | address = (byte*)address + bufferSize;
971 | bufferSize += BASE_BUFFER_SIZE;
972 | } while (bytes is null);
973 | if (fromEncoding.CodePage != Encoding.Unicode.CodePage)
974 | bytes = Encoding.Convert(fromEncoding, Encoding.Unicode, bytes);
975 | fixed (void* p = bytes)
976 | value = new string((char*)p);
977 | return true;
978 | }
979 |
980 | internal static bool ReadInternal(void* processHandle, void* address, void* value, uint length) {
981 | return ReadProcessMemory(processHandle, address, value, length, null);
982 | }
983 | #endregion
984 |
985 | #region write impl
986 | internal static bool WriteByteInternal(void* processHandle, void* address, byte value) {
987 | return WriteInternal(processHandle, address, &value, 1);
988 | }
989 |
990 | internal static bool WriteInt16Internal(void* processHandle, void* address, short value) {
991 | return WriteInternal(processHandle, address, &value, 2);
992 | }
993 |
994 | internal static bool WriteUInt16Internal(void* processHandle, void* address, ushort value) {
995 | return WriteInternal(processHandle, address, &value, 2);
996 | }
997 |
998 | internal static bool WriteInt32Internal(void* processHandle, void* address, int value) {
999 | return WriteInternal(processHandle, address, &value, 4);
1000 | }
1001 |
1002 | internal static bool WriteUInt32Internal(void* processHandle, void* address, uint value) {
1003 | return WriteInternal(processHandle, address, &value, 4);
1004 | }
1005 |
1006 | internal static bool WriteInt64Internal(void* processHandle, void* address, long value) {
1007 | return WriteInternal(processHandle, address, &value, 8);
1008 | }
1009 |
1010 | internal static bool WriteUInt64Internal(void* processHandle, void* address, ulong value) {
1011 | return WriteInternal(processHandle, address, &value, 8);
1012 | }
1013 |
1014 | internal static bool WriteIntPtrInternal(void* processHandle, void* address, IntPtr value) {
1015 | return WriteInternal(processHandle, address, &value, (uint)IntPtr.Size);
1016 | }
1017 |
1018 | internal static bool WriteUIntPtrInternal(void* processHandle, void* address, UIntPtr value) {
1019 | return WriteInternal(processHandle, address, &value, (uint)UIntPtr.Size);
1020 | }
1021 |
1022 | internal static bool WriteSingleInternal(void* processHandle, void* address, float value) {
1023 | return WriteInternal(processHandle, address, &value, 4);
1024 | }
1025 |
1026 | internal static bool WriteDoubleInternal(void* processHandle, void* address, double value) {
1027 | return WriteInternal(processHandle, address, &value, 8);
1028 | }
1029 |
1030 | internal static bool WriteBytesInternal(void* processHandle, void* address, byte[] value) {
1031 | return WriteBytesInternal(processHandle, address, value, 0, (uint)value.Length);
1032 | }
1033 |
1034 | internal static bool WriteBytesInternal(void* processHandle, void* address, byte[] value, uint startIndex, uint length) {
1035 | fixed (void* p = &value[startIndex])
1036 | return WriteInternal(processHandle, address, p, length);
1037 | }
1038 |
1039 | internal static bool WriteStringInternal(void* processHandle, void* address, string value, Encoding toEncoding) {
1040 | value += "\0";
1041 | if (toEncoding.CodePage == Encoding.Unicode.CodePage) {
1042 | fixed (void* p = value)
1043 | return WriteInternal(processHandle, address, p, (uint)(value.Length * 2));
1044 | }
1045 | byte[] buffer = Encoding.Convert(Encoding.Unicode, toEncoding, Encoding.Unicode.GetBytes(value));
1046 | fixed (void* p = buffer)
1047 | return WriteInternal(processHandle, address, p, (uint)buffer.Length);
1048 | }
1049 |
1050 | internal static bool WriteInternal(void* processHandle, void* address, void* value, uint length) {
1051 | return WriteProcessMemory(processHandle, address, value, length, null);
1052 | }
1053 | #endregion
1054 | }
1055 | }
1056 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/MemoryManagement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using static NativeSharp.NativeMethods;
4 |
5 | namespace NativeSharp {
6 | ///
7 | /// 内存保护选项
8 | ///
9 | [Flags]
10 | public enum MemoryProtection : uint {
11 | ///
12 | NoAccess = 0x01,
13 | ///
14 | ReadOnly = 0x02,
15 | ///
16 | ReadWrite = 0x04,
17 | ///
18 | WriteCopy = 0x08,
19 | ///
20 | Execute = 0x10,
21 | ///
22 | ExecuteRead = 0x20,
23 | ///
24 | ExecuteReadWrite = 0x40,
25 | ///
26 | ExecuteWriteCopy = 0x80,
27 | ///
28 | Guard = 0x100,
29 | ///
30 | NoCache = 0x200,
31 | ///
32 | WriteCombine = 0x400
33 | }
34 |
35 | ///
36 | /// 内存类型选项
37 | ///
38 | [Flags]
39 | public enum MemoryType : uint {
40 | ///
41 | Commit = 0x00001000,
42 | ///
43 | Reserve = 0x00002000,
44 | ///
45 | Decommit = 0x00004000,
46 | ///
47 | Release = 0x00008000,
48 | ///
49 | Free = 0x00010000,
50 | ///
51 | Private = 0x00020000,
52 | ///
53 | Mapped = 0x00040000,
54 | ///
55 | Reset = 0x00080000
56 | }
57 |
58 | ///
59 | /// 页面信息
60 | ///
61 | public sealed unsafe class PageInfo {
62 | private readonly void* _address;
63 | private readonly void* _size;
64 | private readonly MemoryProtection _protection;
65 | private readonly MemoryType _type;
66 |
67 | ///
68 | /// 起始地址
69 | ///
70 | public void* Address => _address;
71 |
72 | ///
73 | /// 大小
74 | ///
75 | public void* Size => _size;
76 |
77 | ///
78 | /// 保护
79 | ///
80 | public MemoryProtection Protection => _protection;
81 |
82 | ///
83 | /// 类型
84 | ///
85 | public MemoryType Type => _type;
86 |
87 | internal PageInfo(MEMORY_BASIC_INFORMATION mbi) {
88 | _address = mbi.BaseAddress;
89 | _size = mbi.RegionSize;
90 | _protection = (MemoryProtection)mbi.Protect;
91 | _type = (MemoryType)mbi.Type;
92 | }
93 |
94 | ///
95 | public override string ToString() {
96 | bool is64Bit = (ulong)_address > uint.MaxValue;
97 | return $"Address=0x{((IntPtr)_address).ToString(is64Bit ? "X16" : "X8")} Size=0x{((IntPtr)_size).ToString(is64Bit ? "X16" : "X8")}";
98 | }
99 | }
100 |
101 | unsafe partial class NativeProcess {
102 | ///
103 | /// 获取所有页面信息
104 | ///
105 | ///
106 | public IEnumerable EnumeratePageInfos() {
107 | QuickDemand(ProcessAccess.QueryInformation);
108 | return EnumeratePageInfosInternal((IntPtr)_handle, IntPtr.Zero, (IntPtr)(void*)-1);
109 | }
110 |
111 | ///
112 | /// 获取范围内页面信息
113 | ///
114 | /// 起始地址
115 | /// 结束地址
116 | ///
117 | public IEnumerable EnumeratePageInfos(void* startAddress, void* endAddress) {
118 | QuickDemand(ProcessAccess.QueryInformation);
119 | return EnumeratePageInfosInternal((IntPtr)_handle, (IntPtr)startAddress, (IntPtr)endAddress);
120 | }
121 |
122 | internal static IEnumerable EnumeratePageInfosInternal(IntPtr processHandle, IntPtr startAddress, IntPtr endAddress) {
123 | if (!SafeIs64BitProcessInternal(processHandle, out bool is64Bit))
124 | yield break;
125 | var nextAddress = startAddress;
126 | do {
127 | if (!SafeVirtualQueryEx(processHandle, nextAddress, out var mbi, MEMORY_BASIC_INFORMATION.UnmanagedSize))
128 | break;
129 | yield return new PageInfo(mbi);
130 | nextAddress = SafeGetNextAddress(mbi);
131 | } while ((long)nextAddress > 0 && NextAddressLessThanEndAddress(nextAddress, endAddress));
132 |
133 | static bool SafeIs64BitProcessInternal(IntPtr processHandle_, out bool is64Bit_) {
134 | return Is64BitProcessInternal((void*)processHandle_, out is64Bit_);
135 | }
136 |
137 | static bool SafeVirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength) {
138 | return VirtualQueryEx((void*)hProcess, (void*)lpAddress, out lpBuffer, dwLength);
139 | }
140 |
141 | IntPtr SafeGetNextAddress(MEMORY_BASIC_INFORMATION mbi_) {
142 | return (IntPtr)(void*)(is64Bit ? ((ulong)mbi_.BaseAddress + (ulong)mbi_.RegionSize) : (uint)mbi_.BaseAddress + (uint)mbi_.RegionSize);
143 | }
144 |
145 | bool NextAddressLessThanEndAddress(IntPtr nextAddress_, IntPtr endAddress_) {
146 | return is64Bit ? (ulong)nextAddress_ < (ulong)endAddress_ : (uint)nextAddress_ < (uint)endAddress_;
147 | }
148 | }
149 |
150 | ///
151 | /// 设置内存保护选项
152 | ///
153 | /// 起始地址
154 | /// 内存大小
155 | /// 新内存保护选项
156 | ///
157 | public bool SetProtection(void* address, uint size, MemoryProtection protection) {
158 | return SetProtection(address, size, protection, out _);
159 | }
160 |
161 | ///
162 | /// 设置内存保护选项
163 | ///
164 | /// 起始地址
165 | /// 内存大小
166 | /// 新内存保护选项
167 | /// 原来的内存保护选项
168 | ///
169 | public bool SetProtection(void* address, uint size, MemoryProtection protection, out MemoryProtection oldProtection) {
170 | bool result = VirtualProtectEx(_handle, address, size, (uint)protection, out uint temp);
171 | oldProtection = (MemoryProtection)temp;
172 | return result;
173 | }
174 |
175 | ///
176 | /// 分配内存
177 | ///
178 | /// 大小
179 | /// 是否可写
180 | /// 是否可执行
181 | ///
182 | public void* AllocMemory(uint size, bool writable, bool executable) {
183 | QuickDemand(ProcessAccess.MemoryOperation);
184 | return AllocMemoryInternal(_handle, size, ToProtection(writable, executable));
185 | }
186 |
187 | ///
188 | /// 分配内存
189 | ///
190 | /// 大小
191 | /// 选项
192 | ///
193 | public void* AllocMemory(uint size, MemoryProtection protection) {
194 | QuickDemand(ProcessAccess.MemoryOperation);
195 | return AllocMemoryInternal(_handle, size, protection);
196 | }
197 |
198 | ///
199 | /// 分配内存
200 | ///
201 | /// 地址
202 | /// 大小
203 | /// 选项
204 | ///
205 | public void* AllocMemory(void* address, uint size, MemoryProtection protection) {
206 | QuickDemand(ProcessAccess.MemoryOperation);
207 | return AllocMemoryInternal(_handle, address, size, protection);
208 | }
209 |
210 | internal static void* AllocMemoryInternal(void* processHandle, uint size, bool writable, bool executable) {
211 | return AllocMemoryInternal(processHandle, size, ToProtection(writable, executable));
212 | }
213 |
214 | internal static void* AllocMemoryInternal(void* processHandle, uint size, MemoryProtection protection) {
215 | return VirtualAllocEx(processHandle, null, size, (uint)MemoryType.Commit, (uint)protection);
216 | }
217 |
218 | internal static void* AllocMemoryInternal(void* processHandle, void* address, uint size, MemoryProtection protection) {
219 | return VirtualAllocEx(processHandle, address, size, (uint)MemoryType.Commit, (uint)protection);
220 | }
221 |
222 | private static MemoryProtection ToProtection(bool writable, bool executable) {
223 | if (writable) {
224 | if (executable)
225 | return MemoryProtection.ExecuteReadWrite;
226 | else
227 | return MemoryProtection.ReadWrite;
228 | }
229 | else {
230 | if (executable)
231 | return MemoryProtection.ExecuteRead;
232 | else
233 | return MemoryProtection.ReadOnly;
234 | }
235 | }
236 |
237 | ///
238 | /// 释放内存
239 | ///
240 | /// 地址
241 | ///
242 | public bool FreeMemory(void* address) {
243 | QuickDemand(ProcessAccess.MemoryOperation);
244 | return FreeMemoryInternal(_handle, address);
245 | }
246 |
247 | ///
248 | /// 释放内存
249 | ///
250 | /// 地址
251 | /// 大小
252 | /// 选项
253 | ///
254 | public bool FreeMemory(void* address, uint size, MemoryType type) {
255 | QuickDemand(ProcessAccess.MemoryOperation);
256 | return FreeMemoryInternal(_handle, address, size, type);
257 | }
258 |
259 | internal static bool FreeMemoryInternal(void* processHandle, void* address) {
260 | return VirtualFreeEx(processHandle, address, 0, (uint)MemoryType.Decommit);
261 | }
262 |
263 | internal static bool FreeMemoryInternal(void* processHandle, void* address, uint size, MemoryType type) {
264 | return VirtualFreeEx(processHandle, address, size, (uint)type);
265 | }
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/ModuleInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using static NativeSharp.NativeMethods;
4 |
5 | namespace NativeSharp {
6 | unsafe partial class NativeModule {
7 | ///
8 | /// 名称
9 | ///
10 | public string Name {
11 | get {
12 | _process.QuickDemand(ProcessAccess.MemoryRead | ProcessAccess.QueryInformation);
13 | var name = new StringBuilder((int)MAX_MODULE_NAME32);
14 | return GetModuleBaseName(_process.Handle, _handle, name, MAX_MODULE_NAME32) ? name.ToString() : string.Empty;
15 | }
16 | }
17 |
18 | ///
19 | /// 文件路径
20 | ///
21 | public string ImagePath {
22 | get {
23 | _process.QuickDemand(ProcessAccess.MemoryRead | ProcessAccess.QueryInformation);
24 | var iamgePath = new StringBuilder((int)MAX_PATH);
25 | return GetModuleFileNameEx(_process.Handle, _handle, iamgePath, MAX_PATH) ? iamgePath.ToString() : string.Empty;
26 | }
27 | }
28 |
29 | ///
30 | public override string ToString() {
31 | return $"{Name} (Address: 0x{((IntPtr)Handle).ToString(_process.Is64Bit ? "X16" : "X8")})";
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/ProcessInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using static NativeSharp.NativeMethods;
5 |
6 | namespace NativeSharp {
7 | unsafe partial class NativeProcess {
8 | ///
9 | /// 是否为64位进程
10 | ///
11 | public bool Is64Bit {
12 | get {
13 | QuickDemand(ProcessAccess.QueryInformation);
14 | Is64BitProcessInternal(_handle, out bool is64Bit);
15 | return is64Bit;
16 | }
17 | }
18 |
19 | ///
20 | /// 名称
21 | ///
22 | public string Name => Path.GetFileName(ImagePath);
23 |
24 | ///
25 | /// 文件路径
26 | ///
27 | public string ImagePath {
28 | get {
29 | QuickDemand(ProcessAccess.QueryInformation);
30 | var iamgePath = new StringBuilder((int)MAX_PATH);
31 | uint size = MAX_PATH;
32 | return QueryFullProcessImageName(_handle, 0, iamgePath, &size) ? iamgePath.ToString() : string.Empty;
33 | }
34 | }
35 |
36 | ///
37 | /// 获取所有模块
38 | ///
39 | ///
40 | public NativeModule[] GetModules() {
41 | QuickDemand(ProcessAccess.QueryInformation);
42 | void* moduleHandle;
43 | if (!EnumProcessModulesEx(_handle, &moduleHandle, (uint)IntPtr.Size, out uint size, LIST_MODULES_ALL))
44 | return Array2.Empty();
45 | void*[] moduleHandles = new void*[size / (uint)IntPtr.Size];
46 | fixed (void** p = moduleHandles) {
47 | if (!EnumProcessModulesEx(_handle, p, size, out _, LIST_MODULES_ALL))
48 | return Array2.Empty();
49 | }
50 | var modules = new NativeModule[moduleHandles.Length];
51 | for (int i = 0; i < modules.Length; i++)
52 | modules[i] = UnsafeGetModule(moduleHandles[i]);
53 | return modules;
54 | }
55 |
56 | ///
57 | /// 获取主模块
58 | ///
59 | ///
60 | public NativeModule GetMainModule() {
61 | QuickDemand(ProcessAccess.QueryInformation);
62 | return UnsafeGetModule(IsCurrentProcess ? GetModuleHandle(null) : GetModuleHandleInternal(_handle, true, string.Empty));
63 | }
64 |
65 | ///
66 | /// 获取模块
67 | ///
68 | /// 模块名
69 | ///
70 | public NativeModule GetModule(string moduleName) {
71 | if (string.IsNullOrEmpty(moduleName))
72 | throw new ArgumentNullException(nameof(moduleName));
73 |
74 | QuickDemand(ProcessAccess.MemoryRead | ProcessAccess.QueryInformation);
75 | return UnsafeGetModule(IsCurrentProcess ? GetModuleHandle(moduleName) : GetModuleHandleInternal(_handle, false, moduleName));
76 | }
77 |
78 | ///
79 | /// 通过模块句柄直接获取模块,只要 不为零,均会返回一个 实例
80 | ///
81 | /// 模块句柄
82 | ///
83 | public NativeModule UnsafeGetModule(void* moduleHandle) {
84 | return new NativeModule(this, moduleHandle);
85 | }
86 |
87 | ///
88 | public override string ToString() {
89 | return $"{Name} (Id: 0x{Id:X})";
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/NativeSharp/Additions/ProcessUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Text;
5 | using static NativeSharp.NativeMethods;
6 |
7 | namespace NativeSharp {
8 | ///
9 | /// 模块加载方式
10 | ///
11 | [Flags]
12 | public enum LoadModuleFlags : uint {
13 | ///
14 | AsDatafile = 0x00000002,
15 | ///
16 | WithAlteredSearchPath = 0x00000008,
17 | ///
18 | IgnoreCodeAuthzLevel = 0x00000010,
19 | ///
20 | AsImageResource = 0x00000020,
21 | ///
22 | AsDatafileExclusive = 0x00000040,
23 | ///
24 | RequireSignedTarget = 0x00000080,
25 | ///
26 | SearchDllLoadDir = 0x00000100,
27 | ///
28 | SearchApplicationDir = 0x00000200,
29 | ///
30 | SearchUserDirs = 0x00000400,
31 | ///
32 | SearchSystem32 = 0x00000800,
33 | ///
34 | SearchDefaultDirs = 0x00001000
35 | }
36 |
37 | unsafe partial class NativeProcess {
38 | ///
39 | /// 通过进程名称获取进程ID
40 | ///
41 | /// 进程名称
42 | ///
43 | public static IEnumerable GetProcessIdsByName(string processName) {
44 | if (string.IsNullOrEmpty(processName))
45 | throw new ArgumentNullException(nameof(processName));
46 |
47 | foreach (uint processId in GetAllProcessIds()) {
48 | using var process = Open(processId, ProcessAccess.QueryInformation);
49 | if (process == InvalidProcess)
50 | continue;
51 | if (string.Equals(process.Name, processName, StringComparison.OrdinalIgnoreCase))
52 | yield return processId;
53 | }
54 | }
55 |
56 | ///
57 | /// 获取所有进程ID
58 | ///
59 | ///
60 | public static uint[] GetAllProcessIds() {
61 | uint[]? buffer = null;
62 | uint bytesReturned = 0;
63 | do {
64 | if (buffer is null)
65 | buffer = new uint[0x200];
66 | else
67 | buffer = new uint[buffer.Length * 2];
68 | fixed (uint* p = buffer) {
69 | if (!EnumProcesses(p, (uint)(buffer.Length * 4), out bytesReturned))
70 | return Array2.Empty();
71 | }
72 | } while (bytesReturned == buffer.Length * 4);
73 | uint[] processIds = new uint[bytesReturned / 4];
74 | for (int i = 0; i < processIds.Length; i++)
75 | processIds[i] = buffer[i];
76 | return processIds;
77 | }
78 |
79 | ///
80 | /// 为当前进程加载模块
81 | ///
82 | /// 模块路径
83 | ///
84 | public static NativeModule LoadModule(string modulePath) {
85 | return LoadModule(modulePath, 0);
86 | }
87 |
88 | ///
89 | /// 为当前进程加载模块
90 | ///
91 | /// 模块路径
92 | ///
93 | ///
94 | public static NativeModule LoadModule(string modulePath, LoadModuleFlags flags) {
95 | if (string.IsNullOrEmpty(modulePath))
96 | throw new ArgumentNullException(nameof(modulePath));
97 |
98 | return CurrentProcess.UnsafeGetModule(LoadLibraryEx(modulePath, null, (uint)flags));
99 | }
100 |
101 | internal static bool Is64BitProcessInternal(void* processHandle, out bool is64Bit) {
102 | is64Bit = false;
103 | if (!NativeEnvironment.Is64BitOperatingSystem)
104 | return true;
105 | if (!IsWow64Process(processHandle, out bool isWow64))
106 | return false;
107 | is64Bit = !isWow64;
108 | return true;
109 | }
110 |
111 | internal static void* GetModuleHandleInternal(void* processHandle, bool first, string moduleName) {
112 | void* moduleHandle;
113 | if (!EnumProcessModulesEx(processHandle, &moduleHandle, (uint)IntPtr.Size, out uint size, LIST_MODULES_ALL))
114 | return null;
115 | if (first)
116 | return moduleHandle;
117 | void*[] moduleHandles = new void*[size / (uint)IntPtr.Size];
118 | fixed (void** p = moduleHandles) {
119 | if (!EnumProcessModulesEx(processHandle, p, size, out _, LIST_MODULES_ALL))
120 | return null;
121 | }
122 | var moduleNameBuffer = new StringBuilder((int)MAX_MODULE_NAME32);
123 | for (int i = 0; i < moduleHandles.Length; i++) {
124 | if (!GetModuleBaseName(processHandle, moduleHandles[i], moduleNameBuffer, MAX_MODULE_NAME32))
125 | return null;
126 | if (moduleNameBuffer.ToString().Equals(moduleName, StringComparison.OrdinalIgnoreCase))
127 | return moduleHandles[i];
128 | }
129 | return null;
130 | }
131 |
132 | internal static void ThrowWin32ExceptionIfFalse(bool result) {
133 | if (!result)
134 | throw new Win32Exception();
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/NativeSharp/NativeEnvironment.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using static NativeSharp.NativeMethods;
3 |
4 | namespace NativeSharp {
5 | ///
6 | /// Win32环境
7 | ///
8 | public static unsafe class NativeEnvironment {
9 | private static readonly bool _is64BitOperatingSystem = GetIs64BitOperatingSystem();
10 |
11 | ///
12 | /// 是否为64位操作系统
13 | ///
14 | public static bool Is64BitOperatingSystem => _is64BitOperatingSystem;
15 |
16 | private static bool GetIs64BitOperatingSystem() {
17 | bool is64BitOperatingSystem;
18 | if (IntPtr.Size == 8)
19 | is64BitOperatingSystem = true;
20 | else
21 | IsWow64Process(GetCurrentProcess(), out is64BitOperatingSystem);
22 | return is64BitOperatingSystem;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/NativeSharp/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using System.Text;
3 |
4 | namespace NativeSharp {
5 | internal static unsafe class NativeMethods {
6 | public const uint STANDARD_RIGHTS_REQUIRED = 0xF0000;
7 | public const uint LIST_MODULES_ALL = 0x3;
8 | public const uint MAX_MODULE_NAME32 = 255;
9 | public const uint MAX_PATH = 260;
10 | public const uint INFINITE = 0xFFFFFFFF;
11 |
12 | [StructLayout(LayoutKind.Sequential)]
13 | public struct MEMORY_BASIC_INFORMATION {
14 | public static readonly uint UnmanagedSize = (uint)sizeof(MEMORY_BASIC_INFORMATION);
15 |
16 | public void* BaseAddress;
17 | public void* AllocationBase;
18 | public uint AllocationProtect;
19 | public void* RegionSize;
20 | public uint State;
21 | public uint Protect;
22 | public uint Type;
23 | }
24 |
25 | [StructLayout(LayoutKind.Sequential)]
26 | public struct IMAGE_EXPORT_DIRECTORY {
27 | public static readonly uint UnmanagedSize = (uint)sizeof(IMAGE_EXPORT_DIRECTORY);
28 |
29 | public uint Characteristics;
30 | public uint TimeDateStamp;
31 | public ushort MajorVersion;
32 | public ushort MinorVersion;
33 | public uint Name;
34 | public uint Base;
35 | public uint NumberOfFunctions;
36 | public uint NumberOfNames;
37 | public uint AddressOfFunctions;
38 | public uint AddressOfNames;
39 | public uint AddressOfNameOrdinals;
40 | }
41 |
42 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
43 | public static extern void* OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
44 |
45 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
46 | [return: MarshalAs(UnmanagedType.Bool)]
47 | public static extern bool CloseHandle(void* hObject);
48 |
49 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
50 | public static extern uint GetCurrentProcessId();
51 |
52 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
53 | public static extern uint GetProcessId(void* Process);
54 |
55 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
56 | public static extern void* GetCurrentProcess();
57 |
58 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
59 | [return: MarshalAs(UnmanagedType.Bool)]
60 | public static extern bool IsWow64Process(void* hProcess, [MarshalAs(UnmanagedType.Bool)] out bool Wow64Process);
61 |
62 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
63 | [return: MarshalAs(UnmanagedType.Bool)]
64 | public static extern bool ReadProcessMemory(void* hProcess, void* lpBaseAddress, void* lpBuffer, uint nSize, uint* lpNumberOfBytesRead);
65 |
66 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
67 | [return: MarshalAs(UnmanagedType.Bool)]
68 | public static extern bool WriteProcessMemory(void* hProcess, void* lpBaseAddress, void* lpBuffer, uint nSize, uint* lpNumberOfBytesWritten);
69 |
70 | [DllImport("psapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
71 | [return: MarshalAs(UnmanagedType.Bool)]
72 | public static extern bool EnumProcesses(uint* pProcessIds, uint cb, out uint pBytesReturned);
73 |
74 | [DllImport("psapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
75 | [return: MarshalAs(UnmanagedType.Bool)]
76 | public static extern bool EnumProcessModulesEx(void* hProcess, void** lphModule, uint cb, out uint lpcbNeeded, uint dwFilterFlag);
77 |
78 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
79 | [return: MarshalAs(UnmanagedType.Bool)]
80 | public static extern bool QueryFullProcessImageName(void* hProcess, uint dwFlags, StringBuilder lpExeName, uint* lpdwSize);
81 |
82 | [DllImport("psapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
83 | [return: MarshalAs(UnmanagedType.Bool)]
84 | public static extern bool GetModuleBaseName(void* hProcess, void* hModule, StringBuilder lpBaseName, uint nSize);
85 |
86 | [DllImport("psapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
87 | [return: MarshalAs(UnmanagedType.Bool)]
88 | public static extern bool GetModuleFileNameEx(void* hProcess, void* hModule, StringBuilder lpFilename, uint nSize);
89 |
90 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
91 | public static extern void* VirtualAllocEx(void* hProcess, void* lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
92 |
93 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
94 | [return: MarshalAs(UnmanagedType.Bool)]
95 | public static extern bool VirtualFreeEx(void* hProcess, void* lpAddress, uint dwSize, uint dwFreeType);
96 |
97 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
98 | [return: MarshalAs(UnmanagedType.Bool)]
99 | public static extern bool VirtualQueryEx(void* hProcess, void* lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);
100 |
101 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
102 | [return: MarshalAs(UnmanagedType.Bool)]
103 | public static extern bool VirtualProtectEx(void* hProcess, void* lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
104 |
105 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
106 | public static extern void* CreateRemoteThread(void* hProcess, void* lpThreadAttributes, uint dwStackSize, void* lpStartAddress, void* lpParameter, uint dwCreationFlags, uint* lpThreadId);
107 |
108 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
109 | public static extern uint WaitForSingleObject(void* hHandle, uint dwMilliseconds);
110 |
111 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
112 | [return: MarshalAs(UnmanagedType.Bool)]
113 | public static extern bool GetExitCodeThread(void* hThread, out uint lpExitCode);
114 |
115 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
116 | public static extern void* GetModuleHandle(string? lpModuleName);
117 |
118 | [DllImport("kernel32.dll", BestFitMapping = false, CharSet = CharSet.Unicode, SetLastError = true)]
119 | public static extern void* LoadLibraryEx(string? lpLibFileName, void* hFile, uint dwFlags);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/NativeSharp/NativeModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NativeSharp {
4 | ///
5 | /// Win32模块
6 | ///
7 | public sealed unsafe partial class NativeModule {
8 | private readonly NativeProcess _process;
9 | private readonly void* _handle;
10 |
11 | ///
12 | /// 所属进程
13 | ///
14 | public NativeProcess Process => _process;
15 |
16 | ///
17 | /// 模块句柄
18 | ///
19 | public void* Handle => _handle;
20 |
21 | ///
22 | /// 当前句柄是否为无效句柄
23 | ///
24 | public bool IsInvalid => _handle == null;
25 |
26 | ///
27 | /// 构造器
28 | ///
29 | /// Win32进程
30 | /// 模块句柄
31 | public NativeModule(NativeProcess process, IntPtr handle) : this(process, (void*)handle) {
32 | }
33 |
34 | ///
35 | /// 构造器
36 | ///
37 | /// Win32进程
38 | /// 模块句柄
39 | public NativeModule(NativeProcess process, void* handle) {
40 | if (process is null)
41 | throw new ArgumentNullException(nameof(process));
42 |
43 | _process = process;
44 | _handle = handle;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/NativeSharp/NativeProcess.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using static NativeSharp.NativeMethods;
3 |
4 | namespace NativeSharp {
5 | ///
6 | /// 进程权限
7 | ///
8 | public enum ProcessAccess : uint {
9 | ///
10 | CreateProcess = 0x0080,
11 | ///
12 | CreateThread = 0x0002,
13 | ///
14 | DuplicateHandle = 0x0040,
15 | ///
16 | QueryInformation = 0x0400,
17 | ///
18 | QueryLimitedInformation = 0x1000,
19 | ///
20 | SetInformation = 0x0200,
21 | ///
22 | SetQuota = 0x0100,
23 | ///
24 | SuspendResume = 0x0800,
25 | ///
26 | Synchronize = 0x00100000,
27 | ///
28 | Terminate = 0x0001,
29 | ///
30 | MemoryOperation = 0x0008,
31 | ///
32 | MemoryRead = 0x0010,
33 | ///
34 | MemoryWrite = 0x0020,
35 | ///
36 | AllAccess = STANDARD_RIGHTS_REQUIRED | Synchronize | 0xFFFF
37 | }
38 |
39 | ///
40 | /// Win32进程
41 | ///
42 | public sealed unsafe partial class NativeProcess : IDisposable {
43 | private static readonly NativeProcess _invalidProcess = new NativeProcess(0, null, 0) { _isDisposed = true };
44 | private static readonly NativeProcess _currentProcess = new NativeProcess(GetCurrentProcessId(), GetCurrentProcess(), ProcessAccess.AllAccess);
45 |
46 | private readonly uint _id;
47 | private readonly void* _handle;
48 | private readonly ProcessAccess? _access;
49 | private bool _isDisposed;
50 |
51 | ///
52 | /// 表示一个无效进程
53 | ///
54 | public static NativeProcess InvalidProcess => _invalidProcess;
55 |
56 | ///
57 | /// 当前进程
58 | ///
59 | public static NativeProcess CurrentProcess => _currentProcess;
60 |
61 | ///
62 | /// 当前实例是否当前进程
63 | ///
64 | public bool IsCurrentProcess => this == CurrentProcess;
65 |
66 | ///
67 | /// 进程ID
68 | ///
69 | public uint Id {
70 | get {
71 | QuickDemand(0);
72 | return _id;
73 | }
74 | }
75 |
76 | ///
77 | /// 打开进程时获取的句柄
78 | ///
79 | public void* Handle {
80 | get {
81 | QuickDemand(0);
82 | return _handle;
83 | }
84 | }
85 |
86 | ///
87 | /// 当前句柄是否为无效句柄
88 | ///
89 | public bool IsInvalid => _handle == null;
90 |
91 | private NativeProcess(uint id, void* handle, ProcessAccess? access) {
92 | _id = id;
93 | _handle = handle;
94 | _access = access;
95 | }
96 |
97 | ///
98 | /// 打开进程,失败时返回
99 | ///
100 | /// 进程ID
101 | ///
102 | public static NativeProcess Open(uint id) {
103 | return Open(id, ProcessAccess.AllAccess);
104 | }
105 |
106 | ///
107 | /// 打开进程,失败时返回
108 | ///
109 | /// 进程ID
110 | /// 权限
111 | ///
112 | public static NativeProcess Open(uint id, ProcessAccess access) {
113 | access |= ProcessAccess.QueryInformation;
114 | void* processHandle = OpenProcess((uint)access, false, id);
115 | return processHandle == null ? InvalidProcess : new NativeProcess(id, processHandle, access);
116 | }
117 |
118 | ///
119 | /// 通过已有句柄打开进程,并且跳过权限检查,失败时返回
120 | ///
121 | /// 进程句柄
122 | ///
123 | public static NativeProcess UnsafeOpen(void* handle) {
124 | if (handle == null)
125 | return InvalidProcess;
126 |
127 | uint id = GetProcessId(handle);
128 | return id != 0 ? new NativeProcess(id, handle, null) : InvalidProcess;
129 | }
130 |
131 | ///
132 | /// 通过已有句柄打开进程,并且跳过权限检查,失败时返回
133 | ///
134 | /// 进程ID
135 | /// 进程句柄
136 | ///
137 | public static NativeProcess UnsafeOpen(uint id, void* handle) {
138 | return handle != null ? new NativeProcess(id, handle, null) : InvalidProcess;
139 | }
140 |
141 | ///
142 | /// 确保当前实例未被释放并且确保拥有所需权限
143 | ///
144 | /// 需要的权限
145 | public void QuickDemand(ProcessAccess requireAccess) {
146 | if (_isDisposed)
147 | throw new ObjectDisposedException(nameof(NativeProcess));
148 | if (!(_access is null) && (_access.Value & requireAccess) != requireAccess)
149 | throw new NotSupportedException($"CurrentAccess={_access} RequireAccess={requireAccess}");
150 | }
151 |
152 | ///
153 | /// 确保当前实例未被释放并且确保拥有所需权限
154 | ///
155 | /// 需要的权限
156 | ///
157 | public bool QuickDemandNoThrow(ProcessAccess requireAccess) {
158 | if (_isDisposed)
159 | throw new ObjectDisposedException(nameof(NativeProcess));
160 | return !_access.HasValue || (_access.Value & requireAccess) == requireAccess;
161 | }
162 |
163 | ///
164 | public void Dispose() {
165 | if (_isDisposed)
166 | return;
167 |
168 | CloseHandle(_handle);
169 | _isDisposed = true;
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/NativeSharp/NativeSharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(ProjectName)
4 | 3.0.0.1
5 | Copyright © 2018-2020 Wwh
6 | Win32 functions helper
7 |
8 |
9 | net20;net40;netstandard1.3
10 | true
11 | true
12 | ..\bin\$(Configuration)
13 | 8.0
14 | enable
15 | strict
16 | NativeSharp-lib
17 | Wwh
18 | https://github.com/wwh1004/NativeSharp
19 | MIT
20 | true
21 | true
22 | snupkg
23 |
24 |
25 |
26 | all
27 | runtime; build; native; contentfiles; analyzers; buildtransitive
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/NativeSharp/System/Array2.cs:
--------------------------------------------------------------------------------
1 | namespace NativeSharp {
2 | internal static class Array2 {
3 | public static T[] Empty() {
4 | return EmptyArray.Value;
5 | }
6 |
7 | private static class EmptyArray {
8 | #pragma warning disable CA1825
9 | public static readonly T[] Value = new T[0];
10 | #pragma warning restore CA1825
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NativeSharp
2 | Reads/writes memory, gets process/module info, injects dll, etc.
3 |
4 | ## Requirements
5 | - Windows Vista or later
6 | - .NET Framework 2.x / 4.x
7 |
8 | ## Downloads
9 | GitHub: [Latest release](https://github.com/wwh1004/NativeSharp/releases/latest/download/NativeSharp.zip)
10 |
11 | AppVeyor: [](https://ci.appveyor.com/project/wwh1004/nativesharp)
12 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: '{build}'
2 | image: Visual Studio 2019
3 | configuration: Release
4 | platform: Any CPU
5 | before_build:
6 | - cmd: appveyor-retry nuget restore
7 | build:
8 | project: NativeSharp.sln
9 | verbosity: normal
10 | after_build:
11 | - cmd: >-
12 | dotnet pack NativeSharp\NativeSharp.csproj -c Release
13 | artifacts:
14 | - path: bin\Release\net20
15 | name: NativeSharp-net20
16 | - path: bin\Release\net40
17 | name: NativeSharp-net40
18 | - path: bin\Release\netstandard1.3
19 | name: NativeSharp-netstandard1.3
20 | - path: bin\Release\*.*nupkg
21 | name: NativeSharp NuGet Packages
22 | deploy:
23 | - provider: GitHub
24 | tag: $(APPVEYOR_REPO_TAG_NAME)
25 | release: NativeSharp
26 | auth_token:
27 | secure: +8UJ1C312inNq+80I8WST34vPMrCylnmTx+9rmuIh1qnsArA5x2b8yc+kcwkXmQC
28 | on:
29 | APPVEYOR_REPO_TAG: true
30 | - provider: NuGet
31 | api_key:
32 | secure: cEcRKw03ytO7aOibi1TSgahpSikqWO6+Nm88IUJr6XDxRbY++lNARRJRStbjwoQI
33 | on:
34 | APPVEYOR_REPO_TAG: true
--------------------------------------------------------------------------------