-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPatcher.vb
More file actions
284 lines (251 loc) · 12.8 KB
/
Patcher.vb
File metadata and controls
284 lines (251 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
Imports Mono.Cecil
Imports Mono.Cecil.Cil
Imports System.IO
Imports System.Threading
Public Class Patcher
Implements IDisposable
Private _originalPath As String
Private _tempPath As String
Private _assembly As AssemblyDefinition
Private _disposed As Boolean = False
Public Sub New(originalDllPath As String)
_originalPath = originalDllPath
' Legge tutto il file originale in un array di byte
Dim rawBytes As Byte() = File.ReadAllBytes(_originalPath)
' Prepara il resolver per eventuali dipendenze
Dim resolver As New DefaultAssemblyResolver()
resolver.AddSearchDirectory(Path.GetDirectoryName(_originalPath))
' Carica l'assembly da un MemoryStream (non tiene il file aperto)
Dim memStream As New MemoryStream(rawBytes)
Dim parameters As New ReaderParameters() With {
.ReadWrite = True,
.AssemblyResolver = resolver,
.InMemory = True
}
_assembly = AssemblyDefinition.ReadAssembly(memStream, parameters)
End Sub
' Modifica 1: this.IsRegistered = false -> true (cerca il backing field)
Public Sub SetLicenseRegistered(registered As Boolean, worker As ComponentModel.BackgroundWorker)
Dim licenseType = _assembly.MainModule.GetType("NetLimiter.Service.NLLicense")
If licenseType Is Nothing Then Throw New Exception("Tipo NLLicense non trovato.")
worker.ReportProgress(0, "Trovato tipo NLLicense.")
Dim ctor As MethodDefinition = Nothing
For Each m In licenseType.Methods
If m.IsConstructor AndAlso Not m.IsStatic Then ctor = m : Exit For
Next
If ctor Is Nothing Then Throw New Exception("Costruttore di NLLicense non trovato.")
worker.ReportProgress(0, "Trovato costruttore.")
worker.ReportProgress(0, "Analisi istruzioni del costruttore...")
Dim found As Boolean = False
' Prima cerca chiamate a set_IsRegistered
For Each inst In ctor.Body.Instructions
If (inst.OpCode = OpCodes.Call OrElse inst.OpCode = OpCodes.Callvirt) AndAlso inst.Operand IsNot Nothing Then
Dim methodRef = TryCast(inst.Operand, MethodReference)
If methodRef IsNot Nothing AndAlso methodRef.Name = "set_IsRegistered" Then
worker.ReportProgress(0, "Trovata chiamata a set_IsRegistered.")
' Cerca l'istruzione precedente che carica il valore (ldc.i4.0 o ldc.i4.1)
Dim prev = GetPreviousInstruction(ctor.Body.Instructions, inst)
If prev IsNot Nothing AndAlso (prev.OpCode = OpCodes.Ldc_I4_0 OrElse prev.OpCode = OpCodes.Ldc_I4_1) Then
Dim oldValue = If(prev.OpCode = OpCodes.Ldc_I4_0, "false", "true")
worker.ReportProgress(0, $"Trovato valore {oldValue} prima della chiamata. Imposto a {If(registered, "true", "false")}.")
prev.OpCode = If(registered, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_0)
found = True
Exit For
End If
End If
End If
Next
' Se non trovata, cerca stfld su campo contenente "IsRegistered"
If Not found Then
worker.ReportProgress(0, "Nessuna chiamata a set_IsRegistered trovata. Cerco stfld su campi...")
For Each inst In ctor.Body.Instructions
If inst.OpCode = OpCodes.Stfld AndAlso inst.Operand IsNot Nothing Then
Dim field = TryCast(inst.Operand, FieldDefinition)
If field IsNot Nothing AndAlso field.Name.IndexOf("IsRegistered", StringComparison.OrdinalIgnoreCase) >= 0 Then
worker.ReportProgress(0, $"Trovato stfld su campo: {field.Name}")
Dim prev = GetPreviousInstruction(ctor.Body.Instructions, inst)
If prev IsNot Nothing AndAlso (prev.OpCode = OpCodes.Ldc_I4_0 OrElse prev.OpCode = OpCodes.Ldc_I4_1) Then
Dim oldValue = If(prev.OpCode = OpCodes.Ldc_I4_0, "false", "true")
worker.ReportProgress(0, $"Trovata assegnazione a {field.Name} con valore {oldValue}. Imposto a {If(registered, "true", "false")}.")
prev.OpCode = If(registered, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_0)
found = True
Exit For
End If
End If
End If
Next
End If
If Not found Then
' Debug: elenca tutte le chiamate a metodi e stfld
worker.ReportProgress(0, "ATTENZIONE: Nessuna assegnazione a IsRegistered trovata. Elenco operazioni nel costruttore:")
For Each inst In ctor.Body.Instructions
If inst.OpCode = OpCodes.Stfld Then
Dim field = TryCast(inst.Operand, FieldDefinition)
If field IsNot Nothing Then worker.ReportProgress(0, $" stfld campo: {field.Name}")
ElseIf inst.OpCode = OpCodes.Call OrElse inst.OpCode = OpCodes.Callvirt Then
Dim methodRef = TryCast(inst.Operand, MethodReference)
If methodRef IsNot Nothing Then worker.ReportProgress(0, $" call metodo: {methodRef.Name}")
End If
Next
Throw New Exception("Non è stato possibile trovare l'assegnazione a IsRegistered nel costruttore.")
End If
End Sub
' Modifica 2: DateTime expiration = installTime.AddDays(28.0) -> AddDays(99999.0)
Public Sub ExtendTrial(days As Integer, worker As ComponentModel.BackgroundWorker)
Dim serviceTempType = _assembly.MainModule.GetType("NetLimiter.Service.NLServiceTemp")
If serviceTempType Is Nothing Then Throw New Exception("Tipo NLServiceTemp non trovato.")
worker.ReportProgress(0, "Trovato tipo NLServiceTemp.")
Dim initMethod As MethodDefinition = Nothing
For Each m In serviceTempType.Methods
If m.Name = "InitLicense" Then initMethod = m : Exit For
Next
If initMethod Is Nothing Then Throw New Exception("Metodo InitLicense non trovato.")
worker.ReportProgress(0, "Trovato metodo InitLicense.")
Dim found As Boolean = False
For Each inst In initMethod.Body.Instructions
If (inst.OpCode = OpCodes.Call OrElse inst.OpCode = OpCodes.Callvirt) AndAlso inst.Operand IsNot Nothing Then
Dim methodRef = TryCast(inst.Operand, MethodReference)
If methodRef IsNot Nothing AndAlso methodRef.Name = "AddDays" Then
worker.ReportProgress(0, "Trovata chiamata a AddDays.")
Dim prev = GetPreviousInstruction(initMethod.Body.Instructions, inst)
If prev IsNot Nothing AndAlso prev.OpCode = OpCodes.Ldc_R8 Then
Dim oldValue = Convert.ToDouble(prev.Operand)
worker.ReportProgress(0, $"Trovato valore AddDays: {oldValue}. Imposto a {days}.")
prev.Operand = Convert.ToDouble(days)
found = True
Exit For
End If
End If
End If
Next
If Not found Then
worker.ReportProgress(0, "ATTENZIONE: Nessuna chiamata a AddDays trovata. Elenco COMPLETO delle istruzioni di InitLicense:")
Dim idx As Integer = 0
For Each inst In initMethod.Body.Instructions
Dim oper As String = If(inst.Operand IsNot Nothing, inst.Operand.ToString(), "")
worker.ReportProgress(0, $" [{idx}] {inst.OpCode} {oper}")
idx += 1
Next
Throw New Exception("Non è stato possibile trovare l'istruzione AddDays nel metodo InitLicense.")
End If
End Sub
' Modifica 3: catch (Exception exception) -> catch (System.Exception exception)
Public Sub FixExceptionHandler(worker As ComponentModel.BackgroundWorker)
Dim serviceTempType = _assembly.MainModule.GetType("NetLimiter.Service.NLServiceTemp")
If serviceTempType Is Nothing Then Return
Dim initMethod As MethodDefinition = Nothing
For Each m In serviceTempType.Methods
If m.Name = "InitLicense" Then
initMethod = m
Exit For
End If
Next
If initMethod Is Nothing Then Return
Dim found As Boolean = False
For Each handler In initMethod.Body.ExceptionHandlers
If handler.HandlerType = ExceptionHandlerType.Catch Then
Dim catchType = handler.CatchType
If catchType IsNot Nothing AndAlso catchType.Name = "Exception" Then
worker.ReportProgress(0, "Trovato gestore catch per Exception, sostituisco con System.Exception.")
Dim systemException = _assembly.MainModule.ImportReference(GetType(System.Exception))
handler.CatchType = systemException
found = True
End If
End If
Next
If Not found Then
worker.ReportProgress(0, "Nessun gestore catch per Exception trovato (potrebbe non essere necessario).")
End If
End Sub
' Modifica opzionale: get_RegName restituisce un nome fisso
Public Sub SetRegistrationName(name As String, worker As ComponentModel.BackgroundWorker)
Dim licenseType = _assembly.MainModule.GetType("NetLimiter.Service.NLLicense")
If licenseType Is Nothing Then Return
Dim getRegName As MethodDefinition = Nothing
For Each m In licenseType.Methods
If m.Name = "get_RegName" Then
getRegName = m
Exit For
End If
Next
If getRegName Is Nothing Then
worker.ReportProgress(0, "Metodo get_RegName non trovato.")
Return
End If
worker.ReportProgress(0, $"Modifico get_RegName per restituire '{name}'.")
Dim il = getRegName.Body.GetILProcessor()
il.Body.Instructions.Clear()
il.Append(il.Create(OpCodes.Ldstr, name))
il.Append(il.Create(OpCodes.Ret))
End Sub
' Funzione per ottenere l'istruzione precedente
Private Function GetPreviousInstruction(instructions As Mono.Collections.Generic.Collection(Of Instruction), current As Instruction) As Instruction
For i As Integer = 1 To instructions.Count - 1
If instructions(i) Is current Then
Return instructions(i - 1)
End If
Next
Return Nothing
End Function
Public Sub Save(worker As ComponentModel.BackgroundWorker)
If _disposed Then Throw New ObjectDisposedException("Patcher")
worker.ReportProgress(0, "Scrittura assembly modificato in memoria...")
' Scrive l'assembly in un MemoryStream
Dim outStream As New MemoryStream()
_assembly.Write(outStream)
_assembly.Dispose()
_assembly = Nothing
' Crea un file temporaneo e scrive i byte
_tempPath = Path.GetTempFileName()
File.WriteAllBytes(_tempPath, outStream.ToArray())
outStream.Close()
outStream.Dispose()
worker.ReportProgress(0, $"File temporaneo creato: {_tempPath}")
' Ora sovrascrivi l'originale con il temporaneo
Dim retryCount As Integer = 3
While retryCount > 0
Try
File.Copy(_tempPath, _originalPath, True)
worker.ReportProgress(0, "File originale sovrascritto con successo.")
Exit While
Catch ex As IOException
retryCount -= 1
If retryCount = 0 Then
Throw New Exception("Impossibile sovrascrivere il file originale dopo diversi tentativi. Assicurati che NetLimiter sia fermato.", ex)
End If
worker.ReportProgress(0, $"Tentativo fallito, riprovo tra 500ms... ({retryCount} tentativi rimasti)")
Thread.Sleep(500)
End Try
End While
' Elimina il temporaneo
Try
File.Delete(_tempPath)
worker.ReportProgress(0, "File temporaneo eliminato.")
Catch
End Try
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _disposed Then
If disposing Then
If _assembly IsNot Nothing Then
_assembly.Dispose()
_assembly = Nothing
End If
If _tempPath IsNot Nothing AndAlso File.Exists(_tempPath) Then
Try
File.Delete(_tempPath)
Catch
End Try
End If
End If
_disposed = True
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
End Class