Jump to content
Tuts 4 You

Creating Patch in VB.Net


zackmark29

Recommended Posts

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 by zackmark29
Link to comment

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

Link to comment

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 by Kurapica
  • Thanks 1
Link to comment
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 

spacer.png
 

Edited by zackmark29
Link to comment
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

Link to comment
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

Link to comment
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?

Link to comment
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

Link to comment
2 hours ago, NOP said:

Can you upload your file?

What file do you need?
The crack and original file? or the project file?

Link to comment

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

Link to comment
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.

Link to comment

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.

Link to comment
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

Link to comment

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...