├── .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 |
--------------------------------------------------------------------------------