Exetools  

Go Back   Exetools > General > Source Code

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 10-06-2024, 17:22
ldmd ldmd is offline
Friend
 
Join Date: Sep 2023
Posts: 7
Rept. Given: 0
Rept. Rcvd 2 Times in 1 Post
Thanks Given: 7
Thanks Rcvd at 11 Times in 2 Posts
ldmd Reputation: 2
DLL Injection

Hello, it may be a little long and boring i know
I see that the "trend" of blogs is kinda dying nowadays and RE is pretty interesting so today i will try my best to explain a little bit about one of the classic way to inject something in a process [DLL Injection]


What is Process Injection?
->Process injection is a technique used to inject code into the memory space of a process, or like sneaking some code into a running app so it can hide and do things without being noticed (something we will discuss further). This allows the code to be executed without the permission of the targeted process, which may help it evade security defenses—or maybe not, it depends. One of the common injection methods includes DLL injection, where the DLL (Dynamic Link Library) is forced into the target process, and code hollowing, where [x] code is replaced with [y] instructions or another code.

Memory [ Some Theory ]
Virtual Memory
Before getting into all of this, we should understand some concepts such as virtual memory, pages, and memory permissions and flags.

So, let’s begin with virtual memory. You may ask yourself, what is this thing? Virtual memory is a feature. Why? Because it helps to manage and use memory more efficiently without relying solely on physical memory to run programs. What does that mean, and why is it more efficient? This feature uses extra storage space as if it were additional RAM. But where is this additional “RAM” coming from? Simple: the disk.

Now, our computer has a limited amount of RAM. When you run several programs at once, they all need memory to run, right?

When the RAM fills up, the computer can’t keep everything there, so it uses a part of your HDD or SSD to store some information temporarily. This part is called virtual memory.

The computer will move less-used information from RAM to this virtual memory on our storage disk. This process is called paging. When you need the information again, the computer will bring it back into RAM and may move other information out to make space.

Thanks to this, we don’t have a strict limit on memory use, which in the past led to inefficient resource management and other issues.

One thing we should keep in mind is that accessing data from a hard drive is slower than accessing it from RAM. (Not crucial for our work, but worth noting!


Now, I’m not going to dive deep into this topic. Another thing related to virtual memory is virtual addresses. Yes, it is a set of ranges of virtual addresses that an operating system makes available to a process (thanks Wikipedia definition). These addresses are used to find and access data in memory. Instead of working with the actual physical memory location, the OS translates the virtual address to the real physical address.

VirtualAllocEx function
Okay, now that we know something about paging and virtual memory, let’s move on to allocation because we need to allocate some code. What’s the point of allocating? Let’s put it this way: each process has its own memory space, like a private apartment, where it stores all its data and code. Normally, programs aren’t allowed to enter each other’s “apartments,” which keeps them from messing with each other’s stuff.

The function I mentioned earlier lets one program (the “injector”) reserve some space in another program’s memory. When VirtualAlloc creates space in the target program, it can request specific permissions, such as full access, read, write, or execute. This means the code in this memory can not only sit there but also run within the program.

VirtualProtect
There is another function that we need called VirtualProtect. We’re not going to stretch this discussion too much now, but in order to write data and make changes, we need something that will “relock” the memory with new permissions. This allows changes like switching read-only to executable or vice versa. So, when injecting code into another process, after writing the code into the target process’s memory, you need to use VirtualProtect to ensure that the memory is marked as executable. This step is crucial because, by default, memory might not have the right permission to run the injected code.


Code:
#include 
#include 
#include 

DWORD GetProcId(const char* proc) {
    DWORD procId = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 procEntry;
        procEntry.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(hSnap, &procEntry)) {
            do {
                if (!_stricmp(procEntry.szExeFile, proc)) {
                    procId = procEntry.th32ProcessID;
                    break; 
                }
            } while (Process32Next(hSnap, &procEntry));
        }
        CloseHandle(hSnap);
    }
    return procId;
}
int main()
{
    const char* dllPath = "C:\\Users\\name\\source\\repos\\proc_injec\\Release\\lol.dll";
    const char* procName = "main.exe";
    DWORD procId = 0;

    while (!procId)
    {
        procId = GetProcId(procName);
        Sleep(30);
    }

    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, procId);

    if (hProc && hProc != INVALID_HANDLE_VALUE)
    {
        void* loc = VirtualAllocEx(hProc, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

        WriteProcessMemory(hProc, loc, dllPath, strlen(dllPath) + 1, 0);

        HANDLE hThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, loc, 0, 0);

        if (hThread)
        {
            CloseHandle(hThread);
        }
    }

    if (hProc)
    {
        CloseHandle(hProc);
    }
    return 0;
}


