pwncollege
DojosLeaderboardCommunity
Back to cse365-f2026

Module 4

cse365-f2026
0/146 challenges completed

In this fourth module we will take a look at the fundamentals of computing.

Questions and Discussions (Discord)

  • Chat about the content: Core Material > #computing-101
  • Create a forum post: Getting Started > #getting-started-forum

External Graded Assignments

These external graded assignments are for ASU students only. Non-ASU students do not need to complete them.

  • Demonstration Solves
  • Knowledge Check
  • Reflection

Your First Program

Computers run computer programs to achieve different goals. One program might be your favorite video game, another is the web browser you're using to access this website, and so on.

A program is made of computer code, and this code is made of a huge amount of individual instructions that cause the computer to carry out computation and take certain actions based on the results. Each individual instruction is typically very simple, and only in aggregate do they enable awesome things like letting you look at memes on the internet.

This computation is done by the Central Processing Unit (CPU), in tandem with other pieces of hardware inside your computer. Instructions are specified to the CPU in something called Assembly Language, and each CPU architecture uses a different flavor of this language. Any program, no matter what language it is originally written in (e.g., C, C++, Java, Python, etc.), is eventually converted to or interpreted by Assembly instructions.

Most of pwn.college's material uses the x86 CPU architecture, which is Zardus' favorite architecture. x86 was created by Intel in the dawn of the PC age, and has continued to evolve over the years. Together, x86 and ARM (a different, less cool architecture) make up the majority of PC CPUs out there.

In this module, we will start out with the simplest x86 program that we can imagine, which we will write in x86 assembly, and build up from there! Let's dig in, and write your first program!

1
LECTURE: Computer Architecture
2
LECTURE: Assembly
3
LECTURE: Registers
4
Your First Register
5
Your First Syscall
6
Exit Codes
7
LECTURE: Building Programs
8
Building Executables
9
Moving Between Registers

Computer Memory

Wow, you are a budding x86 assembly programmer! You've set registers, triggered system calls, and wrote your first program that cleanly exits. Now, we have one more big concept for you: memory.

You, as (presumably) a human being, have Short Term Memory and Long Term Memory. When performing specific computation, your brain loads information you've previously learned into your short term memory, then acts on that information, then eventually puts new resulting information into your long-term memory. Societally, we also invented other, longer-term forms of storage: oral histories, journals, books, and wikipedia. If there's not enough space in your long-term memory for some information, or the information is not important to commit to long-term memory, you can always go and look it up on wikipedia, have your brain stick it into long-term memory, and pull it into your short-term memory when you need it later.

