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:
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:
STRUCTURE_NAME struct1 = { 0 }; // All elements initialized to zeroYou 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:
STRUCTURE_NAME struct1 = { 1470, 34 }; // Position-basedDesignated Initializer Syntax (C99):
STRUCTURE_NAME struct1 = { .ID = 1470, .Age = 34 }; // Explicit, order-independentArgument 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.
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.
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.
#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:

