8
\$\begingroup\$

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();
    }
};
}
\$\endgroup\$
2
  • \$\begingroup\$ 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\$
    – yuri
    May 29, 2017 at 9:56
  • \$\begingroup\$ It is C++, not C#, .NET is language agnostic. \$\endgroup\$ Sep 4, 2017 at 7:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.