This multi-level hierarchy of information access from "small but accessible" (your short term memory, which is right there when you need it but only stores 5 to 9 pieces of information to "large but slow" (remembering stuff from your massive long-term memory) to "massive but absolutely glacial" (looking stuff up on wikipedia) is actually the foundation of the Memory Hierarchy of modern computing. We've already learned about the "small but accessible" part of this in the previous module: those are registers, limited but FAST.

More spacious than even all the registers put together, but much much MUCH slower to access, is computer memory, and this is what we'll dig into with this module, giving you a glimpse into another level of the memory hierarchy.

(review) Computer Architecture
Video
Slides
10
LECTURE: Memory
11
Loading From Memory
12
More Loading Practice
13
Dereferencing Pointers
14
Dereferencing Yourself
15
Dereferencing with Offsets
16
Stored Addresses
17
Double Dereference

The Stack

So far, you've been reading from memory addresses that we set up for you. But your program already has a region of memory ready to go: the stack. The stack is pointed to by the rsp register, and it contains useful data about how your program was launched and accumulates other data as the program executes. Let's explore it!

18
The Stack
19
Stack Offsets
20
Program Arguments on the Stack
21
Popping From the Stack
Stack Addresses as a Number Line

Nibbling on Numbers

A byte is eight bits; half of one (four bits) is a nibble. This module nibbles at numbers from the bit up: how a pile of bits comes to mean a positive or a negative number in binary, hexadecimal, and decimal. Understanding this is critical to truly knowing how the CPU processes bits into something more meaningful!

22
LECTURE: Data
Binary Data
Video
Slides
Hex
Video
Slides
Bytes as Hex and Binary
23
Negative Numbers
24
Negative Numbers (16-bit)
25
Negative Numbers (32-bit)
26
Encoding Negatives
27
Binary and Hex Encoding
28
More Hex
29
Decoding Hex
30
Mixed Conversions

Software Introspection

As you write larger and larger programs, you (yes, even you!) might make mistakes when implementing certain functionality, introducing bugs into your programs. When this happens, you'll need to have a reliable toolbox of resources to understand what is going wrong and fix it. Of course, the exact same techniques can be used to understand what is wrong with code that you didn't write, and fix or exploit it as you might desire!

This module will introduce you to several ways to introspect, debug, and understand software. You'll carry this critical knowledge with you and use it throughout pwn.college, so harken well!

31
Disassembling Programs
32
Tracing Syscalls
33
Starting GDB
34
Quitting GDB
35
Starting Programs in GDB
36
Disassembling in GDB
37
Stepping Through Instructions
38
Reading Register Values
39
Setting Register Values
40
Popping Stack Values
41
Examining Memory
42
Examining Stack Pointers
43
Cooperative Debugging
44
Running with Arguments
45
Redirecting Input in GDB

Output and Input

Until now, your program's single interaction with the wider world was changing its exit code when exiting. Of course, more interaction is possible!

In this module, we will learn about the write system call, which is used to write output to the command-line terminal! This is going to be an exciting journey: the logic of this program is going to be both as close as you can possibly get to the hardware itself (e.g., you are writing raw x86 assembly that the CPU directly understands!) and as close as you can possibly get to the Linux operating system (e.g., you are triggering system calls directly!).

46
LECTURE: System Calls
47
Writing Output
48
Chaining Syscalls
49
Writing Strings
50
Reading Data
51
Reading Exactly
52
Opening Files
53
Hardcoding the Filename
54
RIP-Relative Strings

Control Flow

(review) Registers
Video
Slides
55
LECTURE: Control Flow
56
Comparing Values
57
Comparing Characters
58
Conditional Control Flow
59
Comparing Strings
60
Reverse the Password
61
Conditionals Without Conditionals
62
Recognizing Loops
63
Writing Loops
64
Writing From a Shared Library
65
Returning a Value
66
Calling Through a Pointer
67
Calling Through a Pointer with an Argument
68
Saving Caller-Saved Registers
69
Saving Callee-Saved Registers

Endian Escapades

x86 stores every multi-byte value little-endian (low byte first), and that fact turns up everywhere you look at raw memory: hex dumps, debuggers, exploits. To work properly in these contexts, you need to understand byte order. This module makes it second nature.

You'll crack a series of programs that hide a password in their own compiled code, reading it back out of the disassembly at every size, whether it's a "qword", a lone byte, or a structure. By the end, byte order won't trip you up in a hex dump, a debugger, or an exploit ever again (or we'll add more challenges to make it so!).

Little-Endian
Memory Order and Register Values
Bytes, Words, and Friends
70
Sign Extension
71
Little-Endian Bytes
72
Qword by Qword
73
Dword by Dword
74
Word by Word
75
Byte by Byte
76
Cracking a Struct
77
Scrambled Struct

Assembly Assortment

You have a working knowledge of assembly from your journey thus far. Let's broaden it!

This module will explore the effects of a number of different assembly instructions, teaching you to recognize them and not panic in their presence. In most of these challenges, you'll reverse-engineer a binary to understand an instruction's effect on data and feed it input it will accept. In a few others, you'll put an instruction to work yourself, writing a small function around it. Either way, if you understand what the instruction does, you will get flags!

(review) Data
Video
Slides
78
Reverse the Calculation
79
Reverse the Reverse
80
Dealing with Bitwise Operations
81
Even or Odd
82
Masking Bits
83
Lowercase a String
84
Uppercase a String
85
Swap Case
Bit Shifting
86
Shifting Left
87
Shifting Right
Guide: Reading Stored Data in GDB
88
Loops on Data

The Stack, Revisited

Back when you first met the stack, it was just some data the kernel had set up for you: argc, argv, a few pointers. Now that you've written your own functions, made your own calls, and seen rsp move in response to push and pop, it's time to revisit the stack with sharper eyes. How does it actually get laid out? Why does it "grow downwards," and what does that mean for the data you can reach? And how does the way your program was launched shape the addresses of everything on it?

