Hello everyone, today i'm here recoving from my massive hangover and headache so i decided to post an in depth injector tutorial. This tutorial will cover a multi DLL interface that saves options for when you next open your injecor. Before you start i expect you have a little knowlage about Visual Basic and you already have everything you need to start. This tutorial will use a dictionary to handle our multiple DLL's, however there are other ways of completing this task.
If you're going to use this tutorial for your injector all i ask for is a mention in your thread, thank you! (E.g @Codemunkie)
What we'll need:
- 1 x TextBox
- 4 x Buttons
- 1 x ListBox
- 3 x Label
- 2 x Radio Button
- 1 x CheckBox
- 1 x OpenFileDialog
- 2 x Timer (Set both to interval 50, and enable the second one only)
- 1 x GroupBox (Not compulsory)
How to setup your buttons etc.
- Browse = Button1
- Inject = Button 3
- Remove = Button2
- Clear All = Button4
- Status = Label3
- AutoInject = Timer1
- Status Updater = Timer2
Step 1
First you're going to need to setup your GUI. TO make it look sweet and professional i suggest spending quite some time in this step. Try not to use sloppy/curly fonts with random colours. Try and make your buttons aligned in a way that they are easy to access together.
Image backgrounds will usually look horrible unless you're going to make it fit exactly to your injector using colours that match and making sure you can see your labels still. I also suggest you turn off the maximize button, it's in your form properties on the right hand side. Below is an example
Step 2
Now we're going to setup the save options, since it's the easist thing to do. Goto Project > Properties and click the Settings tab. Make a new setting called inject, make it a string. Make another called close and make that an integer. Hit CTRL + S to save and then close the properties.
Step 3
Now double click the header of your form (Where the title is) which will make a new Private Sub. Were going to check what the settings tell us and then alter the radio buttons and check box accordingly. I'll explain the code in a second. Copy and paste this in your form_load sub.
Code:
If My.Settings.inject = "auto" Then
RadioButton1.Checked = True
ElseIf My.Settings.inject = "manual" Then
RadioButton2.Checked = True
Else
RadioButton1.Checked = True
End If
This code is going to check if the setting was last set to auto or manual, and then from there it will change the checkboxes to fit the right setting. Pretty simple. We also used an Else statement at the bottom so if it doesn't find either of those settings (E.g it's the first time you've opened the injector) it will just check the first option.
Step 4
The next step is to do the same for the Close after inject option. It's exactly the same process as the above with a simple IF statement.
Code:
If My.Settings.close = 1 Then
CheckBox1.Checked = True
Else
CheckBox1.Checked = False
End If
Step 5
The next thing to do is to make the settings save when we check or change the state of the radio buttons. We do this by double clicking them to enter the code again. First double click the first radio button which is for manual injection. We're also going to add in some codes for the inject button to make it disabled.
Code:
My.Settings.inject = "auto"
My.Settings.Save()
My.Settings.Reload()
Button3.Enabled = False
Timer1.Start()
This code will save the setting to "auto" which we can use when the form loads again. We also just disabled the Inject button because we're manually injecting. And finally we enabled the timer1 because that's the timer we'll use to check if the process is running later on.
Step 6
We're going to do the same thing for the other radio button, but the options will be opposite.
Code:
My.Settings.inject = "manual"
My.Settings.Save()
My.Settings.Reload()
Button3.Enabled = True
Timer1.Stop()
Step 7
The final bit of this section is for the check box. We just have to see if the checkbox is checked or not and save the setting.
Code:
If CheckBox1.Checked = True Then
My.Settings.close = 1
Else
My.Settings.close = 0
End If
My.Settings.Save()
My.Settings.Reload()
You can do the same for the process if you wan't, it's gotta be pretty self explanatory now.
Step 8
Now we've got all the basic stuff done, we can move on to some more indepth bits. We'll start with the Timer1. This timer is going to check if the process is started and will inject if it is. This timer is only going to be enabled when the Radiobutton for Auto injection is checked remember.
Code:
If ListBox1.Items.Count > 0 Then
Dim TargetProcess As Process() = Process.GetProcessesByName(TextBox1.Text)
If TargetProcess.Length = 0 Then
Label3.Text = ("Waiting for " + TextBox1.Text + ".exe")
Label3.ForeColor = Color.Red
Else
Dim ProcID As Integer = Process.GetProcessesByName(TextBox1.Text)(0).Id
Timer1.Stop()
Timer2.Stop()
'INJECT CODE HERE
End If
End If
Here we are going to first check if theres any DLL's selected. If not, the rest of the code is ignored. Presuming theres a DLL ready to be injected, we check if the process is started. If not, we print "Waiting for process" in the status box. If the process is open and ready, we continue with injection, stoping the timers as they are not needed anymore and then we call the Inject function which we will add later.
Step 9
Next we need to cover the second timer which we'll use to check the status of the whole application. The reason we put this in a seperate timer is because we want the status to continue updating even if they are manually injecting, in which case the Timer1 would stop running, if that makes any sense!
Code:
If TextBox1.Text = "" Then
Label3.Text = "Waiting for process to be set."
Label3.ForeColor = Color.Red
Timer1.Stop()
ElseIf ListBox1.Items.Count = 0 Then
Label3.Text = "Waiting for DLL path."
Label3.ForeColor = Color.Red
Timer1.Stop()
Else
Dim TargetProcess As Process() = Process.GetProcessesByName(TextBox1.Text)
If TargetProcess.Length = 0 Then
Label3.Text = ("Waiting for " + TextBox1.Text + ".exe")
Label3.ForeColor = Color.Red
Else
If RadioButton1.Checked = True Then
Timer1.Start()
End If
End If
End If
The first thing we do is check if the user has typed in a process, if not it will stop the timer1 as theres no need to let it run until we're ready to inject. It will also print a message to our status label. The next thing to check is the DLL. If no DLL is selected then we do the same as we can't cuntinue until the DLL has been specified. The third thing to check is the process to see if its running. If not we print a message and stop the timer1. If everything is set properly after these checks and the user wants automatic injection, we start timer1 so it can call the Inject function.
Step 10
We might aswell declare all our booleans now for the Inject function and setup the actual injection. I'll admit i don't even understand this code! It's not too important if you know how it works or not though, unless it botheres you that you don't understand it. This goes at the top just under "Public Class Form1". We also declared a new dictionary here called dlls.
Code:
Dim dlls As New Dictionary(Of String, String)
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcessId As Integer) As Integer
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal flAllocationType As Integer, ByVal flProtect As Integer) As Integer
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer() As Byte, ByVal nSize As Integer, ByVal lpNumberOfBytesWritten As UInteger) As Boolean
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Integer, ByVal lpProcName As String) As Integer
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Integer
Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Integer, ByVal lpThreadAttributes As Integer, ByVal dwStackSize As Integer, ByVal lpStartAddress As Integer, ByVal lpParameter As Integer, ByVal dwCreationFlags As Integer, ByVal
lpThreadId As Integer) As Integer
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Integer, ByVal dwMilliseconds As Integer) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private Function Inject(ByVal pID As Integer, ByVal dllLocation As String) As Boolean
If IntPtr.Size = 8 Then Throw New ArgumentException("Please make sure this program is compiled as x86, not x64. Memory functions don't work so well otherwise.") '//check our project is compiled to x86, otherwise everything will run fine, but nothing will happen.
Dim hProcess As Integer = OpenProcess(&H1F0FFF, 1, pID) '//copied the access value /tehe
If hProcess = 0 Then Return False '//check that we managed to obtain a handle, if we didn't there is no point continuing.
Dim dllBytes As Byte() = System.Text.Encoding.ASCII.GetBytes(dllLocation)
Dim allocAddress As Integer = VirtualAllocEx(hProcess, 0, dllBytes.Length, &H1000, &H4)
If allocAddress = Nothing Then Return False '//if the memory allocation failed then we gotta quit.
Dim kernelMod As Integer = GetModuleHandle("kernel32.dll") '//kernel holds the LoadLibrary function, and its loaded to a constant address space, so we can find the load address in our own processes memory and assume it will be the same in the target process.
Dim loadLibAddr = GetProcAddress(kernelMod, "LoadLibraryA") '//find the address of LoadLibrary in kernel.
If kernelMod = 0 OrElse loadLibAddr = 0 Then Return False
WriteProcessMemory(hProcess, allocAddress, dllBytes, dllBytes.Length, 0) '// write the dll location as bytes to the process memory in the location we allocated earlier, we'll use this address when we call LoadLibrary so it knows where to load the dll from
Dim libThread As Integer = CreateRemoteThread(hProcess, 0, 0, loadLibAddr, allocAddress, 0, 0) '//call the LoadLibrary function in the target process and pass the location of our DLL to it (actually, we just pass the address to where it should read it from, it does the
rest)
If libThread = 0 Then
Return False '// couldn't create the thread, quit now
Else
WaitForSingleObject(libThread, 5000) '//give the process 5 seconds to finish using the LoadLibrary function if it needs it
CloseHandle(libThread) '//close our handle to the thread.
End If
CloseHandle(hProcess) '//close our handle to the process
Label3.Text = "DLL injected successfully."
If CheckBox1.Checked = True Then
Me.Close()
End If
Label3.ForeColor = Color.Green
Return True
End Function
Thanks to @Jason for this injection code
You'll see at the bottom of our inject function, we used an IF statement to check whether to close the injector. Simply we check if the checkbox is checked (alot of checks!) and then use me.close to close the whole application.
Step 11
Time to add our button codes now. We'll start with the Inject button. Double click it to enter the code.
Code:
If ListBox1.Items.Count > 0 Then
If TextBox1.Text <> "" Then
Dim TargetProcess As Process() = Process.GetProcessesByName(TextBox1.Text)
If TargetProcess.Length = 0 Then
MsgBox(TextBox1.Text + ".exe is not running.", MsgBoxStyle.Critical, "Error")
Else
Timer1.Stop()
Dim ProcID As Integer = Process.GetProcessesByName(TextBox1.Text)(0).Id
'INJECT CODE HERE
End If
Else
MsgBox("You haven't specificed a process.", MsgBoxStyle.Critical, "Error")
End If
Else
MsgBox("You need to select a dll file to inject.", MsgBoxStyle.Critical, "Error")
End If
This is pretty much the same code as for the Timer1 but rearanged to include message boxes. We check if the process is set, if theres any DLL's in the ListBox and if the process is running. Any errors will display in an error message.
Step 12
The browse button is next. Double click it to enter the code.
Code:
OpenFileDialog1.Filter = "DLL (*.dll) |*.dll"
OpenFileDialog1.ShowDialog()
We're simply going to set the filter for the OpenFileDialog so it only lets you open DLL's and then we can display the OpenFileDialog for the user to open a hack.
Step 13
To stop the silly little error from popping up when you browse and then click cancel, we need to add this bit to the File_OK sub. To do this double click your OpenFileDialog and paste this.
Code:
Dim FileName As String = OpenFileDialog1.FileName.Substring(OpenFileDialog1.FileName.LastIndexOf("\"))
Dim DllFileName As String = FileName.Replace("\", "")
ListBox1.Items.Add(DllFileName)
dlls.Add(DllFileName, OpenFileDialog1.FileName)
This is going to take the full filename, cut it down using a few functions so it only displays the name of the hack.dll. Then we can add it to our ListBox. After that we can also add the dll to our dictionary. We do this with a simple dlls.Add function holding the short filename and the full path after.
Step 14
Next is the remove button. This code is a little confusing to grasp unless you're good at maths!
Code:
If ListBox1.SelectedIndex >= 0 Then
OpenFileDialog1.Reset()
dlls.Remove(ListBox1.SelectedItem)
For i As Integer = (ListBox1.SelectedItems.Count - 1) To 0 Step -1
Dim i2 As Integer = i + 2
ListBox1.Items.Remove(ListBox1.SelectedItems(i))
Next
End If
First we check if a dll is even selected, otherwise it brings back an error message. Next we reset the OpenFileDialog to stop any further errors. After we can easily remove the DLL from our dictionary using the key which is the same as what was in the ListBox. Then we have to do a little math to determine which dll in the list to remove. The count function and the selecteditems function both start at different values, which makes it really confusing to do this. Once we have the right Index, we can remove the item with items.remove.
Step 15
Last is the Clear All button, its really straight forward and only requires two lines of code. With a simple function, we can erase everything from the ListBox and with another we can reset out dictionary.
Code:
ListBox1.Items.Clear()
dlls.Clear()
Step 16
The final step is to add in the code to go through each DLL and inject it seperately. TO do this we'll use a For Each statement, which will loop through our dictionary and inject each value using our full path to the DLL. You'll see twice in your code the phrase 'INJECT CODE HERE which is where you need to place this next bit of code.
Code:
For Each inj As KeyValuePair(Of String, String) In dlls
Inject(ProcID, inj.Value)
Next
Step 17
This is the final step to getting your injector working. Goto Tools > Options > Projects & Solutions > General and tick "Show advanced build configurations". Then goto Build > Configuration Manager. On the debug one, click the dropdown box and go New > x86 platform. Now you can use this platform for your debug and release and then click close.
Click here for more info on changing your config for multi platforms.
And there you have it, a fully working multi-dll injector. Thanks for reading and i hope i have helped you on your way in Visual Basic!