Explanation
Now, here we have 2 main things, GetProcId and the stuff inside main . Explaining the whole code would be such a waste of time actually because we know almost everything. But let’s explain the GetProcId function which is important here.
Code:
DWORD GetProcId(const char* proc) {
    DWORD procId = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 procEntry;
        procEntry.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(hSnap, &procEntry)) {
            do {
                if (!_stricmp(procEntry.szExeFile, proc)) {
                    procId = procEntry.th32ProcessID;
                    break; 
                }
            } while (Process32Next(hSnap, &procEntry));
        }
        CloseHandle(hSnap);
    }
    return procId;
}
We have the function CreateToolhelp32Snapshot with two arguments; the important one is TH32CS_SNAPPROCESS, which indicates that we want to take a snapshot of all processes, followed by a condition to ensure that our HANDLE is not invalid.

PROCESSENTRY32 is a structure used to store information about a process, which is why we are going to use it. The member dwSize must be set to the size of PROCESSENTRY32. You may ask yourself why. It’s quite simple: this is a requirement to ensure that the structure is correctly initialized and that the API we use (WinAPI) works properly.

After that, we iterate over processes until we find the target process. Process32First is a function that retrieves information about the first process in the snapshot and fills a structure, which in this case is procEntry.

_stricmp is used to compare two strings: the target process that we declared and the current process from the snapshot. It’s similar to an if statement; if s1 == s2, we have found our process.

Process32Next retrieves information about the next process in the snapshot and updates the procEntry structure.

Now we know how GetProcId works.

Last part of our dll injector
Code:
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, procId);

    if (hProc && hProc != INVALID_HANDLE_VALUE)
    {
        void* loc = VirtualAllocEx(hProc, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

        WriteProcessMemory(hProc, loc, dllPath, strlen(dllPath) + 1, 0);

        HANDLE hThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, loc, 0, 0);

        if (hThread)
        {
            CloseHandle(hThread);
        }
    }
This part is much easier we already know what VirtualAllocEx, But, OpenProcess is called to obtain a handle to the process [procId], and we specify that the handle should have full access;

VirtualAllocEx - allocated memory in the addressspace of our program; -0 we let the function to decide at which address the code should be allocated -MAX_PATH specifies the size of the memoery block to allocate that should be enough to sotre the path of our DLL -MEM_COMMIT | MEM_RESERVE - | means is a combo , check the flags in the table -PAGE_EXECUTE_READWRITE - same, there is a table above which all of those flags.

*loc -> points to the adress of the allocated memoery in our process.
HTML Code:
WriteProcessMemory(hProc, loc, dllPath, strlen(dllPath) + 1, 0);

-loc - the address in our process where the data will be written -dllPath - ), is there any point to explain this one? strlen(dllPath+1) - this is the size of the data to write + null terminator and the last one is used to indicate that we dont need any special options.


CreateRemoteThread - is used to create a thread in our process that will execute a specific function.

- (LPTHREAD_START_ROUTINE)LoadLibraryA - this ia function that will be called to create a thread. LoadLibraryA is used to load the specified DLL [easy and fast explanation]


I started my own blog if you wish to take a look )
My blog
Reply With Quote
The Following 2 Users Gave Reputation+1 to ldmd For This Useful Post:
blue_devil (10-07-2024), MarcElBichon (10-07-2024)
The Following 10 Users Say Thank You to ldmd For This Useful Post:
blue_devil (10-07-2024), diesel (11-01-2024), Doit (10-07-2024), Hypnz (10-06-2024), NoneForce (10-07-2024), tonyweb (10-12-2024), user_hidden (10-07-2024), val2032 (10-06-2024), WRP (10-08-2024), wx69wx2023 (10-07-2024)
  #2  
Old 10-07-2024, 14:58
blue_devil's Avatar
blue_devil blue_devil is offline
Family
 
Join Date: Dec 2011
Location: Observable Universe
Posts: 359
Rept. Given: 81
Rept. Rcvd 52 Times in 25 Posts
Thanks Given: 364
Thanks Rcvd at 537 Times in 179 Posts
blue_devil Reputation: 52
Very neat tutorial (they say writeup these days). I have checked your blog btw. The 'look-and-feel' and the style is very good for a reverse engineering blog. Keep it up.
Also; posting these kind of tutorials ,maybe, suits on the tutorial section.
Reply With Quote
The Following User Says Thank You to blue_devil For This Useful Post:
Hypnz (10-08-2024)
  #3  
Old 10-07-2024, 21:44
ldmd ldmd is offline
Friend
 
Join Date: Sep 2023
Posts: 7
Rept. Given: 0
Rept. Rcvd 2 Times in 1 Post
Thanks Given: 7
Thanks Rcvd at 11 Times in 2 Posts
ldmd Reputation: 2
Thanks for the feedback, next time i will post it there
Reply With Quote
Reply

Tags
process injection dll

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On



All times are GMT +8. The time now is 15:59.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( 1998 - 2024 )