├── .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: [![Build status](https://ci.appveyor.com/api/projects/status/3gpjmjt8ung6yqn5?svg=true)](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 --------------------------------------------------------------------------------