89
Reaching Into the Caller's Frame
90
Loading Stale Stack Data
91
Stealing Stale Stack Data
92
Reserving Your Own Frame
93
Using Your Own Frame
94
Environment Variables on the Stack
95
Aligning the Stack Through the Environment
96
Aligning the Stack Through GDB
97
Aligning the Stack Through GDB, Generalized

Numbers as Strings

You've learned to read and write registers, walk through memory, and package your code as a function inside a shared library. Now let's put those skills together and build some real algorithms. When you need to debug one of these .so submissions, refer back to Writing from a Shared Library for the shared-library debugging pattern.

Through this module, we'll gradually build on our solutions until we create code that addresses a very common program need: turning text into numbers. Along the way, we'll learn how to write reusable assembly code, how text and numbers relate to each other, and how to reason about algorithms (and their failings!). You'll grow in knowledge, and in flags!

(review) Assembly
Video
Slides
98
A Single Digit
99
Two Digits
100
String to Integer
101
Negative Numbers
102
Where the Number Ends
103
A Whole Program
104
A Single Digit, Back to Text
105
Divide and Remainder
106
Drop the Leading Zero
107
Integer to String
108
Negative Numbers, Back to Text
109
Sum Them All

The Calculator

You can turn text into a number with your atoi, and a number back into text with your itoa. Now you'll use both at once to build a small command-line calculator. It reads an expression from argv --- a left operand, an operator, and a right operand --- as in prog 6 + 7. The operands are strings you already know how to handle: atoi each one. The operator is the new piece: a single character you branch on to decide what to compute, quitting on any operator you don't support. Then itoa the result and write it to standard output, exactly as your summing program did. We'll add one operator group at a time --- addition, then subtraction, then multiplication, then the bitwise operators, and finally the unary operators --- each reusing the atoi and itoa you've already written.

110
Addition
111
Subtraction
112
Multiplication
113
Bitwise Operators
114
Unary Operators

printf

Programs rarely print just one fixed string. They print messages assembled from fixed words and changing values: answer: 13, hello, hacker, opened 3 files, and so on. You could write each message by hand, but then every new message shape needs its own copy loops, number conversions, and write calls. A format string is a compact recipe for building those messages. Ordinary characters in the recipe are printed as-is, while special markers say where the next value should go. The code that follows such a recipe is called a formatter. printf is the traditional name for a formatter that prints its result.

This mini-module will have you build printf. Your version will be special: it's yours! Many other versions of printf exist as well. For example, the "standard C library", which includes useful functions to use when writing applications in the C programming language, includes an implementation, and your commandline has it too:

hacker@dojo:~$ printf Hello
Hello
hacker@dojo:~$

We'll build up that idea in small steps: literal text, the ASCII newline byte, escaped syntax characters, decimal numbers, repeated values, strings, and finally arbitrary bytes.

115
Literal Output
116
Newline Escapes
117
Escaped Syntax
118
Decimal Markers
119
Multiple Decimal Markers
120
String Markers
121
Hex Byte Escapes

Debugging Refresher

A critical part of working with computing is understanding what goes wrong when something inevitably does. This module will build on your prior exposure to GDB with some more debugging of programs: digging in, poking around, and gaining knowledge. This is one of the most critical skills that you will learn in your computing journey, and this module will hopefully help water the seed that we planted before.

As you know, GDB is a very powerful dynamic analysis tool which you can use in order to understand the state of a program throughout its execution. You will become more familiar with some of its capabilities in this module.

122
LECTURE: GDB with Robert
GDB Help
123
Debugging Programs
124
Inspecting Registers
125
Examining Memory
126
Setting Breakpoints
127
GDB Scripting
128
Modifying Data
129
Modifying Execution
130
Broken Functions

Building a Web Server

Now that you know how to write and debug assembly, it is time to do something real! In this module, you will develop the skills needed to build a web server from scratch, starting with a simple program and progressing to handling multiple HTTP GET and POST requests. Good luck!


As you proceed in your journey, remember your system call table.

131
LECTURE: Introduction
132
LECTURE: Linux Processes
133
LECTURE: Network System Calls
134
LECTURE: HTTP Refresh
135
LECTURE: Multiprocessing
136
Exit
137
Socket
138
Bind
139
Listen
140
Accept
141
Static Response
142
Dynamic Response
143
Iterative GET Server
144
Concurrent GET Server
145
Concurrent POST Server
146
Web Server