10-Day Plan for Learning Malware Development in C: Day 2 – Understanding Process Management in C - blackgem

W E L C O M E

https://i.imgur.com/fEamA3G.png

Wednesday, October 23, 2024

10-Day Plan for Learning Malware Development in C: Day 2 – Understanding Process Management in C

Welcome to Day 2 of our 10-day series on learning malware development with C! Today, we’ll focus on understanding how processes work in C, which is essential for manipulating system behavior and performing actions like process injection, a key technique used in malware. My goal is that by the end of this day, you'll know how to create, manipulate, and manage processes in both Unix-based and Windows environments


Day 2 – Understanding Process Management in C

Objective

The main goal for today is to get hands-on experience with process creation and management in C. You’ll learn how to create new processes and how child processes inherit variables and behavior from their parent processes. We’ll cover how to do this in both Unix (using 'fork()') and Windows (using 'CreateProcess()'), followed by a microproject to put our new skills to use.


Understanding Processes in C

A process is an instance of a running program. Every program that is executing in your operating system runs within its own process. For malware development, understanding how to create and manage processes is crucial because many malicious actions occur within new or injected processes.

In both Unix-based and Windows systems, processes can create child processes. A child process runs independently but can inherit certain properties from its parent process, such as file descriptors or environment variables. Let’s explore this in more detail.

Image Source: Uppsala University


Creating Processes in Unix Systems

In Unix-based systems (such as Linux and macOS), the function 'fork()' is used to create a new process. When a process calls 'fork()', it creates a child process that runs the same code as the parent. The child process gets a copy of the parent’s variables but has its own separate memory space.


How does 'fork()' work?

- When you call 'fork()', it creates a new process (child) that is a duplicate of the parent process.

- The function returns two values: 

  •   In the parent process, it returns the Process ID (PID) of the child.
  •   In the child process, it returns `0`.

Example: Process Creation with 'fork()'

#include <stdio.h>

#include <unistd.h> int main() { int pid = fork(); // create a new process if (pid < 0){ printf("Failed to create a new process.\n"); } if (pid == 0){ // this block runs in the child process printf("This is the child process. My PID is %d\n", getpid()); execlp("bin/ls","ls",NULL); // Execute the 'ls' command to list files } else { // this block runs in the parent process printf("This is the parent process. My Child's PID is %d.\n", pid); return 0;

    } }

Output

Explanation:

  • We call 'fork()', and based on its return value, we determine whether we are in the parent or child process.
  • In the child process, we use 'execlp()' to replace the current process image with a new program (in this case, the 'ls' command).
  • The parent process continues running independently.


Creating Processes in Windows Systems

On Windows, process creation is done using the 'CreateProcess()' function. Unlike 'fork()' in Unix, 'CreateProcess()' allows you to directly specify which program the child process will execute.

'CreateProcess()' Syntax:


BOOL CreateProcess(

    LPCSTR lpApplicationName,        // Name of the program to execute

    LPSTR lpCommandLine,             // Command-line arguments

    LPSECURITY_ATTRIBUTES lpProcessAttributes,

    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    BOOL bInheritHandles,

    DWORD dwCreationFlags,

    LPVOID lpEnvironment,

    LPCSTR lpCurrentDirectory,

    LPSTARTUPINFO lpStartupInfo,

    LPPROCESS_INFORMATION lpProcessInformation

);

Example: Process Creation with 'CreateProcess()'

Here’s a simple example that creates a child process to list files using the 'cmd.exe' command on Windows.

#include 
#include 

int main() {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    // Initialize memory for the structures
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // Create a new process to run 'cmd.exe' and list files
    if (CreateProcess(NULL, "cmd.exe /c dir", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        // Successfully created the child process
        printf("Child process created. PID: %d\n", pi.dwProcessId);

        // Wait until child process exits
        WaitForSingleObject(pi.hProcess, INFINITE);

        // Close process and thread handles
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    } else {
        printf("Failed to create child process.\n");
    }

    return 0;
}
  

Output

Explanation:

  • We initialize 'STARTUPINFO' and 'PROCESS_INFORMATION' structures that are required by 'CreateProcess()'.
  • Then we call 'CreateProcess()' with 'cmd.exe /c dir' to execute the command to list files in the current directory.
  • The parent process waits for the child process to finish by calling 'WaitForSingleObject()'.


Investigating Inheritance Between Parent and Child Processes

In Unix, child processes inherit the environment variables, file descriptors, and some resources from their parent process. However, changes made to variables in the child process do not affect the parent, because the memory is copied when 'fork()' is called.

For example, if the parent process has an environment variable, the child process can access it, but any modifications the child makes won’t reflect in the parent.

Example: Inheriting Environment Variables in Unix


#include 

#include 

#include 



int main() {

    printf("Parent process environment variable: %s\n", getenv("HOME"));



    int pid = fork();



    if (pid == 0) {

        // Child process

        printf("Child process inherited environment variable: %s\n", getenv("HOME"));

    }



    return 0;

}
Output

In Windows, 'CreateProcess()' has a parameter 'bInheritHandles' that determines whether the new process inherits handles from the parent process.


Microproject – Create a Child Process to List Files

Let’s put what we’ve learned into practice with a microproject. Your goal is to write a C program that creates a child process. The child process should execute a simple task, like listing the files in a directory. 


Instructions:

Unix Approach

  •    Use 'fork()' to create a new child process.
  •    In the child process, use 'execlp()' to execute the 'ls' command and list the files in the current directory.


#include 
#include 
#include 
#include 

int main() {
    // Create a new process using fork()
    int pid = fork();

    if (pid < 0) {
        // If fork() returns a negative value, the process creation failed
        printf("Failed to create a new process.\n");
        return 1;
    }

    if (pid == 0) {
        // This block is executed by the child process
        printf("Child process (PID: %d) is running 'ls' to list files in the current directory...\n", getpid());

        // Replace the current process image with a new program (ls command)
        // execlp takes the program name and its arguments. NULL marks the end of the argument list.
        execlp("/bin/ls", "ls", NULL);

        // If execlp() fails, we print an error message (this line is reached only if execlp fails)
        printf("Error: Failed to execute 'ls' command\n");
        return 1;
    } else {
        // This block is executed by the parent process
        printf("Parent process (PID: %d) is waiting for the child process (PID: %d) to complete...\n", getpid(), pid);

        // Wait for the child process to finish
        wait(NULL);

        // After the child process completes, the parent resumes
        printf("Child process completed. Parent process resuming execution.\n");
    }

    return 0;
}
Make sure to handle any errors (e.g., failed process creation) and test the program on your system.
Output

you can see these processes running in linux with the command ps aux.

Conclusion

By the end of Day 2, you should have a solid understanding of how processes are created and managed in C, both in Unix and Windows environments. This knowledge is crucial when developing malware, as creating and controlling processes allows malicious code to execute tasks like running shell commands, injecting code, or even hiding its activity. Keep practicing, and tomorrow we’ll explore file manipulation and system calls, taking us further down the path of malware development!

Happy Hacking! ❤


No comments:

Post a Comment