├── .gitattributes ├── .gitignore ├── .vs ├── DotnetPatch │ ├── DesignTimeBuild │ │ └── .dtbcache.v2 │ ├── v15 │ │ └── Server │ │ │ └── sqlite3 │ │ │ ├── db.lock │ │ │ ├── storage.ide │ │ │ ├── storage.ide-shm │ │ │ └── storage.ide-wal │ └── v17 │ │ ├── .futdcache.v2 │ │ └── DocumentLayout.json └── ProjectEvaluation │ ├── dotnetpatch.metadata.v7.bin │ └── dotnetpatch.projects.v7.bin ├── ClrFile.cs ├── ClrFileModifier.cs ├── DotnetPatch.csproj ├── DotnetPatch.sln ├── LICENSE.md ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── MetadataIterator.cs ├── MetadataTables.cs ├── PENCIL12.ICO ├── Program.cs ├── Properties ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── README.md ├── Script └── Commands.cs ├── app.config ├── bin └── Release │ └── net6.0-windows │ ├── DotnetPatch.deps.json │ ├── DotnetPatch.dll │ ├── DotnetPatch.dll.config │ ├── DotnetPatch.exe │ ├── DotnetPatch.pdb │ ├── DotnetPatch.runtimeconfig.json │ ├── DotnetPatchBak.exe │ ├── Dsl.dll │ ├── Dsl.pdb │ ├── ILMerge.exe │ ├── UnityEditor.dll │ ├── UnityEngine.UI.dll │ ├── UnityEngine.dll │ └── domerge.bat └── dep ├── Common.dll ├── Common.pdb ├── DotnetStoryScript.dll ├── DotnetStoryScript.pdb ├── Dsl.dll ├── Dsl.pdb ├── LitJson.dll ├── ScriptFrameworkLibrary.dll ├── modify.scp └── redirect.scp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin/Debug 3 | obj 4 | *.sdf 5 | *.suo 6 | *.user 7 | *.opensdf 8 | *.vsidx 9 | *.lock 10 | .vs 11 | -------------------------------------------------------------------------------- /.vs/DotnetPatch/DesignTimeBuild/.dtbcache.v2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/DotnetPatch/DesignTimeBuild/.dtbcache.v2 -------------------------------------------------------------------------------- /.vs/DotnetPatch/v15/Server/sqlite3/db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/DotnetPatch/v15/Server/sqlite3/db.lock -------------------------------------------------------------------------------- /.vs/DotnetPatch/v15/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- 1 | SQLite format 3@ .A  -------------------------------------------------------------------------------- /.vs/DotnetPatch/v15/Server/sqlite3/storage.ide-shm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/DotnetPatch/v15/Server/sqlite3/storage.ide-shm -------------------------------------------------------------------------------- /.vs/DotnetPatch/v15/Server/sqlite3/storage.ide-wal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/DotnetPatch/v15/Server/sqlite3/storage.ide-wal -------------------------------------------------------------------------------- /.vs/DotnetPatch/v17/.futdcache.v2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/DotnetPatch/v17/.futdcache.v2 -------------------------------------------------------------------------------- /.vs/DotnetPatch/v17/DocumentLayout.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": 1, 3 | "WorkspaceRootPath": "F:\\GitHub\\DotnetPatch\\", 4 | "Documents": [ 5 | { 6 | "AbsoluteMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|F:\\GitHub\\DotnetPatch\\script\\commands.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", 7 | "RelativeMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|solutionrelative:script\\commands.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" 8 | }, 9 | { 10 | "AbsoluteMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|f:\\github\\dotnetpatch\\clrfilemodifier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", 11 | "RelativeMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|solutionrelative:clrfilemodifier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" 12 | }, 13 | { 14 | "AbsoluteMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|F:\\GitHub\\DotnetPatch\\mainform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", 15 | "RelativeMoniker": "D:0:0:{96284113-E412-4BC5-88F8-2EDE21EC3ABD}|DotnetPatch.csproj|solutionrelative:mainform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" 16 | } 17 | ], 18 | "DocumentGroupContainers": [ 19 | { 20 | "Orientation": 0, 21 | "VerticalTabListWidth": 256, 22 | "DocumentGroups": [ 23 | { 24 | "DockedWidth": 200, 25 | "SelectedChildIndex": 2, 26 | "Children": [ 27 | { 28 | "$type": "Document", 29 | "DocumentIndex": 2, 30 | "Title": "MainForm.cs", 31 | "DocumentMoniker": "F:\\GitHub\\DotnetPatch\\MainForm.cs", 32 | "RelativeDocumentMoniker": "MainForm.cs", 33 | "ToolTip": "F:\\GitHub\\DotnetPatch\\MainForm.cs", 34 | "RelativeToolTip": "MainForm.cs", 35 | "ViewState": "AQIAAK8AAAAAAAAAAADgv8IAAAABAAAA", 36 | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", 37 | "WhenOpened": "2024-06-18T10:35:30.402Z" 38 | }, 39 | { 40 | "$type": "Document", 41 | "DocumentIndex": 1, 42 | "Title": "ClrFileModifier.cs", 43 | "DocumentMoniker": "F:\\GitHub\\DotnetPatch\\ClrFileModifier.cs", 44 | "RelativeDocumentMoniker": "ClrFileModifier.cs", 45 | "ToolTip": "F:\\GitHub\\DotnetPatch\\ClrFileModifier.cs", 46 | "RelativeToolTip": "ClrFileModifier.cs", 47 | "ViewState": "AQIAAAAAAAAAAAAAAAAAAOoBAAAnAAAA", 48 | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", 49 | "WhenOpened": "2024-06-18T10:35:30.406Z", 50 | "EditorCaption": "" 51 | }, 52 | { 53 | "$type": "Document", 54 | "DocumentIndex": 0, 55 | "Title": "Commands.cs", 56 | "DocumentMoniker": "F:\\GitHub\\DotnetPatch\\Script\\Commands.cs", 57 | "RelativeDocumentMoniker": "Script\\Commands.cs", 58 | "ToolTip": "F:\\GitHub\\DotnetPatch\\Script\\Commands.cs", 59 | "RelativeToolTip": "Script\\Commands.cs", 60 | "ViewState": "AQIAAAAAAAAAAAAAAAAAAAkAAAAcAAAA", 61 | "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", 62 | "WhenOpened": "2024-06-18T10:35:30.411Z", 63 | "EditorCaption": "" 64 | } 65 | ] 66 | } 67 | ] 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /.vs/ProjectEvaluation/dotnetpatch.metadata.v7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/ProjectEvaluation/dotnetpatch.metadata.v7.bin -------------------------------------------------------------------------------- /.vs/ProjectEvaluation/dotnetpatch.projects.v7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/.vs/ProjectEvaluation/dotnetpatch.projects.v7.bin -------------------------------------------------------------------------------- /ClrFile.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/ClrFile.cs -------------------------------------------------------------------------------- /ClrFileModifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | using System.Windows.Forms; 6 | using DotnetStoryScript; 7 | using DotnetStoryScript.DslExpression; 8 | 9 | namespace DotnetPatch 10 | { 11 | public class ClrFileModifier 12 | { 13 | public ClrFileModifier(string s, string path) 14 | { 15 | m_OriginalFile = s; 16 | m_OutputPath = path; 17 | 18 | string fn = Path.GetFileName(m_OriginalFile); 19 | File.Copy(m_OriginalFile, Path.Combine(m_OutputPath, fn), true); 20 | } 21 | 22 | public static List ResultTexts 23 | { 24 | get { return s_ResultTexts; } 25 | } 26 | 27 | public void BeginExtend(uint newSize) 28 | { 29 | Load(); 30 | m_Methods = new byte[newSize]; 31 | m_Pos = 0; 32 | m_Header = m_ClrFile.PrepareNewSectionHeader(".ilcode", newSize, false); 33 | m_Methods.Initialize(); 34 | m_Find = false; 35 | } 36 | 37 | public void Extend(string fullName, string methodName, uint insertSize) 38 | { 39 | string classNs = string.Empty; 40 | string className = fullName; 41 | int srcIx = fullName.LastIndexOf('.'); 42 | if (srcIx > 0) { 43 | classNs = fullName.Substring(0, srcIx); 44 | className = fullName.Substring(srcIx + 1); 45 | } 46 | 47 | int srcStart, srcEnd; 48 | bool srcValid = GetTypeMethods(classNs, className, out srcStart, out srcEnd); 49 | if (!srcValid) { 50 | s_ResultTexts.Add(string.Format("Can't find src {0}->{1}", className, srcValid)); 51 | return; 52 | } 53 | MethodDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtMethodDef] as MethodDefIterator; 54 | for (uint ix = (uint)srcStart; ix < (uint)srcEnd; ++ix) { 55 | it.MoveTo(ix - 1); 56 | string name = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 57 | if (name == methodName) { 58 | uint offset = m_ClrFile.GetFileOffset(it.RVA); 59 | byte ilheader = m_ClrFile.Buffer[offset]; 60 | if ((ilheader & 0x03) == 0x02) { 61 | uint size = (uint)(ilheader >> 2); 62 | if (size + insertSize < 64) { 63 | m_Methods[m_Pos] = (byte)(((size + insertSize) << 2) | 0x02); 64 | Array.Copy(m_ClrFile.Buffer, offset + 1, m_Methods, m_Pos + 1 + insertSize, size); 65 | it.RVA = m_Header.VirtualAddress + m_Pos; 66 | } else { 67 | MetadataTables.WriteUInt(m_Methods, m_Pos, 0x7fff3003); 68 | MetadataTables.WriteUInt(m_Methods, m_Pos + 4, size + insertSize); 69 | MetadataTables.WriteUInt(m_Methods, m_Pos + 8, 0); 70 | Array.Copy(m_ClrFile.Buffer, offset + 1, m_Methods, m_Pos + 12 + insertSize, size); 71 | it.RVA = m_Header.VirtualAddress + m_Pos; 72 | } 73 | } else if ((ilheader & 0x03) == 0x03) { 74 | uint one = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset); 75 | uint two = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset + 4); 76 | uint three = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset + 8); 77 | MetadataTables.WriteUInt(m_Methods, m_Pos, one); 78 | MetadataTables.WriteUInt(m_Methods, m_Pos + 4, two + insertSize); 79 | MetadataTables.WriteUInt(m_Methods, m_Pos + 8, three); 80 | Array.Copy(m_ClrFile.Buffer, offset + 12, m_Methods, m_Pos + 12 + insertSize, two); 81 | it.RVA = m_Header.VirtualAddress + m_Pos; 82 | } 83 | m_Find = true; 84 | break; 85 | } 86 | } 87 | } 88 | 89 | public void EndExtend() 90 | { 91 | if (m_Find) { 92 | SaveWithNewSection(); 93 | } 94 | } 95 | 96 | public void BeginModify() 97 | { 98 | Load(); 99 | } 100 | 101 | public void ModifyWithData(string fullName, string methodName, uint pos, byte[] data) 102 | { 103 | string classNs = string.Empty; 104 | string className = fullName; 105 | int srcIx = fullName.LastIndexOf('.'); 106 | if (srcIx > 0) { 107 | classNs = fullName.Substring(0, srcIx); 108 | className = fullName.Substring(srcIx + 1); 109 | } 110 | 111 | Modify(classNs, className, methodName, (uint offset) => { 112 | Array.Copy(data, 0, m_ClrFile.Buffer, offset + pos, data.Length); 113 | }); 114 | } 115 | public void ModifyWithField(string fullName, string methodName, uint pos, byte op, string fullCn, string fn) 116 | { 117 | string classNs = string.Empty; 118 | string className = fullName; 119 | int srcIx = fullName.LastIndexOf('.'); 120 | if (srcIx > 0) { 121 | classNs = fullName.Substring(0, srcIx); 122 | className = fullName.Substring(srcIx + 1); 123 | } 124 | string ns = string.Empty; 125 | string cn = fullCn; 126 | int targetIx = fullCn.LastIndexOf('.'); 127 | if (targetIx > 0) { 128 | ns = fullCn.Substring(0, targetIx); 129 | cn = fullCn.Substring(targetIx + 1); 130 | } 131 | 132 | Modify(classNs, className, methodName, (uint offset) => { 133 | int srcStart, srcEnd; 134 | bool srcValid = GetTypeFields(ns, cn, out srcStart, out srcEnd); 135 | if (!srcValid) { 136 | s_ResultTexts.Add(string.Format("Can't find src {0}->{1}", cn, srcValid)); 137 | return; 138 | } 139 | FieldIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtFieldDef] as FieldIterator; 140 | for (uint ix = (uint)srcStart; ix < (uint)srcEnd; ++ix) { 141 | it.MoveTo(ix - 1); 142 | string name = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 143 | if (name == fn) { 144 | m_ClrFile.Buffer[offset + pos] = op; 145 | m_ClrFile.Buffer[offset + pos + 1] = (byte)(ix & 0xff); 146 | m_ClrFile.Buffer[offset + pos + 2] = (byte)((ix >> 8) & 0xff); 147 | m_ClrFile.Buffer[offset + pos + 3] = (byte)((ix >> 16) & 0xff); 148 | m_ClrFile.Buffer[offset + pos + 4] = (byte)0x04; 149 | break; 150 | } 151 | } 152 | }); 153 | } 154 | 155 | public void ModifyWithCallMethod(string fullName, string methodName, uint pos, byte op, string fullCn, string mn) 156 | { 157 | string classNs = string.Empty; 158 | string className = fullName; 159 | int srcIx = fullName.LastIndexOf('.'); 160 | if (srcIx > 0) { 161 | classNs = fullName.Substring(0, srcIx); 162 | className = fullName.Substring(srcIx + 1); 163 | } 164 | string ns = string.Empty; 165 | string cn = fullCn; 166 | int targetIx = fullCn.LastIndexOf('.'); 167 | if (targetIx > 0) { 168 | ns = fullCn.Substring(0, targetIx); 169 | cn = fullCn.Substring(targetIx + 1); 170 | } 171 | 172 | Modify(classNs, className, methodName, (uint offset) => { 173 | int srcStart, srcEnd; 174 | bool srcValid = GetTypeMethods(ns, cn, out srcStart, out srcEnd); 175 | if (!srcValid) { 176 | s_ResultTexts.Add(string.Format("Can't find src {0}->{1}", cn, srcValid)); 177 | return; 178 | } 179 | MethodDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtMethodDef] as MethodDefIterator; 180 | for (uint ix = (uint)srcStart; ix < (uint)srcEnd; ++ix) { 181 | it.MoveTo(ix - 1); 182 | string name = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 183 | if (name == mn) { 184 | m_ClrFile.Buffer[offset + pos] = op; 185 | m_ClrFile.Buffer[offset + pos + 1] = (byte)(ix & 0xff); 186 | m_ClrFile.Buffer[offset + pos + 2] = (byte)((ix >> 8) & 0xff); 187 | m_ClrFile.Buffer[offset + pos + 3] = (byte)((ix >> 16) & 0xff); 188 | m_ClrFile.Buffer[offset + pos + 4] = (byte)0x06; 189 | break; 190 | } 191 | } 192 | }); 193 | } 194 | 195 | public void EndModify() 196 | { 197 | Save(); 198 | } 199 | 200 | public void BeginReplace() 201 | { 202 | Load(); 203 | } 204 | 205 | public void Replace(string src, string target) 206 | { 207 | string srcNs = string.Empty; 208 | string srcName = src; 209 | int srcIx = src.LastIndexOf('.'); 210 | if (srcIx > 0) { 211 | srcNs = src.Substring(0, srcIx); 212 | srcName = src.Substring(srcIx + 1); 213 | } 214 | string targetNs = string.Empty; 215 | string targetName = target; 216 | int targetIx = target.LastIndexOf('.'); 217 | if (targetIx > 0) { 218 | targetNs = target.Substring(0, targetIx); 219 | targetName = target.Substring(targetIx + 1); 220 | } 221 | 222 | int srcStart, srcEnd; 223 | int targetStart, targetEnd; 224 | bool srcValid = GetTypeMethods(srcNs, srcName, out srcStart, out srcEnd); 225 | bool targetValid = GetTypeMethods(targetNs, targetName, out targetStart, out targetEnd); 226 | if (!srcValid || !targetValid) { 227 | s_ResultTexts.Add(string.Format("Can't find src {0}->{1} or target {2}->{3}", srcName, srcValid, targetName, targetValid)); 228 | return; 229 | } 230 | MethodDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtMethodDef] as MethodDefIterator; 231 | for (uint ix = (uint)srcStart; ix < (uint)srcEnd; ++ix) { 232 | it.MoveTo(ix - 1); 233 | if (MoveToMatchedMethod(it, targetStart, targetEnd)) { 234 | uint rva = it.RVA; 235 | it.MoveTo(ix - 1); 236 | it.RVA = rva; 237 | 238 | s_ResultTexts.Add(string.Format("Replace {0}->{1} succeeded", srcName, targetName)); 239 | } 240 | } 241 | } 242 | public void ReplaceAssemblyRefName(string src, string target) 243 | { 244 | var it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtAssemblyRef] as AssemblyRefIterator; 245 | it.MoveToFirst(); 246 | do { 247 | string tmp = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 248 | if (tmp == src) { 249 | if (ReplaceString(m_ClrFile.Buffer, m_StringStart, it.Name, target)) { 250 | s_ResultTexts.Add(string.Format("Replace string {0}->{1} succeeded", src, target)); 251 | } 252 | else { 253 | s_ResultTexts.Add(string.Format("Replace string {0}->{1} failed", src, target)); 254 | } 255 | break; 256 | } 257 | } while (it.MoveToNext()); 258 | } 259 | public void RedirectAssembly(string target, IList srcs) 260 | { 261 | uint targetName = 0; 262 | var it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtAssemblyRef] as AssemblyRefIterator; 263 | it.MoveToFirst(); 264 | do { 265 | string tmp = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 266 | if (tmp == target) { 267 | targetName = it.Name; 268 | break; 269 | } 270 | } while (it.MoveToNext()); 271 | if (targetName > 0) { 272 | it.MoveToFirst(); 273 | do { 274 | string tmp = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 275 | if (srcs.Contains(tmp)) { 276 | it.Name = targetName; 277 | 278 | s_ResultTexts.Add(string.Format("Redirect assembly {0}->{1} succeeded", tmp, target)); 279 | } 280 | } while (it.MoveToNext()); 281 | } 282 | else { 283 | s_ResultTexts.Add(string.Format("Redirect asssembly to {0} failed", target)); 284 | } 285 | } 286 | 287 | public void EndReplace() 288 | { 289 | Save(); 290 | } 291 | 292 | private void Load() 293 | { 294 | string fn = Path.GetFileName(m_OriginalFile); 295 | string tmp = Path.Combine(m_OutputPath, fn); 296 | 297 | m_ClrFile = new ClrFile(); 298 | m_ClrFile.Load(tmp); 299 | uint mpos = m_ClrFile.Metadata.MetadataPosition; 300 | uint stringOffset = m_ClrFile.Metadata.StringsHeader.Offset; 301 | uint blobOffset = m_ClrFile.Metadata.BlobHeader.Offset; 302 | 303 | m_StringStart = mpos + stringOffset; 304 | m_BlobStart = mpos + blobOffset; 305 | } 306 | private void Save() 307 | { 308 | string fn = Path.GetFileName(m_OriginalFile); 309 | m_ClrFile.Save(Path.Combine(m_OutputPath, fn)); 310 | } 311 | 312 | private void SaveWithNewSection() 313 | { 314 | string fn = Path.GetFileName(m_OriginalFile); 315 | m_ClrFile.Save(Path.Combine(m_OutputPath, fn), m_Header, m_Methods); 316 | } 317 | 318 | private void Modify(string nsName, string className, string methodName, Action callback) 319 | { 320 | int srcStart, srcEnd; 321 | bool srcValid = GetTypeMethods(nsName, className, out srcStart, out srcEnd); 322 | if (!srcValid) { 323 | s_ResultTexts.Add(string.Format("Can't find src {0}->{1}", className, srcValid)); 324 | return; 325 | } 326 | MethodDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtMethodDef] as MethodDefIterator; 327 | for (uint ix = (uint)srcStart; ix < (uint)srcEnd; ++ix) { 328 | it.MoveTo(ix - 1); 329 | string name = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 330 | if (name == methodName) { 331 | uint offset = m_ClrFile.GetFileOffset(it.RVA); 332 | byte ilheader = m_ClrFile.Buffer[offset]; 333 | if ((ilheader & 0x03) == 0x02) { 334 | uint size = (uint)(ilheader >> 2); 335 | uint headerSize = 1; 336 | 337 | callback(offset + headerSize); 338 | } else if ((ilheader & 0x03) == 0x03) { 339 | uint one = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset); 340 | uint two = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset + 4); 341 | uint three = MetadataTables.ReadUInt(m_ClrFile.Buffer, offset + 8); 342 | 343 | uint headerSize = ((one & 0x0000f000) >> 12) * 4; 344 | 345 | callback(offset + headerSize); 346 | } 347 | } 348 | } 349 | } 350 | 351 | private bool MoveToMatchedMethod(MethodDefIterator it, int start, int end) 352 | { 353 | bool ret = false; 354 | string name = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 355 | string signature = GetBlobString(m_ClrFile.Buffer, m_BlobStart, it.Signature); 356 | if (name == ".ctor" || name == ".cctor") 357 | return false; 358 | for (uint ix = (uint)start; ix < (uint)end; ++ix) { 359 | it.MoveTo(ix - 1); 360 | string name2 = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 361 | string signature2 = GetBlobString(m_ClrFile.Buffer, m_BlobStart, it.Signature); 362 | if (0 == name.CompareTo(name2) && 0 == signature.CompareTo(signature2)) { 363 | ret = true; 364 | break; 365 | } 366 | } 367 | return ret; 368 | } 369 | 370 | private bool GetTypeMethods(string ns, string name, out int start, out int end) 371 | { 372 | start = end = -1; 373 | bool ret = false; 374 | MethodDefIterator methodIt = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtMethodDef] as MethodDefIterator; 375 | TypeDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtTypeDef] as TypeDefIterator; 376 | it.MoveToFirst(); 377 | for (; !it.IsEnd; it.MoveToNext()) { 378 | string nsName = GetString(m_ClrFile.Buffer, m_StringStart, it.NameSpace); 379 | string typeName = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 380 | if (0 == typeName.CompareTo(name) && (string.IsNullOrEmpty(ns) || 0==nsName.CompareTo(ns))) { 381 | start = (int)it.MethodList; 382 | if (it.MoveToNext()) { 383 | end = (int)it.MethodList; 384 | } else { 385 | end = (int)methodIt.RecordNumber; 386 | } 387 | ret = true; 388 | break; 389 | } 390 | } 391 | return ret; 392 | } 393 | private bool GetTypeFields(string ns, string name, out int start, out int end) 394 | { 395 | start = end = -1; 396 | bool ret = false; 397 | FieldIterator fieldIt = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtFieldDef] as FieldIterator; 398 | TypeDefIterator it = m_ClrFile.Metadata.Tables[(int)CorTokenType.mdtTypeDef] as TypeDefIterator; 399 | it.MoveToFirst(); 400 | for (; !it.IsEnd; it.MoveToNext()) { 401 | string nsName = GetString(m_ClrFile.Buffer, m_StringStart, it.NameSpace); 402 | string typeName = GetString(m_ClrFile.Buffer, m_StringStart, it.Name); 403 | if (0 == typeName.CompareTo(name) && (string.IsNullOrEmpty(ns) || 0 == nsName.CompareTo(ns))) { 404 | start = (int)it.FieldList; 405 | if (it.MoveToNext()) { 406 | end = (int)it.FieldList; 407 | } else { 408 | end = (int)fieldIt.RecordNumber; 409 | } 410 | ret = true; 411 | break; 412 | } 413 | } 414 | return ret; 415 | } 416 | 417 | private static bool ReplaceString(byte[] buffer, uint start, uint offset, string target) 418 | { 419 | int pos = (int)(start + offset); 420 | if (pos < 0 || pos > buffer.Length) 421 | return false; 422 | var bytes = System.Text.Encoding.UTF8.GetBytes(target); 423 | int nlen = 0; 424 | for (; buffer[pos + nlen] > 0; nlen++) ; 425 | if (nlen <= 0 || nlen < bytes.Length) 426 | return false; 427 | for (int ix = 0; ix < nlen; ++ix) { 428 | if (ix < bytes.Length) 429 | buffer[pos + ix] = bytes[ix]; 430 | else 431 | buffer[pos + ix] = 0; 432 | } 433 | return true; 434 | } 435 | private static string GetString(byte[] buffer, uint start, uint offset) 436 | { 437 | int pos = (int)(start + offset); 438 | if (pos < 0 || pos > buffer.Length) 439 | return null; 440 | int nlen = 0; 441 | for (; buffer[pos + nlen] > 0; nlen++) ; 442 | if (nlen <= 0) 443 | return null; 444 | return System.Text.Encoding.UTF8.GetString(buffer, (int)pos, nlen); 445 | } 446 | private static string GetBlobString(byte[] buffer, uint start, uint offset) 447 | { 448 | int pos = (int)(start + offset); 449 | if (pos < 0 || pos > buffer.Length) 450 | return ""; 451 | byte b = buffer[pos]; 452 | int len = 0; 453 | if ((b & 0x80) == 0) { 454 | len = (b & 0x7F); 455 | pos++; 456 | } else if ((b & 0x40) == 0) { 457 | ushort v1 = b; 458 | ushort v2 = buffer[pos + 1]; 459 | len = ((v1 & 0x3F) << 8) + v2; 460 | pos += 2; 461 | } else if ((b & 0x20) == 0) { 462 | uint v1 = b; 463 | uint v2 = buffer[pos + 1]; 464 | uint v3 = buffer[pos + 2]; 465 | uint v4 = buffer[pos + 3]; 466 | len = (int)(((v1 & 0x1F) << 24) + (v2 << 16) + (v3 << 8) + v4); 467 | pos += 4; 468 | } else 469 | return ""; 470 | string s = ""; 471 | for (int i = 0; i < len; i++) { 472 | b = buffer[pos + i]; 473 | s += b.ToString("X2"); 474 | } 475 | return s; 476 | } 477 | 478 | private string m_OriginalFile = null; 479 | private string m_OutputPath = null; 480 | private ClrFile m_ClrFile = null; 481 | private uint m_StringStart = 0; 482 | private uint m_BlobStart = 0; 483 | 484 | private byte[] m_Methods = null; 485 | private uint m_Pos = 0; 486 | private IMAGE_SECTION_HEADER m_Header; 487 | bool m_Find = false; 488 | 489 | private static List s_ResultTexts = new List(); 490 | } 491 | public static class ScriptProcessor 492 | { 493 | public static void Init() 494 | { 495 | s_Calculator.Init(); 496 | 497 | //注册Gm命令 498 | s_Calculator.Register("begin", string.Empty, new ExpressionFactoryHelper()); 499 | s_Calculator.Register("end", string.Empty, new ExpressionFactoryHelper()); 500 | s_Calculator.Register("beginfile", string.Empty, new ExpressionFactoryHelper()); 501 | s_Calculator.Register("endfile", string.Empty, new ExpressionFactoryHelper()); 502 | s_Calculator.Register("beginreplace", string.Empty, new ExpressionFactoryHelper()); 503 | s_Calculator.Register("replace", string.Empty, new ExpressionFactoryHelper()); 504 | s_Calculator.Register("replaceassemblyrefname", string.Empty, new ExpressionFactoryHelper()); 505 | s_Calculator.Register("redirectassembly", string.Empty, new ExpressionFactoryHelper()); 506 | s_Calculator.Register("endreplace", string.Empty, new ExpressionFactoryHelper()); 507 | s_Calculator.Register("beginextend", string.Empty, new ExpressionFactoryHelper()); 508 | s_Calculator.Register("extend", string.Empty, new ExpressionFactoryHelper()); 509 | s_Calculator.Register("endextend", string.Empty, new ExpressionFactoryHelper()); 510 | s_Calculator.Register("beginmodify", string.Empty, new ExpressionFactoryHelper()); 511 | s_Calculator.Register("endmodify", string.Empty, new ExpressionFactoryHelper()); 512 | s_Calculator.Register("writeloadarg", string.Empty, new ExpressionFactoryHelper()); 513 | s_Calculator.Register("writeloadlocal", string.Empty, new ExpressionFactoryHelper()); 514 | s_Calculator.Register("writeloadfield", string.Empty, new ExpressionFactoryHelper()); 515 | s_Calculator.Register("writeloadstaticfield", string.Empty, new ExpressionFactoryHelper()); 516 | s_Calculator.Register("writecall", string.Empty, new ExpressionFactoryHelper()); 517 | s_Calculator.Register("writecallvirt", string.Empty, new ExpressionFactoryHelper()); 518 | s_Calculator.Register("writenops", string.Empty, new ExpressionFactoryHelper()); 519 | s_Calculator.Register("getfilelist", string.Empty, new ExpressionFactoryHelper()); 520 | s_Calculator.Register("log", string.Empty, new ExpressionFactoryHelper()); 521 | } 522 | public static void Start(IList files, string outputPath, string scpFile) 523 | { 524 | s_FileList.Clear(); 525 | s_FileList.AddRange(files); 526 | s_OutputPath = outputPath; 527 | 528 | s_Calculator.LoadDsl(scpFile); 529 | s_Calculator.Calc("main"); 530 | } 531 | public static IList GetFileList() 532 | { 533 | return s_FileList; 534 | } 535 | public static void Begin(string info) 536 | { 537 | s_CurNum = 0; 538 | s_TotalNum = s_FileList.Count; 539 | Program.MainForm.ProgressBar.Value = 0; 540 | Program.MainForm.StatusBar.Text = info; 541 | 542 | ClrFileModifier.ResultTexts.Clear(); 543 | s_ClrFileModifiers.Clear(); 544 | } 545 | public static void End(string info) 546 | { 547 | Program.MainForm.StatusBar.Text = info; 548 | Program.MainForm.ResultCtrl.Text = string.Join("\r\n", ClrFileModifier.ResultTexts.ToArray()); 549 | ClrFileModifier.ResultTexts.Clear(); 550 | } 551 | public static void BeginFile(string file, string info) 552 | { 553 | Program.MainForm.StatusBar.Text = info; 554 | 555 | if (!s_ClrFileModifiers.ContainsKey(file)) { 556 | ClrFileModifier methodBodyModifier = new ClrFileModifier(file, s_OutputPath); 557 | s_ClrFileModifiers[file] = methodBodyModifier; 558 | } 559 | } 560 | public static void EndFile() 561 | { 562 | s_CurNum++; 563 | Program.MainForm.ProgressBar.Value = s_CurNum * 100 / s_TotalNum; 564 | } 565 | public static void BeginReplace(string file) 566 | { 567 | s_ClrFileModifiers[file].BeginReplace(); 568 | } 569 | public static void EndReplace(string file) 570 | { 571 | s_ClrFileModifiers[file].EndReplace(); 572 | } 573 | public static void Replace(string file, string src, string target) 574 | { 575 | s_ClrFileModifiers[file].Replace(src, target); 576 | } 577 | public static void ReplaceAssemblyRefName(string file, string src, string target) 578 | { 579 | s_ClrFileModifiers[file].ReplaceAssemblyRefName(src, target); 580 | } 581 | public static void RedirectAssembly(string file, string target, IList srcs) 582 | { 583 | s_ClrFileModifiers[file].RedirectAssembly(target, srcs); 584 | } 585 | public static void BeginExtend(string file, uint newSize) 586 | { 587 | s_ClrFileModifiers[file].BeginExtend(newSize); 588 | } 589 | public static void Extend(string file, string fullClassName, string methodName, uint insertSize) 590 | { 591 | s_ClrFileModifiers[file].Extend(fullClassName, methodName, insertSize); 592 | } 593 | public static void EndExtend(string file) 594 | { 595 | s_ClrFileModifiers[file].EndExtend(); 596 | } 597 | public static void BeginModify(string file) 598 | { 599 | s_ClrFileModifiers[file].BeginModify(); 600 | } 601 | public static void EndModify(string file) 602 | { 603 | s_ClrFileModifiers[file].EndModify(); 604 | } 605 | public static void WriteLoadArg(string file, string fullClassName, string methodName, uint pos, int index) 606 | { 607 | if (index >= 0 && index <= 3) { 608 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { (byte)(0x02 + index) }); 609 | } else if (index <= 0xff) { 610 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { 0x0E, (byte)index }); 611 | } else if (index <= 0xffff) { 612 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { 0xFE, 0x09, (byte)(index & 0xff), (byte)((index >> 8) & 0xff) }); 613 | } 614 | } 615 | public static void WriteLoadLocal(string file, string fullClassName, string methodName, uint pos, int index) 616 | { 617 | if (index >= 0 && index <= 3) { 618 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { (byte)(0x06 + index) }); 619 | } else if (index <= 0xff) { 620 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { 0x11, (byte)index }); 621 | } else if (index <= 0xffff) { 622 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, new byte[] { 0xFE, 0x0C, (byte)(index & 0xff), (byte)((index >> 8) & 0xff) }); 623 | } 624 | } 625 | public static void WriteLoadField(string file, string fullClassName, string methodName, uint pos, string cn, string fn) 626 | { 627 | s_ClrFileModifiers[file].ModifyWithField(fullClassName, methodName, pos, 0x7B, cn, fn); 628 | } 629 | public static void WriteLoadStaticField(string file, string fullClassName, string methodName, uint pos, string cn, string fn) 630 | { 631 | s_ClrFileModifiers[file].ModifyWithField(fullClassName, methodName, pos, 0x7E, cn, fn); 632 | } 633 | public static void WriteCall(string file, string fullClassName, string methodName, uint pos, string cn, string fn) 634 | { 635 | s_ClrFileModifiers[file].ModifyWithCallMethod(fullClassName, methodName, pos, 0x28, cn, fn); 636 | } 637 | public static void WriteCallVirt(string file, string fullClassName, string methodName, uint pos, string cn, string fn) 638 | { 639 | s_ClrFileModifiers[file].ModifyWithCallMethod(fullClassName, methodName, pos, 0x6F, cn, fn); 640 | } 641 | public static void WriteNops(string file, string fullClassName, string methodName, uint pos, int size) 642 | { 643 | byte[] nops = new byte[size]; 644 | for (int ix = 0; ix < size; ++ix) { 645 | nops[ix] = 0; 646 | } 647 | s_ClrFileModifiers[file].ModifyWithData(fullClassName, methodName, pos, nops); 648 | } 649 | 650 | private static DslCalculator s_Calculator = new DslCalculator(); 651 | private static Dictionary s_ClrFileModifiers = new Dictionary(); 652 | private static List s_FileList = new List(); 653 | private static string s_OutputPath = string.Empty; 654 | private static string s_Class = string.Empty; 655 | private static string s_Method = string.Empty; 656 | private static int s_CurNum = 0; 657 | private static int s_TotalNum = 0; 658 | } 659 | } 660 | -------------------------------------------------------------------------------- /DotnetPatch.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0-windows 4 | WinExe 5 | PENCIL12.ICO 6 | false 7 | False 8 | true 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | dep\Common.dll 18 | 19 | 20 | dep\DotnetStoryScript.dll 21 | 22 | 23 | dep\Dsl.dll 24 | 25 | 26 | dep\ScriptFrameworkLibrary.dll 27 | 28 | 29 | -------------------------------------------------------------------------------- /DotnetPatch.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30501.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetPatch", "DotnetPatch.csproj", "{96284113-E412-4BC5-88F8-2EDE21EC3ABD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {96284113-E412-4BC5-88F8-2EDE21EC3ABD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {96284113-E412-4BC5-88F8-2EDE21EC3ABD}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {96284113-E412-4BC5-88F8-2EDE21EC3ABD}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {96284113-E412-4BC5-88F8-2EDE21EC3ABD}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 可以任意使用与修改,只需要承认出处就可以了。 2 | -------------------------------------------------------------------------------- /MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace DotnetPatch 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// 必需的设计器变量。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 清理所有正在使用的资源。 12 | /// 13 | /// 如果应释放托管资源,为 true;否则为 false。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows 窗体设计器生成的代码 24 | 25 | /// 26 | /// 设计器支持所需的方法 - 不要 27 | /// 使用代码编辑器修改此方法的内容。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 32 | this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); 33 | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 34 | this.progressBar = new System.Windows.Forms.ToolStripProgressBar(); 35 | this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel(); 36 | this.infoLabel = new System.Windows.Forms.ToolStripStatusLabel(); 37 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 38 | this.assemblyList = new System.Windows.Forms.ListBox(); 39 | this.resultCtrl = new System.Windows.Forms.TextBox(); 40 | this.toolStrip1 = new System.Windows.Forms.ToolStrip(); 41 | this.addBtn = new System.Windows.Forms.ToolStripButton(); 42 | this.clearBtn = new System.Windows.Forms.ToolStripButton(); 43 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); 44 | this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel(); 45 | this.exportDir = new System.Windows.Forms.ToolStripTextBox(); 46 | this.folderBtn = new System.Windows.Forms.ToolStripButton(); 47 | this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); 48 | this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); 49 | this.srcClassName = new System.Windows.Forms.ToolStripTextBox(); 50 | this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); 51 | this.targetClassName = new System.Windows.Forms.ToolStripTextBox(); 52 | this.replaceMethodBody = new System.Windows.Forms.ToolStripButton(); 53 | this.extendMethodBody = new System.Windows.Forms.ToolStripButton(); 54 | this.toolStripContainer1.BottomToolStripPanel.SuspendLayout(); 55 | this.toolStripContainer1.ContentPanel.SuspendLayout(); 56 | this.toolStripContainer1.TopToolStripPanel.SuspendLayout(); 57 | this.toolStripContainer1.SuspendLayout(); 58 | this.statusStrip1.SuspendLayout(); 59 | this.splitContainer1.Panel1.SuspendLayout(); 60 | this.splitContainer1.Panel2.SuspendLayout(); 61 | this.splitContainer1.SuspendLayout(); 62 | this.toolStrip1.SuspendLayout(); 63 | this.SuspendLayout(); 64 | // 65 | // toolStripContainer1 66 | // 67 | // 68 | // toolStripContainer1.BottomToolStripPanel 69 | // 70 | this.toolStripContainer1.BottomToolStripPanel.Controls.Add(this.statusStrip1); 71 | // 72 | // toolStripContainer1.ContentPanel 73 | // 74 | this.toolStripContainer1.ContentPanel.Controls.Add(this.splitContainer1); 75 | this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(881, 447); 76 | this.toolStripContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 77 | this.toolStripContainer1.Location = new System.Drawing.Point(0, 0); 78 | this.toolStripContainer1.Name = "toolStripContainer1"; 79 | this.toolStripContainer1.Size = new System.Drawing.Size(881, 494); 80 | this.toolStripContainer1.TabIndex = 0; 81 | this.toolStripContainer1.Text = "toolStripContainer1"; 82 | // 83 | // toolStripContainer1.TopToolStripPanel 84 | // 85 | this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1); 86 | // 87 | // statusStrip1 88 | // 89 | this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; 90 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 91 | this.progressBar, 92 | this.statusLabel, 93 | this.infoLabel}); 94 | this.statusStrip1.Location = new System.Drawing.Point(0, 0); 95 | this.statusStrip1.Name = "statusStrip1"; 96 | this.statusStrip1.Size = new System.Drawing.Size(881, 22); 97 | this.statusStrip1.TabIndex = 1; 98 | this.statusStrip1.Text = "statusStrip1"; 99 | // 100 | // progressBar 101 | // 102 | this.progressBar.Name = "progressBar"; 103 | this.progressBar.Size = new System.Drawing.Size(100, 16); 104 | // 105 | // statusLabel 106 | // 107 | this.statusLabel.Name = "statusLabel"; 108 | this.statusLabel.Size = new System.Drawing.Size(617, 17); 109 | this.statusLabel.Spring = true; 110 | this.statusLabel.Text = "OK."; 111 | this.statusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 112 | // 113 | // infoLabel 114 | // 115 | this.infoLabel.IsLink = true; 116 | this.infoLabel.Name = "infoLabel"; 117 | this.infoLabel.Size = new System.Drawing.Size(147, 17); 118 | this.infoLabel.Text = "dreaman_163@163.com"; 119 | // 120 | // splitContainer1 121 | // 122 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 123 | this.splitContainer1.Location = new System.Drawing.Point(0, 0); 124 | this.splitContainer1.Name = "splitContainer1"; 125 | // 126 | // splitContainer1.Panel1 127 | // 128 | this.splitContainer1.Panel1.Controls.Add(this.assemblyList); 129 | // 130 | // splitContainer1.Panel2 131 | // 132 | this.splitContainer1.Panel2.Controls.Add(this.resultCtrl); 133 | this.splitContainer1.Size = new System.Drawing.Size(881, 447); 134 | this.splitContainer1.SplitterDistance = 320; 135 | this.splitContainer1.TabIndex = 0; 136 | // 137 | // assemblyList 138 | // 139 | this.assemblyList.Dock = System.Windows.Forms.DockStyle.Fill; 140 | this.assemblyList.FormattingEnabled = true; 141 | this.assemblyList.ItemHeight = 12; 142 | this.assemblyList.Location = new System.Drawing.Point(0, 0); 143 | this.assemblyList.Name = "assemblyList"; 144 | this.assemblyList.Size = new System.Drawing.Size(320, 447); 145 | this.assemblyList.TabIndex = 1; 146 | // 147 | // resultCtrl 148 | // 149 | this.resultCtrl.Dock = System.Windows.Forms.DockStyle.Fill; 150 | this.resultCtrl.Location = new System.Drawing.Point(0, 0); 151 | this.resultCtrl.Multiline = true; 152 | this.resultCtrl.Name = "resultCtrl"; 153 | this.resultCtrl.Size = new System.Drawing.Size(557, 447); 154 | this.resultCtrl.TabIndex = 0; 155 | // 156 | // toolStrip1 157 | // 158 | this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None; 159 | this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 160 | this.addBtn, 161 | this.clearBtn, 162 | this.toolStripSeparator1, 163 | this.toolStripLabel1, 164 | this.exportDir, 165 | this.folderBtn, 166 | this.toolStripSeparator2, 167 | this.toolStripLabel2, 168 | this.srcClassName, 169 | this.toolStripLabel3, 170 | this.targetClassName, 171 | this.replaceMethodBody, 172 | this.extendMethodBody}); 173 | this.toolStrip1.Location = new System.Drawing.Point(3, 0); 174 | this.toolStrip1.Name = "toolStrip1"; 175 | this.toolStrip1.Size = new System.Drawing.Size(869, 25); 176 | this.toolStrip1.TabIndex = 0; 177 | // 178 | // addBtn 179 | // 180 | this.addBtn.Image = ((System.Drawing.Image)(resources.GetObject("addBtn.Image"))); 181 | this.addBtn.ImageTransparentColor = System.Drawing.Color.Magenta; 182 | this.addBtn.Name = "addBtn"; 183 | this.addBtn.Size = new System.Drawing.Size(52, 22); 184 | this.addBtn.Text = "添加"; 185 | this.addBtn.Click += new System.EventHandler(this.addBtn_Click); 186 | // 187 | // clearBtn 188 | // 189 | this.clearBtn.Image = ((System.Drawing.Image)(resources.GetObject("clearBtn.Image"))); 190 | this.clearBtn.ImageTransparentColor = System.Drawing.Color.Magenta; 191 | this.clearBtn.Name = "clearBtn"; 192 | this.clearBtn.Size = new System.Drawing.Size(52, 22); 193 | this.clearBtn.Text = "清空"; 194 | this.clearBtn.Click += new System.EventHandler(this.clearBtn_Click); 195 | // 196 | // toolStripSeparator1 197 | // 198 | this.toolStripSeparator1.Name = "toolStripSeparator1"; 199 | this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); 200 | // 201 | // toolStripLabel1 202 | // 203 | this.toolStripLabel1.Name = "toolStripLabel1"; 204 | this.toolStripLabel1.Size = new System.Drawing.Size(68, 22); 205 | this.toolStripLabel1.Text = "输出目录:"; 206 | // 207 | // exportDir 208 | // 209 | this.exportDir.Name = "exportDir"; 210 | this.exportDir.Size = new System.Drawing.Size(200, 25); 211 | this.exportDir.ToolTipText = "输出目录"; 212 | // 213 | // folderBtn 214 | // 215 | this.folderBtn.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 216 | this.folderBtn.Image = ((System.Drawing.Image)(resources.GetObject("folderBtn.Image"))); 217 | this.folderBtn.ImageTransparentColor = System.Drawing.Color.Magenta; 218 | this.folderBtn.Name = "folderBtn"; 219 | this.folderBtn.Size = new System.Drawing.Size(23, 22); 220 | this.folderBtn.Text = "..."; 221 | this.folderBtn.ToolTipText = "选择输出目录"; 222 | this.folderBtn.Click += new System.EventHandler(this.folderBtn_Click); 223 | // 224 | // toolStripSeparator2 225 | // 226 | this.toolStripSeparator2.Name = "toolStripSeparator2"; 227 | this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25); 228 | // 229 | // toolStripLabel2 230 | // 231 | this.toolStripLabel2.Name = "toolStripLabel2"; 232 | this.toolStripLabel2.Size = new System.Drawing.Size(56, 22); 233 | this.toolStripLabel2.Text = "被替换类"; 234 | // 235 | // srcClassName 236 | // 237 | this.srcClassName.Name = "srcClassName"; 238 | this.srcClassName.Size = new System.Drawing.Size(100, 25); 239 | // 240 | // toolStripLabel3 241 | // 242 | this.toolStripLabel3.Name = "toolStripLabel3"; 243 | this.toolStripLabel3.Size = new System.Drawing.Size(44, 22); 244 | this.toolStripLabel3.Text = "替换类"; 245 | // 246 | // targetClassName 247 | // 248 | this.targetClassName.Name = "targetClassName"; 249 | this.targetClassName.Size = new System.Drawing.Size(100, 25); 250 | // 251 | // replaceMethodBody 252 | // 253 | this.replaceMethodBody.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 254 | this.replaceMethodBody.Image = ((System.Drawing.Image)(resources.GetObject("replaceMethodBody.Image"))); 255 | this.replaceMethodBody.ImageTransparentColor = System.Drawing.Color.Magenta; 256 | this.replaceMethodBody.Name = "replaceMethodBody"; 257 | this.replaceMethodBody.Size = new System.Drawing.Size(84, 22); 258 | this.replaceMethodBody.Text = "方法实现替换"; 259 | this.replaceMethodBody.Click += new System.EventHandler(this.replaceMethodBody_Click); 260 | // 261 | // extendMethodBody 262 | // 263 | this.extendMethodBody.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 264 | this.extendMethodBody.Image = ((System.Drawing.Image)(resources.GetObject("extendMethodBody.Image"))); 265 | this.extendMethodBody.ImageTransparentColor = System.Drawing.Color.Magenta; 266 | this.extendMethodBody.Name = "extendMethodBody"; 267 | this.extendMethodBody.Size = new System.Drawing.Size(60, 22); 268 | this.extendMethodBody.Text = "脚本处理"; 269 | this.extendMethodBody.Click += new System.EventHandler(this.execScript_Click); 270 | // 271 | // MainForm 272 | // 273 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 274 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 275 | this.ClientSize = new System.Drawing.Size(881, 494); 276 | this.Controls.Add(this.toolStripContainer1); 277 | this.Name = "MainForm"; 278 | this.Text = "DotNet补丁工具"; 279 | this.Load += new System.EventHandler(this.MainForm_Load); 280 | this.toolStripContainer1.BottomToolStripPanel.ResumeLayout(false); 281 | this.toolStripContainer1.BottomToolStripPanel.PerformLayout(); 282 | this.toolStripContainer1.ContentPanel.ResumeLayout(false); 283 | this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false); 284 | this.toolStripContainer1.TopToolStripPanel.PerformLayout(); 285 | this.toolStripContainer1.ResumeLayout(false); 286 | this.toolStripContainer1.PerformLayout(); 287 | this.statusStrip1.ResumeLayout(false); 288 | this.statusStrip1.PerformLayout(); 289 | this.splitContainer1.Panel1.ResumeLayout(false); 290 | this.splitContainer1.Panel2.ResumeLayout(false); 291 | this.splitContainer1.Panel2.PerformLayout(); 292 | this.splitContainer1.ResumeLayout(false); 293 | this.toolStrip1.ResumeLayout(false); 294 | this.toolStrip1.PerformLayout(); 295 | this.ResumeLayout(false); 296 | 297 | } 298 | 299 | #endregion 300 | 301 | private System.Windows.Forms.ToolStripContainer toolStripContainer1; 302 | private System.Windows.Forms.ToolStrip toolStrip1; 303 | private System.Windows.Forms.ToolStripButton addBtn; 304 | private System.Windows.Forms.ToolStripTextBox exportDir; 305 | private System.Windows.Forms.ToolStripButton folderBtn; 306 | private System.Windows.Forms.ToolStripLabel toolStripLabel1; 307 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; 308 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; 309 | private System.Windows.Forms.ToolStripButton clearBtn; 310 | private System.Windows.Forms.StatusStrip statusStrip1; 311 | private System.Windows.Forms.ToolStripProgressBar progressBar; 312 | private System.Windows.Forms.ToolStripStatusLabel statusLabel; 313 | private System.Windows.Forms.ToolStripStatusLabel infoLabel; 314 | private System.Windows.Forms.SplitContainer splitContainer1; 315 | private System.Windows.Forms.ListBox assemblyList; 316 | private System.Windows.Forms.TextBox resultCtrl; 317 | private System.Windows.Forms.ToolStripButton replaceMethodBody; 318 | private System.Windows.Forms.ToolStripLabel toolStripLabel2; 319 | private System.Windows.Forms.ToolStripTextBox srcClassName; 320 | private System.Windows.Forms.ToolStripLabel toolStripLabel3; 321 | private System.Windows.Forms.ToolStripTextBox targetClassName; 322 | private System.Windows.Forms.ToolStripButton extendMethodBody; 323 | } 324 | } 325 | 326 | -------------------------------------------------------------------------------- /MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using System.IO; 9 | using System.CodeDom.Compiler; 10 | using Microsoft.CSharp; 11 | using System.Security.Cryptography; 12 | 13 | namespace DotnetPatch 14 | { 15 | public partial class MainForm : Form 16 | { 17 | public ToolStripProgressBar ProgressBar 18 | { 19 | get 20 | { 21 | return progressBar; 22 | } 23 | } 24 | public ToolStripStatusLabel StatusBar 25 | { 26 | get 27 | { 28 | return statusLabel; 29 | } 30 | } 31 | public TextBox ResultCtrl 32 | { 33 | get 34 | { 35 | return resultCtrl; 36 | } 37 | } 38 | 39 | public MainForm() 40 | { 41 | InitializeComponent(); 42 | } 43 | 44 | private void MainForm_Load(object sender, EventArgs e) 45 | { 46 | resultCtrl.Text = @""; 47 | ScriptProcessor.Init(); 48 | } 49 | 50 | private void addBtn_Click(object sender, EventArgs e) 51 | { 52 | Dictionary existFiles = new Dictionary(); 53 | foreach (string s in assemblyList.Items) 54 | { 55 | existFiles[s] = true; 56 | } 57 | 58 | OpenFileDialog ofd = new OpenFileDialog(); 59 | if (!string.IsNullOrEmpty(m_LastInputDir)) { 60 | ofd.InitialDirectory = m_LastInputDir; 61 | } 62 | ofd.Filter = "exe/dll文件|*.exe;*.dll|所有文件|*.*||"; 63 | ofd.CheckPathExists = true; 64 | ofd.CheckFileExists = true; 65 | ofd.Multiselect = true; 66 | ofd.Title = "请指定要添加的.net程序文件"; 67 | if (DialogResult.OK == ofd.ShowDialog()) 68 | { 69 | foreach (string s in ofd.FileNames) 70 | { 71 | if (!existFiles.ContainsKey(s)) 72 | assemblyList.Items.Add(s); 73 | } 74 | if (ofd.FileNames.Length > 0 && exportDir.Text.Trim().Length <= 0) 75 | { 76 | string as0 = ofd.FileNames[0]; 77 | string path = Path.GetDirectoryName(as0); 78 | m_LastInputDir = path; 79 | exportDir.Text = Path.GetDirectoryName(path); 80 | } 81 | statusLabel.Text = "OK."; 82 | } 83 | ofd.Dispose(); 84 | } 85 | 86 | private void clearBtn_Click(object sender, EventArgs e) 87 | { 88 | assemblyList.Items.Clear(); 89 | statusLabel.Text = "OK."; 90 | } 91 | 92 | private void folderBtn_Click(object sender, EventArgs e) 93 | { 94 | string path = exportDir.Text.Trim(); 95 | FolderBrowserDialog fbd = new FolderBrowserDialog(); 96 | if (!string.IsNullOrEmpty(m_LastOutputDir)) { 97 | fbd.SelectedPath = m_LastOutputDir; 98 | } 99 | fbd.Description = "请指定一个输出目录(注意不要使用原文件所在目录,否则会覆盖原文件!)"; 100 | fbd.ShowNewFolderButton = true; 101 | fbd.SelectedPath = path; 102 | if (DialogResult.OK == fbd.ShowDialog()) 103 | { 104 | m_LastOutputDir= fbd.SelectedPath; 105 | exportDir.Text = fbd.SelectedPath; 106 | statusLabel.Text = "OK."; 107 | } 108 | else 109 | { 110 | return; 111 | } 112 | } 113 | 114 | private void replaceMethodBody_Click(object sender, EventArgs e) 115 | { 116 | if (assemblyList.Items.Count <= 0) { 117 | MessageBox.Show("请先添加要处理的dotnet exe/dll!"); 118 | return; 119 | } 120 | string path = exportDir.Text.Trim(); 121 | if (path.Length <= 0) { 122 | MessageBox.Show("请先选择一个输出目录!"); 123 | return; 124 | } 125 | 126 | int curNum = 0; 127 | int totalNum = assemblyList.Items.Count; 128 | progressBar.Value = 0; 129 | statusLabel.Text = "开始方法体替换......"; 130 | 131 | ClrFileModifier.ResultTexts.Clear(); 132 | Dictionary methodBodyModifiers = new Dictionary(); 133 | foreach (string s in assemblyList.Items) { 134 | statusLabel.Text = "对文件 " + s + " 进行方法体替换中......"; 135 | Application.DoEvents(); 136 | 137 | if (!methodBodyModifiers.ContainsKey(s)) { 138 | ClrFileModifier methodBodyModifier = new ClrFileModifier(s, path); 139 | methodBodyModifiers[s] = methodBodyModifier; 140 | } 141 | methodBodyModifiers[s].BeginReplace(); 142 | methodBodyModifiers[s].Replace(srcClassName.Text, targetClassName.Text); 143 | methodBodyModifiers[s].EndReplace(); 144 | 145 | curNum++; 146 | progressBar.Value = curNum * 100 / totalNum; 147 | Application.DoEvents(); 148 | } 149 | progressBar.Value = 0; 150 | statusLabel.Text = "方法体替换完毕."; 151 | resultCtrl.Text = string.Join("\r\n", ClrFileModifier.ResultTexts.ToArray()); 152 | ClrFileModifier.ResultTexts.Clear(); 153 | 154 | MessageBox.Show($"方法体替换完毕,修改文件在{exportDir.Text}目录下"); 155 | } 156 | 157 | private void execScript_Click(object sender, EventArgs e) 158 | { 159 | if (assemblyList.Items.Count <= 0) { 160 | MessageBox.Show("请先添加要处理的dotnet exe/dll!"); 161 | return; 162 | } 163 | string path = exportDir.Text.Trim(); 164 | if (path.Length <= 0) { 165 | MessageBox.Show("请先选择一个输出目录!"); 166 | return; 167 | } 168 | 169 | OpenFileDialog ofd = new OpenFileDialog(); 170 | ofd.InitialDirectory = m_LastScriptDir; 171 | ofd.DefaultExt = "scp"; 172 | ofd.Filter = "脚本文件|*.scp|所有文件|*.*||"; 173 | ofd.CheckPathExists = true; 174 | ofd.CheckFileExists = true; 175 | ofd.Multiselect = false; 176 | ofd.Title = "请指定脚本文件"; 177 | if (DialogResult.OK == ofd.ShowDialog()) { 178 | string file = ofd.FileName; 179 | m_LastScriptDir = Path.GetDirectoryName(file); 180 | 181 | List files = new List(); 182 | foreach (string s in assemblyList.Items) { 183 | files.Add(s); 184 | } 185 | ScriptProcessor.Start(files, path, file); 186 | 187 | MessageBox.Show($"脚本执行完成,修改文件在{exportDir.Text}目录下"); 188 | } 189 | } 190 | 191 | private string m_LastInputDir = string.Empty; 192 | private string m_LastOutputDir = string.Empty; 193 | private string m_LastScriptDir = Environment.CurrentDirectory; 194 | } 195 | } -------------------------------------------------------------------------------- /MainForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 136, 17 122 | 123 | 124 | 17, 17 125 | 126 | 127 | 128 | 129 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 130 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 131 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 132 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 133 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 134 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 135 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 136 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 137 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 138 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 139 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 140 | 141 | 142 | 143 | 144 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 145 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 146 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 147 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 148 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 149 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 150 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 151 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 152 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 153 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 154 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 155 | 156 | 157 | 158 | 159 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 160 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 161 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 162 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 163 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 164 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 165 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 166 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 167 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 168 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 169 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 170 | 171 | 172 | 173 | 174 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 175 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 176 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 177 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 178 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 179 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 180 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 181 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 182 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 183 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 184 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 185 | 186 | 187 | 188 | 189 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 190 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 191 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 192 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 193 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 194 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 195 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 196 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 197 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 198 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 199 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 200 | 201 | 202 | -------------------------------------------------------------------------------- /MetadataIterator.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/MetadataIterator.cs -------------------------------------------------------------------------------- /MetadataTables.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace DotnetPatch 7 | { 8 | public class MetadataTables 9 | { 10 | public uint MetadataPosition 11 | { 12 | get { return metadataPosition; } 13 | } 14 | 15 | public uint MetadataSize 16 | { 17 | get { return metadataSize; } 18 | } 19 | 20 | public MetadataRoot Root 21 | { 22 | get { return root; } 23 | } 24 | 25 | public StreamHeader MetadataHeader 26 | { 27 | get { return metadataHeader; } 28 | } 29 | 30 | public StreamHeader StringsHeader 31 | { 32 | get { return stringsHeader; } 33 | } 34 | 35 | public StreamHeader UserStringsHeader 36 | { 37 | get { return userStringsHeader; } 38 | } 39 | 40 | public StreamHeader GuidHeader 41 | { 42 | get { return guidHeader; } 43 | } 44 | 45 | public StreamHeader BlobHeader 46 | { 47 | get { return blobHeader; } 48 | } 49 | 50 | public MetadataStream MetadataStreamRoot 51 | { 52 | get { return metadataStreamRoot; } 53 | } 54 | 55 | public IMetadataIterator[] Tables 56 | { 57 | get { return tables; } 58 | } 59 | 60 | public uint BlobIndexSize 61 | { 62 | get { return blobIndexSize; } 63 | } 64 | 65 | public uint GuidIndexSize 66 | { 67 | get { return guidIndexSize; } 68 | } 69 | 70 | public uint StringIndexSize 71 | { 72 | get { return stringIndexSize; } 73 | } 74 | 75 | public uint GetTableIndexSize(CorTokenType id) 76 | { 77 | uint v = (0x01 << 16); 78 | int index = (int)id; 79 | if (NumberOfTableRow[index] >= v) { 80 | return 4; 81 | } else { 82 | return 2; 83 | } 84 | } 85 | public uint GetCodedIndexSize(CodedIndexType type) 86 | { 87 | return CodedIndexSize.GetSize(type, NumberOfTableRow); 88 | } 89 | 90 | public MetadataTables(byte[] buffer, uint pos, uint size) 91 | { 92 | metadataPosition = pos; 93 | metadataSize = size; 94 | 95 | ReadMetadataRoot(buffer, pos); 96 | pos += metadataHeader.Offset; 97 | 98 | sortedOfTable = new bool[64]; 99 | numberOfTableRow = new uint[64]; 100 | tables = new IMetadataIterator[64]; 101 | metadataStreamRoot = ReadMetadataStream(buffer, pos); 102 | pos += MetadataStream.StructSize; 103 | if (((HeapSizeType)MetadataStreamRoot.HeapSizes & HeapSizeType.Blob) == HeapSizeType.Blob) { 104 | blobIndexSize = 4; 105 | } else { 106 | blobIndexSize = 2; 107 | } 108 | if (((HeapSizeType)MetadataStreamRoot.HeapSizes & HeapSizeType.GUID) == HeapSizeType.GUID) { 109 | guidIndexSize = 4; 110 | } else { 111 | guidIndexSize = 2; 112 | } 113 | if (((HeapSizeType)MetadataStreamRoot.HeapSizes & HeapSizeType.String) == HeapSizeType.String) { 114 | stringIndexSize = 4; 115 | } else { 116 | stringIndexSize = 2; 117 | } 118 | for (int i = 0; i < 64; i++) { 119 | UInt64 bit = (((UInt64)0x01) << i); 120 | if ((MetadataStreamRoot.Valid & bit) == bit) { 121 | numberOfTableRow[i] = ReadUInt(buffer, pos); 122 | pos += 4; 123 | } else { 124 | numberOfTableRow[i] = 0; 125 | } 126 | if ((MetadataStreamRoot.Sorted & bit) == bit) { 127 | sortedOfTable[i] = true; 128 | } else { 129 | sortedOfTable[i] = false; 130 | } 131 | } 132 | for (int i = 0; i < 64; i++) { 133 | CorTokenType type = (CorTokenType)i; 134 | tables[i] = MetadataIterator.Create(this, buffer, pos, type); 135 | tables[i].MoveToEnd(); 136 | pos = tables[i].Position; 137 | } 138 | } 139 | 140 | internal bool[] SortedOfTable 141 | { 142 | get { return sortedOfTable; } 143 | } 144 | 145 | internal uint[] NumberOfTableRow 146 | { 147 | get { return numberOfTableRow; } 148 | } 149 | 150 | internal static unsafe uint ReadUInt(byte[] buffer, uint pos) 151 | { 152 | uint v = 0; 153 | fixed (byte* p = buffer) { 154 | uint* ptr = (uint*)(p + pos); 155 | v = *ptr; 156 | } 157 | return v; 158 | } 159 | internal static unsafe ushort ReadUShort(byte[] buffer, uint pos) 160 | { 161 | ushort v = 0; 162 | fixed (byte* p = buffer) { 163 | ushort* ptr = (ushort*)(p + pos); 164 | v = *ptr; 165 | } 166 | return v; 167 | } 168 | 169 | internal static unsafe void WriteUInt(byte[] buffer, uint pos, uint val) 170 | { 171 | fixed (byte* p = buffer) { 172 | uint* ptr = (uint*)(p + pos); 173 | *ptr = val; 174 | } 175 | } 176 | internal static unsafe void WriteUShort(byte[] buffer, uint pos, ushort val) 177 | { 178 | fixed (byte* p = buffer) { 179 | ushort* ptr = (ushort*)(p + pos); 180 | *ptr = val; 181 | } 182 | } 183 | 184 | private unsafe void ReadMetadataRoot(byte[] buffer, uint pos) 185 | { 186 | root = new MetadataRoot(buffer, pos); 187 | pos += root.StructSize; 188 | ushort streamNum = ReadUShort(buffer, pos); 189 | pos += sizeof(ushort); 190 | for (uint i = 0; i < streamNum; i++) { 191 | StreamHeader header = new StreamHeader(buffer, pos); 192 | pos += header.StructSize; 193 | 194 | if (header.Name == "#~") { 195 | metadataHeader = header; 196 | } else if (header.Name == "#Strings") { 197 | stringsHeader = header; 198 | } else if (header.Name == "#US") { 199 | userStringsHeader = header; 200 | } else if (header.Name == "#GUID") { 201 | guidHeader = header; 202 | } else if (header.Name == "#Blob") { 203 | blobHeader = header; 204 | } 205 | } 206 | } 207 | private static unsafe MetadataStream ReadMetadataStream(byte[] buffer, uint pos) 208 | { 209 | MetadataStream meta = new MetadataStream(); 210 | fixed (byte* p = buffer) { 211 | MetadataStream* ptr = (MetadataStream*)(p + pos); 212 | meta = *ptr; 213 | } 214 | return meta; 215 | } 216 | 217 | private MetadataRoot root = null; 218 | private StreamHeader metadataHeader; 219 | private StreamHeader stringsHeader; 220 | private StreamHeader userStringsHeader; 221 | private StreamHeader guidHeader; 222 | private StreamHeader blobHeader; 223 | 224 | private MetadataStream metadataStreamRoot; 225 | private IMetadataIterator[] tables = null; 226 | 227 | private bool[] sortedOfTable; 228 | private uint[] numberOfTableRow; 229 | 230 | private uint blobIndexSize; 231 | private uint guidIndexSize; 232 | private uint stringIndexSize; 233 | 234 | private uint metadataPosition = 0; 235 | private uint metadataSize = 0; 236 | } 237 | 238 | public class MetadataRoot 239 | { 240 | public uint StructSize 241 | { 242 | get { return structSize; } 243 | } 244 | 245 | public uint Signature 246 | { 247 | get { return signature; } 248 | } 249 | 250 | public ushort MajorVersion 251 | { 252 | get { return majorVersion; } 253 | } 254 | 255 | public ushort MinorVersion 256 | { 257 | get { return minorVersion; } 258 | } 259 | 260 | public string Version 261 | { 262 | get { return version; } 263 | } 264 | 265 | public MetadataRoot(byte[] data, uint _pos) 266 | { 267 | uint pos = _pos; 268 | signature = MetadataTables.ReadUInt(data, pos); 269 | pos += sizeof(uint); 270 | majorVersion = MetadataTables.ReadUShort(data, pos); 271 | pos += sizeof(ushort); 272 | minorVersion = MetadataTables.ReadUShort(data, pos); 273 | pos += sizeof(ushort); 274 | pos += 4;//Reserved; 275 | uint len = MetadataTables.ReadUInt(data, pos); 276 | pos += sizeof(uint); 277 | version = System.Text.Encoding.UTF8.GetString(data, (int)pos, (int)len); 278 | len = Alignment.Calc(len, 4); 279 | pos += len; 280 | pos += 2;//Flags 281 | structSize = pos - _pos; 282 | } 283 | 284 | private uint structSize = 0; 285 | private uint signature;//0x424A5342 = "BSJB" 286 | private ushort majorVersion; 287 | private ushort minorVersion; 288 | private string version; 289 | } 290 | public class StreamHeader 291 | { 292 | public uint Position 293 | { 294 | get { return position; } 295 | } 296 | 297 | public uint StructSize 298 | { 299 | get { return structSize; } 300 | } 301 | 302 | public uint Offset 303 | { 304 | get 305 | { 306 | return offset; 307 | } 308 | set 309 | { 310 | offset = value; 311 | MetadataTables.WriteUInt(data, position + OffsetOffset, value); 312 | } 313 | } 314 | 315 | public uint Size 316 | { 317 | get 318 | { 319 | return size; 320 | } 321 | set 322 | { 323 | size = value; 324 | MetadataTables.WriteUInt(data, position + SizeOffset, value); 325 | } 326 | } 327 | 328 | public string Name 329 | { 330 | get { return name; } 331 | } 332 | 333 | public StreamHeader(byte[] _data, uint _pos) 334 | { 335 | data = _data; 336 | position = _pos; 337 | 338 | uint pos = _pos; 339 | offset = MetadataTables.ReadUInt(data, pos); 340 | pos += sizeof(uint); 341 | size = MetadataTables.ReadUInt(data, pos); 342 | pos += sizeof(uint); 343 | int nlen = 0; 344 | for (; data[pos + nlen] > 0; nlen++) ; 345 | name = System.Text.Encoding.ASCII.GetString(data, (int)pos, nlen); 346 | nlen = Alignment.Calc(nlen + 1, 4); 347 | pos += (uint)nlen; 348 | structSize = pos - position; 349 | } 350 | 351 | private uint OffsetOffset 352 | { 353 | get 354 | { 355 | return 0; 356 | } 357 | } 358 | 359 | private uint SizeOffset 360 | { 361 | get 362 | { 363 | return 4; 364 | } 365 | } 366 | 367 | private byte[] data = null; 368 | private uint position = 0; 369 | private uint structSize = 0; 370 | private uint offset; 371 | private uint size; 372 | private string name; 373 | } 374 | [StructLayout(LayoutKind.Sequential)] 375 | public struct MetadataStream 376 | { 377 | public uint Reserved1; 378 | public byte MajorVersion; 379 | public byte MinorVersion; 380 | public byte HeapSizes; 381 | public byte Reserved2; 382 | public UInt64 Valid; 383 | public UInt64 Sorted; 384 | 385 | public static unsafe uint StructSize 386 | { 387 | get 388 | { 389 | return (uint)sizeof(MetadataStream); 390 | } 391 | } 392 | } 393 | public enum HeapSizeType : byte 394 | { 395 | None = 0, 396 | String = 0x01, 397 | GUID = 0x02, 398 | Blob = 0x04, 399 | String_GUID = 0x03, 400 | String_Blob = 0x05, 401 | GUID_Blob = 0x06, 402 | ALL = 0x07 403 | } 404 | public enum CorTokenType 405 | { 406 | mdtModule = 0x00, 407 | mdtTypeRef = 0x01, 408 | mdtTypeDef = 0x02, 409 | mdtUnused03 = 0x03, 410 | mdtFieldDef = 0x04, 411 | mdtUnused05 = 0x05, 412 | mdtMethodDef = 0x06, 413 | mdtUnused07 = 0x07, 414 | mdtParamDef = 0x08, 415 | mdtInterfaceImpl = 0x09, 416 | mdtMemberRef = 0x0a, 417 | mdtConstant = 0x0b, 418 | mdtCustomAttribute = 0x0c, 419 | mdtFieldMarshal = 0x0d, 420 | mdtDeclSecurity = 0x0e, 421 | mdtClassLayout = 0x0f, 422 | mdtFieldLayout = 0x10, 423 | mdtSignature = 0x11, 424 | mdtEventMap = 0x12, 425 | mdtUnused13 = 0x13, 426 | mdtEvent = 0x14, 427 | mdtPropertyMap = 0x15, 428 | mdtUnused16 = 0x16, 429 | mdtProperty = 0x17, 430 | mdtMethodSemantics = 0x18, 431 | mdtMethodImpl = 0x19, 432 | mdtModuleRef = 0x1a, 433 | mdtTypeSpec = 0x1b, 434 | mdtImplMap = 0x1c, 435 | mdtFieldRVA = 0x1d, 436 | mdtUnused1E = 0x1e, 437 | mdtUnused1F = 0x1f, 438 | mdtAssembly = 0x20, 439 | mdtAssemblyProcessor = 0x21, 440 | mdtAssemblyOS = 0x22, 441 | mdtAssemblyRef = 0x23, 442 | mdtAssemblyRefProcessor = 0x24, 443 | mdtAssemblyRefOS = 0x25, 444 | mdtFile = 0x26, 445 | mdtExportedType = 0x27, 446 | mdtManifestResource = 0x28, 447 | mdtNestedClass = 0x29, 448 | mdtGenericParam = 0x2a, 449 | mdtMethodSpec = 0x2b, 450 | mdtGenericParamConstraint = 0x2c, 451 | mdtUnused2D = 0x2d, 452 | mdtUnused2E = 0x2e, 453 | mdtUnused2F = 0x2f, 454 | mdtUnused30 = 0x30, 455 | mdtUnused31 = 0x31, 456 | mdtUnused32 = 0x32, 457 | mdtUnused33 = 0x33, 458 | mdtUnused34 = 0x34, 459 | mdtUnused35 = 0x35, 460 | mdtUnused36 = 0x36, 461 | mdtUnused37 = 0x37, 462 | mdtUnused38 = 0x38, 463 | mdtUnused39 = 0x39, 464 | mdtUnused3A = 0x3a, 465 | mdtUnused3B = 0x3b, 466 | mdtUnused3C = 0x3c, 467 | mdtUnused3D = 0x3d, 468 | mdtUnused3E = 0x3e, 469 | mdtUnused3F = 0x3f, 470 | mdtMaxTokenType = 0x3f 471 | } 472 | public enum CodedIndexType 473 | { 474 | TypeDefOrRef = 0, 475 | HasConstant = 1, 476 | HasCustomAttribute = 2, 477 | HasFieldMarshall = 3, 478 | HasDeclSecurity = 4, 479 | MemberRefParent = 5, 480 | HasSemantics = 6, 481 | MethodDefOrRef = 7, 482 | MemberForwarded = 8, 483 | Implementation = 9, 484 | CustomAttributeType = 10, 485 | ResolutionScope = 11, 486 | TypeOrMethodDef = 12 487 | } 488 | internal static class CodedIndexSize 489 | { 490 | static CodedIndexSize() 491 | { 492 | codedIndexTypes[CodedIndexType.TypeDefOrRef] = new CorTokenType[] 493 | { 494 | CorTokenType.mdtTypeDef, 495 | CorTokenType.mdtTypeRef, 496 | CorTokenType.mdtTypeSpec 497 | }; 498 | codedIndexTypes[CodedIndexType.HasConstant] = new CorTokenType[] 499 | { 500 | CorTokenType.mdtFieldDef, 501 | CorTokenType.mdtParamDef, 502 | CorTokenType.mdtProperty 503 | }; 504 | codedIndexTypes[CodedIndexType.HasCustomAttribute] = new CorTokenType[] 505 | { 506 | CorTokenType.mdtMethodDef, 507 | CorTokenType.mdtFieldDef, 508 | CorTokenType.mdtTypeRef, 509 | CorTokenType.mdtTypeDef, 510 | CorTokenType.mdtParamDef, 511 | CorTokenType.mdtInterfaceImpl, 512 | CorTokenType.mdtMemberRef, 513 | CorTokenType.mdtModule, 514 | CorTokenType.mdtDeclSecurity, 515 | CorTokenType.mdtProperty, 516 | CorTokenType.mdtEvent, 517 | CorTokenType.mdtSignature, 518 | CorTokenType.mdtModuleRef, 519 | CorTokenType.mdtTypeSpec, 520 | CorTokenType.mdtAssembly, 521 | CorTokenType.mdtAssemblyRef, 522 | CorTokenType.mdtFile, 523 | CorTokenType.mdtExportedType, 524 | CorTokenType.mdtManifestResource, 525 | CorTokenType.mdtGenericParam, 526 | CorTokenType.mdtGenericParamConstraint, 527 | CorTokenType.mdtMethodSpec 528 | }; 529 | codedIndexTypes[CodedIndexType.HasFieldMarshall] = new CorTokenType[] 530 | { 531 | CorTokenType.mdtFieldDef, 532 | CorTokenType.mdtParamDef 533 | }; 534 | codedIndexTypes[CodedIndexType.HasDeclSecurity] = new CorTokenType[] 535 | { 536 | CorTokenType.mdtTypeDef, 537 | CorTokenType.mdtMethodDef, 538 | CorTokenType.mdtAssembly 539 | }; 540 | codedIndexTypes[CodedIndexType.MemberRefParent] = new CorTokenType[] 541 | { 542 | CorTokenType.mdtTypeDef, 543 | CorTokenType.mdtTypeRef, 544 | CorTokenType.mdtModuleRef, 545 | CorTokenType.mdtMethodDef, 546 | CorTokenType.mdtTypeSpec 547 | }; 548 | codedIndexTypes[CodedIndexType.HasSemantics] = new CorTokenType[] 549 | { 550 | CorTokenType.mdtEvent, 551 | CorTokenType.mdtProperty 552 | }; 553 | codedIndexTypes[CodedIndexType.MethodDefOrRef] = new CorTokenType[] 554 | { 555 | CorTokenType.mdtMethodDef, 556 | CorTokenType.mdtMemberRef 557 | }; 558 | codedIndexTypes[CodedIndexType.MemberForwarded] = new CorTokenType[] 559 | { 560 | CorTokenType.mdtFieldDef, 561 | CorTokenType.mdtMethodDef 562 | }; 563 | codedIndexTypes[CodedIndexType.Implementation] = new CorTokenType[] 564 | { 565 | CorTokenType.mdtFile, 566 | CorTokenType.mdtAssemblyRef, 567 | CorTokenType.mdtExportedType 568 | }; 569 | codedIndexTypes[CodedIndexType.CustomAttributeType] = new CorTokenType[] 570 | { 571 | CorTokenType.mdtMaxTokenType, 572 | CorTokenType.mdtMaxTokenType, 573 | CorTokenType.mdtMethodDef, 574 | CorTokenType.mdtMemberRef, 575 | CorTokenType.mdtMaxTokenType 576 | }; 577 | codedIndexTypes[CodedIndexType.ResolutionScope] = new CorTokenType[] 578 | { 579 | CorTokenType.mdtModule, 580 | CorTokenType.mdtModuleRef, 581 | CorTokenType.mdtAssemblyRef, 582 | CorTokenType.mdtTypeRef 583 | }; 584 | codedIndexTypes[CodedIndexType.TypeOrMethodDef] = new CorTokenType[] 585 | { 586 | CorTokenType.mdtTypeDef, 587 | CorTokenType.mdtMethodDef 588 | }; 589 | 590 | codedIndexBits[CodedIndexType.TypeDefOrRef] = 2; 591 | codedIndexBits[CodedIndexType.HasConstant] = 2; 592 | codedIndexBits[CodedIndexType.HasCustomAttribute] = 5; 593 | codedIndexBits[CodedIndexType.HasFieldMarshall] = 1; 594 | codedIndexBits[CodedIndexType.HasDeclSecurity] = 2; 595 | codedIndexBits[CodedIndexType.MemberRefParent] = 3; 596 | codedIndexBits[CodedIndexType.HasSemantics] = 1; 597 | codedIndexBits[CodedIndexType.MethodDefOrRef] = 1; 598 | codedIndexBits[CodedIndexType.MemberForwarded] = 1; 599 | codedIndexBits[CodedIndexType.Implementation] = 2; 600 | codedIndexBits[CodedIndexType.CustomAttributeType] = 3; 601 | codedIndexBits[CodedIndexType.ResolutionScope] = 2; 602 | codedIndexBits[CodedIndexType.TypeOrMethodDef] = 1; 603 | } 604 | public static uint GetSize(CodedIndexType type, uint[] numberOfTableRow) 605 | { 606 | if (codedIndexTypes.ContainsKey(type) && codedIndexBits.ContainsKey(type)) { 607 | CorTokenType[] tokens = codedIndexTypes[type]; 608 | uint v = 0x01; 609 | int bits = codedIndexBits[type]; 610 | v <<= 16 - bits; 611 | uint size = 0; 612 | foreach (CorTokenType token in tokens) { 613 | int ix = (int)token; 614 | uint tsize = numberOfTableRow[ix]; 615 | if (tsize > size) 616 | size = tsize; 617 | } 618 | if (size >= v) 619 | return 4; 620 | else 621 | return 2; 622 | } 623 | return 0; 624 | } 625 | private static Dictionary codedIndexTypes = new Dictionary(); 626 | private static Dictionary codedIndexBits = new Dictionary(); 627 | } 628 | public enum MethodType : byte 629 | { 630 | TinyFormat = 0x2, 631 | FatFormat = 0x3, 632 | MoreSects = 0x8, 633 | InitLocals = 0x10 634 | } 635 | public enum MethodSectType : byte 636 | { 637 | EHTable = 0x1, 638 | ILTable = 0x2, 639 | FatFormat = 0x40, 640 | MoreSects = 0x80 641 | } 642 | public enum EHClauseType : ushort 643 | { 644 | Exception = 0x0000, 645 | Filter = 0x0001, 646 | Finally = 0x0002, 647 | Fault = 0x0004 648 | } 649 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 650 | public struct TinyMethodHeader 651 | { 652 | public byte Flags 653 | { 654 | get 655 | { 656 | return (byte)(data & 0x03); 657 | } 658 | set 659 | { 660 | data |= 0x03; 661 | data &= (byte)(value & 0x03); 662 | } 663 | } 664 | public byte Size 665 | { 666 | get 667 | { 668 | return (byte)((data & 0xFC) >> 2); 669 | } 670 | set 671 | { 672 | byte v = (byte)(value << 2); 673 | data |= 0xFC; 674 | data &= (byte)(v & 0xFC); 675 | } 676 | } 677 | public static unsafe uint StructSize 678 | { 679 | get 680 | { 681 | return (uint)sizeof(TinyMethodHeader); 682 | } 683 | } 684 | private byte data; 685 | } 686 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 687 | public struct FatMethodHeader 688 | { 689 | public ushort Flags 690 | { 691 | get 692 | { 693 | return (ushort)(FlagsAndSize & 0x0FFF); 694 | } 695 | set 696 | { 697 | FlagsAndSize |= 0x0FFF; 698 | FlagsAndSize &= (ushort)(value & 0x0FFF); 699 | } 700 | } 701 | public byte Size 702 | { 703 | get 704 | { 705 | return (byte)((FlagsAndSize & 0xF000) >> 12); 706 | } 707 | set 708 | { 709 | ushort v = (ushort)(value << 12); 710 | FlagsAndSize |= 0xF000; 711 | FlagsAndSize &= (ushort)(v & 0xF000); 712 | } 713 | } 714 | private ushort FlagsAndSize; 715 | public ushort MaxStack; 716 | public uint CodeSize; 717 | public uint LocalVarSigTok; 718 | 719 | public static unsafe uint StructSize 720 | { 721 | get 722 | { 723 | return (uint)sizeof(FatMethodHeader); 724 | } 725 | } 726 | } 727 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 728 | public struct ExceptionHeader 729 | { 730 | public bool IsFat 731 | { 732 | get 733 | { 734 | return (Kind & (byte)MethodSectType.FatFormat) == (byte)MethodSectType.FatFormat; 735 | } 736 | } 737 | public byte Kind; 738 | public byte SmallDataSize 739 | { 740 | get 741 | { 742 | return data1; 743 | } 744 | set 745 | { 746 | data1 = value; 747 | data2 = 0; 748 | data3 = 0; 749 | } 750 | } 751 | public uint FatDataSize 752 | { 753 | get 754 | { 755 | return (uint)((data3 << 16) + (data2 << 8) + data1); 756 | } 757 | set 758 | { 759 | data3 = (byte)((value & 0x00FF0000) >> 16); 760 | data2 = (byte)((value & 0x0000FF00) >> 8); 761 | data1 = (byte)(value & 0x0000FF); 762 | } 763 | } 764 | private byte data1; 765 | private byte data2; 766 | private byte data3; 767 | 768 | public static unsafe uint StructSize 769 | { 770 | get 771 | { 772 | return (uint)sizeof(ExceptionHeader); 773 | } 774 | } 775 | } 776 | public class EHClause 777 | { 778 | public uint Position 779 | { 780 | get { return position; } 781 | } 782 | public uint Size 783 | { 784 | get 785 | { 786 | return (uint)(isFat ? 24 : 12); 787 | } 788 | } 789 | public uint Flags 790 | { 791 | get 792 | { 793 | if (isFat) 794 | return MetadataTables.ReadUInt(data, position + 0); 795 | else 796 | return (uint)MetadataTables.ReadUShort(data, position + 0); 797 | } 798 | set 799 | { 800 | if (isFat) 801 | MetadataTables.WriteUInt(data, position + 0, value); 802 | else 803 | MetadataTables.WriteUShort(data, position + 0, (ushort)value); 804 | } 805 | } 806 | public uint TryOffset 807 | { 808 | get 809 | { 810 | if (isFat) 811 | return MetadataTables.ReadUInt(data, position + 4); 812 | else 813 | return (uint)MetadataTables.ReadUShort(data, position + 2); 814 | } 815 | set 816 | { 817 | if (isFat) 818 | MetadataTables.WriteUInt(data, position + 4, value); 819 | else 820 | MetadataTables.WriteUShort(data, position + 2, (ushort)value); 821 | } 822 | } 823 | public uint TryLength 824 | { 825 | get 826 | { 827 | if (isFat) 828 | return MetadataTables.ReadUInt(data, position + 8); 829 | else 830 | return (uint)data[position + 4]; 831 | } 832 | set 833 | { 834 | if (isFat) 835 | MetadataTables.WriteUInt(data, position + 8, value); 836 | else 837 | data[position + 4] = (byte)value; 838 | } 839 | } 840 | public uint HandlerOffset 841 | { 842 | get 843 | { 844 | if (isFat) 845 | return MetadataTables.ReadUInt(data, position + 12); 846 | else 847 | return (uint)MetadataTables.ReadUShort(data, position + 5); 848 | } 849 | set 850 | { 851 | if (isFat) 852 | MetadataTables.WriteUInt(data, position + 12, value); 853 | else 854 | MetadataTables.WriteUShort(data, position + 5, (ushort)value); 855 | } 856 | } 857 | public uint HandlerLength 858 | { 859 | get 860 | { 861 | if (isFat) 862 | return MetadataTables.ReadUInt(data, position + 16); 863 | else 864 | return (uint)data[position + 7]; 865 | } 866 | set 867 | { 868 | if (isFat) 869 | MetadataTables.WriteUInt(data, position + 16, value); 870 | else 871 | data[position + 7] = (byte)value; 872 | } 873 | } 874 | public uint ClassToken 875 | { 876 | get 877 | { 878 | if (isFat) 879 | return MetadataTables.ReadUInt(data, position + 20); 880 | else 881 | return MetadataTables.ReadUInt(data, position + 8); 882 | } 883 | set 884 | { 885 | if (isFat) 886 | MetadataTables.WriteUInt(data, position + 20, value); 887 | else 888 | MetadataTables.WriteUInt(data, position + 8, value); 889 | } 890 | } 891 | public uint FilterOffset 892 | { 893 | get 894 | { 895 | if (isFat) 896 | return MetadataTables.ReadUInt(data, position + 20); 897 | else 898 | return MetadataTables.ReadUInt(data, position + 8); 899 | } 900 | set 901 | { 902 | if (isFat) 903 | MetadataTables.WriteUInt(data, position + 20, value); 904 | else 905 | MetadataTables.WriteUInt(data, position + 8, value); 906 | } 907 | } 908 | 909 | public EHClause(byte[] buffer, uint pos, bool fat) 910 | { 911 | data = buffer; 912 | position = pos; 913 | 914 | isFat = fat; 915 | } 916 | 917 | private byte[] data = null; 918 | private uint position = 0; 919 | private bool isFat = false; 920 | } 921 | public class ClrMethod 922 | { 923 | public bool IsFat 924 | { 925 | get 926 | { 927 | return isFat; 928 | } 929 | } 930 | public uint Position 931 | { 932 | get { return position; } 933 | } 934 | 935 | public TinyMethodHeader TinyMethodHeader 936 | { 937 | get { return tinyMethodHeader; } 938 | } 939 | public FatMethodHeader FatmethodHeader 940 | { 941 | get { return fatMethodHeader; } 942 | } 943 | public bool HaveExceptionData 944 | { 945 | get 946 | { 947 | if (!IsFat) 948 | return false; 949 | return (fatMethodHeader.Flags & (ushort)MethodType.MoreSects) == (ushort)MethodType.MoreSects; 950 | } 951 | } 952 | public ExceptionHeader ExceptionHeader 953 | { 954 | get { return exceptionHeader; } 955 | } 956 | public EHClause[] Clauses 957 | { 958 | get { return clauses; } 959 | } 960 | 961 | public ClrMethod(byte[] buffer, uint pos) 962 | { 963 | data = buffer; 964 | position = pos; 965 | 966 | byte b = buffer[pos]; 967 | if (!IsFatFlags(b)) { 968 | isFat = false; 969 | 970 | tinyMethodHeader = ReadTinyMethodHeader(buffer, pos); 971 | } else { 972 | isFat = true; 973 | 974 | fatMethodHeader = ReadFatMethodHeader(buffer, pos); 975 | pos += FatMethodHeader.StructSize; 976 | pos += fatMethodHeader.CodeSize; 977 | pos = Alignment.Calc(pos, 4); 978 | if (HaveExceptionData) { 979 | exceptionHeader = ReadExceptionHeader(buffer, pos); 980 | pos += ExceptionHeader.StructSize; 981 | 982 | if (exceptionHeader.IsFat) { 983 | uint size = exceptionHeader.FatDataSize; 984 | uint n = (size - 4) / 24; 985 | 986 | clauses = new EHClause[n]; 987 | for (int i = 0; i < n; i++) { 988 | Clauses[i] = new EHClause(buffer, pos, true); 989 | pos += Clauses[i].Size; 990 | } 991 | } else { 992 | uint size = exceptionHeader.SmallDataSize; 993 | uint n = (size - 4) / 12; 994 | 995 | clauses = new EHClause[n]; 996 | for (int i = 0; i < n; i++) { 997 | Clauses[i] = new EHClause(buffer, pos, false); 998 | pos += Clauses[i].Size; 999 | } 1000 | } 1001 | } 1002 | } 1003 | } 1004 | private static bool IsFatFlags(byte firstByte) 1005 | { 1006 | if ((firstByte & (byte)MethodType.FatFormat) == (byte)MethodType.FatFormat) 1007 | return true; 1008 | else 1009 | return false; 1010 | } 1011 | 1012 | private static unsafe TinyMethodHeader ReadTinyMethodHeader(byte[] buffer, uint pos) 1013 | { 1014 | TinyMethodHeader methodHeader = new TinyMethodHeader(); 1015 | fixed (byte* p = buffer) { 1016 | TinyMethodHeader* ptr = (TinyMethodHeader*)(p + pos); 1017 | methodHeader = *ptr; 1018 | } 1019 | return methodHeader; 1020 | } 1021 | private static unsafe FatMethodHeader ReadFatMethodHeader(byte[] buffer, uint pos) 1022 | { 1023 | FatMethodHeader methodHeader = new FatMethodHeader(); 1024 | fixed (byte* p = buffer) { 1025 | FatMethodHeader* ptr = (FatMethodHeader*)(p + pos); 1026 | methodHeader = *ptr; 1027 | } 1028 | return methodHeader; 1029 | } 1030 | private static unsafe ExceptionHeader ReadExceptionHeader(byte[] buffer, uint pos) 1031 | { 1032 | ExceptionHeader exceptionHeader = new ExceptionHeader(); 1033 | fixed (byte* p = buffer) { 1034 | ExceptionHeader* ptr = (ExceptionHeader*)(p + pos); 1035 | exceptionHeader = *ptr; 1036 | } 1037 | return exceptionHeader; 1038 | } 1039 | 1040 | private static unsafe void WriteTinyMethodHeader(byte[] buffer, uint pos, TinyMethodHeader header) 1041 | { 1042 | fixed (byte* p = buffer) { 1043 | TinyMethodHeader* ptr = (TinyMethodHeader*)(p + pos); 1044 | *ptr = header; 1045 | } 1046 | } 1047 | private static unsafe void WriteFatMethodHeader(byte[] buffer, uint pos, FatMethodHeader header) 1048 | { 1049 | fixed (byte* p = buffer) { 1050 | FatMethodHeader* ptr = (FatMethodHeader*)(p + pos); 1051 | *ptr = header; 1052 | } 1053 | } 1054 | private static unsafe void WriteExceptionHeader(byte[] buffer, uint pos, ExceptionHeader header) 1055 | { 1056 | fixed (byte* p = buffer) { 1057 | ExceptionHeader* ptr = (ExceptionHeader*)(p + pos); 1058 | *ptr = header; 1059 | } 1060 | } 1061 | 1062 | private bool isFat = false; 1063 | private TinyMethodHeader tinyMethodHeader; 1064 | private FatMethodHeader fatMethodHeader; 1065 | private ExceptionHeader exceptionHeader; 1066 | private EHClause[] clauses = null; 1067 | 1068 | private byte[] data = null; 1069 | private uint position = 0; 1070 | } 1071 | } 1072 | -------------------------------------------------------------------------------- /PENCIL12.ICO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/PENCIL12.ICO -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace DotnetPatch 6 | { 7 | static class Program 8 | { 9 | public static MainForm MainForm 10 | { 11 | get { return s_MainForm; } 12 | } 13 | /// 14 | /// 应用程序的主入口点。 15 | /// 16 | [STAThread] 17 | static void Main() 18 | { 19 | Application.EnableVisualStyles(); 20 | Application.SetCompatibleTextRenderingDefault(false); 21 | s_MainForm = new MainForm(); 22 | Application.Run(s_MainForm); 23 | } 24 | 25 | private static MainForm s_MainForm; 26 | } 27 | } -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DotnetPatch.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DotnetPatch.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DotnetPatch.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/README.md -------------------------------------------------------------------------------- /Script/Commands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using DotnetPatch; 6 | using ScriptableFramework; 7 | using DotnetStoryScript; 8 | using DotnetStoryScript.DslExpression; 9 | 10 | namespace DotnetStoryScript.DslExpression 11 | { 12 | //--------------------------------------------------------------------------------------------------------------- 13 | internal class BeginCommand : SimpleExpressionBase 14 | { 15 | protected override BoxedValue OnCalc(IList operands) 16 | { 17 | string info = operands[0].AsString; 18 | ScriptProcessor.Begin(info); 19 | return 0; 20 | } 21 | } 22 | internal class EndCommand : SimpleExpressionBase 23 | { 24 | protected override BoxedValue OnCalc(IList operands) 25 | { 26 | string info = operands[0].AsString; 27 | ScriptProcessor.End(info); 28 | return 0; 29 | } 30 | } 31 | internal class BeginFileCommand : SimpleExpressionBase 32 | { 33 | protected override BoxedValue OnCalc(IList operands) 34 | { 35 | string file = operands[0].AsString; 36 | string info = operands[1].AsString; 37 | ScriptProcessor.BeginFile(file, info); 38 | return 0; 39 | } 40 | } 41 | internal class EndFileCommand : SimpleExpressionBase 42 | { 43 | protected override BoxedValue OnCalc(IList operands) 44 | { 45 | ScriptProcessor.EndFile(); 46 | return 0; 47 | } 48 | } 49 | internal class BeginReplaceCommand : SimpleExpressionBase 50 | { 51 | protected override BoxedValue OnCalc(IList operands) 52 | { 53 | string file = operands[0].AsString; 54 | ScriptProcessor.BeginReplace(file); 55 | return 0; 56 | } 57 | } 58 | internal class ReplaceCommand : SimpleExpressionBase 59 | { 60 | protected override BoxedValue OnCalc(IList operands) 61 | { 62 | string file = operands[0].AsString; 63 | string srcClass = operands[1].AsString; 64 | string targetClass = operands[2].AsString; 65 | ScriptProcessor.Replace(file, srcClass, targetClass); 66 | return 0; 67 | } 68 | } 69 | internal class ReplaceAssemblyRefNameCommand : SimpleExpressionBase 70 | { 71 | protected override BoxedValue OnCalc(IList operands) 72 | { 73 | string file = operands[0].AsString; 74 | string srcName = operands[1].AsString; 75 | string targetName = operands[2].AsString; 76 | ScriptProcessor.ReplaceAssemblyRefName(file, srcName, targetName); 77 | return 0; 78 | } 79 | } 80 | internal class RedirectAssemblyCommand : SimpleExpressionBase 81 | { 82 | protected override BoxedValue OnCalc(IList operands) 83 | { 84 | string file = operands[0].AsString; 85 | string targetAssem = operands[1].AsString; 86 | List srcAssems = new List(); 87 | for (int i = 2; i < operands.Count; ++i) { 88 | var str = operands[i].AsString; 89 | if (null != str) { 90 | srcAssems.Add(str); 91 | } 92 | else { 93 | var strList = operands[i].As(); 94 | if (null != strList) { 95 | foreach (var strObj in strList) { 96 | var tempStr = strObj as string; 97 | if (null != tempStr) 98 | srcAssems.Add(tempStr); 99 | } 100 | } 101 | } 102 | } 103 | ScriptProcessor.RedirectAssembly(file, targetAssem, srcAssems); 104 | return 0; 105 | } 106 | } 107 | internal class EndReplaceCommand : SimpleExpressionBase 108 | { 109 | protected override BoxedValue OnCalc(IList operands) 110 | { 111 | string file = operands[0].AsString; 112 | ScriptProcessor.EndReplace(file); 113 | return 0; 114 | } 115 | } 116 | internal class BeginExtendCommand : SimpleExpressionBase 117 | { 118 | protected override BoxedValue OnCalc(IList operands) 119 | { 120 | string file = operands[0].AsString; 121 | uint newSize = CastTo(operands[1]); 122 | ScriptProcessor.BeginExtend(file, newSize); 123 | return 0; 124 | } 125 | } 126 | internal class ExtendCommand : SimpleExpressionBase 127 | { 128 | protected override BoxedValue OnCalc(IList operands) 129 | { 130 | string file = operands[0].AsString; 131 | string className = operands[1].AsString; 132 | string methodName = operands[2].AsString; 133 | uint insertSize = CastTo(operands[3]); 134 | ScriptProcessor.Extend(file, className, methodName, insertSize); 135 | return 0; 136 | } 137 | } 138 | internal class EndExtendCommand : SimpleExpressionBase 139 | { 140 | protected override BoxedValue OnCalc(IList operands) 141 | { 142 | string file = operands[0].AsString; 143 | ScriptProcessor.EndExtend(file); 144 | return 0; 145 | } 146 | } 147 | internal class BeginModifyCommand : SimpleExpressionBase 148 | { 149 | protected override BoxedValue OnCalc(IList operands) 150 | { 151 | string file = operands[0].AsString; 152 | ScriptProcessor.BeginModify(file); 153 | return 0; 154 | } 155 | } 156 | internal class EndModifyCommand : SimpleExpressionBase 157 | { 158 | protected override BoxedValue OnCalc(IList operands) 159 | { 160 | string file = operands[0].AsString; 161 | ScriptProcessor.EndModify(file); 162 | return 0; 163 | } 164 | } 165 | //--------------------------------------------------------------------------------------------------------------- 166 | internal class WriteLoadArgCommand : SimpleExpressionBase 167 | { 168 | protected override BoxedValue OnCalc(IList operands) 169 | { 170 | string file = operands[0].AsString; 171 | string className = operands[1].AsString; 172 | string methodName = operands[2].AsString; 173 | uint pos = CastTo(operands[3]); 174 | int index = CastTo(operands[4]); 175 | ScriptProcessor.WriteLoadArg(file, className, methodName, pos, index); 176 | return 0; 177 | } 178 | } 179 | internal class WriteLoadLocalCommand : SimpleExpressionBase 180 | { 181 | protected override BoxedValue OnCalc(IList operands) 182 | { 183 | string file = operands[0].AsString; 184 | string className = operands[1].AsString; 185 | string methodName = operands[2].AsString; 186 | uint pos = CastTo(operands[3]); 187 | int index = CastTo(operands[4]); 188 | ScriptProcessor.WriteLoadLocal(file, className, methodName, pos, index); 189 | return 0; 190 | } 191 | } 192 | internal class WriteLoadFieldCommand : SimpleExpressionBase 193 | { 194 | protected override BoxedValue OnCalc(IList operands) 195 | { 196 | string file = operands[0].AsString; 197 | string className = operands[1].AsString; 198 | string methodName = operands[2].AsString; 199 | uint pos = CastTo(operands[3]); 200 | string cn = operands[4].AsString; 201 | string fn = operands[5].AsString; 202 | ScriptProcessor.WriteLoadField(file, className, methodName, pos, cn, fn); 203 | return 0; 204 | } 205 | } 206 | internal class WriteLoadStaticFieldCommand : SimpleExpressionBase 207 | { 208 | protected override BoxedValue OnCalc(IList operands) 209 | { 210 | string file = operands[0].AsString; 211 | string className = operands[1].AsString; 212 | string methodName = operands[2].AsString; 213 | uint pos = CastTo(operands[3]); 214 | string cn = operands[4].AsString; 215 | string fn = operands[5].AsString; 216 | ScriptProcessor.WriteLoadStaticField(file, className, methodName, pos, cn, fn); 217 | return 0; 218 | } 219 | } 220 | internal class WriteCallCommand : SimpleExpressionBase 221 | { 222 | protected override BoxedValue OnCalc(IList operands) 223 | { 224 | string file = operands[0].AsString; 225 | string className = operands[1].AsString; 226 | string methodName = operands[2].AsString; 227 | uint pos = CastTo(operands[3]); 228 | string cn = operands[4].AsString; 229 | string mn = operands[5].AsString; 230 | ScriptProcessor.WriteCall(file, className, methodName, pos, cn, mn); 231 | return 0; 232 | } 233 | } 234 | internal class WriteCallVirtCommand : SimpleExpressionBase 235 | { 236 | protected override BoxedValue OnCalc(IList operands) 237 | { 238 | string file = operands[0].AsString; 239 | string className = operands[1].AsString; 240 | string methodName = operands[2].AsString; 241 | uint pos = CastTo(operands[3]); 242 | string cn = operands[4].AsString; 243 | string mn = operands[5].AsString; 244 | ScriptProcessor.WriteCallVirt(file, className, methodName, pos, cn, mn); 245 | return 0; 246 | } 247 | } 248 | internal class WriteNopsCommand : SimpleExpressionBase 249 | { 250 | protected override BoxedValue OnCalc(IList operands) 251 | { 252 | string file = operands[0].AsString; 253 | string className = operands[1].AsString; 254 | string methodName = operands[2].AsString; 255 | uint pos = CastTo(operands[3]); 256 | int size = CastTo(operands[4]); 257 | ScriptProcessor.WriteNops(file, className, methodName, pos, size); 258 | return 0; 259 | } 260 | } 261 | internal class GetFileListCommand : SimpleExpressionBase 262 | { 263 | protected override BoxedValue OnCalc(IList operands) 264 | { 265 | return BoxedValue.FromObject(ScriptProcessor.GetFileList()); 266 | } 267 | } 268 | //--------------------------------------------------------------------------------------------------------------- 269 | internal class LogCommand : SimpleExpressionBase 270 | { 271 | protected override BoxedValue OnCalc(IList operands) 272 | { 273 | if (operands.Count > 0) { 274 | string format = operands[0].AsString; 275 | List vargs = new List(); 276 | for(int i = 1; i < operands.Count; ++i) { 277 | var opd = operands[i].GetObject(); 278 | vargs.Add(opd); 279 | } 280 | ClrFileModifier.ResultTexts.Add(string.Format(format, vargs.ToArray())); 281 | } 282 | return 0; 283 | } 284 | } 285 | //--------------------------------------------------------------------------------------------------------------- 286 | } 287 | -------------------------------------------------------------------------------- /app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeTarget": { 3 | "name": ".NETCoreApp,Version=v6.0", 4 | "signature": "" 5 | }, 6 | "compilationOptions": {}, 7 | "targets": { 8 | ".NETCoreApp,Version=v6.0": { 9 | "DotnetPatch/1.0.0": { 10 | "dependencies": { 11 | "Dsl": "0.0.0.0" 12 | }, 13 | "runtime": { 14 | "DotnetPatch.dll": {} 15 | } 16 | }, 17 | "Dsl/0.0.0.0": { 18 | "runtime": { 19 | "Dsl.dll": { 20 | "assemblyVersion": "0.0.0.0", 21 | "fileVersion": "0.0.0.0" 22 | } 23 | } 24 | } 25 | } 26 | }, 27 | "libraries": { 28 | "DotnetPatch/1.0.0": { 29 | "type": "project", 30 | "serviceable": false, 31 | "sha512": "" 32 | }, 33 | "Dsl/0.0.0.0": { 34 | "type": "reference", 35 | "serviceable": false, 36 | "sha512": "" 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/DotnetPatch.dll -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.dll.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/DotnetPatch.exe -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/DotnetPatch.pdb -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatch.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "net6.0", 4 | "frameworks": [ 5 | { 6 | "name": "Microsoft.NETCore.App", 7 | "version": "6.0.0" 8 | }, 9 | { 10 | "name": "Microsoft.WindowsDesktop.App", 11 | "version": "6.0.0" 12 | } 13 | ], 14 | "configProperties": { 15 | "System.Reflection.Metadata.MetadataUpdater.IsSupported": false 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/DotnetPatchBak.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/DotnetPatchBak.exe -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/Dsl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/Dsl.dll -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/Dsl.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/Dsl.pdb -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/ILMerge.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/ILMerge.exe -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/UnityEditor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/UnityEditor.dll -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/UnityEngine.UI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/UnityEngine.UI.dll -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/UnityEngine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/bin/Release/net6.0-windows/UnityEngine.dll -------------------------------------------------------------------------------- /bin/Release/net6.0-windows/domerge.bat: -------------------------------------------------------------------------------- 1 | @echo on 2 | move /Y DotnetPatch.exe DotnetPatchBak.exe 3 | ilmerge /target:winexe /out:DotnetPatch.exe DotnetPatchBak.exe Dsl.dll 4 | -------------------------------------------------------------------------------- /dep/Common.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/Common.dll -------------------------------------------------------------------------------- /dep/Common.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/Common.pdb -------------------------------------------------------------------------------- /dep/DotnetStoryScript.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/DotnetStoryScript.dll -------------------------------------------------------------------------------- /dep/DotnetStoryScript.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/DotnetStoryScript.pdb -------------------------------------------------------------------------------- /dep/Dsl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/Dsl.dll -------------------------------------------------------------------------------- /dep/Dsl.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/Dsl.pdb -------------------------------------------------------------------------------- /dep/LitJson.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/LitJson.dll -------------------------------------------------------------------------------- /dep/ScriptFrameworkLibrary.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamanlan/DotnetPatch/9f85a074ac437ab6f4568039ed78eeeec1f97b54/dep/ScriptFrameworkLibrary.dll -------------------------------------------------------------------------------- /dep/modify.scp: -------------------------------------------------------------------------------- 1 | script(main) 2 | { 3 | $files = getfilelist(); 4 | begin("开始脚本处理"); 5 | looplist($files){ 6 | $file=$$; 7 | beginfile($file,"开始对"+$file+"进行修改。。。"); 8 | beginreplace($file); 9 | replace($file,"Game","GamePatch"); 10 | endreplace($file); 11 | beginmodify($file); 12 | writeloadarg($file,"PlayerController","Update",0x38,0); 13 | writeloadfield($file,"PlayerController","Update",0x39,"PlayerController","m_player"); 14 | writeloadarg($file,"PlayerController","Update",0x3e,0); 15 | writeloadfield($file,"PlayerController","Update",0x3f,"PlayerController","m_moveElapseTime"); 16 | writecall($file,"PlayerController","Update",0x44,"DebugConsoleHelper","Move"); 17 | writenops($file,"PlayerController","Update",0x49,0x22); 18 | endmodify($file); 19 | endfile($file); 20 | }; 21 | end("结束脚本处理"); 22 | }; -------------------------------------------------------------------------------- /dep/redirect.scp: -------------------------------------------------------------------------------- 1 | script(main) 2 | { 3 | $files = getfilelist(); 4 | begin("开始脚本处理"); 5 | looplist($files){ 6 | $file=$$; 7 | beginfile($file,"开始对"+$file+"进行修改。。。"); 8 | beginreplace($file); 9 | replaceassemblyrefname($file, "UnityEngine.CoreModule", "UnityEngine"); 10 | redirectassembly($file,"UnityEditor", 11 | "UnityEngine.CoreModule" 12 | ); 13 | redirectassembly($file,"UnityEngine", 14 | "UnityEngine.UIModule", 15 | "UnityEngine.TextRenderingModule", 16 | "UnityEngine.PhysicsModule", 17 | "UnityEngine.Physics2DModule", 18 | "UnityEngine.IMGUIModule", 19 | "UnityEngine.AnimationModule", 20 | "UnityEngine.UIElementsModule", 21 | "UnityEngine.InputLegacyModule", 22 | "UnityEngine.CoreModule", 23 | "UnityEngine.TilemapModule", 24 | "UnityEngine.SpriteShapeModule" 25 | ); 26 | endreplace($file); 27 | endfile($file); 28 | }; 29 | end("结束脚本处理"); 30 | }; --------------------------------------------------------------------------------