Lesson 1.1 · Foundations· 3 min read
Program flow: from entry point to behavior
Start the malware development learning path by separating initialization, decisions, behavior, and cleanup in a small C program.
- Platform:
- Cross-platform
- Language:
- C
- Difficulty:
- Beginner
What you will learn
Trace execution through initialization, a decision, a handler, and cleanup before studying individual malware mechanisms.
Before you begin: Basic C syntax: functions, variables, conditionals, and return values.
Start with the program, then the technique
Learning how malware is built starts with understanding how a program reaches a behavior. A named technique is only one part of that story: some code prepares state, some decides what runs, and some performs the operation. Keeping those responsibilities separate makes later implementation lessons easier to follow.
This first lesson introduces a vocabulary for the path: initialization, decision, handler, and cleanup. These are useful roles for reading code, not a universal sequence followed by every malware sample. The example below is an original teaching program whose only visible effect is printed text.
Code example
#include <stdio.h>
struct context {
int ready;
unsigned int completed;
};
static void demonstrate_behavior(struct context *ctx)
{
puts("behavior handler reached");
ctx->completed += 1;
}
int main(void)
{
struct context ctx = {0, 0};
puts("initialize");
ctx.ready = 1;
if (ctx.ready) {
demonstrate_behavior(&ctx);
}
printf("completed: %u\n", ctx.completed);
ctx.ready = 0;
puts("cleanup");
return 0;
}
Trace one execution
The context groups the state used by this demonstration. Initialization marks it ready. A condition then selects whether the behavior handler runs. Passing the address of the context allows that handler to update the same counter that main later prints.
The final assignment resets the readiness flag. It represents a cleanup stage in the teaching model; there are no acquired files, sockets, or allocated buffers to release here. The program returns after printing the final message. Its expected output is:
initialize
behavior handler reached
completed: 1
cleanup
Connect the model to malware implementation
When studying an implementation, ask which function prepares an operation, which condition enables it, and which function actually performs it. Avoid attributing an effect to a function merely because it appears nearby or has a suggestive name. Trace the data and the branch that lead to it.
The same discipline applies to later lessons. A comparison function supplies a decision; a dispatcher selects a handler; an environment check supplies another condition. Studying these boundaries separately helps explain how mechanisms fit into a program without assuming that every possible behavior happens during every execution.
Exercise
Before running the example, predict what happens if the assignment before the condition becomes ctx.ready = 0. Write down both the output and the final value of completed. Then identify the single statement that can increment the counter.
Check your understanding
With readiness set to zero, the handler is skipped. The output contains initialization, completed: 0, and cleanup. The increment lives inside demonstrate_behavior, so it cannot occur on that path. The condition controls whether the call happens; the handler owns the state change.
Before the next lesson
You should be able to distinguish a function's return value from its side effects and explain why a branch was taken. The next lesson examines a small real-source comparison helper: getting its return convention wrong can reverse your interpretation of a caller's control flow.