I built a DLL Injector with User-Interface. The program lists all processes, the user chooses one of them and a DLL, and inject it. It's my first project in C++, and I know it's not exactly C++ because it runs with .NET, but still.
Please look for efficiency problems, memory leaks, or irregular coding standard.
Full Code: DLL Injector
These are the important classes:
CustomProcess.cpp
> #include "CustomProcess.h"
//Process list maximum size
#define ARRAY_SIZE 300
/**
* 2 parameters constructor:
* Process Name and a Process ID
*/
CustomProcess::CustomProcess(System::String^ processName, DWORD processID)
{
this->_name = processName;
this->_id = processID;
}
//Inject a given DLL to the process
bool CustomProcess::injectDLL(System::String^ DLL_PATH)
{
//Handle to the process
HANDLE hProcess;
//Handle to the remote thread we'll create
HANDLE hRemote;
LPVOID paramAddr;
// Instance to kernel32.dll - to get the LoadLibraryA function from
HINSTANCE hDLL = LoadLibrary("KERNEL32");
//Function pointer to the "LoadLibraryA" function at the kernel32.dll
fpLoadLibrary loadLibraryAddr = (fpLoadLibrary)GetProcAddress(hDLL, "LoadLibraryA");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, this->_id);
if (hProcess == nullptr)
return false;
paramAddr = VirtualAllocEx(hProcess, 0, DLL_PATH->Length + 1, MEM_COMMIT, PAGE_READWRITE);
if (paramAddr == nullptr)
CustomProcess::collectGarbage(hProcess, nullptr, nullptr);
//WriteProcessMemory doesn't accepts System::String^ object, so let's convert it to char array
char* ch = new char[DLL_PATH->Length + 1];
copyString(DLL_PATH, ch);
BOOL written = WriteProcessMemory(hProcess, paramAddr, ch, DLL_PATH->Length, NULL);
if (!written)
{
CustomProcess::collectGarbage(hProcess, nullptr, ch);
return false;
}
try
{
hRemote = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddr, paramAddr, 0, 0);
if (!hRemote)
if (!ntCreateRemoteThreadEx(hProcess, (LPTHREAD_START_ROUTINE)loadLibraryAddr, paramAddr))
{
CustomProcess::collectGarbage(hProcess, hRemote, ch);
return false;
}
}
catch (Exception^ e)
{
delete e;
CustomProcess::collectGarbage(hProcess, hRemote, ch);
return false;
}
CustomProcess::collectGarbage(hProcess, hRemote, ch);
return true;
}
//Closing Handles and get rid of the memory we allocated for the injectDLL function
void CustomProcess::collectGarbage(HANDLE hProcess, HANDLE hRemote, char* ch)
{
if (hProcess != nullptr)
CloseHandle(hProcess);
if (hRemote != nullptr)
CloseHandle(hRemote);
if (ch != nullptr)
delete ch;
}
/**
* This function gets a System::String^ Object as a source and a char array as a destination,
* and copies the chars in the string to the char array
*/
void CustomProcess::copyString(System::String^ str, char* dest)
{
for (int i = 0; i < str->Length; i++)
dest[i] = static_cast<char>(str[i]);
}
/**
* Creates remote thread for x64 processes.
*/
HANDLE CustomProcess::ntCreateRemoteThreadEx(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) {
HANDLE hRemoteThread = NULL;
LPVOID ntCreateThreadExAddr = NULL;
DWORD temp1 = 0;
DWORD temp2 = 0;
NtCreateThreadExBuffer ntbuffer;
ntCreateThreadExAddr = GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx");
//Call to ntCreateThreadEx function succeeded
if (ntCreateThreadExAddr) {
ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;
LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr;
NTSTATUS status = funNtCreateThreadEx(
&hRemoteThread,
0x1FFFFF,
NULL,
hHandle,
(LPTHREAD_START_ROUTINE)loadLibAddr,
dllPathAddr,
FALSE,
NULL,
NULL,
NULL,
&ntbuffer
);
if (hRemoteThread == NULL)
{
// NtCreateRemoteThreadEx Failed!
return NULL;
}
else
{
//NtCreateRemoteThreadEx Succeeded!
return hRemoteThread;
}
}
CloseHandle(hRemoteThread);
return NULL;
}
//Get Process ID
DWORD CustomProcess::getPID()
{
return this->_id;
}
//Set Process ID
void CustomProcess::setPID(DWORD pid)
{
this->_id = pid;
}
//Get Process Name
System::String^ CustomProcess::getName()
{
return this->_name;
}
//Set Process Name
void CustomProcess::setName(System::String^ processName)
{
this->_name = (processName != nullptr) ? processName : this->_name;
}
//Returns description of the Process in this format: "[Process Name] <-> [Process ID]"
System::String^ CustomProcess::ToString()
{
System::String^ str = this->_name + " <-> " + this->_id;
return str;
}
//Generates a list of all the running processes in the system
array<CustomProcess^>^ CustomProcess::getProcessList()
{
array<CustomProcess ^> ^ process_list = gcnew array<CustomProcess ^>(ARRAY_SIZE);
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
HANDLE hProcessSnap;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
int i = 0;
if (Process32First(hProcessSnap, &pe32))
{
do
{
process_list[i] = gcnew CustomProcess(gcnew System::String(pe32.szExeFile), pe32.th32ProcessID);
i++;
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
return process_list;
}
CustomProcess.h
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#pragma once
using namespace System;
using namespace System::IO;
ref class CustomProcess
{
public:
CustomProcess(System::String^ processName, DWORD processID);
bool injectDLL(System::String^ DLL_PATH);
static array<CustomProcess^>^ getProcessList();
DWORD getPID();
void setPID(DWORD pid);
System::String^ getName();
void setName(System::String^ processName);
System::String^ ToString() override;
private:
System::String^ _name;
DWORD _id;
typedef HINSTANCE (*fpLoadLibrary)(char*);
value struct NtCreateThreadExBuffer {
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};
typedef NTSTATUS(WINAPI *LPFUN_NtCreateThreadEx) (
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN ULONG StackZeroBits,
IN ULONG SizeOfStackCommit,
IN ULONG SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);
void collectGarbage(HANDLE hProcess, HANDLE hRemote, char* ch);
void copyString(System::String^ str, char* dest);
HANDLE ntCreateRemoteThreadEx(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr);
};
MyForm.h
#pragma once
#include "CustomProcess.h"
#include "Form_Instructions.h"
#include "Form_About.h"
namespace DLL_Injector {
using namespace System;
using namespace System::IO;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~MyForm()
{
if (components)
{
delete components;
}
}
protected:
private: System::Windows::Forms::Button^ buttonInject;
private: System::Windows::Forms::ListView^ listView1;
private: System::Windows::Forms::Button^ buttonOpenDLL;
private: System::Windows::Forms::OpenFileDialog^ openDLL;
private: System::String^ DLL_PATH;
private: System::Windows::Forms::TextBox^ dll_path_box;
private: System::Windows::Forms::Button^ buttonRefresh;
private: System::Windows::Forms::ListView^ listProgress;
private: System::Windows::Forms::MenuStrip^ menuStrip1;
private: System::Windows::Forms::ToolStripMenuItem^ helpToolStripMenuItem;
private: System::Windows::Forms::ToolStripMenuItem^ instructionsToolStripMenuItem;
private: System::Windows::Forms::ToolStripMenuItem^ aboutToolStripMenuItem;
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(MyForm::typeid));
this->buttonInject = (gcnew System::Windows::Forms::Button());
this->listView1 = (gcnew System::Windows::Forms::ListView());
this->buttonOpenDLL = (gcnew System::Windows::Forms::Button());
this->openDLL = (gcnew System::Windows::Forms::OpenFileDialog());
this->dll_path_box = (gcnew System::Windows::Forms::TextBox());
this->buttonRefresh = (gcnew System::Windows::Forms::Button());
this->listProgress = (gcnew System::Windows::Forms::ListView());
this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip());
this->helpToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
this->instructionsToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
this->aboutToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
this->menuStrip1->SuspendLayout();
this->SuspendLayout();
//
// buttonInject
//
this->buttonInject->AutoSize = true;
this->buttonInject->BackColor = System::Drawing::Color::Transparent;
this->buttonInject->Enabled = false;
this->buttonInject->Location = System::Drawing::Point(272, 36);
this->buttonInject->Name = L"buttonInject";
this->buttonInject->Size = System::Drawing::Size(75, 23);
this->buttonInject->TabIndex = 1;
this->buttonInject->Text = L"Inject";
this->buttonInject->UseVisualStyleBackColor = false;
this->buttonInject->Click += gcnew System::EventHandler(this, &MyForm::button1_Click);
//
// listView1
//
this->listView1->Location = System::Drawing::Point(38, 103);
this->listView1->Name = L"listView1";
this->listView1->Size = System::Drawing::Size(239, 381);
this->listView1->TabIndex = 2;
this->listView1->UseCompatibleStateImageBehavior = false;
this->listView1->SelectedIndexChanged += gcnew System::EventHandler(this, &MyForm::listView1_SelectedIndexChanged);
//
// buttonOpenDLL
//
this->buttonOpenDLL->BackColor = System::Drawing::Color::Transparent;
this->buttonOpenDLL->Location = System::Drawing::Point(410, 36);
this->buttonOpenDLL->Name = L"buttonOpenDLL";
this->buttonOpenDLL->Size = System::Drawing::Size(111, 23);
this->buttonOpenDLL->TabIndex = 3;
this->buttonOpenDLL->Text = L"Choose DLL";
this->buttonOpenDLL->UseVisualStyleBackColor = false;
this->buttonOpenDLL->Click += gcnew System::EventHandler(this, &MyForm::buttonOpenDLL_Click);
//
// openDLL
//
this->openDLL->FileName = L"DLL_PATH";
this->openDLL->Filter = L"DLL File|*.dll";
this->openDLL->Title = L"Choose Your DLL";
//
// dll_path_box
//
this->dll_path_box->Location = System::Drawing::Point(38, 77);
this->dll_path_box->Name = L"dll_path_box";
this->dll_path_box->ReadOnly = true;
this->dll_path_box->Size = System::Drawing::Size(542, 22);
this->dll_path_box->TabIndex = 4;
//
// buttonRefresh
//
this->buttonRefresh->BackColor = System::Drawing::Color::Transparent;
this->buttonRefresh->Location = System::Drawing::Point(113, 36);
this->buttonRefresh->Name = L"buttonRefresh";
this->buttonRefresh->Size = System::Drawing::Size(75, 23);
this->buttonRefresh->TabIndex = 5;
this->buttonRefresh->Text = L"Refresh";
this->buttonRefresh->UseVisualStyleBackColor = false;
this->buttonRefresh->Click += gcnew System::EventHandler(this, &MyForm::buttonRefresh_Click);
//
// listProgress
//
this->listProgress->Location = System::Drawing::Point(339, 103);
this->listProgress->Name = L"listProgress";
this->listProgress->Size = System::Drawing::Size(241, 381);
this->listProgress->TabIndex = 6;
this->listProgress->UseCompatibleStateImageBehavior = false;
this->listProgress->Columns->Add("Logs");
//
// menuStrip1
//
this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(1) { this->helpToolStripMenuItem });
this->menuStrip1->Location = System::Drawing::Point(0, 0);
this->menuStrip1->Name = L"menuStrip1";
this->menuStrip1->Size = System::Drawing::Size(616, 24);
this->menuStrip1->TabIndex = 7;
this->menuStrip1->Text = L"menuStrip1";
//
// helpToolStripMenuItem
//
this->helpToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(2) {
this->instructionsToolStripMenuItem,
this->aboutToolStripMenuItem
});
this->helpToolStripMenuItem->Name = L"helpToolStripMenuItem";
this->helpToolStripMenuItem->Size = System::Drawing::Size(43, 20);
this->helpToolStripMenuItem->Text = L"Help";
//
// instructionsToolStripMenuItem
//
this->instructionsToolStripMenuItem->Name = L"instructionsToolStripMenuItem";
this->instructionsToolStripMenuItem->Size = System::Drawing::Size(152, 22);
this->instructionsToolStripMenuItem->Text = L"Instructions";
this->instructionsToolStripMenuItem->Click += gcnew System::EventHandler(this, &MyForm::instructionsToolStripMenuItem_Click);
//
// aboutToolStripMenuItem
//
this->aboutToolStripMenuItem->Name = L"aboutToolStripMenuItem";
this->aboutToolStripMenuItem->Size = System::Drawing::Size(152, 22);
this->aboutToolStripMenuItem->Text = L"About";
this->aboutToolStripMenuItem->Click += gcnew System::EventHandler(this, &MyForm::aboutToolStripMenuItem_Click);
//
// MyForm
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->BackColor = System::Drawing::SystemColors::GradientInactiveCaption;
this->ClientSize = System::Drawing::Size(616, 511);
this->Controls->Add(this->listProgress);
this->Controls->Add(this->buttonRefresh);
this->Controls->Add(this->dll_path_box);
this->Controls->Add(this->buttonOpenDLL);
this->Controls->Add(this->listView1);
this->Controls->Add(this->buttonInject);
this->Controls->Add(this->menuStrip1);
this->Font = (gcnew System::Drawing::Font(L"Segoe UI", 8.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
this->Icon = (cli::safe_cast<System::Drawing::Icon^>(resources->GetObject(L"$this.Icon")));
this->MainMenuStrip = this->menuStrip1;
this->Name = L"MyForm";
this->Text = L"DLL Injector";
this->menuStrip1->ResumeLayout(false);
this->menuStrip1->PerformLayout();
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
System::String^ current;
array<CustomProcess^>^ process_list;
//Inject
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
this->listProgress->View = View::Details;
this->listProgress->Columns[0]->Width = this->listView1->Width - 4;
int count = 0;
buttonRefresh_Click(nullptr, nullptr);
for (int i = 0; ((i < process_list->Length) && (process_list[i] != nullptr)); i++)
{
try
{
System::String^ str1 = process_list[i]->ToString();
System::String^ str2 = current;
if (str1->Equals(str2))
{
if (!process_list[i]->injectDLL(DLL_PATH))
{
this->listProgress->Items->Add("Couldn't Inject DLL To: " + process_list[i]->ToString());
this->listProgress->Items->Add("Maybe you don't have permissions?");
Sleep(500);
}
else
{
MessageBox::Show("DLL Injected Successfully!");
this->listProgress->Items->Add("DLL Injected To: " + process_list[i]->ToString());
this->buttonInject->Enabled = false;
}
}
}
catch (Exception^ e)
{
MessageBox::Show(e->Message);
}
}
}
private: System::Void listView1_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e)
{
if (listView1->SelectedItems->Count > 0)
current = listView1->SelectedItems[0]->Text;
isOkayToInject();
}
private: void isOkayToInject()
{
if (listView1->SelectedItems->Count < 1)
return;
else if (DLL_PATH == nullptr)
return;
else
this->buttonInject->Enabled = true;
}
private: System::Void buttonOpenDLL_Click(System::Object^ sender, System::EventArgs^ e)
{
if (openDLL->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
DLL_PATH = openDLL->FileName;
this->dll_path_box->Text = DLL_PATH;
isOkayToInject();
}
}
private: System::Void buttonRefresh_Click(System::Object^ sender, System::EventArgs^ e)
{
this->listView1->Clear();
this->listView1->View = View::Details;
this->listView1->Columns->Add("Process Name <-> PID");
this->listView1->Columns[0]->Width = this->listView1->Width - 4;
process_list = CustomProcess::getProcessList();
for (int i = 0; i < process_list->Length; i++)
{
if (process_list[i] == nullptr)
break;
this->listView1->Items->Add(process_list[i]->ToString());
}
}
private: System::Void instructionsToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
DLL_Injector::Form_Instructions^ instructions = gcnew DLL_Injector::Form_Instructions();
instructions->ShowDialog();
}
private: System::Void aboutToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
DLL_Injector::Form_About^ about = gcnew DLL_Injector::Form_About();
about->ShowDialog();
}
};
}
I know it's not exactly C++ because it runs with .NET, but still.
So it is actually C# and not C++? In that case you should probably remove the C++ tag in favor of a C# one. \$\endgroup\$