Skip to content

MalDev - Coding Basics (Structures and Memory Management)

An introduction to C structures and memory management techniques essential for interacting with the Windows API in Malware Development.

MalDev: Understanding C Structures and Argument Passing

A fundamental understanding of C is a prerequisite for advanced malware development. One of the most critical concepts for interacting with the Windows API (WinAPI) is the use of Structures, which allow you to group related data items of different types into a single unit.

The Goal

The primary goal is to master how data is organized and passed between functions. Many Windows APIs require a populated structure as input, while others will take a declared structure and populate it with system information (such as process or thread data) for you to use.

Defining and Initializing Structures

Structures are generally declared using the typedef keyword to create aliases, making the code more readable:

c
typedef struct _STRUCTURE_NAME {
    // structure elements
} STRUCTURE_NAME, *PSTRUCTURE_NAME;

Microsoft typically uses the P prefix to indicate a pointer type for a structure (e.g., PSTRUCTURE_NAME is a pointer to STRUCTURE_NAME).

To avoid issues with "junk data" in memory, structures should always be initialized to zero using the { 0 } syntax:

c
STRUCTURE_NAME struct1 = { 0 };  // All elements initialized to zero

You can access members directly using the dot operator (.) or through a pointer using the arrow operator (->), where structpointer->ID is equivalent to (*structpointer).ID.

Structure Initialization Methods

Traditional Initialization:

c
STRUCTURE_NAME struct1 = { 1470, 34 };  // Position-based

Designated Initializer Syntax (C99):

c
STRUCTURE_NAME struct1 = { .ID = 1470, .Age = 34 };  // Explicit, order-independent

Argument Passing: Value vs Reference

Passing by Value:

When an argument is passed by value, the function receives a copy. Any modifications made inside the function only affect the local copy, not the original object.

c
int add(int a, int b) {  // a and b are copies
    return a + b;
}

Passing by Reference:

By passing a pointer (memory address), the function can access and modify the object directly without creating a local copy. This is more memory-efficient and necessary for most WinAPI interactions.

c
void add(int *a, int *b, int *result) {
    *result = *a + *b;  // Directly modifies original memory
}

Complete Example

The following example demonstrates how to define a structure, initialize it using designated initializer syntax, and modify it by passing by reference.

c
#include <stdio.h>

typedef struct _USER_DATA {
    int ID;
    int Age;
} USER_DATA, *PUSER_DATA;

void UpdateUserAge(PUSER_DATA pUser, int newAge) {
    if (pUser != NULL) {
        pUser->Age = newAge;
        printf("[Inside UpdateUserAge] Age set to: %d\n", pUser->Age);
    }
}

int main() {
    USER_DATA user1 = { .ID = 1470, .Age = 34 };

    printf("[*] Initial User Information:\n");
    printf("    ID: %d\n", user1.ID);
    printf("    Age: %d\n", user1.Age);

    UpdateUserAge(&user1, 35);

    printf("\n[*] After function call:\n");
    printf("    ID: %d (unchanged)\n", user1.ID);
    printf("    Age: %d (modified via reference)\n", user1.Age);

    return 0;
}

References

For a deeper look into common WinAPI structures like THREADENTRY32, refer to the official documentation:

Released under the MIT License. Sitemap | RSS