zackmark29 Posted April 23, 2020 Posted April 23, 2020 (edited) Hi everyone. I was having trouble of creating and learning of patching with VB.NET Can anybody tell me what's wrong with that code? I tried many times but the bytes still not replacing Please help Imports System.Runtime.CompilerServices Imports System.IO Public Class Form1 Private Shared ReadOnly FindHex As Byte() = {&HE0, &H42, &HFC, &HB1, &H3, &H40, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H75, &H8F, &H75, &H74} Private Shared ReadOnly ReplaceHex As Byte() = {&H0, &H0, &H0, &H0, &H0, &HE0, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H74, &H8E, &HEB, &HEB} <MethodImpl(MethodImplOptions.NoInlining)> Private Shared Function DP(sequence As Byte(), position As Integer) As Boolean If position + FindHex.Length > sequence.Length Then Return False End If For i As Integer = 0 To FindHex.Length - 1 If FindHex(i) <> sequence(position + i) Then Return False End If Next Return True End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim DT As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) Dim FD As Byte() = File.ReadAllBytes(DT & "\ew\ORIGINAL.exe") For F As Integer = 0 To FD.Length - 1 If Not DP(FD, F) Then Continue For End If For R As Integer = 0 To FindHex.Length - 1 FD(F + R) = ReplaceHex(R) Next Next If System.IO.File.Exists(DT & "\ew\ORIGINAL.exe") Then System.IO.File.Move(DT & "\ew\ORIGINAL.exe", DT & "\ew\ORIGINAL_bak.exe") File.WriteAllBytes(DT & "\ew\ORIGINAL_PATCHED.exe", FD) Else 'Write Other Codes End If End Sub End Class Edited April 24, 2020 by zackmark29
NOP Posted April 24, 2020 Posted April 24, 2020 Instead of asking so many questions for every single step, have you tried to debug the program you write? Step through it and see what it is or isn't doing, it is the only way you will learn
Kurapica Posted April 24, 2020 Posted April 24, 2020 (edited) Man you need to debug your stuff and find where it fails, I have something similar to what you are trying to do but It's in C# I will just paste the code from dnspy in VB.NET syntax, the rest is your job Imports System Imports System.Collections.Generic Imports System.IO Imports System.Reflection Namespace SnD ' Token: 0x02000002 RID: 2 Friend Module ByteArrayRocks ' Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250 <System.Runtime.CompilerServices.ExtensionAttribute()> Public Function Locate(self As Byte(), candidate As Byte()) As Integer() Dim result As Integer() If ByteArrayRocks.IsEmptyLocate(self, candidate) Then result = ByteArrayRocks.Empty Else Dim list As List(Of Integer) = New List(Of Integer)() For i As Integer = 0 To self.Length - 1 If ByteArrayRocks.IsMatch(self, i, candidate) Then list.Add(i) End If Next result = If((list.Count = 0), ByteArrayRocks.Empty, list.ToArray()) End If Return result End Function ' Token: 0x06000002 RID: 2 RVA: 0x000020C0 File Offset: 0x000002C0 Private Function IsMatch(array As Byte(), position As Integer, candidate As Byte()) As Boolean Dim result As Boolean If candidate.Length > array.Length - position Then result = False Else For i As Integer = 0 To candidate.Length - 1 If array(position + i) <> candidate(i) Then Return False End If Next result = True End If Return result End Function ' Token: 0x06000003 RID: 3 RVA: 0x0000210C File Offset: 0x0000030C Private Function IsEmptyLocate(array As Byte(), candidate As Byte()) As Boolean Return array Is Nothing OrElse candidate Is Nothing OrElse array.Length = 0 OrElse candidate.Length = 0 OrElse candidate.Length > array.Length End Function ' Token: 0x06000004 RID: 4 RVA: 0x0000215C File Offset: 0x0000035C Private Sub Main() Dim data As Byte() = File.ReadAllBytes(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\whatever.exe") Dim patchedBytes As Byte() = New Byte() { 144, 144, 144, 144, 144, 144 } Dim pattern As Byte() = New Byte() { 15, 140, 94, 248, Byte.MaxValue, Byte.MaxValue, 65, 188, 63, 0, 0, 0, 69, 139, 239, 65, 131, 126, 56, 0 } Dim locations As Integer() = data.Locate(pattern) If locations IsNot Nothing AndAlso locations.Length = 1 Then Dim offset As Long = CLng(locations(0)) Dim target As FileStream = New FileStream(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\whatever.exe", FileMode.Open) target.Seek(offset, SeekOrigin.Begin) For i As Integer = 0 To patchedBytes.Length - 1 target.WriteByte(patchedBytes(i)) Next target.Flush() target.Close() Console.WriteLine("Successfully fixed !, exiting ....") Console.ReadKey() Else Console.WriteLine("An error has occured !, exiting ....") Console.ReadKey() End If End Sub ' Token: 0x04000001 RID: 1 Private Empty As Integer() = New Integer(-1) {} End Module End Namespace Edited April 24, 2020 by Kurapica 1
zackmark29 Posted April 24, 2020 Author Posted April 24, 2020 (edited) 12 minutes ago, Kurapica said: Man you need to debug your stuff and find where it fails, I have something similar to what you are trying to do but It's in C# I will just paste the code from dnspy in VB.NET syntax, the rest is your job I actually did debug it but, Here's actually my problem now. I almost fix the problem but the first 2 bytes are keep repeating see screenshot When i try to replace old byte: 31 35 new byte: 4C 6D It keeps repeating Edited April 24, 2020 by zackmark29
zackmark29 Posted April 24, 2020 Author Posted April 24, 2020 37 minutes ago, NOP said: Instead of asking so many questions for every single step, have you tried to debug the program you write? Step through it and see what it is or isn't doing, it is the only way you will learn Yeah already did I can't just figure out patching multiple bytes i can only patch the if the pattern is like this Searchpattern : 83 E0 0F 83 C0 0F A3 14 ED 6F 00 C6 Replacepattern : B8 FF FF FF 7F 90 ?? ?? ?? ?? ?? ?? but if I try to patch like this Searchpattern : 31 35 53 00 02 00 40 81 Replacepattern : 4C 6D ?? ?? ?? ?? ?? ?? It's just keep repeating
zackmark29 Posted April 24, 2020 Author Posted April 24, 2020 12 minutes ago, Kurapica said: Man you need to debug your stuff and find where it fails, I have something similar to what you are trying to do but It's in C# I will just paste the code from dnspy in VB.NET syntax, the rest is your job Imports System Imports System.Collections.Generic Imports System.IO Imports System.Reflection Namespace SnD ' Token: 0x02000002 RID: 2 Friend Module ByteArrayRocks ' Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250 <System.Runtime.CompilerServices.ExtensionAttribute()> Public Function Locate(self As Byte(), candidate As Byte()) As Integer() Dim result As Integer() If ByteArrayRocks.IsEmptyLocate(self, candidate) Then result = ByteArrayRocks.Empty Else Dim list As List(Of Integer) = New List(Of Integer)() For i As Integer = 0 To self.Length - 1 If ByteArrayRocks.IsMatch(self, i, candidate) Then list.Add(i) End If Next result = If((list.Count = 0), ByteArrayRocks.Empty, list.ToArray()) End If Return result End Function ' Token: 0x06000002 RID: 2 RVA: 0x000020C0 File Offset: 0x000002C0 Private Function IsMatch(array As Byte(), position As Integer, candidate As Byte()) As Boolean Dim result As Boolean If candidate.Length > array.Length - position Then result = False Else For i As Integer = 0 To candidate.Length - 1 If array(position + i) <> candidate(i) Then Return False End If Next result = True End If Return result End Function ' Token: 0x06000003 RID: 3 RVA: 0x0000210C File Offset: 0x0000030C Private Function IsEmptyLocate(array As Byte(), candidate As Byte()) As Boolean Return array Is Nothing OrElse candidate Is Nothing OrElse array.Length = 0 OrElse candidate.Length = 0 OrElse candidate.Length > array.Length End Function ' Token: 0x06000004 RID: 4 RVA: 0x0000215C File Offset: 0x0000035C Private Sub Main() Dim data As Byte() = File.ReadAllBytes(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\whatever.exe") Dim patchedBytes As Byte() = New Byte() { 144, 144, 144, 144, 144, 144 } Dim pattern As Byte() = New Byte() { 15, 140, 94, 248, Byte.MaxValue, Byte.MaxValue, 65, 188, 63, 0, 0, 0, 69, 139, 239, 65, 131, 126, 56, 0 } Dim locations As Integer() = data.Locate(pattern) If locations IsNot Nothing AndAlso locations.Length = 1 Then Dim offset As Long = CLng(locations(0)) Dim target As FileStream = New FileStream(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\whatever.exe", FileMode.Open) target.Seek(offset, SeekOrigin.Begin) For i As Integer = 0 To patchedBytes.Length - 1 target.WriteByte(patchedBytes(i)) Next target.Flush() target.Close() Console.WriteLine("Successfully fixed !, exiting ....") Console.ReadKey() Else Console.WriteLine("An error has occured !, exiting ....") Console.ReadKey() End If End Sub ' Token: 0x04000001 RID: 1 Private Empty As Integer() = New Integer(-1) {} End Module End Namespace I'll try your code hopefully I will success
zackmark29 Posted April 24, 2020 Author Posted April 24, 2020 16 minutes ago, Kurapica said: Man you need to debug your stuff and find where it fails, I have something similar to what you are trying to do but It's in C# I will just paste the code from dnspy in VB.NET syntax, the rest is your job Could you please upload the file that you open on dnspy?
Kurapica Posted April 24, 2020 Posted April 24, 2020 That's all the code in it, It was a simple Seek and Replace small program Need any help ? 1
zackmark29 Posted April 25, 2020 Author Posted April 25, 2020 11 hours ago, Kurapica said: That's all the code in it, It was a simple Seek and Replace small program Need any help ? hehe I can't understand for now how it works But I got a little idea with your code and It worked for me. My problem now is I can't patch 1 byte or 2 bytes in a pattern like in this example Search pattern: 83 3D 10 ED 6F 00 00 0F 85 DE 01 00 Replace pattern: C6 05 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? Nothing is happening even if I already separated the patch code
zackmark29 Posted April 25, 2020 Author Posted April 25, 2020 2 hours ago, NOP said: Can you upload your file? What file do you need? The crack and original file? or the project file?
NOP Posted April 25, 2020 Posted April 25, 2020 Compiled crack and original file, if file is commercial copyrighted then can you use a simplified file you can include which has the same problem I don't use VB but can look it over using C# from compiled file to see where your problem is
Kurapica Posted April 25, 2020 Posted April 25, 2020 3 hours ago, zackmark29 said: hehe I can't understand for now how it works But I got a little idea with your code and It worked for me. My problem now is I can't patch 1 byte or 2 bytes in a pattern like in this example Search pattern: 83 3D 10 ED 6F 00 00 0F 85 DE 01 00 Replace pattern: C6 05 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? Nothing is happening even if I already separated the patch code It's simple you provide the pattern you want to find in that file "Dim pattern As Byte()" "locations" is an array of integers, each integer is a beginning of a found pattern, this is where you should write your patchedbytes.
Progman Posted April 25, 2020 Posted April 25, 2020 Just for info, both code patterns posted here could be optimized to not have a conditional in the loop. The length check could instead be done up front by just subtracting the length of the pattern from the length of the search - which will be an O(n) condition check speed up. Not that it matters so much to optimize it if the n - the size of the binary in bytes is not that large. Also I think you will find much better performance using Enumerable.SequenceEqual rather than doing byte by byte comparison. However, under the hood, I am not sure if it makes a difference - it should its the difference between a cmp/jz loop and a repne cmpsb in assembly. And there is no comparison on performance there, repne cmpsb is a highly optimized pattern. Compilers will typically floor divide by 4, do a repne cmpsd, then a cmpsw if there is a remainder of 2, and a cmpsb if there is a remainder of 1. Most of us reversers have seen this nice compiler asm pattern many times. The problem is if you want to provide a pattern that should only be replaced once. Then you need to make sure your pattern is unique across the entirety of the file. Using extra bytes that come before or after, or even wildcard patterns would work. Of course a byte array won't be ideal for the matching then as you need to represent the wildcard byte state. Using a Nullable<byte> might work, but it will prevent Enumerable.SequenceEqual from being used and require an extra level of indirection constantly. Maybe what you wanted is Searchpattern : 31 35 53 00 02 00 40 81 Replacepattern : 4C 6D 53 00 02 00 40 81 For the replace pattern for sure I would use something like the Nullable<byte> as you could just do Replacepattern : 4C 6D null null null null null null Try to do some tutorials on coding and debugging in this regard. I wrote a patch engine long ago and eventually like has happened to many a happy patcher, it moved to embedding a resource text script which I parsed and generically could apply any patches to a file and even had a UI built into the script that would render on the fly to allow selection of which patches would be applied. Using ?? for wildcard bytes was usually the strategy there.
zackmark29 Posted April 25, 2020 Author Posted April 25, 2020 1 hour ago, Progman said: Just for info, both code patterns posted here could be optimized to not have a conditional in the loop. The length check could instead be done up front by just subtracting the length of the pattern from the length of the search - which will be an O(n) condition check speed up. Not that it matters so much to optimize it if the n - the size of the binary in bytes is not that large. Also I think you will find much better performance using Enumerable.SequenceEqual rather than doing byte by byte comparison. However, under the hood, I am not sure if it makes a difference - it should its the difference between a cmp/jz loop and a repne cmpsb in assembly. And there is no comparison on performance there, repne cmpsb is a highly optimized pattern. Compilers will typically floor divide by 4, do a repne cmpsd, then a cmpsw if there is a remainder of 2, and a cmpsb if there is a remainder of 1. Most of us reversers have seen this nice compiler asm pattern many times. The problem is if you want to provide a pattern that should only be replaced once. Then you need to make sure your pattern is unique across the entirety of the file. Using extra bytes that come before or after, or even wildcard patterns would work. Of course a byte array won't be ideal for the matching then as you need to represent the wildcard byte state. Using a Nullable<byte> might work, but it will prevent Enumerable.SequenceEqual from being used and require an extra level of indirection constantly. Maybe what you wanted is Searchpattern : 31 35 53 00 02 00 40 81 Replacepattern : 4C 6D 53 00 02 00 40 81 For the replace pattern for sure I would use something like the Nullable<byte> as you could just do Replacepattern : 4C 6D null null null null null null Try to do some tutorials on coding and debugging in this regard. I wrote a patch engine long ago and eventually like has happened to many a happy patcher, it moved to embedding a resource text script which I parsed and generically could apply any patches to a file and even had a UI built into the script that would render on the fly to allow selection of which patches would be applied. Using ?? for wildcard bytes was usually the strategy there. Your idea help me a lot I already solved the problem by including the other bytes from pattern and replace with null Also thank for everyone who gives me idea as well
BlackHat Posted May 1, 2020 Posted May 1, 2020 Not Sure What you are looking for -- But See this, https://github.com/mobile46/DotNetUniversalPatcher/releases
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now