├── .gitattributes ├── .gitignore ├── Example1 ├── Example1.csproj └── Program.cs ├── Example2 ├── Example2.csproj └── Program.cs ├── FastWin32.sln ├── FastWin32 ├── Asm │ ├── AsmCompileException.cs │ ├── AsmTable.cs │ └── Assembler.cs ├── Diagnostics │ ├── Injector.cs │ ├── Module32.cs │ └── Process32.cs ├── FastWin32.csproj ├── FastWin32.snk ├── FastWin32Settings.cs ├── Hook │ ├── Method │ │ ├── LocalHook.cs │ │ ├── LocalHookOld.cs │ │ └── RemoteHook.cs │ └── WindowMessage │ │ ├── KeyboardHook.cs │ │ └── MessageProxy.cs ├── Memory │ ├── MemoryIO.cs │ ├── MemoryManagement.cs │ ├── PageInfo.cs │ └── Pointer.cs ├── NativeMethods.cs ├── Properties │ └── AssemblyInfo.cs ├── SafeNativeHandle.cs └── Windowing │ └── Window.cs └── README.md /.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 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | # Custom 264 | .gitattributes 265 | .gitignore 266 | 读写内存模板.txt 267 | 模板使用代码.txt 268 | TrueRandom.cs 269 | FastWin32无用代码/ -------------------------------------------------------------------------------- /Example1/Example1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F9D3BE50-E65D-4B47-886D-43CDD306EA99} 8 | Exe 9 | Example1 10 | Example1 11 | v4.0 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | {0B6AC808-3A51-4072-954F-D55DE4F0209B} 39 | FastWin32 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Example1/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | using FastWin32.Memory; 5 | 6 | namespace Example1 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | uint processId; 13 | Pointer pointer; 14 | int value; 15 | 16 | processId = (uint)Process.Start("Tutorial-i386.exe").Id; 17 | Console.WriteLine("Go to \"Step 6\" then continue"); 18 | Console.ReadKey(); 19 | pointer = new Pointer("Tutorial-i386.exe", 0x1FD630, 0); 20 | MemoryIO.ReadInt32(processId, pointer, out value); 21 | Console.WriteLine($"Current value:{value}. Now we lock it"); 22 | while (true) 23 | { 24 | MemoryIO.WriteInt32(processId, pointer, 5000); 25 | Thread.Sleep(1); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Example2/Example2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {89265691-7C84-48B4-BB46-878A67C5F748} 8 | Exe 9 | Example2 10 | Example2 11 | v4.0 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | {0B6AC808-3A51-4072-954F-D55DE4F0209B} 42 | FastWin32 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using FastWin32.Diagnostics; 4 | 5 | namespace Example2 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | var list = (new int[0]).Select(dummy => new { moduleHandle = default(IntPtr), moduleName = default(string), pFunction = default(IntPtr), functionName = default(string), ordinal = default(short) }).ToList(); 12 | Module32.EnumModules(Process32.GetCurrentProcessId(), (IntPtr moduleHandle, string moduleName, string filePath) => 13 | { 14 | list.Clear(); 15 | Module32.EnumFunctions(Process32.GetCurrentProcessId(), moduleHandle, (IntPtr pFunction, string functionName, short ordinal) => 16 | { 17 | list.Add(new { moduleHandle, moduleName, pFunction, functionName, ordinal }); 18 | return true; 19 | }); 20 | list = list.OrderBy(item => item.moduleName).ToList(); 21 | list.ForEach(item => Console.WriteLine($"MH:{item.moduleHandle.ToString("X16")} MN:{item.moduleName} PF:{item.pFunction.ToString("X16")} FN:{item.functionName} OD:{item.ordinal.ToString()}")); 22 | return true; 23 | }); 24 | Console.ReadKey(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FastWin32.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26724.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastWin32", "FastWin32\FastWin32.csproj", "{0B6AC808-3A51-4072-954F-D55DE4F0209B}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example1", "Example1\Example1.csproj", "{F9D3BE50-E65D-4B47-886D-43CDD306EA99}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example2", "Example2\Example2.csproj", "{89265691-7C84-48B4-BB46-878A67C5F748}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {0B6AC808-3A51-4072-954F-D55DE4F0209B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {0B6AC808-3A51-4072-954F-D55DE4F0209B}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {0B6AC808-3A51-4072-954F-D55DE4F0209B}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {0B6AC808-3A51-4072-954F-D55DE4F0209B}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {F9D3BE50-E65D-4B47-886D-43CDD306EA99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {F9D3BE50-E65D-4B47-886D-43CDD306EA99}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {F9D3BE50-E65D-4B47-886D-43CDD306EA99}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {F9D3BE50-E65D-4B47-886D-43CDD306EA99}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {89265691-7C84-48B4-BB46-878A67C5F748}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {89265691-7C84-48B4-BB46-878A67C5F748}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {89265691-7C84-48B4-BB46-878A67C5F748}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {89265691-7C84-48B4-BB46-878A67C5F748}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {5E1F2938-1FE5-4247-A2BC-DD1BFECF604A} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /FastWin32/Asm/AsmCompileException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FastWin32.Asm 4 | { 5 | /// 6 | /// Asm编译/反编译错误 7 | /// 8 | [Serializable] 9 | public sealed class AsmCompilerException : Exception 10 | { 11 | /// 12 | /// 用指定的错误消息创建新实例 13 | /// 14 | /// 描述错误的消息 15 | internal AsmCompilerException(string message) : base(message) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /FastWin32/Asm/AsmTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace FastWin32.Asm 5 | { 6 | /// 7 | /// 汇编指令,机器码对应表 8 | /// 9 | public sealed class AsmData 10 | { 11 | internal List _byteList; 12 | 13 | /// 14 | /// 汇编指令 15 | /// 16 | public string Opcode { get; internal set; } 17 | 18 | /// 19 | /// 机器码 20 | /// 21 | public byte[] Bytes { get; internal set; } 22 | 23 | /// 24 | /// 实例化对应表 25 | /// 26 | /// 汇编指令 27 | internal AsmData(string opcode) 28 | { 29 | Opcode = opcode; 30 | _byteList = new List(); 31 | } 32 | 33 | /// 34 | /// 更新对应的机器码,设置,转换为只读模式 35 | /// 36 | internal void AsReadOnly() 37 | { 38 | Bytes = _byteList.ToArray(); 39 | _byteList = null; 40 | } 41 | 42 | /// 43 | /// 返回表示当前对象的字符串。 44 | /// 45 | /// 46 | public override string ToString() 47 | { 48 | return $"{Opcode} - {BitConverter.ToString(Bytes).Replace("-", string.Empty)}"; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FastWin32/Asm/Assembler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using FastWin32.Memory; 9 | using static FastWin32.NativeMethods; 10 | using size_t = System.IntPtr; 11 | 12 | namespace FastWin32.Asm 13 | { 14 | /// 15 | /// 汇编器,提供编译与反编译支持 16 | /// 17 | public static class Assembler 18 | { 19 | /// 20 | /// 汇编器路径 21 | /// 22 | private static string _nasmPath; 23 | 24 | /// 25 | /// 反汇编器路径 26 | /// 27 | private static string _ndisasmPath; 28 | 29 | /// 30 | /// 汇编器路径 31 | /// 32 | public static string NasmPath 33 | { 34 | get => _nasmPath; 35 | set 36 | { 37 | if (string.IsNullOrEmpty(value)) 38 | throw new ArgumentNullException(); 39 | 40 | value = Path.GetFullPath(value); 41 | if (!File.Exists(value)) 42 | throw new FileNotFoundException(); 43 | _nasmPath = value; 44 | } 45 | } 46 | 47 | /// 48 | /// 反汇编器路径 49 | /// 50 | public static string NdisasmPath 51 | { 52 | get => _ndisasmPath; 53 | set 54 | { 55 | if (string.IsNullOrEmpty(value)) 56 | throw new ArgumentNullException(); 57 | 58 | value = Path.GetFullPath(value); 59 | if (!File.Exists(value)) 60 | throw new FileNotFoundException(); 61 | _ndisasmPath = value; 62 | } 63 | } 64 | 65 | /// 66 | /// 汇编指令转机器码 67 | /// 68 | /// 汇编指令 69 | /// 是否使用64位汇编 70 | /// 71 | public static IList OpcodesToBytes(string[] opcodes, bool is64) 72 | { 73 | if (opcodes == null || opcodes.Length == 0) 74 | throw new ArgumentNullException(); 75 | if (string.IsNullOrEmpty(_nasmPath)) 76 | throw new FileNotFoundException("未设置编译器\"nasm.exe\"的路径"); 77 | 78 | string[] output; 79 | string[] tokens; 80 | int n; 81 | List asmDataList; 82 | 83 | output = OpcodesToBytesRaw(opcodes, is64); 84 | n = 0; 85 | asmDataList = new List(opcodes.Length); 86 | foreach (string line in output) 87 | { 88 | if (string.IsNullOrEmpty(line)) 89 | continue; 90 | tokens = GetTokensNasm(line); 91 | if (int.Parse(tokens[0]) == n) 92 | { 93 | //汇编指令太长,机器码用了2行或更长 94 | for (int i = 0; i < tokens[1].Length; i += 2) 95 | asmDataList[n - 1]._byteList.Add(Convert.ToByte(tokens[1].Substring(i, 2), 16)); 96 | //追加机器码到上一行 97 | } 98 | else 99 | { 100 | //下一句汇编指令 101 | asmDataList.Add(new AsmData(opcodes[n])); 102 | for (int i = 0; i < tokens[1].Length; i += 2) 103 | asmDataList[n]._byteList.Add(Convert.ToByte(tokens[1].Substring(i, 2), 16)); 104 | n++; 105 | } 106 | } 107 | foreach (AsmData asmData in asmDataList) 108 | asmData.AsReadOnly(); 109 | return asmDataList; 110 | } 111 | 112 | /// 113 | /// 汇编指令转机器码保留原始数据 114 | /// 115 | /// 汇编指令 116 | /// 是否使用64位汇编 117 | /// 118 | private static string[] OpcodesToBytesRaw(string[] opcodes, bool is64) 119 | { 120 | string tempFilePathOpcodes; 121 | string tempFilePathBytes; 122 | ProcessStartInfo startInfo; 123 | Process process; 124 | string error; 125 | StringBuilder stringBuilder; 126 | 127 | tempFilePathOpcodes = GetTempFileName(); 128 | File.WriteAllLines(tempFilePathOpcodes, opcodes); 129 | tempFilePathBytes = GetTempFileName(); 130 | startInfo = new ProcessStartInfo 131 | { 132 | Arguments = string.Format(" -f win{0} -l {1} {2}", is64 ? "64" : "32", Path.GetFileName(tempFilePathBytes), Path.GetFileName(tempFilePathOpcodes)), 133 | CreateNoWindow = true, 134 | FileName = _nasmPath, 135 | RedirectStandardError = true, 136 | UseShellExecute = false, 137 | WorkingDirectory = Path.GetTempPath() 138 | }; 139 | process = new Process 140 | { 141 | StartInfo = startInfo 142 | }; 143 | process.Start(); 144 | process.WaitForExit(); 145 | error = process.StandardError.ReadLine(); 146 | if (string.IsNullOrEmpty(error)) 147 | return File.ReadAllLines(tempFilePathBytes); 148 | else 149 | { 150 | stringBuilder = new StringBuilder(); 151 | stringBuilder.AppendLine(error); 152 | while (true) 153 | { 154 | error = process.StandardError.ReadLine(); 155 | if (string.IsNullOrEmpty(error)) 156 | break; 157 | else 158 | stringBuilder.AppendLine(error); 159 | } 160 | throw new AsmCompilerException(stringBuilder.ToString()); 161 | } 162 | } 163 | 164 | /// 165 | /// 获取nasm编译后生成list的Token 166 | /// 167 | /// list中的一行 168 | /// 169 | private static string[] GetTokensNasm(string line) 170 | { 171 | string[] tokens; 172 | 173 | tokens = new string[2]; 174 | tokens[0] = line.Substring(0, 6).Trim(); 175 | //第n条汇编指令 176 | tokens[1] = line.Substring(16, 18).Trim(); 177 | //对应的机器码 178 | return tokens; 179 | } 180 | 181 | /// 182 | /// 获取中所有机器码(相当于将的返回值拼接为一个数组) 183 | /// 184 | /// 列表 185 | /// 186 | public static byte[] GetAllBytes(this IList asmDataList) 187 | { 188 | if (asmDataList == null) 189 | throw new ArgumentNullException(); 190 | 191 | return asmDataList.SelectMany(asmData => asmData.Bytes).ToArray(); 192 | } 193 | 194 | /// 195 | /// 获取中所有机器码数组 196 | /// 197 | /// 列表 198 | /// 199 | public static byte[][] GetAllBytesArray(this IList asmDataList) 200 | { 201 | if (asmDataList == null) 202 | throw new ArgumentNullException(); 203 | 204 | return asmDataList.Select(asmData => asmData.Bytes).ToArray(); 205 | } 206 | 207 | /// 208 | /// 机器码转汇编指令 209 | /// 210 | /// 机器码 211 | /// 是否使用64位汇编 212 | /// 213 | public static IList BytesToOpcodes(byte[] bytes, bool is64) 214 | { 215 | if (bytes == null || bytes.Length == 0) 216 | throw new ArgumentNullException(); 217 | if (string.IsNullOrEmpty(_ndisasmPath)) 218 | throw new FileNotFoundException("未设置反编译器\"ndisasm.exe\"的路径"); 219 | 220 | string[] output; 221 | string[] tokens; 222 | int n; 223 | List asmDataList; 224 | 225 | output = BytesToOpcodesRaw(bytes, is64); 226 | n = 0; 227 | asmDataList = new List(output.Length); 228 | foreach (string line in output) 229 | { 230 | if (string.IsNullOrEmpty(line)) 231 | continue; 232 | tokens = GetTokensNdisasm(line); 233 | if (tokens[1] == null) 234 | { 235 | //汇编指令太长,机器码用了2行或更长 236 | for (int i = 0; i < tokens[0].Length; i += 2) 237 | asmDataList[n - 1]._byteList.Add(Convert.ToByte(tokens[0].Substring(i, 2), 16)); 238 | //追加机器码到上一行 239 | } 240 | else 241 | { 242 | //下一句汇编指令 243 | asmDataList.Add(new AsmData(tokens[1])); 244 | for (int i = 0; i < tokens[0].Length; i += 2) 245 | asmDataList[n]._byteList.Add(Convert.ToByte(tokens[0].Substring(i, 2), 16)); 246 | n++; 247 | } 248 | } 249 | foreach (AsmData asmData in asmDataList) 250 | asmData.AsReadOnly(); 251 | return asmDataList; 252 | } 253 | 254 | /// 255 | /// 机器码转汇编指令保留原始数据 256 | /// 257 | /// 机器码 258 | /// 是否使用64位汇编 259 | /// 260 | private static string[] BytesToOpcodesRaw(byte[] bytes, bool is64) 261 | { 262 | if (bytes == null || bytes.Length == 0) 263 | throw new ArgumentNullException(); 264 | if (string.IsNullOrEmpty(_ndisasmPath)) 265 | throw new FileNotFoundException("未设置反编译器\"ndisasm.exe\"的路径"); 266 | 267 | string tempFilePathBytes; 268 | ProcessStartInfo startInfo; 269 | Process process; 270 | string line; 271 | List output; 272 | 273 | tempFilePathBytes = GetTempFileName(); 274 | File.WriteAllBytes(tempFilePathBytes, bytes); 275 | startInfo = new ProcessStartInfo 276 | { 277 | Arguments = string.Format(" -b {0} {1}", is64 ? "64" : "32", Path.GetFileName(tempFilePathBytes)), 278 | CreateNoWindow = true, 279 | FileName = _ndisasmPath, 280 | RedirectStandardOutput = true, 281 | UseShellExecute = false, 282 | WorkingDirectory = Path.GetTempPath() 283 | }; 284 | process = new Process 285 | { 286 | StartInfo = startInfo 287 | }; 288 | process.Start(); 289 | process.WaitForExit(); 290 | output = new List(); 291 | while (true) 292 | { 293 | line = process.StandardOutput.ReadLine(); 294 | if (string.IsNullOrEmpty(line)) 295 | break; 296 | else 297 | output.Add(line); 298 | } 299 | return output.ToArray(); 300 | } 301 | 302 | /// 303 | /// 获取ndisasm反编译后生成list的Token 304 | /// 305 | /// list中的一行 306 | /// 307 | private static string[] GetTokensNdisasm(string line) 308 | { 309 | string[] tokens; 310 | 311 | tokens = new string[2]; 312 | if (line[9] == '-') 313 | { 314 | tokens[0] = line.Substring(10).Trim(); 315 | //机器码 316 | } 317 | else 318 | { 319 | tokens[0] = line.Substring(10, 16).Trim(); 320 | //机器码 321 | tokens[1] = line.Substring(28).Trim(); 322 | //汇编指令 323 | } 324 | return tokens; 325 | } 326 | 327 | /// 328 | /// 获取中所有汇编指令 329 | /// 330 | /// 列表 331 | /// 332 | public static string[] GetAllOpcodes(this IList asmDataList) 333 | { 334 | if (asmDataList == null) 335 | throw new ArgumentNullException(); 336 | 337 | return asmDataList.Select(asmData => asmData.Opcode).ToArray(); 338 | } 339 | 340 | /// 341 | /// 获取临时文件 342 | /// 343 | /// 344 | private static string GetTempFileName() 345 | { 346 | string path; 347 | 348 | path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".tmp"); 349 | File.WriteAllText(path, null); 350 | return path; 351 | } 352 | 353 | /// 354 | /// 将机器码写入内存,返回函数指针。如果执行失败,返回 355 | /// 356 | /// 机器码 357 | /// 358 | public static IntPtr GetFunctionPointer(byte[] bytes) 359 | { 360 | if (bytes == null || bytes.Length == 0) 361 | throw new ArgumentNullException(); 362 | 363 | IntPtr pAsm; 364 | 365 | pAsm = MemoryManagement.AllocMemoryInternal((size_t)bytes.Length, PAGE_EXECUTE_READ); 366 | //分配内存(可执行) 367 | if (MemoryIO.WriteBytesInternal(CURRENT_PROCESS, pAsm, bytes)) 368 | return pAsm; 369 | else 370 | return IntPtr.Zero; 371 | } 372 | 373 | /// 374 | /// 将汇编指令写入内存,返回函数指针。如果执行失败,返回 375 | /// 376 | /// 汇编指令 377 | /// 是否使用64位汇编 378 | /// 379 | public static IntPtr GetFunctionPointer(string[] opcodes, bool is64) 380 | { 381 | if (opcodes == null || opcodes.Length == 0) 382 | throw new ArgumentNullException(); 383 | 384 | return GetFunctionPointer(OpcodesToBytes(opcodes, is64).GetAllBytes()); 385 | } 386 | 387 | /// 388 | /// 将机器码写入内存,返回对应的委托。如果执行失败,返回 389 | /// 390 | /// 委托 391 | /// 机器码 392 | /// 393 | public static TDelegate GetDelegate(byte[] bytes) 394 | { 395 | if (bytes == null || bytes.Length == 0) 396 | throw new ArgumentNullException(); 397 | 398 | IntPtr pFunction; 399 | 400 | pFunction = GetFunctionPointer(bytes); 401 | if (pFunction == IntPtr.Zero) 402 | return default(TDelegate); 403 | else 404 | return (TDelegate)(object)Marshal.GetDelegateForFunctionPointer(pFunction, typeof(TDelegate)); 405 | } 406 | 407 | /// 408 | /// 将机器码写入内存,返回对应的委托。如果执行失败,返回 409 | /// 410 | /// 411 | /// 汇编指令 412 | /// 是否使用64位汇编 413 | /// 414 | public static TDelegate GetDelegate(string[] opcodes, bool is64) 415 | { 416 | if (opcodes == null || opcodes.Length == 0) 417 | throw new ArgumentNullException(); 418 | 419 | return (TDelegate)(object)Marshal.GetDelegateForFunctionPointer(GetFunctionPointer(opcodes, is64), typeof(TDelegate)); 420 | } 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /FastWin32/Diagnostics/Injector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using FastWin32.Memory; 5 | using static FastWin32.NativeMethods; 6 | using size_t = System.IntPtr; 7 | 8 | namespace FastWin32.Diagnostics 9 | { 10 | /// 11 | /// 注入 12 | /// 13 | public static unsafe class Injector 14 | { 15 | #region Constant 16 | private const int AssemblyPathOffset = 0x200; 17 | 18 | private const int TypeNameOffset = 0x800; 19 | 20 | private const int MethodNameOffset = 0x980; 21 | 22 | private const int ReturnValueOffset = 0xA00; 23 | 24 | private const int CLRVersionOffset = 0xA10; 25 | 26 | private const int CLSID_CLRMetaHostOffset = 0xA60; 27 | 28 | private const int IID_ICLRMetaHostOffset = 0xA70; 29 | 30 | private const int IID_ICLRRuntimeInfoOffset = 0xA80; 31 | 32 | private const int CLSID_CLRRuntimeHostOffset = 0xA90; 33 | 34 | private const int IID_ICLRRuntimeHostOffset = 0xAA0; 35 | 36 | private const int ArgumentOffset = 0xB00; 37 | 38 | private readonly static byte[] CLSID_CLRMetaHost = new Guid(0x9280188D, 0x0E8E, 0x4867, 0xB3, 0x0C, 0x7F, 0xA8, 0x38, 0x84, 0xE8, 0xDE).ToByteArray(); 39 | 40 | private readonly static byte[] IID_ICLRMetaHost = new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16).ToByteArray(); 41 | 42 | private readonly static byte[] IID_ICLRRuntimeInfo = new Guid(0xBD39D1D2, 0xBA2F, 0x486A, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91).ToByteArray(); 43 | 44 | private readonly static byte[] CLSID_CLRRuntimeHost = new Guid(0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray(); 45 | 46 | private readonly static byte[] IID_ICLRRuntimeHost = new Guid(0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray(); 47 | #endregion 48 | 49 | private struct Section 50 | { 51 | public uint VirtualSize; 52 | 53 | public uint VirtualAddress; 54 | 55 | public uint SizeOfRawData; 56 | 57 | public uint PointerToRawData; 58 | 59 | public Section(uint virtualSize, uint virtualAddress, uint sizeOfRawData, uint pointerToRawData) 60 | { 61 | VirtualSize = virtualSize; 62 | VirtualAddress = virtualAddress; 63 | SizeOfRawData = sizeOfRawData; 64 | PointerToRawData = pointerToRawData; 65 | } 66 | } 67 | 68 | /// 69 | /// 打开进程(注入使用) 70 | /// 71 | /// 进程句柄 72 | /// 73 | private static SafeNativeHandle OpenProcessInjecting(uint processId) 74 | { 75 | return SafeOpenProcess(FastWin32Settings.SeDebugPrivilege ? PROCESS_ALL_ACCESS : PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, false, processId); 76 | } 77 | 78 | /// 79 | /// 注入非托管DLL 80 | /// 81 | /// 要注入的进程ID 82 | /// 要注入程序集的路径 83 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB) 84 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument) 85 | /// 参数,可传入null。 86 | /// 87 | public static bool InjectManaged(uint processId, string assemblyPath, string typeName, string methodName, string argument) 88 | { 89 | if (string.IsNullOrEmpty(assemblyPath)) 90 | throw new ArgumentNullException(); 91 | if (!File.Exists(assemblyPath)) 92 | throw new FileNotFoundException(); 93 | if (string.IsNullOrEmpty(typeName)) 94 | throw new ArgumentNullException(); 95 | if (string.IsNullOrEmpty(methodName)) 96 | throw new ArgumentNullException(); 97 | 98 | SafeNativeHandle processHandle; 99 | int returnValue; 100 | 101 | using (processHandle = OpenProcessInjecting(processId)) 102 | if (processHandle.IsValid) 103 | return InjectManagedInternal(processHandle, assemblyPath, typeName, methodName, argument, out returnValue, false); 104 | else 105 | return false; 106 | } 107 | 108 | /// 109 | /// 注入非托管DLL,并获取被调用方法的返回值(警告:被调用方法返回后才能获取到返回值,方法将一直等待到被调用方法返回。如果仅注入程序集而不需要获取返回值,请使用重载版本) 110 | /// 111 | /// 要注入的进程ID 112 | /// 要注入程序集的路径 113 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB) 114 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument) 115 | /// 参数,可传入null。 116 | /// 被调用方法返回的整数值 117 | /// 118 | public static bool InjectManaged(uint processId, string assemblyPath, string typeName, string methodName, string argument, out int returnValue) 119 | { 120 | if (string.IsNullOrEmpty(assemblyPath)) 121 | throw new ArgumentNullException(); 122 | if (!File.Exists(assemblyPath)) 123 | throw new FileNotFoundException(); 124 | if (string.IsNullOrEmpty(typeName)) 125 | throw new ArgumentNullException(); 126 | if (string.IsNullOrEmpty(methodName)) 127 | throw new ArgumentNullException(); 128 | 129 | SafeNativeHandle processHandle; 130 | 131 | using (processHandle = OpenProcessInjecting(processId)) 132 | if (processHandle.IsValid) 133 | return InjectManagedInternal(processHandle, assemblyPath, typeName, methodName, argument, out returnValue, true); 134 | else 135 | { 136 | returnValue = 0; 137 | return false; 138 | } 139 | } 140 | 141 | /// 142 | /// 注入非托管DLL 143 | /// 144 | /// 进程句柄 145 | /// 要注入程序集的路径 146 | /// 类型名(命名空间+类型名,比如NamespaceA.ClassB) 147 | /// 方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument) 148 | /// 参数,可传入null。 149 | /// 被调用方法返回的整数值 150 | /// 是否等待返回值 151 | /// 152 | internal static bool InjectManagedInternal(IntPtr processHandle, string assemblyPath, string typeName, string methodName, string argument, out int returnValue, bool wait) 153 | { 154 | bool isAssembly; 155 | bool is64; 156 | string clrVersion; 157 | IntPtr pFunction; 158 | IntPtr threadHandle; 159 | uint exitCode; 160 | 161 | returnValue = 0; 162 | assemblyPath = Path.GetFullPath(assemblyPath); 163 | //获取绝对路径 164 | IsAssembly(assemblyPath, out isAssembly, out clrVersion); 165 | if (!isAssembly) 166 | throw new NotSupportedException("将注入的DLL为不是程序集,应该调用InjectUnmanaged方法而非调用InjectManaged方法"); 167 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 168 | return false; 169 | if (!InjectUnmanagedInternal(processHandle, Path.Combine(GetSystemPath(is64), "mscoree.dll"))) 170 | return false; 171 | //加载对应进程位数的mscoree.dll 172 | pFunction = WriteAsm(processHandle, clrVersion, assemblyPath, typeName, methodName, argument); 173 | //获取远程进程中启动CLR的函数指针 174 | if (pFunction == IntPtr.Zero) 175 | return false; 176 | threadHandle = CreateRemoteThread(processHandle, null, size_t.Zero, pFunction, pFunction + ReturnValueOffset, 0, null); 177 | if (threadHandle == IntPtr.Zero) 178 | return false; 179 | if (wait) 180 | { 181 | WaitForSingleObject(threadHandle, INFINITE); 182 | //等待线程结束 183 | if (!GetExitCodeThread(threadHandle, out exitCode)) 184 | return false; 185 | if (!MemoryIO.ReadInt32Internal(processHandle, pFunction + ReturnValueOffset, out returnValue)) 186 | return false; 187 | //获取程序集中被调用方法的返回值 188 | if (!MemoryManagement.FreeMemoryExInternal(processHandle, pFunction)) 189 | return false; 190 | return (int)exitCode >= 0; 191 | //ICLRRuntimeHost::ExecuteInDefaultAppDomain返回S_OK(0)表示成功。HRESULT不能直接比较,大于等于0就是成功 192 | } 193 | return true; 194 | } 195 | 196 | /// 197 | /// 注入非托管DLL 198 | /// 199 | /// 要注入的进程ID 200 | /// 要注入DLL的路径 201 | /// 202 | public static bool InjectUnmanaged(uint processId, string dllPath) 203 | { 204 | if (string.IsNullOrEmpty(dllPath)) 205 | throw new ArgumentNullException(); 206 | if (!File.Exists(dllPath)) 207 | throw new FileNotFoundException(); 208 | 209 | SafeNativeHandle processHandle; 210 | bool isAssembly; 211 | string clrVersion; 212 | 213 | using (processHandle = OpenProcessInjecting(processId)) 214 | if (processHandle.IsValid) 215 | { 216 | dllPath = Path.GetFullPath(dllPath); 217 | //获取绝对路径 218 | IsAssembly(dllPath, out isAssembly, out clrVersion); 219 | if (isAssembly) 220 | throw new NotSupportedException("将注入的DLL为程序集,应该调用InjectManaged方法而非调用InjectUnmanaged方法"); 221 | return InjectUnmanagedInternal(processHandle, dllPath); 222 | //注入非托管DLL 223 | } 224 | else 225 | return false; 226 | } 227 | 228 | /// 229 | /// 注入非托管Dll 230 | /// 231 | /// 进程句柄 232 | /// 要注入的Dll的路径 233 | /// 234 | internal static bool InjectUnmanagedInternal(IntPtr processHandle, string dllPath) 235 | { 236 | bool is64; 237 | IntPtr pLoadLibrary; 238 | IntPtr pDllPath; 239 | IntPtr threadHandle; 240 | uint exitCode; 241 | 242 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 243 | return false; 244 | pLoadLibrary = Module32.GetProcAddressInternal(processHandle, "kernel32.dll", "LoadLibraryW"); 245 | //获取LoadLibrary的函数地址 246 | pDllPath = MemoryManagement.AllocMemoryExInternal(processHandle, (size_t)(dllPath.Length * 2 + 2), PAGE_EXECUTE_READ); 247 | try 248 | { 249 | if (pDllPath == IntPtr.Zero) 250 | return false; 251 | if (!MemoryIO.WriteStringInternal(processHandle, pDllPath, dllPath)) 252 | return false; 253 | threadHandle = CreateRemoteThread(processHandle, null, size_t.Zero, pLoadLibrary, pDllPath, 0, null); 254 | if (threadHandle == IntPtr.Zero) 255 | return false; 256 | WaitForSingleObject(threadHandle, INFINITE); 257 | //等待线程结束 258 | GetExitCodeThread(threadHandle, out exitCode); 259 | return exitCode != 0; 260 | //LoadLibrary返回值不为0则调用成功,否则失败 261 | } 262 | finally 263 | { 264 | MemoryManagement.FreeMemoryExInternal(processHandle, pDllPath); 265 | } 266 | } 267 | 268 | /// 269 | /// 获取系统文件夹路径 270 | /// 271 | /// 是否64位 272 | /// 273 | private static string GetSystemPath(bool is64) 274 | { 275 | return Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), (!FastWin32Settings.Is64BitOperatingSystem || is64) ? "System32" : "SysWOW64"); 276 | } 277 | 278 | /// 279 | /// 写入启动CLR的机器码,返回函数指针 280 | /// 281 | /// 进程句柄 282 | /// CLR版本 283 | /// 程序集路径(绝对路径) 284 | /// 类型名 285 | /// 方法名 286 | /// 参数(可空,如果非空,长度必须小于2000) 287 | /// 288 | private static IntPtr WriteAsm(IntPtr processHandle, string clrVersion, string assemblyPath, string typeName, string methodName, string argument) 289 | { 290 | bool is64; 291 | byte[] asm; 292 | IntPtr pFunction; 293 | IntPtr pCorBindToRuntimeEx; 294 | IntPtr pCLRCreateInstance; 295 | 296 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 297 | return IntPtr.Zero; 298 | asm = GetAsmCommon(clrVersion, assemblyPath, typeName, methodName, argument); 299 | pFunction = MemoryManagement.AllocMemoryExInternal(processHandle, (size_t)(0x1000 + (argument == null ? 0 : argument.Length * 2)), PAGE_EXECUTE_READWRITE); 300 | if (pFunction == IntPtr.Zero) 301 | return IntPtr.Zero; 302 | try 303 | { 304 | fixed (byte* p = &asm[0]) 305 | { 306 | switch (clrVersion) 307 | { 308 | case "v2.0.50727": 309 | pCorBindToRuntimeEx = Module32.GetProcAddressInternal(processHandle, "mscoree.dll", "CorBindToRuntimeEx"); 310 | if (pCorBindToRuntimeEx == IntPtr.Zero) 311 | return IntPtr.Zero; 312 | if (is64) 313 | SetAsm64V2(p, (long)pFunction, (long)pCorBindToRuntimeEx); 314 | else 315 | SetAsm32V2(p, (int)pFunction, (int)pCorBindToRuntimeEx); 316 | break; 317 | case "v4.0.30319": 318 | pCLRCreateInstance = Module32.GetProcAddressInternal(processHandle, "mscoree.dll", "CLRCreateInstance"); 319 | if (pCLRCreateInstance == IntPtr.Zero) 320 | return IntPtr.Zero; 321 | if (is64) 322 | SetAsm64V4(p, (long)pFunction, (long)pCLRCreateInstance); 323 | else 324 | SetAsm32V4(p, (int)pFunction, (int)pCLRCreateInstance); 325 | break; 326 | default: 327 | return IntPtr.Zero; 328 | } 329 | } 330 | if (!MemoryIO.WriteBytesInternal(processHandle, pFunction, asm)) 331 | return IntPtr.Zero; 332 | } 333 | catch 334 | { 335 | MemoryManagement.FreeMemoryExInternal(processHandle, pFunction); 336 | return IntPtr.Zero; 337 | } 338 | return pFunction; 339 | } 340 | 341 | /// 342 | /// 获取设置好参数的机器码 343 | /// 344 | /// CLR版本 345 | /// 程序集路径(绝对路径) 346 | /// 类型名 347 | /// 方法名 348 | /// 参数(可空,如果非空,长度必须小于2000) 349 | /// 350 | private static byte[] GetAsmCommon(string clrVersion, string assemblyPath, string typeName, string methodName, string argument) 351 | { 352 | MemoryStream memoryStream; 353 | byte[] bytes; 354 | 355 | using (memoryStream = new MemoryStream(0x1000 + (argument == null ? 0 : argument.Length * 2))) 356 | { 357 | bytes = Encoding.Unicode.GetBytes(assemblyPath); 358 | memoryStream.Position = AssemblyPathOffset; 359 | memoryStream.Write(bytes, 0, bytes.Length); 360 | //assemblyPath 361 | bytes = Encoding.Unicode.GetBytes(typeName); 362 | memoryStream.Position = TypeNameOffset; 363 | memoryStream.Write(bytes, 0, bytes.Length); 364 | //typeName 365 | bytes = Encoding.Unicode.GetBytes(methodName); 366 | memoryStream.Position = MethodNameOffset; 367 | memoryStream.Write(bytes, 0, bytes.Length); 368 | //methodName 369 | bytes = argument == null ? new byte[0] : Encoding.Unicode.GetBytes(argument); 370 | memoryStream.Position = ArgumentOffset; 371 | memoryStream.Write(bytes, 0, bytes.Length); 372 | //argument 373 | bytes = Encoding.Unicode.GetBytes(clrVersion); 374 | memoryStream.Position = CLRVersionOffset; 375 | memoryStream.Write(bytes, 0, bytes.Length); 376 | //clrVersion 377 | memoryStream.Position = CLSID_CLRMetaHostOffset; 378 | memoryStream.Write(CLSID_CLRMetaHost, 0, CLSID_CLRMetaHost.Length); 379 | memoryStream.Position = IID_ICLRMetaHostOffset; 380 | memoryStream.Write(IID_ICLRMetaHost, 0, IID_ICLRMetaHost.Length); 381 | memoryStream.Position = IID_ICLRRuntimeInfoOffset; 382 | memoryStream.Write(IID_ICLRRuntimeInfo, 0, IID_ICLRRuntimeInfo.Length); 383 | memoryStream.Position = CLSID_CLRRuntimeHostOffset; 384 | memoryStream.Write(CLSID_CLRRuntimeHost, 0, CLSID_CLRRuntimeHost.Length); 385 | memoryStream.Position = IID_ICLRRuntimeHostOffset; 386 | memoryStream.Write(IID_ICLRRuntimeHost, 0, IID_ICLRRuntimeHost.Length); 387 | memoryStream.SetLength(memoryStream.Capacity); 388 | return memoryStream.ToArray(); 389 | } 390 | } 391 | 392 | /// 393 | /// 设置启动32位CLR V2的机器码 394 | /// 395 | /// 机器码指针 396 | /// 函数指针 397 | /// CorBindToRuntimeEx的函数指针 398 | private static void SetAsm32V2(byte* p, int pFunction, int pCorBindToRuntimeEx) 399 | { 400 | //HRESULT WINAPI LoadCLR2(DWORD *pReturnValue) 401 | #region { 402 | p[0] = 0x55; 403 | p += 1; 404 | //push ebp 405 | p[0] = 0x89; 406 | p[1] = 0xE5; 407 | p += 2; 408 | //mov ebp,esp 409 | p[0] = 0x83; 410 | p[1] = 0xEC; 411 | p[2] = 0x44; 412 | p += 3; 413 | //sub esp,byte +0x44 414 | p[0] = 0x53; 415 | p += 1; 416 | //push ebx 417 | p[0] = 0x56; 418 | p += 1; 419 | //push esi 420 | p[0] = 0x57; 421 | p += 1; 422 | //push edi 423 | p[0] = 0xC7; 424 | p[1] = 0x45; 425 | p[2] = 0xFC; 426 | p[3] = 0x00; 427 | p[4] = 0x00; 428 | p[5] = 0x00; 429 | p[6] = 0x00; 430 | p += 7; 431 | #endregion 432 | #region ICLRRuntimeHost *pRuntimeHost = nullptr; 433 | //mov dword [ebp-0x4],0x0 434 | p[0] = 0x8D; 435 | p[1] = 0x45; 436 | p[2] = 0xFC; 437 | p += 3; 438 | #endregion 439 | #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost); 440 | //lea eax,[ebp-0x4] 441 | p[0] = 0x50; 442 | p += 1; 443 | //push eax 444 | p[0] = 0x68; 445 | *(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset; 446 | p += 5; 447 | //push dword PIID_ICLRRuntimeHost 448 | p[0] = 0x68; 449 | *(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset; 450 | p += 5; 451 | //push dword pCLSID_CLRRuntimeHost 452 | p[0] = 0x6A; 453 | p[1] = 0x00; 454 | p += 2; 455 | //push byte +0x0 456 | p[0] = 0x6A; 457 | p[1] = 0x00; 458 | p += 2; 459 | //push byte +0x0 460 | p[0] = 0x68; 461 | *(int*)(p + 1) = pFunction + CLRVersionOffset; 462 | p += 5; 463 | //push dword pCLRVersion 464 | p[0] = 0xB9; 465 | *(int*)(p + 1) = pCorBindToRuntimeEx; 466 | p += 5; 467 | //mov ecx,pCorBindToRuntimeEx 468 | p[0] = 0xFF; 469 | p[1] = 0xD1; 470 | p += 2; 471 | //call ecx 472 | #endregion 473 | #region pRuntimeHost->Start(); 474 | p[0] = 0x8B; 475 | p[1] = 0x45; 476 | p[2] = 0xFC; 477 | p += 3; 478 | //mov eax,[ebp-0x4] 479 | p[0] = 0x8B; 480 | p[1] = 0x08; 481 | p += 2; 482 | //mov ecx,[eax] 483 | p[0] = 0x8B; 484 | p[1] = 0x55; 485 | p[2] = 0xFC; 486 | p += 3; 487 | //mov edx,[ebp-0x4] 488 | p[0] = 0x52; 489 | p += 1; 490 | //push edx 491 | p[0] = 0x8B; 492 | p[1] = 0x41; 493 | p[2] = 0x0C; 494 | p += 3; 495 | //mov eax,[ecx+0xc] 496 | p[0] = 0xFF; 497 | p[1] = 0xD0; 498 | p += 2; 499 | //call eax 500 | #endregion 501 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue); 502 | p[0] = 0x8B; 503 | p[1] = 0x45; 504 | p[2] = 0x08; 505 | p += 3; 506 | //mov eax,[ebp+0x8] 507 | p[0] = 0x50; 508 | p += 1; 509 | //push eax 510 | p[0] = 0x68; 511 | *(int*)(p + 1) = pFunction + ArgumentOffset; 512 | p += 5; 513 | //push dword pArgument 514 | p[0] = 0x68; 515 | *(int*)(p + 1) = pFunction + MethodNameOffset; 516 | p += 5; 517 | //push dword pMethodName 518 | p[0] = 0x68; 519 | *(int*)(p + 1) = pFunction + TypeNameOffset; 520 | p += 5; 521 | //push dword pTypeName 522 | p[0] = 0x68; 523 | *(int*)(p + 1) = pFunction + AssemblyPathOffset; 524 | p += 5; 525 | //push dword pAssemblyPath 526 | p[0] = 0x8B; 527 | p[1] = 0x4D; 528 | p[2] = 0xFC; 529 | p += 3; 530 | //mov ecx,[ebp-0x4] 531 | p[0] = 0x8B; 532 | p[1] = 0x11; 533 | p += 2; 534 | //mov edx,[ecx] 535 | p[0] = 0x8B; 536 | p[1] = 0x45; 537 | p[2] = 0xFC; 538 | p += 3; 539 | //mov eax,[ebp-0x4] 540 | p[0] = 0x50; 541 | p += 1; 542 | //push eax 543 | p[0] = 0x8B; 544 | p[1] = 0x4A; 545 | p[2] = 0x2C; 546 | p += 3; 547 | //mov ecx,[edx+0x2c] 548 | p[0] = 0xFF; 549 | p[1] = 0xD1; 550 | p += 2; 551 | //call ecx 552 | #endregion 553 | #region } 554 | p[0] = 0x5F; 555 | p += 1; 556 | //pop edi 557 | p[0] = 0x5E; 558 | p += 1; 559 | //pop esi 560 | p[0] = 0x5B; 561 | p += 1; 562 | //pop ebx 563 | p[0] = 0x89; 564 | p[1] = 0xEC; 565 | p += 2; 566 | //mov esp,ebp 567 | p[0] = 0x5D; 568 | p += 1; 569 | //pop ebp 570 | p[0] = 0xC2; 571 | p[1] = 0x04; 572 | p[2] = 0x00; 573 | p += 3; 574 | //ret 0x4 575 | #endregion 576 | } 577 | 578 | /// 579 | /// 设置启动32位CLR V4的机器码 580 | /// 581 | /// 机器码指针 582 | /// 函数指针 583 | /// CLRCreateInstance的函数指针 584 | private static void SetAsm32V4(byte* p, int pFunction, int pCLRCreateInstance) 585 | { 586 | //HRESULT WINAPI LoadCLR4(DWORD *pReturnValue) 587 | #region { 588 | p[0] = 0x55; 589 | p += 1; 590 | //push ebp 591 | p[0] = 0x89; 592 | p[1] = 0xE5; 593 | p += 2; 594 | //mov ebp,esp 595 | p[0] = 0x83; 596 | p[1] = 0xEC; 597 | p[2] = 0x4C; 598 | p += 3; 599 | //sub esp,byte +0x4c 600 | p[0] = 0x53; 601 | p += 1; 602 | //push ebx 603 | p[0] = 0x56; 604 | p += 1; 605 | //push esi 606 | p[0] = 0x57; 607 | p += 1; 608 | //push edi 609 | #endregion 610 | #region ICLRMetaHost *pMetaHost = nullptr; 611 | p[0] = 0xC7; 612 | p[1] = 0x45; 613 | p[2] = 0xFC; 614 | p[3] = 0x00; 615 | p[4] = 0x00; 616 | p[5] = 0x00; 617 | p[6] = 0x00; 618 | p += 7; 619 | //mov dword [ebp-0x4],0x0 620 | #endregion 621 | #region ICLRRuntimeInfo *pRuntimeInfo = nullptr; 622 | p[0] = 0xC7; 623 | p[1] = 0x45; 624 | p[2] = 0xF8; 625 | p[3] = 0x00; 626 | p[4] = 0x00; 627 | p[5] = 0x00; 628 | p[6] = 0x00; 629 | p += 7; 630 | //mov dword [ebp-0x8],0x0 631 | #endregion 632 | #region ICLRRuntimeHost *pRuntimeHost = nullptr; 633 | p[0] = 0xC7; 634 | p[1] = 0x45; 635 | p[2] = 0xF4; 636 | p[3] = 0x00; 637 | p[4] = 0x00; 638 | p[5] = 0x00; 639 | p[6] = 0x00; 640 | p += 7; 641 | //mov dword [ebp-0xc],0x0 642 | #endregion 643 | #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 644 | p[0] = 0x8D; 645 | p[1] = 0x45; 646 | p[2] = 0xFC; 647 | p += 3; 648 | //lea eax,[ebp-0x4] 649 | p[0] = 0x50; 650 | p += 1; 651 | //push eax 652 | p[0] = 0x68; 653 | *(int*)(p + 1) = pFunction + IID_ICLRMetaHostOffset; 654 | p += 5; 655 | //push dword pIID_ICLRMetaHost 656 | p[0] = 0x68; 657 | *(int*)(p + 1) = pFunction + CLSID_CLRMetaHostOffset; 658 | p += 5; 659 | //push dword pCLSID_CLRMetaHost 660 | p[0] = 0xB9; 661 | *(int*)(p + 1) = pCLRCreateInstance; 662 | p += 5; 663 | //mov ecx,pCLRCreateInstance 664 | p[0] = 0xFF; 665 | p[1] = 0xD1; 666 | p += 2; 667 | //call ecx 668 | #endregion 669 | #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); 670 | p[0] = 0x8D; 671 | p[1] = 0x45; 672 | p[2] = 0xF8; 673 | p += 3; 674 | //lea eax,[ebp-0x8] 675 | p[0] = 0x50; 676 | p += 1; 677 | //push eax 678 | p[0] = 0x68; 679 | *(int*)(p + 1) = pFunction + IID_ICLRRuntimeInfoOffset; 680 | p += 5; 681 | //push dword pIID_ICLRRuntimeInfo 682 | p[0] = 0x68; 683 | *(int*)(p + 1) = pFunction + CLRVersionOffset; 684 | p += 5; 685 | //push dword pCLRVersion 686 | p[0] = 0x8B; 687 | p[1] = 0x4D; 688 | p[2] = 0xFC; 689 | p += 3; 690 | //mov ecx,[ebp-0x4] 691 | p[0] = 0x8B; 692 | p[1] = 0x11; 693 | p += 2; 694 | //mov edx,[ecx] 695 | p[0] = 0x8B; 696 | p[1] = 0x45; 697 | p[2] = 0xFC; 698 | p += 3; 699 | //mov eax,[ebp-0x4] 700 | p[0] = 0x50; 701 | p += 1; 702 | //push eax 703 | p[0] = 0x8B; 704 | p[1] = 0x4A; 705 | p[2] = 0x0C; 706 | p += 3; 707 | //mov ecx,[edx+0xc] 708 | p[0] = 0xFF; 709 | p[1] = 0xD1; 710 | p += 2; 711 | //call ecx 712 | #endregion 713 | #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost); 714 | p[0] = 0x8D; 715 | p[1] = 0x45; 716 | p[2] = 0xF4; 717 | p += 3; 718 | //lea eax,[ebp-0xc] 719 | p[0] = 0x50; 720 | p += 1; 721 | //push eax 722 | p[0] = 0x68; 723 | *(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset; 724 | p += 5; 725 | //push dword pIID_ICLRRuntimeHost 726 | p[0] = 0x68; 727 | *(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset; 728 | p += 5; 729 | //push dword pCLSID_CLRRuntimeHost 730 | p[0] = 0x8B; 731 | p[1] = 0x4D; 732 | p[2] = 0xF8; 733 | p += 3; 734 | //mov ecx,[ebp-0x8] 735 | p[0] = 0x8B; 736 | p[1] = 0x11; 737 | p += 2; 738 | //mov edx,[ecx] 739 | p[0] = 0x8B; 740 | p[1] = 0x45; 741 | p[2] = 0xF8; 742 | p += 3; 743 | //mov eax,[ebp-0x8] 744 | p[0] = 0x50; 745 | p += 1; 746 | //push eax 747 | p[0] = 0x8B; 748 | p[1] = 0x4A; 749 | p[2] = 0x24; 750 | p += 3; 751 | //mov ecx,[edx+0x24] 752 | p[0] = 0xFF; 753 | p[1] = 0xD1; 754 | p += 2; 755 | //call ecx 756 | #endregion 757 | #region pRuntimeHost->Start(); 758 | p[0] = 0x8B; 759 | p[1] = 0x45; 760 | p[2] = 0xF4; 761 | p += 3; 762 | //mov eax,[ebp-0xc] 763 | p[0] = 0x8B; 764 | p[1] = 0x08; 765 | p += 2; 766 | //mov ecx,[eax] 767 | p[0] = 0x8B; 768 | p[1] = 0x55; 769 | p[2] = 0xF4; 770 | p += 3; 771 | //mov edx,[ebp-0xc] 772 | p[0] = 0x52; 773 | p += 1; 774 | //push edx 775 | p[0] = 0x8B; 776 | p[1] = 0x41; 777 | p[2] = 0x0C; 778 | p += 3; 779 | //mov eax,[ecx+0xc] 780 | p[0] = 0xFF; 781 | p[1] = 0xD0; 782 | p += 2; 783 | //call eax 784 | #endregion 785 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue); 786 | p[0] = 0x8B; 787 | p[1] = 0x45; 788 | p[2] = 0x08; 789 | p += 3; 790 | //mov eax,[ebp+0x8] 791 | p[0] = 0x50; 792 | p += 1; 793 | //push eax 794 | p[0] = 0x68; 795 | *(int*)(p + 1) = pFunction + ArgumentOffset; 796 | p += 5; 797 | //push dword pArgument 798 | p[0] = 0x68; 799 | *(int*)(p + 1) = pFunction + MethodNameOffset; 800 | p += 5; 801 | //push dword pMethodName 802 | p[0] = 0x68; 803 | *(int*)(p + 1) = pFunction + TypeNameOffset; 804 | p += 5; 805 | //push dword pTypeName 806 | p[0] = 0x68; 807 | *(int*)(p + 1) = pFunction + AssemblyPathOffset; 808 | p += 5; 809 | //push dword pAssemblyPath 810 | p[0] = 0x8B; 811 | p[1] = 0x4D; 812 | p[2] = 0xF4; 813 | p += 3; 814 | //mov ecx,[ebp-0xc] 815 | p[0] = 0x8B; 816 | p[1] = 0x11; 817 | p += 2; 818 | //mov edx,[ecx] 819 | p[0] = 0x8B; 820 | p[1] = 0x45; 821 | p[2] = 0xF4; 822 | p += 3; 823 | //mov eax,[ebp-0xc] 824 | p[0] = 0x50; 825 | p += 1; 826 | //push eax 827 | p[0] = 0x8B; 828 | p[1] = 0x4A; 829 | p[2] = 0x2C; 830 | p += 3; 831 | //mov ecx,[edx+0x2c] 832 | p[0] = 0xFF; 833 | p[1] = 0xD1; 834 | p += 2; 835 | //call ecx 836 | #endregion 837 | #region } 838 | p[0] = 0x5F; 839 | p += 1; 840 | //pop edi 841 | p[0] = 0x5E; 842 | p += 1; 843 | //pop esi 844 | p[0] = 0x5B; 845 | p += 1; 846 | //pop ebx 847 | p[0] = 0x89; 848 | p[1] = 0xEC; 849 | p += 2; 850 | //mov esp,ebp 851 | p[0] = 0x5D; 852 | p += 1; 853 | //pop ebp 854 | p[0] = 0xC2; 855 | p[1] = 0x04; 856 | p[2] = 0x00; 857 | p += 3; 858 | //ret 0x4 859 | #endregion 860 | } 861 | 862 | /// 863 | /// 设置启动64位CLR V2的机器码 864 | /// 865 | /// 机器码指针 866 | /// 函数指针 867 | /// CorBindToRuntimeEx的函数指针 868 | private static void SetAsm64V2(byte* p, long pFunction, long pCorBindToRuntimeEx) 869 | { 870 | //HRESULT WINAPI LoadCLR2(DWORD *pReturnValue) 871 | #region { 872 | p[0] = 0x48; 873 | p[1] = 0x89; 874 | p[2] = 0x4C; 875 | p[3] = 0x24; 876 | p[4] = 0x08; 877 | p += 5; 878 | //mov [rsp+0x8],rcx 879 | p[0] = 0x55; 880 | p += 1; 881 | //push rbp 882 | p[0] = 0x48; 883 | p[1] = 0x81; 884 | p[2] = 0xEC; 885 | p[3] = 0x80; 886 | p[4] = 0x00; 887 | p[5] = 0x00; 888 | p[6] = 0x00; 889 | p += 7; 890 | //sub rsp,0x80 891 | p[0] = 0x48; 892 | p[1] = 0x8D; 893 | p[2] = 0x6C; 894 | p[3] = 0x24; 895 | p[4] = 0x30; 896 | p += 5; 897 | //lea rbp,[rsp+0x30] 898 | #endregion 899 | #region ICLRRuntimeHost *pRuntimeHost = nullptr; 900 | p[0] = 0x48; 901 | p[1] = 0xC7; 902 | p[2] = 0x45; 903 | p[3] = 0x00; 904 | p[4] = 0x00; 905 | p[5] = 0x00; 906 | p[6] = 0x00; 907 | p[7] = 0x00; 908 | p += 8; 909 | //mov qword [rbp+0x0],0x0 910 | #endregion 911 | #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost); 912 | p[0] = 0x48; 913 | p[1] = 0x8D; 914 | p[2] = 0x45; 915 | p[3] = 0x00; 916 | p += 4; 917 | //lea rax,[rbp+0x0] 918 | p[0] = 0x48; 919 | p[1] = 0x89; 920 | p[2] = 0x44; 921 | p[3] = 0x24; 922 | p[4] = 0x28; 923 | p += 5; 924 | //mov [rsp+0x28],rax 925 | p[0] = 0x48; 926 | p[1] = 0xB8; 927 | *(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset; 928 | p += 10; 929 | //mov rax,pIID_ICLRRuntimeHost 930 | p[0] = 0x48; 931 | p[1] = 0x89; 932 | p[2] = 0x44; 933 | p[3] = 0x24; 934 | p[4] = 0x20; 935 | p += 5; 936 | //mov [rsp+0x20],rax 937 | p[0] = 0x49; 938 | p[1] = 0xB9; 939 | *(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset; 940 | p += 10; 941 | //mov r9,pCLSID_CLRRuntimeHost 942 | p[0] = 0x45; 943 | p[1] = 0x31; 944 | p[2] = 0xC0; 945 | p += 3; 946 | //xor r8d,r8d 947 | p[0] = 0x31; 948 | p[1] = 0xD2; 949 | p += 2; 950 | //xor edx,edx 951 | p[0] = 0x48; 952 | p[1] = 0xB9; 953 | *(long*)(p + 2) = pFunction + CLRVersionOffset; 954 | p += 10; 955 | //mov rcx,pCLRVersion 956 | p[0] = 0x49; 957 | p[1] = 0xBF; 958 | *(long*)(p + 2) = pCorBindToRuntimeEx; 959 | p += 10; 960 | //mov r15,pCorBindToRuntimeEx 961 | p[0] = 0x41; 962 | p[1] = 0xFF; 963 | p[2] = 0xD7; 964 | p += 3; 965 | //call r15 966 | #endregion 967 | #region pRuntimeHost->Start(); 968 | p[0] = 0x48; 969 | p[1] = 0x8B; 970 | p[2] = 0x45; 971 | p[3] = 0x00; 972 | p += 4; 973 | //mov rax,[rbp+0x0] 974 | p[0] = 0x48; 975 | p[1] = 0x8B; 976 | p[2] = 0x00; 977 | p += 3; 978 | //mov rax,[rax] 979 | p[0] = 0x48; 980 | p[1] = 0x8B; 981 | p[2] = 0x4D; 982 | p[3] = 0x00; 983 | p += 4; 984 | //mov rcx,[rbp+0x0] 985 | p[0] = 0xFF; 986 | p[1] = 0x50; 987 | p[2] = 0x18; 988 | p += 3; 989 | //call [rax+0x18] 990 | #endregion 991 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue); 992 | p[0] = 0x48; 993 | p[1] = 0x8B; 994 | p[2] = 0x45; 995 | p[3] = 0x00; 996 | p += 4; 997 | //mov rax,[rbp+0x0] 998 | p[0] = 0x48; 999 | p[1] = 0x8B; 1000 | p[2] = 0x00; 1001 | p += 3; 1002 | //mov rax,[rax] 1003 | p[0] = 0x48; 1004 | p[1] = 0x8B; 1005 | p[2] = 0x4D; 1006 | p[3] = 0x60; 1007 | p += 4; 1008 | //mov rcx,[rbp+0x60] 1009 | p[0] = 0x48; 1010 | p[1] = 0x89; 1011 | p[2] = 0x4C; 1012 | p[3] = 0x24; 1013 | p[4] = 0x28; 1014 | p += 5; 1015 | //mov [rsp+0x28],rcx 1016 | p[0] = 0x48; 1017 | p[1] = 0xB9; 1018 | *(long*)(p + 2) = pFunction + ArgumentOffset; 1019 | p += 10; 1020 | //mov rcx,pArgument 1021 | p[0] = 0x48; 1022 | p[1] = 0x89; 1023 | p[2] = 0x4C; 1024 | p[3] = 0x24; 1025 | p[4] = 0x20; 1026 | p += 5; 1027 | //mov [rsp+0x20],rcx 1028 | p[0] = 0x49; 1029 | p[1] = 0xB9; 1030 | *(long*)(p + 2) = pFunction + MethodNameOffset; 1031 | p += 10; 1032 | //mov r9,pMethodName 1033 | p[0] = 0x49; 1034 | p[1] = 0xB8; 1035 | *(long*)(p + 2) = pFunction + TypeNameOffset; 1036 | p += 10; 1037 | //mov r8,pTypeName 1038 | p[0] = 0x48; 1039 | p[1] = 0xBA; 1040 | *(long*)(p + 2) = pFunction + AssemblyPathOffset; 1041 | p += 10; 1042 | //mov rdx,pAssemblyPath 1043 | p[0] = 0x48; 1044 | p[1] = 0x8B; 1045 | p[2] = 0x4D; 1046 | p[3] = 0x00; 1047 | p += 4; 1048 | //mov rcx,[rbp+0x0] 1049 | p[0] = 0xFF; 1050 | p[1] = 0x50; 1051 | p[2] = 0x58; 1052 | p += 3; 1053 | //call [rax+0x58] 1054 | #endregion 1055 | #region } 1056 | p[0] = 0x48; 1057 | p[1] = 0x8D; 1058 | p[2] = 0x65; 1059 | p[3] = 0x50; 1060 | p += 4; 1061 | //lea rsp,[rbp+0x50] 1062 | p[0] = 0x5D; 1063 | p += 1; 1064 | //pop rbp 1065 | p[0] = 0xC3; 1066 | p += 1; 1067 | //ret 1068 | #endregion 1069 | } 1070 | 1071 | /// 1072 | /// 设置启动64位CLR V4的机器码 1073 | /// 1074 | /// 机器码指针 1075 | /// 函数指针 1076 | /// CLRCreateInstance的函数指针 1077 | private static void SetAsm64V4(byte* p, long pFunction, long pCLRCreateInstance) 1078 | { 1079 | //HRESULT WINAPI LoadCLR4(DWORD *pReturnValue) 1080 | #region { 1081 | p[0] = 0x48; 1082 | p[1] = 0x89; 1083 | p[2] = 0x4C; 1084 | p[3] = 0x24; 1085 | p[4] = 0x08; 1086 | p += 5; 1087 | //mov [rsp+0x8],rcx 1088 | p[0] = 0x55; 1089 | p += 1; 1090 | //push rbp 1091 | p[0] = 0x48; 1092 | p[1] = 0x81; 1093 | p[2] = 0xEC; 1094 | p[3] = 0x90; 1095 | p[4] = 0x00; 1096 | p[5] = 0x00; 1097 | p[6] = 0x00; 1098 | p += 7; 1099 | //sub rsp,0x90 1100 | p[0] = 0x48; 1101 | p[1] = 0x8D; 1102 | p[2] = 0x6C; 1103 | p[3] = 0x24; 1104 | p[4] = 0x30; 1105 | p += 5; 1106 | //lea rbp,[rsp+0x30] 1107 | #endregion 1108 | #region ICLRMetaHost *pMetaHost = nullptr; 1109 | p[0] = 0x48; 1110 | p[1] = 0xC7; 1111 | p[2] = 0x45; 1112 | p[3] = 0x00; 1113 | p[4] = 0x00; 1114 | p[5] = 0x00; 1115 | p[6] = 0x00; 1116 | p[7] = 0x00; 1117 | p += 8; 1118 | //mov qword [rbp+0x0],0x0 1119 | #endregion 1120 | #region ICLRRuntimeInfo *pRuntimeInfo = nullptr; 1121 | p[0] = 0x48; 1122 | p[1] = 0xC7; 1123 | p[2] = 0x45; 1124 | p[3] = 0x08; 1125 | p[4] = 0x00; 1126 | p[5] = 0x00; 1127 | p[6] = 0x00; 1128 | p[7] = 0x00; 1129 | p += 8; 1130 | //mov qword [rbp+0x8],0x0 1131 | #endregion 1132 | #region ICLRRuntimeHost *pRuntimeHost = nullptr; 1133 | p[0] = 0x48; 1134 | p[1] = 0xC7; 1135 | p[2] = 0x45; 1136 | p[3] = 0x10; 1137 | p[4] = 0x00; 1138 | p[5] = 0x00; 1139 | p[6] = 0x00; 1140 | p[7] = 0x00; 1141 | p += 8; 1142 | //mov qword [rbp+0x10],0x0 1143 | #endregion 1144 | #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 1145 | p[0] = 0x4C; 1146 | p[1] = 0x8D; 1147 | p[2] = 0x45; 1148 | p[3] = 0x00; 1149 | p += 4; 1150 | //lea r8,[rbp+0x0] 1151 | p[0] = 0x48; 1152 | p[1] = 0xBA; 1153 | *(long*)(p + 2) = pFunction + IID_ICLRMetaHostOffset; 1154 | p += 10; 1155 | //mov rdx,pIID_ICLRMetaHost 1156 | p[0] = 0x48; 1157 | p[1] = 0xB9; 1158 | *(long*)(p + 2) = pFunction + CLSID_CLRMetaHostOffset; 1159 | p += 10; 1160 | //mov rcx,pCLSID_CLRMetaHost 1161 | p[0] = 0x49; 1162 | p[1] = 0xBF; 1163 | *(long*)(p + 2) = pCLRCreateInstance; 1164 | p += 10; 1165 | //mov r15,pCLRCreateInstance 1166 | p[0] = 0x41; 1167 | p[1] = 0xFF; 1168 | p[2] = 0xD7; 1169 | p += 3; 1170 | //call r15 1171 | #endregion 1172 | #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); 1173 | p[0] = 0x48; 1174 | p[1] = 0x8B; 1175 | p[2] = 0x45; 1176 | p[3] = 0x00; 1177 | p += 4; 1178 | //mov rax,[rbp+0x0] 1179 | p[0] = 0x48; 1180 | p[1] = 0x8B; 1181 | p[2] = 0x00; 1182 | p += 3; 1183 | //mov rax,[rax] 1184 | p[0] = 0x4C; 1185 | p[1] = 0x8D; 1186 | p[2] = 0x4D; 1187 | p[3] = 0x08; 1188 | p += 4; 1189 | //lea r9,[rbp+0x8] 1190 | p[0] = 0x49; 1191 | p[1] = 0xB8; 1192 | *(long*)(p + 2) = pFunction + IID_ICLRRuntimeInfoOffset; 1193 | p += 10; 1194 | //mov r8,pIID_ICLRRuntimeInfo 1195 | p[0] = 0x48; 1196 | p[1] = 0xBA; 1197 | *(long*)(p + 2) = pFunction + CLRVersionOffset; 1198 | p += 10; 1199 | //mov rdx,pCLRVersion 1200 | p[0] = 0x48; 1201 | p[1] = 0x8B; 1202 | p[2] = 0x4D; 1203 | p[3] = 0x00; 1204 | p += 4; 1205 | //mov rcx,[rbp+0x0] 1206 | p[0] = 0xFF; 1207 | p[1] = 0x50; 1208 | p[2] = 0x18; 1209 | p += 3; 1210 | //call [rax+0x18] 1211 | #endregion 1212 | #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost); 1213 | p[0] = 0x48; 1214 | p[1] = 0x8B; 1215 | p[2] = 0x45; 1216 | p[3] = 0x08; 1217 | p += 4; 1218 | //mov rax,[rbp+0x8] 1219 | p[0] = 0x48; 1220 | p[1] = 0x8B; 1221 | p[2] = 0x00; 1222 | p += 3; 1223 | //mov rax,[rax] 1224 | p[0] = 0x4C; 1225 | p[1] = 0x8D; 1226 | p[2] = 0x4D; 1227 | p[3] = 0x10; 1228 | p += 4; 1229 | //lea r9,[rbp+0x10] 1230 | p[0] = 0x49; 1231 | p[1] = 0xB8; 1232 | *(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset; 1233 | p += 10; 1234 | //mov r8,pIID_ICLRRuntimeHost 1235 | p[0] = 0x48; 1236 | p[1] = 0xBA; 1237 | *(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset; 1238 | p += 10; 1239 | //mov rdx,pCLSID_CLRRuntimeHost 1240 | p[0] = 0x48; 1241 | p[1] = 0x8B; 1242 | p[2] = 0x4D; 1243 | p[3] = 0x08; 1244 | p += 4; 1245 | //mov rcx,[rbp+0x8] 1246 | p[0] = 0xFF; 1247 | p[1] = 0x50; 1248 | p[2] = 0x48; 1249 | p += 3; 1250 | //call [rax+0x48] 1251 | #endregion 1252 | #region pRuntimeHost->Start(); 1253 | p[0] = 0x48; 1254 | p[1] = 0x8B; 1255 | p[2] = 0x45; 1256 | p[3] = 0x10; 1257 | p += 4; 1258 | //mov rax,[rbp+0x10] 1259 | p[0] = 0x48; 1260 | p[1] = 0x8B; 1261 | p[2] = 0x00; 1262 | p += 3; 1263 | //mov rax,[rax] 1264 | p[0] = 0x48; 1265 | p[1] = 0x8B; 1266 | p[2] = 0x4D; 1267 | p[3] = 0x10; 1268 | p += 4; 1269 | //mov rcx,[rbp+0x10] 1270 | p[0] = 0xFF; 1271 | p[1] = 0x50; 1272 | p[2] = 0x18; 1273 | p += 3; 1274 | //call [rax+0x18] 1275 | #endregion 1276 | #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue); 1277 | p[0] = 0x48; 1278 | p[1] = 0x8B; 1279 | p[2] = 0x45; 1280 | p[3] = 0x10; 1281 | p += 4; 1282 | //mov rax,[rbp+0x10] 1283 | p[0] = 0x48; 1284 | p[1] = 0x8B; 1285 | p[2] = 0x00; 1286 | p += 3; 1287 | //mov rax,[rax] 1288 | p[0] = 0x48; 1289 | p[1] = 0x8B; 1290 | p[2] = 0x4D; 1291 | p[3] = 0x70; 1292 | p += 4; 1293 | //mov rcx,[rbp+0x70] 1294 | p[0] = 0x48; 1295 | p[1] = 0x89; 1296 | p[2] = 0x4C; 1297 | p[3] = 0x24; 1298 | p[4] = 0x28; 1299 | p += 5; 1300 | //mov [rsp+0x28],rcx 1301 | p[0] = 0x48; 1302 | p[1] = 0xB9; 1303 | *(long*)(p + 2) = pFunction + ArgumentOffset; 1304 | p += 10; 1305 | //mov rcx,pArgument 1306 | p[0] = 0x48; 1307 | p[1] = 0x89; 1308 | p[2] = 0x4C; 1309 | p[3] = 0x24; 1310 | p[4] = 0x20; 1311 | p += 5; 1312 | //mov [rsp+0x20],rcx 1313 | p[0] = 0x49; 1314 | p[1] = 0xB9; 1315 | *(long*)(p + 2) = pFunction + MethodNameOffset; 1316 | p += 10; 1317 | //mov r9,pMethodName 1318 | p[0] = 0x49; 1319 | p[1] = 0xB8; 1320 | *(long*)(p + 2) = pFunction + TypeNameOffset; 1321 | p += 10; 1322 | //mov r8,pTypeName 1323 | p[0] = 0x48; 1324 | p[1] = 0xBA; 1325 | *(long*)(p + 2) = pFunction + AssemblyPathOffset; 1326 | p += 10; 1327 | //mov rdx,pAssemblyPath 1328 | p[0] = 0x48; 1329 | p[1] = 0x8B; 1330 | p[2] = 0x4D; 1331 | p[3] = 0x10; 1332 | p += 4; 1333 | //mov rcx,[rbp+0x10] 1334 | p[0] = 0xFF; 1335 | p[1] = 0x50; 1336 | p[2] = 0x58; 1337 | p += 3; 1338 | //call [rax+0x58] 1339 | #endregion 1340 | #region } 1341 | p[0] = 0x48; 1342 | p[1] = 0x8D; 1343 | p[2] = 0x65; 1344 | p[3] = 0x60; 1345 | p += 4; 1346 | //lea rsp,[rbp+0x60] 1347 | p[0] = 0x5D; 1348 | p += 1; 1349 | //pop rbp 1350 | p[0] = 0xC3; 1351 | p += 1; 1352 | //ret 1353 | #endregion 1354 | } 1355 | 1356 | /// 1357 | /// 判断是否为程序集,如果是,输出CLR版本 1358 | /// 1359 | /// 路径 1360 | /// 是否程序集 1361 | /// CLR版本 1362 | private static void IsAssembly(string path, out bool isAssembly, out string clrVersion) 1363 | { 1364 | BinaryReader binaryReader; 1365 | 1366 | try 1367 | { 1368 | using (binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read))) 1369 | clrVersion = GetVersionString(binaryReader); 1370 | isAssembly = true; 1371 | } 1372 | catch 1373 | { 1374 | clrVersion = null; 1375 | isAssembly = false; 1376 | } 1377 | } 1378 | 1379 | /// 1380 | /// 获取CLR版本 1381 | /// 1382 | /// 1383 | /// 1384 | private static string GetVersionString(BinaryReader binaryReader) 1385 | { 1386 | uint peOffset; 1387 | bool is64; 1388 | Section[] sections; 1389 | uint rva; 1390 | Section? section; 1391 | 1392 | GetPEInfo(binaryReader, out peOffset, out is64); 1393 | binaryReader.BaseStream.Position = peOffset + (is64 ? 0xF8 : 0xE8); 1394 | rva = binaryReader.ReadUInt32(); 1395 | //.Net MetaData Directory RVA 1396 | if (rva == 0) 1397 | throw new BadImageFormatException("文件不是程序集"); 1398 | sections = GetSections(binaryReader); 1399 | section = GetSection(rva, sections); 1400 | if (section == null) 1401 | throw new InvalidDataException("未知格式的二进制文件"); 1402 | binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0x8; 1403 | //.Net MetaData Directory FileOffset 1404 | rva = binaryReader.ReadUInt32(); 1405 | //.Net MetaData RVA 1406 | if (rva == 0) 1407 | throw new BadImageFormatException("文件不是程序集"); 1408 | section = GetSection(rva, sections); 1409 | if (section == null) 1410 | throw new InvalidDataException("未知格式的二进制文件"); 1411 | binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0xC; 1412 | //.Net MetaData FileOffset 1413 | return Encoding.UTF8.GetString(binaryReader.ReadBytes(binaryReader.ReadInt32() - 2)); 1414 | } 1415 | 1416 | /// 1417 | /// 获取PE信息 1418 | /// 1419 | /// 1420 | /// 1421 | /// 1422 | private static void GetPEInfo(BinaryReader binaryReader, out uint peOffset, out bool is64) 1423 | { 1424 | ushort machine; 1425 | 1426 | binaryReader.BaseStream.Position = 0x3C; 1427 | peOffset = binaryReader.ReadUInt32(); 1428 | binaryReader.BaseStream.Position = peOffset + 0x4; 1429 | machine = binaryReader.ReadUInt16(); 1430 | if (machine != 0x14C && machine != 0x8664) 1431 | throw new InvalidDataException("未知格式的二进制文件"); 1432 | is64 = machine == 0x8664; 1433 | } 1434 | 1435 | /// 1436 | /// 获取节 1437 | /// 1438 | /// 1439 | /// 1440 | private static Section[] GetSections(BinaryReader binaryReader) 1441 | { 1442 | uint ntHeaderOffset; 1443 | bool is64; 1444 | ushort numberOfSections; 1445 | Section[] sections; 1446 | 1447 | GetPEInfo(binaryReader, out ntHeaderOffset, out is64); 1448 | numberOfSections = binaryReader.ReadUInt16(); 1449 | binaryReader.BaseStream.Position = ntHeaderOffset + (is64 ? 0x108 : 0xF8); 1450 | sections = new Section[numberOfSections]; 1451 | for (int i = 0; i < numberOfSections; i++) 1452 | { 1453 | binaryReader.BaseStream.Position += 0x8; 1454 | sections[i] = new Section(binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32()); 1455 | binaryReader.BaseStream.Position += 0x10; 1456 | } 1457 | return sections; 1458 | } 1459 | 1460 | /// 1461 | /// 获取RVA对应节 1462 | /// 1463 | /// 1464 | /// 1465 | /// 1466 | private static Section? GetSection(uint rva, Section[] sections) 1467 | { 1468 | foreach (Section section in sections) 1469 | if (rva >= section.VirtualAddress && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData)) 1470 | return section; 1471 | return null; 1472 | } 1473 | } 1474 | } 1475 | -------------------------------------------------------------------------------- /FastWin32/Diagnostics/Module32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using FastWin32.Memory; 4 | using static FastWin32.NativeMethods; 5 | using size_t = System.IntPtr; 6 | 7 | namespace FastWin32.Diagnostics 8 | { 9 | /// 10 | /// 遍历模块回调方法,要继续遍历,返回true;要停止遍历,返回false 11 | /// 12 | /// 模块句柄 13 | /// 模块名 14 | /// 模块文件所在路径 15 | /// 16 | public delegate bool EnumModulesCallback(IntPtr moduleHandle, string moduleName, string filePath); 17 | 18 | /// 19 | /// 遍历模块导出函数回调方法,要继续遍历,返回true;要停止遍历,返回false 20 | /// 21 | /// 函数指针 22 | /// 函数名,当函数以序号方式导出时,此参数为null 23 | /// 函数导出序号 24 | /// 25 | public delegate bool EnumFunctionsCallback(IntPtr pFunction, string functionName, short ordinal); 26 | 27 | /// 28 | /// 模块 29 | /// 30 | public static unsafe class Module32 31 | { 32 | /// 33 | /// 打开进程(内存读+查询) 34 | /// 35 | /// 进程ID 36 | /// 37 | private static SafeNativeHandle OpenProcessVMReadQuery(uint processId) 38 | { 39 | return SafeOpenProcess(FastWin32Settings.SeDebugPrivilege ? PROCESS_ALL_ACCESS : PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, false, processId); 40 | } 41 | 42 | /// 43 | /// 获取当前进程主模块句柄 44 | /// 45 | /// 46 | public static IntPtr GetHandle() 47 | { 48 | return GetModuleHandle(null); 49 | } 50 | 51 | /// 52 | /// 获取当前进程模块句柄,获取失败时返回 53 | /// 54 | /// 模块名 55 | /// 56 | public static IntPtr GetHandle(string moduleName) 57 | { 58 | if (string.IsNullOrEmpty(moduleName)) 59 | throw new ArgumentNullException(); 60 | 61 | return GetModuleHandle(moduleName); 62 | } 63 | 64 | /// 65 | /// 获取主模块句柄,获取失败时返回 66 | /// 67 | /// 进程ID 68 | /// 69 | public static IntPtr GetHandle(uint processId) 70 | { 71 | SafeNativeHandle processHandle; 72 | 73 | using (processHandle = OpenProcessVMReadQuery(processId)) 74 | if (processHandle.IsValid) 75 | return GetHandleInternal(processHandle, true, null); 76 | else 77 | return IntPtr.Zero; 78 | } 79 | 80 | /// 81 | /// 获取模块句柄,获取失败时返回 82 | /// 83 | /// 进程ID 84 | /// 模块名 85 | /// 86 | public static IntPtr GetHandle(uint processId, string moduleName) 87 | { 88 | if (string.IsNullOrEmpty(moduleName)) 89 | throw new ArgumentNullException(); 90 | 91 | SafeNativeHandle processHandle; 92 | 93 | using (processHandle = OpenProcessVMReadQuery(processId)) 94 | if (processHandle.IsValid) 95 | return GetHandleInternal(processHandle, false, moduleName); 96 | else 97 | return IntPtr.Zero; 98 | } 99 | 100 | /// 101 | /// 获取模块句柄,获取失败时返回 102 | /// 103 | /// 进程句柄 104 | /// 是否返回第一个模块句柄 105 | /// 模块名 106 | /// 107 | internal static IntPtr GetHandleInternal(IntPtr processHandle, bool first, string moduleName) 108 | { 109 | bool is64; 110 | bool isXP; 111 | IntPtr moduleHandle; 112 | uint size; 113 | IntPtr[] moduleHandles; 114 | StringBuilder moduleNameBuffer; 115 | 116 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 117 | return IntPtr.Zero; 118 | isXP = Environment.OSVersion.Version.Major == 5; 119 | if (isXP) 120 | { 121 | //XP兼容 122 | if (!EnumProcessModules(processHandle, &moduleHandle, (uint)IntPtr.Size, out size)) 123 | return IntPtr.Zero; 124 | } 125 | else 126 | { 127 | if (!EnumProcessModulesEx(processHandle, &moduleHandle, (uint)IntPtr.Size, out size, is64 ? LIST_MODULES_64BIT : LIST_MODULES_32BIT)) 128 | //先获取储存所有模块句柄所需的字节数 129 | return IntPtr.Zero; 130 | } 131 | if (first) 132 | //返回第一个模块句柄 133 | return moduleHandle; 134 | moduleHandles = new IntPtr[size / IntPtr.Size]; 135 | fixed (IntPtr* p = &moduleHandles[0]) 136 | if (isXP) 137 | { 138 | //XP兼容 139 | if (!EnumProcessModules(processHandle, p, size, out size)) 140 | return IntPtr.Zero; 141 | } 142 | else 143 | { 144 | if (!EnumProcessModulesEx(processHandle, p, size, out size, is64 ? LIST_MODULES_64BIT : LIST_MODULES_32BIT)) 145 | //获取所有模块句柄 146 | return IntPtr.Zero; 147 | } 148 | moduleNameBuffer = new StringBuilder((int)MAX_MODULE_NAME32); 149 | for (int i = 0; i < moduleHandles.Length; i++) 150 | { 151 | if (!GetModuleBaseName(processHandle, moduleHandles[i], moduleNameBuffer, MAX_MODULE_NAME32)) 152 | return IntPtr.Zero; 153 | if (moduleNameBuffer.ToString().Equals(moduleName, StringComparison.OrdinalIgnoreCase)) 154 | return moduleHandles[i]; 155 | } 156 | return IntPtr.Zero; 157 | } 158 | 159 | /// 160 | /// 遍历模块,遍历成功返回true,失败返回false(返回值与回调方法的返回值无关) 161 | /// 162 | /// 进程ID 163 | /// 回调方法,不能为空 164 | /// 是否向回调方法提供模块名,默认为是 165 | /// 是否向回调方法提供模块文件路径,默认为否 166 | /// 167 | public static bool EnumModules(uint processId, EnumModulesCallback callback, bool getModuleName = true, bool getFilePath = false) 168 | { 169 | if (callback == null) 170 | throw new ArgumentNullException(); 171 | 172 | SafeNativeHandle processHandle; 173 | bool is64; 174 | bool isXP; 175 | IntPtr moduleHandle; 176 | uint size; 177 | IntPtr[] moduleHandles; 178 | StringBuilder moduleName; 179 | StringBuilder filePath; 180 | 181 | using (processHandle = OpenProcessVMReadQuery(processId)) 182 | if (processHandle.IsValid) 183 | { 184 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 185 | return false; 186 | isXP = Environment.OSVersion.Version.Major == 5; 187 | if (isXP) 188 | { 189 | //XP兼容 190 | if (!EnumProcessModules(processHandle, &moduleHandle, (uint)IntPtr.Size, out size)) 191 | return false; 192 | } 193 | else 194 | { 195 | if (!EnumProcessModulesEx(processHandle, &moduleHandle, (uint)IntPtr.Size, out size, is64 ? LIST_MODULES_64BIT : LIST_MODULES_32BIT)) 196 | //先获取储存所有模块句柄所需的字节数 197 | return false; 198 | } 199 | moduleHandles = new IntPtr[size / IntPtr.Size]; 200 | fixed (IntPtr* p = &moduleHandles[0]) 201 | if (isXP) 202 | { 203 | //XP兼容 204 | if (!EnumProcessModules(processHandle, p, size, out size)) 205 | return false; 206 | } 207 | else 208 | { 209 | if (!EnumProcessModulesEx(processHandle, p, size, out size, is64 ? LIST_MODULES_64BIT : LIST_MODULES_32BIT)) 210 | //获取所有模块句柄 211 | return false; 212 | } 213 | moduleName = getModuleName ? new StringBuilder((int)MAX_MODULE_NAME32) : null; 214 | filePath = getFilePath ? new StringBuilder((int)MAX_PATH) : null; 215 | for (int i = 0; i < moduleHandles.Length; i++) 216 | { 217 | if (getModuleName && !GetModuleBaseName(processHandle, moduleHandles[i], moduleName, MAX_MODULE_NAME32)) 218 | return false; 219 | if (getFilePath && GetModuleFileName(processHandle, filePath, MAX_PATH) == 0) 220 | return false; 221 | if (!callback(moduleHandles[i], getModuleName ? moduleName.ToString() : null, getFilePath ? filePath.ToString() : null)) 222 | return true; 223 | } 224 | return true; 225 | } 226 | else 227 | return false; 228 | } 229 | 230 | /// 231 | /// 获取函数地址 232 | /// 233 | /// 模块名 234 | /// 函数名 235 | /// 236 | public static IntPtr GetProcAddress(string moduleName, string functionName) 237 | { 238 | if (string.IsNullOrEmpty(moduleName)) 239 | throw new ArgumentNullException(); 240 | if (string.IsNullOrEmpty(functionName)) 241 | throw new ArgumentNullException(); 242 | 243 | return GetProcAddressInternal(moduleName, functionName); 244 | } 245 | 246 | /// 247 | /// 获取远程进程函数地址 248 | /// 249 | /// 进程ID 250 | /// 模块名 251 | /// 函数名 252 | /// 253 | public static IntPtr GetProcAddress(uint processId, string moduleName, string functionName) 254 | { 255 | if (string.IsNullOrEmpty(moduleName)) 256 | throw new ArgumentNullException(); 257 | if (string.IsNullOrEmpty(functionName)) 258 | throw new ArgumentNullException(); 259 | 260 | SafeNativeHandle processHandle; 261 | 262 | using (processHandle = OpenProcessVMReadQuery(processId)) 263 | if (processHandle.IsValid) 264 | return GetProcAddressInternal(processHandle, moduleName, functionName); 265 | else 266 | return IntPtr.Zero; 267 | } 268 | 269 | /// 270 | /// 获取函数地址 271 | /// 272 | /// 模块名 273 | /// 函数名 274 | /// 275 | internal static IntPtr GetProcAddressInternal(string moduleName, string functionName) 276 | { 277 | IntPtr moduleHandle; 278 | 279 | moduleHandle = GetModuleHandle(moduleName); 280 | if (moduleHandle == IntPtr.Zero) 281 | return IntPtr.Zero; 282 | return NativeMethods.GetProcAddress(moduleHandle, functionName); 283 | } 284 | 285 | /// 286 | /// 获取远程进程函数地址 287 | /// 288 | /// 进程句柄 289 | /// 模块名 290 | /// 函数名 291 | /// 292 | internal static IntPtr GetProcAddressInternal(IntPtr processHandle, string moduleName, string functionName) 293 | { 294 | IntPtr moduleHandle; 295 | int ntHeaderOffset; 296 | bool is64; 297 | int iedRVA; 298 | IMAGE_EXPORT_DIRECTORY ied; 299 | int[] nameOffsets; 300 | string name; 301 | short ordinal; 302 | int addressOffset; 303 | 304 | moduleHandle = GetHandleInternal(processHandle, false, moduleName); 305 | if (moduleHandle == IntPtr.Zero) 306 | return IntPtr.Zero; 307 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + 0x3C, out ntHeaderOffset)) 308 | return IntPtr.Zero; 309 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 310 | return IntPtr.Zero; 311 | if (is64) 312 | { 313 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x88, out iedRVA)) 314 | return IntPtr.Zero; 315 | } 316 | else 317 | { 318 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x78, out iedRVA)) 319 | return IntPtr.Zero; 320 | } 321 | if (!ReadProcessMemory(processHandle, moduleHandle + iedRVA, &ied, (size_t)40, null)) 322 | return IntPtr.Zero; 323 | nameOffsets = new int[ied.NumberOfNames]; 324 | fixed (void* p = &nameOffsets[0]) 325 | if (!ReadProcessMemory(processHandle, moduleHandle + (int)ied.AddressOfNames, p, (size_t)(ied.NumberOfNames * 4), null)) 326 | return IntPtr.Zero; 327 | for (int i = 0; i < ied.NumberOfNames; i++) 328 | { 329 | if (!MemoryIO.ReadStringInternal(processHandle, moduleHandle + nameOffsets[i], out name, 40, false, Encoding.ASCII)) 330 | return IntPtr.Zero; 331 | if (name == functionName) 332 | { 333 | if (!MemoryIO.ReadInt16Internal(processHandle, moduleHandle + (int)ied.AddressOfNameOrdinals + i * 2, out ordinal)) 334 | return IntPtr.Zero; 335 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + (int)ied.AddressOfFunctions + ordinal * 4, out addressOffset)) 336 | return IntPtr.Zero; 337 | return moduleHandle + addressOffset; 338 | } 339 | } 340 | return IntPtr.Zero; 341 | } 342 | 343 | /// 344 | /// 枚举模块导出函数 345 | /// 346 | /// 进程ID 347 | /// 模块名 348 | /// 回调函数 349 | /// 350 | public static bool EnumFunctions(uint processId, string moduleName, EnumFunctionsCallback callback) 351 | { 352 | if (string.IsNullOrEmpty(moduleName)) 353 | throw new ArgumentNullException(); 354 | if (callback == null) 355 | throw new ArgumentNullException(); 356 | 357 | SafeNativeHandle processHandle; 358 | 359 | using (processHandle = OpenProcessVMReadQuery(processId)) 360 | if (processHandle.IsValid) 361 | return EnumFunctionsInternal(processHandle, moduleName, callback); 362 | else 363 | return false; 364 | } 365 | 366 | /// 367 | /// 枚举模块导出函数 368 | /// 369 | /// 进程ID 370 | /// 模块句柄 371 | /// 回调函数 372 | /// 373 | public static bool EnumFunctions(uint processId, IntPtr moduleHandle, EnumFunctionsCallback callback) 374 | { 375 | if (callback == null) 376 | throw new ArgumentNullException(); 377 | 378 | SafeNativeHandle processHandle; 379 | 380 | using (processHandle = OpenProcessVMReadQuery(processId)) 381 | if (processHandle.IsValid) 382 | return EnumFunctionsInternal(processHandle, moduleHandle, callback); 383 | else 384 | return false; 385 | } 386 | 387 | /// 388 | /// 枚举模块导出函数 389 | /// 390 | /// 进程句柄 391 | /// 模块名 392 | /// 回调函数 393 | /// 394 | internal static bool EnumFunctionsInternal(IntPtr processHandle, string moduleName, EnumFunctionsCallback callback) 395 | { 396 | IntPtr moduleHandle; 397 | 398 | moduleHandle = GetHandleInternal(processHandle, false, moduleName); 399 | if (moduleHandle == IntPtr.Zero) 400 | return false; 401 | return EnumFunctionsInternal(processHandle, moduleHandle, callback); 402 | } 403 | 404 | /// 405 | /// 枚举模块导出函数 406 | /// 407 | /// 进程句柄 408 | /// 模块句柄 409 | /// 回调函数 410 | /// 411 | internal static bool EnumFunctionsInternal(IntPtr processHandle, IntPtr moduleHandle, EnumFunctionsCallback callback) 412 | { 413 | int ntHeaderOffset; 414 | bool is64; 415 | int iedRVA; 416 | IMAGE_EXPORT_DIRECTORY ied; 417 | int[] nameOffsets; 418 | string functionName; 419 | short ordinal; 420 | int addressOffset; 421 | 422 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + 0x3C, out ntHeaderOffset)) 423 | return false; 424 | if (!Process32.Is64BitProcessInternal(processHandle, out is64)) 425 | return false; 426 | if (is64) 427 | { 428 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x88, out iedRVA)) 429 | return false; 430 | } 431 | else 432 | { 433 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x78, out iedRVA)) 434 | return false; 435 | } 436 | if (!ReadProcessMemory(processHandle, moduleHandle + iedRVA, &ied, (size_t)40, null)) 437 | return false; 438 | if (ied.NumberOfNames == 0) 439 | //无按名称导出函数 440 | return true; 441 | nameOffsets = new int[ied.NumberOfNames]; 442 | fixed (void* p = &nameOffsets[0]) 443 | if (!ReadProcessMemory(processHandle, moduleHandle + (int)ied.AddressOfNames, p, (size_t)(ied.NumberOfNames * 4), null)) 444 | return false; 445 | for (int i = 0; i < ied.NumberOfNames; i++) 446 | { 447 | if (!MemoryIO.ReadStringInternal(processHandle, moduleHandle + nameOffsets[i], out functionName, 40, false, Encoding.ASCII)) 448 | return false; 449 | if (!MemoryIO.ReadInt16Internal(processHandle, moduleHandle + ((int)ied.AddressOfNameOrdinals + i * 2), out ordinal)) 450 | return false; 451 | if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ((int)ied.AddressOfFunctions + ordinal * 4), out addressOffset)) 452 | return false; 453 | if (!callback(moduleHandle + addressOffset, functionName, ordinal)) 454 | return true; 455 | } 456 | return true; 457 | } 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /FastWin32/Diagnostics/Process32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text; 5 | using static FastWin32.NativeMethods; 6 | 7 | namespace FastWin32.Diagnostics 8 | { 9 | /// 10 | /// 进程 11 | /// 12 | public static unsafe class Process32 13 | { 14 | /// 15 | /// 打开进程(内存读+查询) 16 | /// 17 | /// 进程ID 18 | /// 19 | private static SafeNativeHandle OpenProcessQuery(uint processId) 20 | { 21 | return SafeOpenProcess(FastWin32Settings.SeDebugPrivilege ? PROCESS_ALL_ACCESS : PROCESS_QUERY_INFORMATION, false, processId); 22 | } 23 | 24 | /// 25 | /// 打开进程(进程挂起/恢复) 26 | /// 27 | /// 进程ID 28 | /// 29 | private static SafeNativeHandle OpenProcessProcessSuspendResume(uint processId) 30 | { 31 | return SafeOpenProcess(FastWin32Settings.SeDebugPrivilege ? PROCESS_ALL_ACCESS : PROCESS_SUSPEND_RESUME, false, processId); 32 | } 33 | 34 | /// 35 | /// 通过窗口句柄获取进程ID 36 | /// 37 | /// 38 | /// 39 | public static uint GetProcessIdByWindowHandle(IntPtr windowHandle) 40 | { 41 | uint processId; 42 | 43 | GetWindowThreadProcessId(windowHandle, &processId); 44 | return processId; 45 | } 46 | 47 | /// 48 | /// 通过线程ID获取进程ID 49 | /// 50 | /// 线程ID 51 | /// 52 | public static uint GetProcessIdByThreadId(uint threadId) 53 | { 54 | SafeNativeHandle threadHandle; 55 | 56 | using (threadHandle = SafeOpenThread(THREAD_QUERY_INFORMATION, false, threadId)) 57 | if (threadHandle.IsValid) 58 | return GetProcessIdOfThread(threadHandle); 59 | else 60 | return 0; 61 | } 62 | 63 | /// 64 | /// 获取当前进程ID 65 | /// 66 | /// 67 | public static uint GetCurrentProcessId() 68 | { 69 | return NativeMethods.GetCurrentProcessId(); 70 | } 71 | 72 | /// 73 | /// 获取所有进程ID,失败返回null 74 | /// 75 | /// 76 | public static uint[] GetAllProcessIds() 77 | { 78 | uint[] processIds; 79 | uint bytesReturned; 80 | 81 | processIds = null; 82 | do 83 | { 84 | if (processIds == null) 85 | processIds = new uint[0x200]; 86 | else 87 | processIds = new uint[processIds.Length * 2]; 88 | if (!EnumProcesses(ref processIds[0], (uint)(processIds.Length * 4), out bytesReturned)) 89 | return null; 90 | } while (bytesReturned == processIds.Length * 4); 91 | return processIds.Take((int)bytesReturned / 4).ToArray(); 92 | } 93 | 94 | /// 95 | /// 获取进程名 96 | /// 97 | /// 进程ID 98 | /// 99 | public static string GetProcessName(uint processId) 100 | { 101 | SafeNativeHandle processHandle; 102 | 103 | using (processHandle = OpenProcessQuery(processId)) 104 | if (processHandle.IsValid) 105 | return GetProcessNameInternal(processHandle); 106 | else 107 | return null; 108 | } 109 | 110 | /// 111 | /// 获取进程名 112 | /// 113 | /// 进程句柄 114 | /// 115 | internal static string GetProcessNameInternal(IntPtr processHandle) 116 | { 117 | StringBuilder filePath; 118 | 119 | filePath = new StringBuilder((int)MAX_MODULE_NAME32); 120 | if (GetProcessImageFileName(processHandle, filePath, (int)MAX_MODULE_NAME32) == 0) 121 | return null; 122 | return Path.GetFileName(filePath.ToString()); 123 | } 124 | 125 | /// 126 | /// 获取进程路径 127 | /// 128 | /// 进程ID 129 | /// 130 | public static string GetProcessPath(uint processId) 131 | { 132 | SafeNativeHandle processHandle; 133 | 134 | using (processHandle = OpenProcessQuery(processId)) 135 | if (processHandle.IsValid) 136 | return GetProcessPathInternal(processHandle); 137 | else 138 | return null; 139 | } 140 | 141 | /// 142 | /// 获取进程路径 143 | /// 144 | /// 进程句柄 145 | /// 146 | internal static string GetProcessPathInternal(IntPtr processHandle) 147 | { 148 | StringBuilder filePath; 149 | 150 | filePath = new StringBuilder((int)MAX_PATH); 151 | if (GetProcessImageFileName(processHandle, filePath, MAX_PATH) == 0) 152 | return null; 153 | return filePath.ToString(); 154 | } 155 | 156 | /// 157 | /// 判断进程是否为64位进程,返回值为方法是否执行成功 158 | /// 159 | /// 进程ID 160 | /// 是否为64位进程 161 | /// 162 | public static bool Is64BitProcess(uint processId, out bool is64) 163 | { 164 | SafeNativeHandle processHandle; 165 | 166 | if (!FastWin32Settings.Is64BitOperatingSystem) 167 | { 168 | //不是64位系统肯定不会是64位进程 169 | is64 = false; 170 | return true; 171 | } 172 | using (processHandle = OpenProcessQuery(processId)) 173 | if (processHandle.IsValid) 174 | return Is64BitProcessInternal(processHandle, out is64); 175 | else 176 | { 177 | is64 = false; 178 | return false; 179 | } 180 | } 181 | 182 | /// 183 | /// 判断进程是否为64位进程,返回值为方法是否执行成功 184 | /// 185 | /// 进程句柄 186 | /// 是否为64位进程 187 | /// 188 | internal static bool Is64BitProcessInternal(IntPtr processHandle, out bool is64) 189 | { 190 | bool isWow64; 191 | 192 | if (!FastWin32Settings.Is64BitOperatingSystem) 193 | { 194 | //不是64位系统肯定不会是64位进程 195 | is64 = false; 196 | return true; 197 | } 198 | if (!IsWow64Process(processHandle, out isWow64)) 199 | { 200 | //执行失败 201 | is64 = false; 202 | return false; 203 | } 204 | is64 = !isWow64; 205 | return true; 206 | } 207 | 208 | /// 209 | /// 暂停进程 210 | /// 211 | /// 进程ID 212 | /// 213 | public static bool SuspendProcess(uint processId) 214 | { 215 | SafeNativeHandle processHandle; 216 | 217 | using (processHandle = OpenProcessProcessSuspendResume(processId)) 218 | if (processHandle.IsValid) 219 | return SuspendProcessInternal(processHandle); 220 | else 221 | return false; 222 | } 223 | 224 | /// 225 | /// 暂停进程 226 | /// 227 | /// 进程句柄 228 | /// 229 | internal static bool SuspendProcessInternal(IntPtr processHandle) 230 | { 231 | return ZwSuspendProcess(processHandle) != unchecked((uint)-1); 232 | } 233 | 234 | /// 235 | /// 恢复进程 236 | /// 237 | /// 进程ID 238 | /// 239 | public static bool ResumeProcess(uint processId) 240 | { 241 | SafeNativeHandle processHandle; 242 | 243 | using (processHandle = OpenProcessProcessSuspendResume(processId)) 244 | if (processHandle.IsValid) 245 | return ResumeProcessInternal(processHandle); 246 | else 247 | return false; 248 | } 249 | 250 | /// 251 | /// 恢复进程 252 | /// 253 | /// 进程句柄 254 | /// 255 | internal static bool ResumeProcessInternal(IntPtr processHandle) 256 | { 257 | return ZwResumeProcess(processHandle) != unchecked((uint)-1); 258 | } 259 | 260 | /// 261 | /// 动态提升进程权限,以管理员模式运行当前进程,如果执行成功当前进程将退出,执行失败无反应 262 | /// 263 | /// 主窗口的句柄 264 | /// 265 | public static void SelfElevate(IntPtr windowHandle) 266 | { 267 | StringBuilder filePath; 268 | SHELLEXECUTEINFO shellExecuteInfo; 269 | 270 | filePath = new StringBuilder((int)MAX_PATH); 271 | if (GetModuleFileName(IntPtr.Zero, filePath, MAX_PATH) == 0) 272 | return; 273 | shellExecuteInfo = new SHELLEXECUTEINFO 274 | { 275 | cbSize = SHELLEXECUTEINFO.UnmanagedSize, 276 | hwnd = windowHandle, 277 | lpVerb = "runas", 278 | lpFile = filePath.ToString(), 279 | nShow = 1 280 | }; 281 | if (ShellExecuteEx(ref shellExecuteInfo)) 282 | Environment.Exit(0); 283 | } 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /FastWin32/FastWin32.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0B6AC808-3A51-4072-954F-D55DE4F0209B} 8 | Library 9 | Properties 10 | FastWin32 11 | v4.0 12 | 512 13 | 14 | 15 | true 16 | pdbonly 17 | false 18 | bin\Debug\ 19 | TRACE;DEBUG 20 | prompt 21 | 4 22 | true 23 | bin\Debug\FastWin32.xml 24 | false 25 | default 26 | IDE0001 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | true 37 | bin\Release\FastWin32.xml 38 | false 39 | default 40 | IDE0001 41 | 42 | 43 | true 44 | 45 | 46 | FastWin32.snk 47 | 48 | 49 | FastWin32 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /FastWin32/FastWin32.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-jlion/FastWin32/6bbc7652f7276970414598a273ad93ac211bd3c0/FastWin32/FastWin32.snk -------------------------------------------------------------------------------- /FastWin32/FastWin32Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace FastWin32 5 | { 6 | /// 7 | /// 全局设置 8 | /// 9 | public static class FastWin32Settings 10 | { 11 | /// 12 | /// 确定当前操作系统是否为 64 位操作系统。 13 | /// 14 | public static readonly bool Is64BitOperatingSystem = Environment.Is64BitOperatingSystem; 15 | 16 | /// 17 | /// SeDebugPrivilege特权 18 | /// 19 | public static bool SeDebugPrivilege { get; private set; } 20 | 21 | /// 22 | /// 将SeDebugPrivilege特权赋予当前进程 23 | /// 24 | /// 25 | public static bool EnableDebugPrivilege() 26 | { 27 | if (SeDebugPrivilege) 28 | return true; 29 | try 30 | { 31 | Process.EnterDebugMode(); 32 | SeDebugPrivilege = true; 33 | return true; 34 | } 35 | catch 36 | { 37 | return false; 38 | } 39 | } 40 | 41 | /// 42 | /// 取消当前进程的SeDebugPrivilege特权 43 | /// 44 | /// 45 | public static bool DisableDebugPrivilege() 46 | { 47 | if (!SeDebugPrivilege) 48 | return true; 49 | try 50 | { 51 | Process.LeaveDebugMode(); 52 | SeDebugPrivilege = false; 53 | return true; 54 | } 55 | catch 56 | { 57 | return false; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /FastWin32/Hook/Method/LocalHook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using FastWin32.Diagnostics; 4 | using FastWin32.Memory; 5 | using static FastWin32.NativeMethods; 6 | 7 | namespace FastWin32.Hook.Method 8 | { 9 | /// 10 | /// 挂钩当前进程API 11 | /// 12 | public sealed class LocalHook 13 | { 14 | /// 15 | /// 杀死函数,让函数不执行任何动作 16 | /// 17 | /// 模块名 18 | /// 函数名 19 | /// 20 | public static bool Kill(string moduleName, string apiName) 21 | { 22 | if (string.IsNullOrEmpty(moduleName) || string.IsNullOrEmpty(apiName)) 23 | throw new ArgumentNullException(); 24 | 25 | return Kill(Module32.GetProcAddressInternal(moduleName, apiName)); 26 | } 27 | 28 | /// 29 | /// 杀死方法,让方法不执行任何动作 30 | /// 31 | /// 方法信息 32 | /// 33 | public static bool Kill(MethodInfo methodInfo) 34 | { 35 | if (methodInfo == null) 36 | throw new ArgumentNullException(); 37 | 38 | return Kill(methodInfo.MethodHandle.GetFunctionPointer()); 39 | } 40 | 41 | /// 42 | /// 杀死函数,让函数不执行任何动作 43 | /// 44 | /// 函数入口地址 45 | /// 46 | public static bool Kill(IntPtr entry) 47 | { 48 | return MemoryIO.WriteByteInternal(CURRENT_PROCESS, entry, 0xC3); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FastWin32/Hook/Method/LocalHookOld.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.ComponentModel; 3 | //using System.Reflection; 4 | //using static FastWin32.NativeMethods; 5 | 6 | //namespace FastWin32.Hook.Method 7 | //{ 8 | // /// 9 | // /// 改变托管/非托管函数的执行过程与结果,若要Hook其他进程,配合Injector类注入Dll使用 10 | // /// 11 | // public class LocalHookOld : IHook,IDisposable 12 | // { 13 | // /// 14 | // /// 原函数入口地址 15 | // /// 16 | // private IntPtr _origEntry; 17 | // /// 18 | // /// 新函数入口地址 19 | // /// 20 | // private IntPtr _newEntry; 21 | // /// 22 | // /// 是否已经安装 23 | // /// 24 | // private bool _isInstalled; 25 | // private byte[] _origBytes; 26 | // private byte[] _newBytes; 27 | // private bool _isFirst; 28 | 29 | // /// 30 | // /// 实例化API钩子(用非托管函数替换非托管函数) 31 | // /// 32 | // /// 原非托管函数所在模块 33 | // /// 原非托管函数名(如果该参数是序数值,则它必须在低位字中; 高阶字必须为零) 34 | // /// 新非托管函数所在模块 35 | // /// 新非托管函数名(如果该参数是序数值,则它必须在低位字中; 高阶字必须为零) 36 | // public LocalHookOld(string origModuleName, string origApiName, string newModuleName, string newApiName) : this(GetProcAddressInternal(origModuleName, origApiName), GetProcAddressInternal(newModuleName, newApiName)) { } 37 | 38 | // /// 39 | // /// 实例化API钩子(用托管方法替换非托管函数) 40 | // /// 41 | // /// 原非托管函数所在模块 42 | // /// 原非托管函数名(如果该参数是序数值,则它必须在低位字中; 高阶字必须为零) 43 | // /// 新托管方法元数据 44 | // public LocalHookOld(string origModuleName, string origApiName, MethodInfo newMethodInfo) : this(GetProcAddressInternal(origModuleName, origApiName), newMethodInfo.MethodHandle.GetFunctionPointer()) { } 45 | 46 | // /// 47 | // /// 实例化API钩子(用非托管函数替换托管方法) 48 | // /// 49 | // /// 原托管方法元数据 50 | // /// 新非托管函数所在模块 51 | // /// 新非托管函数名(如果该参数是序数值,则它必须在低位字中; 高阶字必须为零) 52 | // public LocalHookOld(MethodInfo origMethodInfo, string newModuleName, string newApiName) : this(origMethodInfo.MethodHandle.GetFunctionPointer(), GetProcAddressInternal(newModuleName, newApiName)) { } 53 | 54 | // /// 55 | // /// 实例化API钩子(用托管方法数替换托管方法) 56 | // /// 57 | // /// 原托管方法元数据 58 | // /// 新托管方法元数据 59 | // public LocalHookOld(MethodInfo origMethodInfo, MethodInfo newMethodInfo) : this(origMethodInfo.MethodHandle.GetFunctionPointer(), newMethodInfo.MethodHandle.GetFunctionPointer()) { } 60 | 61 | // /// 62 | // /// 实例化API钩子 63 | // /// 64 | // /// 原入口 65 | // /// 新入口 66 | // public LocalHookOld(IntPtr origEntry, IntPtr newEntry) 67 | // { 68 | // if (origEntry == newEntry) 69 | // throw new ArgumentException("新入口与原入口一致"); 70 | 71 | // _origEntry = origEntry; 72 | // _newEntry = newEntry; 73 | // } 74 | 75 | // /// 76 | // /// 获取函数地址 77 | // /// 78 | // /// 模块名 79 | // /// 函数名 80 | // /// 81 | // internal static IntPtr GetProcAddressInternal(string moduleName, string procName) 82 | // { 83 | // if (moduleName == null || procName == null) 84 | // throw new ArgumentNullException(); 85 | // if (moduleName.Length == 0 || procName.Length == 0) 86 | // throw new ArgumentOutOfRangeException(); 87 | 88 | // IntPtr moduleHandle; 89 | // IntPtr pFunction; 90 | 91 | // moduleHandle = GetModuleHandle(moduleName); 92 | // if (moduleHandle == IntPtr.Zero) 93 | // throw new Win32Exception(); 94 | // pFunction = GetProcAddress(moduleHandle, procName); 95 | // if (pFunction == IntPtr.Zero) 96 | // throw new Win32Exception(); 97 | // return pFunction; 98 | // } 99 | 100 | // /// 101 | // /// 安装钩子 102 | // /// 103 | // public bool Install() 104 | // { 105 | // _isInstalled = true; 106 | // } 107 | 108 | // /// 109 | // /// 生成跳转需要的字节数组 110 | // /// 111 | // /// 112 | // private byte[] GenBytes() 113 | // { 114 | // if (Environment.Is64BitProcess) 115 | // { 116 | // byte[] bytAddr; 117 | 118 | // bytAddr = BitConverter.GetBytes((long)_origEntry); 119 | // //获取地址的字节数组形式 120 | // return new byte[] 121 | // { 122 | // 0x48, 0xB8, bytAddr[0], bytAddr[1], bytAddr[2], bytAddr[3], bytAddr[4], bytAddr[5], bytAddr[6], bytAddr[7], 123 | // //mov rax, addr 124 | // 0x50, 125 | // //push rax 126 | // 0xC3 127 | // //ret 128 | // }; 129 | // //64位麻烦一些,因为push imm64不被支持,也就是不能直接push 1234567812345678h 130 | // } 131 | // else 132 | // { 133 | // byte[] bytAddr; 134 | 135 | // bytAddr = BitConverter.GetBytes((int)_newEntry); 136 | // //获取地址的字节数组形式 137 | // return new byte[] 138 | // { 139 | // 0x68, bytAddr[0], bytAddr[1], bytAddr[2], bytAddr[3], 140 | // //push addr 141 | // 0xC3 142 | // //ret 143 | // }; 144 | // } 145 | // } 146 | 147 | // /// 148 | // /// 卸载钩子 149 | // /// 150 | // public bool Uninstall() 151 | // { 152 | // if (!_isInstalled) 153 | // throw new NotSupportedException("") 154 | // } 155 | 156 | // #region IDisposable Support 157 | // private bool disposedValue = false; // 要检测冗余调用 158 | 159 | // protected virtual void Dispose(bool disposing) 160 | // { 161 | // if (!disposedValue) 162 | // { 163 | // if (disposing) 164 | // { 165 | // // TODO: 释放托管状态(托管对象)。 166 | // } 167 | 168 | // // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 169 | // // TODO: 将大型字段设置为 null。 170 | 171 | // disposedValue = true; 172 | // } 173 | // } 174 | 175 | // // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 176 | // // ~LocalHook() { 177 | // // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 178 | // // Dispose(false); 179 | // // } 180 | 181 | // // 添加此代码以正确实现可处置模式。 182 | // public void Dispose() 183 | // { 184 | // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 185 | // Dispose(true); 186 | // // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 187 | // // GC.SuppressFinalize(this); 188 | // } 189 | // #endregion 190 | // } 191 | //} 192 | -------------------------------------------------------------------------------- /FastWin32/Hook/Method/RemoteHook.cs: -------------------------------------------------------------------------------- 1 | namespace FastWin32.Hook.Method 2 | { 3 | /// 4 | /// 挂钩远程进程API 5 | /// 6 | public sealed class RemoteHook 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FastWin32/Hook/WindowMessage/KeyboardHook.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Reflection; 3 | //using System.Threading; 4 | //using System.Windows.Forms; 5 | //using FastWin32.Diagnostics; 6 | //using static FastWin32.NativeMethods; 7 | 8 | //namespace FastWin32.Hook.WindowMessage 9 | //{ 10 | // /// 11 | // /// 参数,触发条件与 相同,但此事件有返回值。返回 表示将此次消息继续发送给下一个钩子,返回 表示屏蔽此次消息,目标窗口将无法收到此次消息 12 | // /// 13 | // /// 14 | // /// 15 | // /// 16 | // public delegate bool KeyHookEventHandler(KeyboardHook sender, KeyEventArgs e); 17 | 18 | // /// 19 | // /// 参数,触发条件与 相同,但此事件有返回值。返回 表示将此次消息继续发送给下一个钩子,返回 表示屏蔽此次消息,目标窗口将无法收到此次消息 20 | // /// 21 | // /// 22 | // /// 23 | // /// 24 | // public delegate bool KeyPressHookEventHandler(KeyboardHook sender, KeyPressEventArgs e); 25 | 26 | // /// 27 | // /// 键盘消息钩子 28 | // /// 29 | // public sealed class KeyboardHook 30 | // { 31 | // private byte[] _keyboardState = new byte[256]; 32 | 33 | // private uint _targetThreadId; 34 | 35 | // private IntPtr _hookHandle; 36 | 37 | // private Thread _hookThread; 38 | 39 | // /// 40 | // /// 是否安装 41 | // /// 42 | // public bool IsInstalled { get; private set; } 43 | 44 | // /// 45 | // /// 按键按下事件 46 | // /// 47 | // public event KeyHookEventHandler KeyDown; 48 | 49 | // /// 50 | // /// 按键弹起事件 51 | // /// 52 | // public event KeyHookEventHandler KeyUp; 53 | 54 | // /// 55 | // /// 按键按压事件 56 | // /// 57 | // public event KeyPressHookEventHandler KeyPress; 58 | 59 | // /// 60 | // /// 创建全局键盘钩子实例 61 | // /// 62 | // public KeyboardHook() 63 | // { 64 | // } 65 | 66 | // /// 67 | // /// 对指定线程创建键盘钩子 68 | // /// 69 | // /// 线程ID 70 | // public KeyboardHook(uint targetThreadId) 71 | // { 72 | // _targetThreadId = targetThreadId; 73 | // } 74 | 75 | // /// 76 | // /// 对指定窗口创建键盘钩子 77 | // /// 78 | // /// 窗口句柄 79 | // public KeyboardHook(IntPtr windowHandle) 80 | // { 81 | // if (!IsWindow(windowHandle)) 82 | // throw new ArgumentNullException("无效窗口句柄"); 83 | 84 | // _targetThreadId = GetWindowThreadProcessId(windowHandle, null); 85 | // } 86 | 87 | // /// 88 | // /// 安装钩子 89 | // /// 90 | // public bool Install() 91 | // { 92 | // if (IsInstalled) 93 | // throw new NotSupportedException("无法重复安装钩子"); 94 | 95 | // bool finished; 96 | // bool result; 97 | 98 | // finished = false; 99 | // result = false; 100 | // if (Application.MessageLoop) 101 | // { 102 | // //调用此方法的线程如果有消息循环,就不需要开新线程启动消息循环 103 | // result = InstallPrivate(); 104 | // finished = true; 105 | // } 106 | // else 107 | // { 108 | // _hookThread = new Thread(() => 109 | // { 110 | // result = InstallPrivate(); 111 | // finished = true; 112 | // Application.Run(); 113 | // }) 114 | // { 115 | // IsBackground = true 116 | // }; 117 | // _hookThread.Start(); 118 | // } 119 | // while (!finished) 120 | // Thread.Sleep(0); 121 | // if (result) 122 | // { 123 | // IsInstalled = true; 124 | // return true; 125 | // } 126 | // else 127 | // { 128 | // _hookThread?.Abort(); 129 | // return false; 130 | // } 131 | // } 132 | 133 | // /// 134 | // /// 安装钩子 135 | // /// 136 | // /// 137 | // private bool InstallPrivate() 138 | // { 139 | // uint processId; 140 | // string guid; 141 | // int returnValue; 142 | 143 | // if (_targetThreadId == 0) 144 | // { 145 | // _hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardHookProc, IntPtr.Zero, 0); 146 | // return _hookHandle != IntPtr.Zero; 147 | // } 148 | // else 149 | // { 150 | // guid = Guid.NewGuid().ToString(); 151 | // //TODO 152 | // //TODO 153 | // //TODO 154 | // //TODO 155 | // //TODO 156 | // //TODO 157 | // //TODO 158 | // //TODO 159 | // //TODO 160 | // //TODO 161 | // //TODO 162 | // return (processId = Process32.GetProcessIdByThreadId(_targetThreadId)) != 0 && Injector.InjectManaged(processId, Assembly.GetExecutingAssembly().Location, "FastWin32.Hook.WindowMessage.MessageProxy", "StartServer", guid, out returnValue) && returnValue == 1; 163 | // } 164 | // } 165 | 166 | // /// 167 | // /// 键盘消息回调函数 168 | // /// 169 | // /// 挂钩过程用于确定如何处理消息的代码。如果代码小于0,挂钩过程必须将消息传递给CallNextHookEx函数,无需进一步处理,并应返回CallNextHookEx返回的值。 170 | // /// 产生击键消息的密钥的虚拟密钥代码。 171 | // /// 重复计数,扫描码,扩展密钥标志,上下文代码,先前的密钥状态标志和转换状态标志。有关lParam参数的更多信息,请参阅按键消息标志。下表描述了该值的位。 172 | // /// 173 | // private IntPtr LowLevelKeyboardHookProc(int nCode, size_t wParam, size_t lParam) 174 | // { 175 | // if (nCode < 0 || (KeyDown == null && KeyUp == null && KeyPress == null)) 176 | // //如果nCode小于零,则钩子过程必须返回CallNextHookEx返回的值并且不对钩子消息做处理。如果3个事件均未被订阅,直接返回 177 | // return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); 178 | // else 179 | // { 180 | // if (OnKeyEvent((uint)wParam, ((KBDLLHOOKSTRUCT*)lParam)->vkCode, ((KBDLLHOOKSTRUCT*)lParam)->scanCode)) 181 | // return (IntPtr)(-1); 182 | // else 183 | // return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); 184 | // } 185 | // } 186 | 187 | // /// 188 | // /// 引发事件 189 | // /// 190 | // /// 消息类型 191 | // /// 虚拟键码 192 | // /// 扫描码 193 | // /// 194 | // private bool OnKeyEvent(uint messageType, uint vkCode, uint scanCode) 195 | // { 196 | // bool isBlock; 197 | // char keyChar; 198 | 199 | // isBlock = false; 200 | // if (KeyDown != null && (messageType == WM_KEYDOWN || messageType == WM_SYSKEYDOWN)) 201 | // isBlock = KeyDown(this, new KeyEventArgs((Keys)vkCode)); 202 | // if (KeyUp != null && (messageType == WM_KEYUP || messageType == WM_SYSKEYUP)) 203 | // isBlock = KeyUp(this, new KeyEventArgs((Keys)vkCode)); 204 | // if (KeyPress != null && messageType == WM_KEYDOWN) 205 | // { 206 | // GetKeyState(0); 207 | // GetKeyboardState(_keyboardState); 208 | // if (ToAscii(vkCode, scanCode, _keyboardState, out keyChar, 0) == 1) 209 | // isBlock = KeyPress(this, new KeyPressEventArgs(keyChar)); 210 | // } 211 | // return isBlock; 212 | // } 213 | 214 | // /// 215 | // /// 卸载钩子 216 | // /// 217 | // public bool Uninstall() 218 | // { 219 | // if (!IsInstalled) 220 | // throw new NotSupportedException("未安装钩子"); 221 | 222 | // if (_targetThreadId == 0) 223 | // { 224 | // //全局钩子 225 | // if (!UnhookWindowsHookEx(_hookHandle)) 226 | // //钩子卸载失败 227 | // return false; 228 | // } 229 | // else 230 | // //线程钩子 231 | // _hookThread.Abort(); 232 | // IsInstalled = false; 233 | // return true; 234 | // } 235 | // } 236 | //} 237 | -------------------------------------------------------------------------------- /FastWin32/Hook/WindowMessage/MessageProxy.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Threading; 3 | //using System.Windows.Forms; 4 | //using static FastWin32.NativeMethods; 5 | 6 | //namespace FastWin32.Hook.WindowMessage 7 | //{ 8 | // /// 9 | // /// 转发消息 10 | // /// 11 | // internal sealed class MessageProxy 12 | // { 13 | // private IntPtr _hookHandle; 14 | 15 | // private Thread _hookThread; 16 | 17 | // /// 18 | // /// 启动代理 19 | // /// 20 | // /// 21 | // private bool Install() 22 | // { 23 | // bool finished; 24 | // bool result; 25 | 26 | // finished = false; 27 | // result = false; 28 | // _hookThread = new Thread(() => 29 | // { 30 | // //_hookHandle = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, IntPtr.Zero,TargetThreadId); 31 | // throw new NotImplementedException(); 32 | // result = _hookHandle != IntPtr.Zero; 33 | // finished = true; 34 | // Application.Run(); 35 | // }) 36 | // { 37 | // IsBackground = true 38 | // }; 39 | // _hookThread.Start(); 40 | // while (!finished) 41 | // Thread.Sleep(0); 42 | // if (result) 43 | // return true; 44 | // else 45 | // { 46 | // _hookThread.Abort(); 47 | // return false; 48 | // } 49 | // } 50 | 51 | // private IntPtr KeyboardProc(int nCode, size_t wParam, size_t lParam) 52 | // { 53 | // if (nCode < 0) 54 | // //如果nCode小于零,则钩子过程必须返回CallNextHookEx返回的值并且不对钩子消息做处理。如果3个事件均未被订阅,直接返回 55 | // return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); 56 | // else 57 | // { 58 | // //if (keyboardHook.OnHookProc((uint)wParam, (uint)lParam, (uint)lParam)) 59 | // // return (IntPtr)(-1); 60 | // //else 61 | // // return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam); 62 | // throw new NotImplementedException(); 63 | // } 64 | // } 65 | 66 | // ///// 67 | // ///// 停止代理 68 | // ///// 69 | // ///// 70 | // //public bool Uninstall() 71 | // //{ 72 | // // if (_hookThread.ThreadState == ThreadState.Running) 73 | // // _hookThread.Abort(); 74 | // // return UnhookWindowsHookEx(_hookHandle); 75 | // //} 76 | 77 | // /// 78 | // /// 启动代理,注入DLL使用 79 | // /// 80 | // /// 参数 81 | // /// 82 | // public static int StartServer(string arg) 83 | // { 84 | // return new MessageProxy { }.Install() ? 1 : 0; 85 | // } 86 | // } 87 | //} 88 | -------------------------------------------------------------------------------- /FastWin32/Memory/MemoryManagement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static FastWin32.NativeMethods; 3 | using size_t = System.IntPtr; 4 | 5 | namespace FastWin32.Memory 6 | { 7 | /// 8 | /// 内存管理 9 | /// 10 | public static class MemoryManagement 11 | { 12 | /// 13 | /// 打开进程(内存操作) 14 | /// 15 | /// 进程ID 16 | /// 17 | private static SafeNativeHandle OpenProcessVMOperation(uint processId) 18 | { 19 | return SafeOpenProcess(FastWin32Settings.SeDebugPrivilege ? PROCESS_ALL_ACCESS : PROCESS_VM_OPERATION, false, processId); 20 | } 21 | 22 | #region ProtectionFlagsGenerator 23 | /// 24 | /// 所有内存保护选项 25 | /// 26 | private const uint AllMemoryProtectionFlags = 27 | PAGE_EXECUTE_READ | 28 | PAGE_EXECUTE_READWRITE | 29 | PAGE_READONLY | 30 | PAGE_READWRITE; 31 | 32 | /// 33 | /// 根据提供选项生成对应的内存保护标识 34 | /// 35 | /// 可写 36 | /// 可执行 37 | /// 38 | private static uint ProtectionFlagsGenerator(bool writable, bool executable) 39 | { 40 | uint writableFlags; 41 | uint executableFlags; 42 | 43 | writableFlags = 44 | PAGE_EXECUTE_READWRITE | 45 | PAGE_READWRITE; 46 | //可写 47 | if (!writable) 48 | //如果不可写 49 | writableFlags ^= AllMemoryProtectionFlags; 50 | executableFlags = 51 | PAGE_EXECUTE_READ | 52 | PAGE_EXECUTE_READWRITE; 53 | //可执行 54 | if (!executable) 55 | //如果不可执行 56 | executableFlags ^= AllMemoryProtectionFlags; 57 | return writableFlags & executableFlags; 58 | } 59 | #endregion 60 | 61 | #region AllocMemory 62 | /// 63 | /// 在当前进程中分配内存(默认可写,不可执行) 64 | /// 65 | /// 要分配内存的大小 66 | /// 分配得到的内存所在地址 67 | public static IntPtr AllocMemory(size_t size) 68 | { 69 | return AllocMemory(size, true, false); 70 | } 71 | 72 | /// 73 | /// 在当前进程中分配内存 74 | /// 75 | /// 要分配内存的大小 76 | /// 可写 77 | /// 可执行 78 | /// 分配得到的内存所在地址 79 | public static IntPtr AllocMemory(size_t size, bool writable, bool executable) 80 | { 81 | return AllocMemoryInternal(size, ProtectionFlagsGenerator(writable, executable)); 82 | } 83 | 84 | /// 85 | /// 分配内存(默认可写,不可执行) 86 | /// 87 | /// 进程ID 88 | /// 要分配内存的大小 89 | /// 分配得到的内存所在地址 90 | public static IntPtr AllocMemoryEx(uint processId, size_t size) 91 | { 92 | return AllocMemoryEx(processId, size, true, false); 93 | } 94 | 95 | /// 96 | /// 分配内存 97 | /// 98 | /// 进程ID 99 | /// 要分配内存的大小 100 | /// 可写 101 | /// 可执行 102 | /// 分配得到的内存所在地址 103 | public static IntPtr AllocMemoryEx(uint processId, size_t size, bool writable, bool executable) 104 | { 105 | SafeNativeHandle processHandle; 106 | 107 | using (processHandle = OpenProcessVMOperation(processId)) 108 | if (processHandle.IsValid) 109 | return AllocMemoryExInternal(processHandle, size, ProtectionFlagsGenerator(writable, executable)); 110 | else 111 | return IntPtr.Zero; 112 | } 113 | 114 | /// 115 | /// 在当前进程中分配内存(默认可写,不可执行) 116 | /// 117 | /// 要分配内存的大小 118 | /// 分配得到的内存所在地址 119 | internal static IntPtr AllocMemoryInternal(size_t size) 120 | { 121 | return VirtualAlloc(IntPtr.Zero, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 122 | } 123 | 124 | /// 125 | /// 在当前进程中分配内存 126 | /// 127 | /// 要分配内存的大小 128 | /// 内存保护选项 129 | /// 分配得到的内存所在地址 130 | internal static IntPtr AllocMemoryInternal(size_t size, uint flags) 131 | { 132 | return VirtualAlloc(IntPtr.Zero, size, MEM_COMMIT | MEM_RESERVE, flags); 133 | } 134 | 135 | /// 136 | /// 分配内存(默认可写,不可执行) 137 | /// 138 | /// 进程句柄 139 | /// 要分配内存的大小 140 | /// 分配得到的内存所在地址 141 | internal static IntPtr AllocMemoryExInternal(IntPtr processHandle, size_t size) 142 | { 143 | return VirtualAllocEx(processHandle, IntPtr.Zero, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 144 | } 145 | 146 | /// 147 | /// 分配内存 148 | /// 149 | /// 进程句柄 150 | /// 要分配内存的大小 151 | /// 内存保护选项 152 | /// 分配得到的内存所在地址 153 | internal static IntPtr AllocMemoryExInternal(IntPtr processHandle, size_t size, uint flags) 154 | { 155 | return VirtualAllocEx(processHandle, IntPtr.Zero, size, MEM_COMMIT | MEM_RESERVE, flags); 156 | } 157 | #endregion 158 | 159 | #region FreeMemory 160 | /// 161 | /// 在当前进程中释放内存(MEM_RELEASE) 162 | /// 163 | /// 指定释放内存的地址 164 | /// 165 | public static bool FreeMemory(IntPtr addr) 166 | { 167 | return FreeMemoryInternal(addr); 168 | } 169 | 170 | /// 171 | /// 在当前进程中释放内存(MEM_DECOMMIT) 172 | /// 173 | /// 指定释放内存的地址 174 | /// 要释放内存的大小 175 | public static bool FreeMemory(IntPtr addr, size_t size) 176 | { 177 | return FreeMemoryInternal(addr, size); 178 | } 179 | 180 | /// 181 | /// 释放内存(MEM_RELEASE) 182 | /// 183 | /// 进程ID 184 | /// 指定释放内存的地址 185 | /// 186 | public static bool FreeMemoryEx(uint processId, IntPtr addr) 187 | { 188 | SafeNativeHandle processHandle; 189 | 190 | using (processHandle = OpenProcessVMOperation(processId)) 191 | if (processHandle.IsValid) 192 | return FreeMemoryInternal(processHandle, addr); 193 | else 194 | return false; 195 | } 196 | 197 | /// 198 | /// 释放内存(MEM_DECOMMIT) 199 | /// 200 | /// 进程ID 201 | /// 指定释放内存的地址 202 | /// 要释放内存的大小 203 | public static bool FreeMemoryEx(uint processId, IntPtr addr, size_t size) 204 | { 205 | SafeNativeHandle processHandle; 206 | 207 | using (processHandle = OpenProcessVMOperation(processId)) 208 | if (processHandle.IsValid) 209 | return FreeMemoryExInternal(processHandle, addr, size); 210 | else 211 | return false; 212 | } 213 | 214 | /// 215 | /// 在当前进程中释放内存(MEM_RELEASE) 216 | /// 217 | /// 指定释放内存的地址 218 | /// 219 | internal static bool FreeMemoryInternal(IntPtr addr) 220 | { 221 | return VirtualFree(addr, size_t.Zero, MEM_RELEASE); 222 | } 223 | 224 | /// 225 | /// 在当前进程中释放内存(MEM_DECOMMIT) 226 | /// 227 | /// 指定释放内存的地址 228 | /// 要释放内存的大小 229 | internal static bool FreeMemoryInternal(IntPtr addr, size_t size) 230 | { 231 | return VirtualFree(addr, size, MEM_DECOMMIT); 232 | } 233 | 234 | /// 235 | /// 释放内存(MEM_RELEASE) 236 | /// 237 | /// 进程句柄 238 | /// 指定释放内存的地址 239 | /// 240 | internal static bool FreeMemoryExInternal(IntPtr processHandle, IntPtr addr) 241 | { 242 | return VirtualFreeEx(processHandle, addr, size_t.Zero, MEM_RELEASE); 243 | } 244 | 245 | /// 246 | /// 释放内存(MEM_DECOMMIT) 247 | /// 248 | /// 进程句柄 249 | /// 指定释放内存的地址 250 | /// 要释放内存的大小 251 | internal static bool FreeMemoryExInternal(IntPtr processHandle, IntPtr addr, size_t size) 252 | { 253 | return VirtualFreeEx(processHandle, addr, size, MEM_DECOMMIT); 254 | } 255 | #endregion 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /FastWin32/Memory/PageInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static FastWin32.NativeMethods; 3 | using size_t = System.IntPtr; 4 | 5 | namespace FastWin32.Memory 6 | { 7 | /// 8 | /// 内存页面信息 9 | /// 10 | public class PageInfo 11 | { 12 | /// 13 | /// 地址 14 | /// 15 | public IntPtr Address { get; } 16 | 17 | /// 18 | /// 大小 19 | /// 20 | public size_t Size { get; } 21 | 22 | /// 23 | /// 保护选项 24 | /// 25 | public uint Protect { get; } 26 | 27 | /// 28 | /// 页面类型 29 | /// 30 | public uint Type { get; } 31 | 32 | internal PageInfo(MEMORY_BASIC_INFORMATION mbi) 33 | { 34 | Address = mbi.BaseAddress; 35 | Size = mbi.RegionSize; 36 | Protect = mbi.Protect; 37 | Type = mbi.Type; 38 | } 39 | 40 | /// 41 | /// 返回表示当前对象的字符串 42 | /// 43 | /// 44 | public override string ToString() 45 | { 46 | bool is64; 47 | 48 | is64 = (ulong)Address > uint.MaxValue; 49 | return $"Address=0x{Address.ToString(is64 ? "X16" : "X8")} Size=0x{Size.ToString(is64 ? "X16" : "X8")}"; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /FastWin32/Memory/Pointer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace FastWin32.Memory 4 | { 5 | /// 6 | /// 指针类型 7 | /// 8 | internal enum PointerType 9 | { 10 | /// 11 | /// 模块名+偏移 12 | /// 13 | ModuleName_Offset, 14 | 15 | /// 16 | /// 地址+偏移 17 | /// 18 | Address_Offset 19 | } 20 | 21 | /// 22 | /// 指针 23 | /// 24 | public sealed class Pointer 25 | { 26 | internal string _moduleName; 27 | 28 | internal uint _moduleOffset; 29 | 30 | internal IntPtr _baseAddr; 31 | 32 | internal uint[] _offset; 33 | 34 | internal PointerType _type; 35 | 36 | internal IntPtr _lastAddr; 37 | 38 | /// 39 | /// 模块名 40 | /// 41 | public string ModuleName => _type == PointerType.ModuleName_Offset ? _moduleName : throw new NotSupportedException("使用了地址+偏移,未使用模块名"); 42 | 43 | /// 44 | /// 模块偏移 45 | /// 46 | public uint ModuleOffset => _type == PointerType.ModuleName_Offset ? _moduleOffset : throw new NotSupportedException("使用了地址+偏移,未使用模块偏移"); 47 | 48 | /// 49 | /// 基础地址 50 | /// 51 | public IntPtr BaseAddr => _type == PointerType.Address_Offset ? _baseAddr : throw new NotSupportedException("使用了模块偏移,未使用地址+偏移"); 52 | 53 | /// 54 | /// 偏移 55 | /// 56 | public uint[] Offset => _offset; 57 | 58 | /// 59 | /// 实例化指针结构 60 | /// 61 | /// 模块名 62 | /// 模块偏移 63 | /// 偏移 64 | public Pointer(string moduleName, uint moduleOffset, params uint[] offset) 65 | { 66 | if (string.IsNullOrEmpty(moduleName)) 67 | throw new ArgumentOutOfRangeException(); 68 | 69 | _moduleName = moduleName; 70 | _moduleOffset = moduleOffset; 71 | _offset = offset; 72 | _type = PointerType.ModuleName_Offset; 73 | } 74 | 75 | /// 76 | /// 实例化指针结构 77 | /// 78 | /// 基础地址 79 | /// 偏移 80 | public Pointer(IntPtr baseAddr, params uint[] offset) 81 | { 82 | _baseAddr = baseAddr; 83 | _offset = offset; 84 | _type = PointerType.Address_Offset; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /FastWin32/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("FastWin32")] 5 | [assembly: AssemblyConfiguration("")] 6 | [assembly: AssemblyCompany("")] 7 | [assembly: AssemblyProduct("FastWin32")] 8 | [assembly: AssemblyCopyright("Copyright © Wwh 2018")] 9 | [assembly: AssemblyTrademark("")] 10 | [assembly: AssemblyCulture("")] 11 | [assembly: ComVisible(false)] 12 | [assembly: Guid("0b6ac808-3a51-4072-954f-d55de4f0209b")] 13 | [assembly: AssemblyVersion("2.6.*")] 14 | -------------------------------------------------------------------------------- /FastWin32/SafeNativeHandle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static FastWin32.NativeMethods; 3 | 4 | namespace FastWin32 5 | { 6 | /// 7 | /// 安全句柄 8 | /// 9 | internal struct SafeNativeHandle : IDisposable 10 | { 11 | private IntPtr _handle; 12 | 13 | private bool _isDisposed; 14 | 15 | public bool IsValid => _handle != IntPtr.Zero; 16 | 17 | public static implicit operator SafeNativeHandle(IntPtr value) => new SafeNativeHandle() { _handle = value }; 18 | 19 | public static implicit operator IntPtr(SafeNativeHandle value) => value._handle; 20 | 21 | public void Dispose() 22 | { 23 | if (_isDisposed) 24 | return; 25 | 26 | if (_handle != CURRENT_PROCESS) 27 | CloseHandle(_handle); 28 | _isDisposed = true; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /FastWin32/Windowing/Window.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static FastWin32.NativeMethods; 3 | 4 | namespace FastWin32.Windowing 5 | { 6 | /// 7 | /// 窗口 8 | /// 9 | public static unsafe class Window 10 | { 11 | /// 12 | /// 遍历窗口回调函数,继续遍历返回true,否则返回false 13 | /// 14 | /// 窗口句柄 15 | /// 16 | public delegate bool EnumWindowsCallback(IntPtr windowHandle); 17 | 18 | /// 19 | /// 获取包含桌面ListView的句柄 20 | /// 21 | /// 22 | public static IntPtr GetDesktopView() 23 | { 24 | IntPtr workerW; 25 | IntPtr programManager; 26 | IntPtr shell; 27 | 28 | workerW = IntPtr.Zero; 29 | shell = IntPtr.Zero; 30 | if (Environment.OSVersion.Version.Major >= 6) 31 | { 32 | //Vista及以上 33 | NativeMethods.EnumWindows((windowHandle, lParam) => 34 | { 35 | shell = FindWindowEx(windowHandle, IntPtr.Zero, "SHELLDLL_DefView", null); 36 | if (shell != IntPtr.Zero) 37 | { 38 | //如果当前窗口存在类名为SHELLDLL_DefView的子窗口 39 | workerW = FindWindowEx(IntPtr.Zero, windowHandle, "WorkerW", null); 40 | return false; 41 | } 42 | return true; 43 | }, IntPtr.Zero); 44 | } 45 | else 46 | { 47 | //XP及以下 48 | programManager = GetShellWindow(); 49 | //XP的SHELLDLL_DefView在Program Manager里 50 | shell = FindWindowEx(programManager, IntPtr.Zero, "SHELLDLL_DefView", null); 51 | } 52 | //先获取WorkerW 53 | return FindWindowEx(shell, IntPtr.Zero, "SysListView32", "FolderView"); 54 | } 55 | 56 | /// 57 | /// 将窗口置顶并激活(单次,非永久),非直接调用Win32API SetForegroundWindow,成功率高 58 | /// 59 | /// 窗口句柄 60 | public static void SetForegroundWindow(IntPtr windowHandle) 61 | { 62 | if (!IsWindow(windowHandle)) 63 | throw new ArgumentException("无效窗口句柄"); 64 | 65 | uint currentThreadId; 66 | uint foregroundThreadId; 67 | 68 | currentThreadId = GetCurrentThreadId(); 69 | //获取当前线程ID 70 | foregroundThreadId = GetWindowThreadProcessId(GetForegroundWindow(), null); 71 | //获取要附加到的线程的ID 72 | AttachThreadInput(currentThreadId, foregroundThreadId, true); 73 | //附加到线程 74 | NativeMethods.SetForegroundWindow(windowHandle); 75 | SetActiveWindow(windowHandle); 76 | SetFocus(windowHandle); 77 | AttachThreadInput(currentThreadId, foregroundThreadId, false); 78 | //分离 79 | } 80 | 81 | /// 82 | /// 查找窗口 83 | /// 84 | /// 窗口类名 85 | /// 窗口标题 86 | /// 87 | public static IntPtr FindWindow(string className, string windowName) 88 | { 89 | return NativeMethods.FindWindow(className, windowName); 90 | } 91 | 92 | /// 93 | /// 查找窗口 94 | /// 95 | /// 父窗口句柄 96 | /// 从此窗口之后开始查找(此窗口必须为父窗口的直接子窗口) 97 | /// 窗口类名 98 | /// 窗口标题 99 | /// 100 | public static IntPtr FindWindow(IntPtr parentWindowHandle, IntPtr afterWindowHandle, string className, string windowName) 101 | { 102 | return FindWindowEx(parentWindowHandle, afterWindowHandle, className, windowName); 103 | } 104 | 105 | /// 106 | /// 遍历所有顶级窗口 107 | /// 108 | /// 查找到窗口时的回调函数 109 | /// 110 | public static bool EnumWindows(EnumWindowsCallback callback) 111 | { 112 | if (callback == null) 113 | throw new ArgumentNullException(); 114 | 115 | return NativeMethods.EnumWindows((windowHandle, lParam) => callback(windowHandle), IntPtr.Zero); 116 | } 117 | 118 | /// 119 | /// 遍历所有子窗口 120 | /// 121 | /// 父窗口 122 | /// 查找到窗口时的回调函数 123 | /// 124 | public static bool EnumChildWindows(IntPtr windowHandleParent, EnumWindowsCallback callback) 125 | { 126 | if (callback == null) 127 | throw new ArgumentNullException(); 128 | 129 | return NativeMethods.EnumChildWindows(windowHandleParent, (windowHandle, lParam) => callback(windowHandle), IntPtr.Zero); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastWin32 2 | MemoryReadWrite FunctionHook InlineAsm Managed/UnmanagedInject 3 | 4 | Exampe1:Read/WriteMemory 5 | ``` 6 | namespace Example1 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | uint processId; 13 | Pointer pointer; 14 | int value; 15 | 16 | processId = (uint)Process.Start("Tutorial-i386.exe").Id; 17 | Console.WriteLine("Go to \"Step 6\" then continue"); 18 | Console.ReadKey(); 19 | pointer = new Pointer("Tutorial-i386.exe", 0x1FD630, 0); 20 | MemoryIO.ReadInt32(processId, pointer, out value); 21 | Console.WriteLine($"Current value:{value}. Now we lock it"); 22 | while (true) 23 | { 24 | MemoryIO.WriteInt32(processId, pointer, 5000); 25 | Thread.Sleep(1); 26 | } 27 | } 28 | } 29 | } 30 | ``` 31 | --------------------------------------------------------------------------------