TLDR: If you're writing in Assembly, you're not living in a high-level la-la land, you're dealing with raw bytes, memory dumps, and bit flips. That means you need to think like the hardware: binary, hex, and decimal all day, every day.
🧬 Why Data Representation Matters
Assembly language programmers don’t abstract memory, coz they have to deal with it. That means:
You read/write exact memory values
You debug by examining registers and stack frames
You’ll see data in binary, decimal, and hex, sometimes all at once
So, if you can’t mentally switch between 0b1010, 10, and 0xA… you’re gonna have a bad time.
⚙️ Numbering Systems 101
Each numbering system has a base, this means the total number of unique digits it can use before it "starts over" or carries over to the next place value.
For example, base 10 (decimal) uses 10 digits: 0 through 9. When you count past 9, you reset to 0 and carry over, that's how you get 10.
Base 2 (binary) only has 2 digits: 0 and 1. So after 1 comes 10 (binary for 2). It rolls over faster because it runs out of digits quicker.
Why Hexadecimal is the Real MVP
Hexadecimal is the standard for low-level analysis because it provides a perfect balance between human readability and machine accuracy. While binary is how the computer thinks, hex is how humans manage that thought process without getting lost in a sea of digits.
Efficiency and Conciseness
Hex is significantly more compact than binary. Since a single hex digit represents exactly 4 bits (a "nibble"), you can represent an entire 8-bit byte with just two characters. This makes reading memory dumps or complex addresses like 0xFFEF43A0 manageable, whereas the binary equivalent would be a staggering 32-character string of ones and zeros.
Standardization in Tooling
This is exactly why you will almost never see raw binary in a disassembler or debugger. From machine instructions to memory addresses and hardware manuals, hexadecimal is the universal language. It allows you to visualize the structure of the data and code without the visual clutter of binary or the mathematical abstraction of decimal.
The Required Mental Flex
To work effectively at this level, certain mental shortcuts need to become second nature. Mastery in this domain requires:
Instant Conversion: The ability to pivot between binary, decimal, and hex without reaching for a calculator.
Pattern Recognition: Instantly recognizing common values (e.g., 0xFF is 255 in decimal or 11111111 in binary).
Error Detection: Developing the intuition to spot mistakes in memory reads or writes just by glancing at the numerical patterns.
Skill Check:
0x3C in decimal? 60.
11001100 in hex? 0xCC.
If there is any hesitation here, it’s a sign that more keyboard time is needed. In reverse engineering, a single flipped bit can result in a corrupted address, a wrong jump (diverting the program flow), or a total system crash.
Real-World Assembly Scenario
Imagine you are looking at a piece of code in a disassembler.
You see a series of bytes, and your job is to determine if the program is about to perform a legitimate function or if it has been diverted by a packer or a manual patch.
Without hex, you'd be staring at thousands of binary digits trying to find the one instruction that changed.
With hex, the patterns of the opcodes, like the 0x55 that often signals the start of a function, jump right out at you.
You need to instantly know:
What data is going into which register.
How big each number is (in bits).
What it's doing behind the scenes in memory.
✅ Recap: What You Gotta Know
Assembly doesn’t sugarcoat anything — it deals in raw data.
Know your binary, decimal, and hex like your own name.
You’ll constantly convert between these — get fluent.
Hex is king in memory and ASM.
Why do we write numbers like 0x2F, 10101010b, or 075 instead of just normal numbers like 47❓
✅ Answer: Because we’re not always using base 10 (decimal). Sometimes we need to show numbers in other bases — like binary, octal, or hexadecimal — and we need a way to tell them apart clearly.
Computers use binary (base 2), but humans often use base 10.
So, to communicate properly — especially in code — we use prefixes or suffixes to show which base we're using.
Here's how it breaks down:
The Importance of Base Prefixes: A Language Analogy
Think of base prefixes as a language identifier. If you tell someone a phone number but don't specify the language, they might dial the wrong digits. In programming, the prefix tells the computer, "Hey! This number is in Hex, not Decimal!" Without them, the machine (and the developer) would be guessing the intent behind the data.
Why We Use Different Number Systems
Hexadecimal (Hex) — e.g., 0xFF
Hexadecimal is a Base 16 system, using digits 0–9 and letters A–F. It is the gold standard for low-level work because one hex digit maps perfectly to exactly 4 bits (a nibble).
Why it’s essential: It is compact and prevents visual fatigue when reading large datasets.
Common uses:
Memory addresses (e.g., 0x00403000)
Color codes in web and graphics (e.g., #FF33AA)
Opcode dumps during disassembly (e.g., 0xB8, 0xC3)
Bitfields and memory masks
Binary — e.g., 0b10101010
Binary is Base 2, consisting only of 0s and 1s. This is the "language of the metal," representing the actual high/low voltage states of a CPU.
Why it’s essential: It allows you to see the raw state of every individual bit.
Common uses:
Bitwise operations like shifting (>>, <<)
Manually setting or clearing specific CPU flags
Logic masking (AND, OR, XOR)
Example: If you need to enable the third bit in a register, you would use a mask like 0b00001000.
Octal — e.g., 0755
Octal is a Base 8 system, using digits 0–7. While less common in modern general programming, it still holds a specific niche.
Why it’s essential: It was historically used when computers had 12-bit, 24-bit, or 36-bit words (all multiples of 3).
Common uses:
Unix/Linux file permissions (e.g., chmod 755)
Legacy shell scripting
The Zero Trap: In languages like C and C++, starting a number with a leading zero (like 012) tells the compiler to treat it as octal. Therefore, 012 actually equals 10 in decimal, not twelve.
Decimal — e.g., 123
Decimal is Base 10, the standard human number system using digits 0–9.
Why it’s essential: It is our instinctive way of counting and performing math.
Common uses:
High-level application logic
User-facing logs and outputs
General mathematics and financial calculations
Constraint: While great for humans, it is often imprecise for hardware tasks because decimal numbers don't align cleanly with the power-of-two boundaries used by CPUs and RAM.
⚠️ The Gotcha Warning
Modern developers are generally advised to avoid leading zeros in decimal numbers.
Accidental octal notation is a common source of bugs where a value like 012 results in a calculation error because the developer intended it to be twelve, but the machine processed it as ten.
Since we will be working with tools like Themida or Obsidium, we shall run into many cases where they use octal for obfuscation, and where they mostly stick to messy hex jumps.
🚨 KEY RULE: How to Write Numbers in Code (Especially in C/ASM)
✅ Bottom Line:
Use hex (0x) for memory, bitfields, opcodes, and compact representation.
Use binary (0b) for manipulating individual bits (masks, flags).
Use octal (0...) only when you're doing Unix file permissions or legacy stuff.
Use decimal when writing output for human eyes.
Alright, let’s go full beast mode 👹 and show real-world code examples where Hex, Binary, Octal, and Decimal each have their place, especially in Assembly, WinAPI, and low-level C/C++ stuff. This is for beginners and curious pros who wanna see the why, not just the what.
1. HEX (0x…) – The king of low-level programming
🔧 Use Case: Memory addresses, opcodes, hardware registers
✅ When to use:
Reading memory maps
Accessing hardware (MMIO registers, BIOS)
Looking at raw shellcode or hex dumps
Coloring (e.g., HTML/CSS: 0xFF33AA)
2. BINARY (0b…) – The mask ninja
🔧 Use Case: Bit flags, hardware settings, shifting
✅ When to use:
Bit masks
GPIO pin toggling
Permission bits
Status registers
3. OCTAL (0…) – The UNIX hipster 🧔🧂
🔧 Use Case: File permissions (only really used in Unix/Linux)
⚠️ Avoid in most modern code unless you’re on Unix and know what you're doing.
4. DECIMAL – Human readable, boring but necessary
🔧 Use Case: Output for users, constants in formulas
✅ When to use:
User-facing numbers
Calculations or percentages
Output/logs
TLDR – When to Use What?
Back to data conversion
You got it — let's crack open the "BINARY INTEGERS" section like a pro and a patient teacher explaining to beginners who’ve never even thought of what “binary” really means.
What is a Binary Integer, really?
At its core, a binary integer is simply a number composed entirely of 0s and 1s. This system exists because computers operate using only two electrical states: a 1 represents "on" (electricity flowing), and a 0 represents "off" (no electricity). While the decimal system we use in daily life is base-10 and uses digits from 0 to 9, the binary system is base-2 and relies strictly on 0 and 1.
Computers only know two states:
1 = ON (Electricity flowing)
0 = OFF (No electricity)
So instead of decimal (base-10) where digits go from 0–9, binary (base-2) digits are only:
0 or 1
Let’s take this binary number:
01001110
From the right side (lift your right hand), we move going to the left side. We go 20 to 28
Now we add up the values that align with the 1’s that is, 2+4+8+64 = 78
So, 01001110 in binary = 78 in decimal.
🧭 LSB vs MSB — Understanding Bit Positions
LSB = Least Significant Bit → This is the rightmost bit (position 0). It affects the smallest part of the number, like the “ones place” in decimal.
MSB = Most Significant Bit → This is the leftmost bit. It carries the heaviest weight, like the “hundreds” or “millions” place in big numbers.
Example:
1. Unsigned Binary Integers
Unsigned binary integers are the simplest type of binary numbers. The term “unsigned” means there is no dedicated sign bit, so the number can only represent zero or positive values.
Each bit, whether 0 or 1, contributes directly to the value based on its position. This follows the standard binary place value system, where each position represents a power of 2 (for example, 2⁰, 2¹, 2², and so on). There are no special rules, transformations, or encodings involved.
For example, in a 4-bit unsigned binary number:
0000 represents 0
0001 represents 1
0010 represents 2
0101 represents 5
1111 represents 15
So, with 4 bits, the range of values is from 0 to 15.
✅ Example (8 bits = 1 byte):
With 8 bits, you can count from: 0 to 255
Why 255? Because that’s the highest value you can make with all 8 bits set to 1:
There are 2⁸ = 256 total values, ranging from 0 to 255 (0 inclusive).
Why there’s “No tricks” with unsigned binary integers?
Because you’re not using any encoding scheme (like Two’s complement for negative numbers).
The bits are treated purely as a base-2 number. So:
✅ All values are positive or zero.
✅ Every bit combination maps to a valid number.
✅ It’s simple and straightforward.
2. Signed Binary Integers
📌 What it means:
These binary numbers can represent both positive and negative values.
But to make that work, one bit (the MSB, or most significant bit) is used to indicate the sign of the number.
🔄 How it works:
In signed binary, the first (leftmost) bit tells you whether the number is positive or negative:
0 in the MSB → the number is positive
1 in the MSB → the number is negative
But here’s the important twist:
Computers don’t just add a minus sign when MSB is 1, they use a system called Two’s Complement to represent negative numbers.
What is Two’s Complement?
Two’s complement is a system used by computers to represent negative numbers using binary (just 1s and 0s).
🔍 What’s the challenge?
Computers use binary numbers, which are naturally positive. So we need a way to represent negative values in binary, and still let the computer do addition and subtraction correctly.
✅ Two’s Complement to the rescue!
Instead of having a "negative" flag, Two’s complement uses the most significant bit (MSB)—the leftmost bit—to indicate the sign:
If MSB is 0, the number is positive.
If MSB is 1, the number is negative—but interpreted differently.
🧪 How does it work?
For an 8-bit binary number (example):
1. Positive 5: Binary: 00000101. MSB is 0 → interpreted as +5.
2. Negative 5 in two’s complement:
Start with +5 → 00000101
Step 1: Invert the bits → 11111010
Step 2: Add 1 → 11111011
✅ Now 11111011 means -5 in two’s complement.
🎯 Why it’s smart:
Now, adding 00000101 (+5) and 11111011 (–5) gives:
Math just works cleanly, even with negative numbers.
🤔 How can 11111111 be 255 and not called signed int?
It can be called a signed, but it comes down to context — whether the number is treated as unsigned or signed. Read the last paragraph to get the quick context.
255 as an unsigned binary: This is the one we’re used to.
All bits are used to represent the value. No sign. Just straight-up counting.
So, with 8 bits ➡️ 28 -1 ➡️ 255 as the largest value:
In unsigned context, 11111111 is 255 — the largest value 8 bits can hold.
📌 255 as a signed binary integer (Two’s complement):
When we apply the 2’s complement on the same value.
Now the leftmost bit (MSB) is used as a sign bit.
0 = positive
1 = negative → value is encoded using Two’s complement
So, 11111111 is not 255 anymore — it's –1.
Let’s prove it:
Start with 11111111
Invert the bits → 00000000
Add 1 → 00000001
Result = 1 → So original was –1
In signed (Two’s complement) context, 11111111 means –1
🔑 Key takeaway:
The same binary pattern can mean different numbers, depending on how it's interpreted:
Why it works this way:
Unsigned binary uses all bits for the number.
Signed (Two's complement) reserves 1 bit (the MSB) to handle negatives.
The bit pattern doesn’t lie, how you choose to read it is the real question.
NB: READ THIS FIVE TIMES
The binary number 11111111 can be interpreted in different ways depending on the context. If we’re talking about unsigned binary, it simply represents the value 255, the highest number that can be stored with 8 bits.
But if we interpret the same 8 bits using Two’s complement, then the most significant bit (MSB) is treated as a sign bit, and 11111111 represents –1 instead. So, the same binary pattern can mean different values, depending on whether it’s being used in a signed or unsigned system.
📎 READING & WRITING LARGE BINARY NUMBERS
When binary numbers get long, they become hard to read — like looking at a wall of 1s and 0s.
💡 So what do we do?
We break them into groups — usually every 4 bits or 8 bits, just like how we write big decimal numbers with commas or spaces e.g.
This doesn’t change the value — it’s just formatting to help our human brains.
🔢 Unsigned Binary: Bit by Bit
Let’s say you’ve got 8 bits. Here’s how they work:
You multiply each bit by its weight, and then add:
This is unsigned binary — meaning no negatives, just raw value.
Quick Question: Can we represent the number 8 using 3 bits?
Nope.
Let’s break it down:
⚙️ With 3 bits:
You get 2³ = 8 values
But the range is from 000 to 111
That’s 0 to 7 in decimal
So, you can store up to 7, but not 8.
✅ To store the number 8, you need 4 bits
🔍 Why?
Because:
The leftmost bit is in the 2³ position, which equals 8.
The rest are 0s:
So, if you tried to cram 8 into 3 bits, it would overflow — you simply don’t have enough bits to hold the value.
✅ Key Idea:
The number of values you can represent with n bits is 2ⁿ … but the maximum value is 2ⁿ - 1.
So, 8 is past 23 – 1 range, thus we need 4 bits.
Now let’s jump straight into conversions, we’ve been holding back for so long.
Irrelevant for everyone.
🤣 BROOOOOOOO I FEEL YOU.
The contraction game in English be like:
let’s = let us (but somehow not always...)
it’s = it is (easy enough)
that’s = that is
you’re = you are
But then…
let’s go sounds like a team call
let us go sounds like you’re begging your kidnappers 💀
Same words, different vibes.
Here's the real deal:
1. “Let’s” = “let us” (but not always replaceable 1:1)
✅ Let’s eat. → “Let us eat.” (kinda formal, but okay)
❌ Let’s go to the club. → “Let us go to the club.” sounds like you’re asking for permission from your strict dad 😭
✅ Let’s reverse this binary. → Cool and casual
❌ Let us reverse this binary. → Feels like you're quoting Shakespeare and summoning hackers from 1742
So even though grammatically it's the same, in practice it ain’t always swappable. "Let’s" is a suggestion, while "let us" can sound like a request or plea depending on the tone.
2. “It’s” = “It is”
This one is straightforward.
“It’s” is simply a contraction of “it is.”
It’s raining → It is raining
It’s broken → It is broken
In most cases, you can safely expand “it’s” to “it is” without changing the meaning.
The “its” vs “it’s” trap
This is where people often get confused:
It’s = it is
Its = possessive form (like “his” or “hers”)
Examples:
It’s alive → It is alive
The robot lost its arm → “its” shows ownership, not “it is arm”
Why this happens
English has developed over time through many influences, which has led to inconsistent patterns. Apostrophes are usually used for possession, but “its” is an exception. Instead, the apostrophe in “it’s” signals a contraction.
Key takeaway
Do not rely on swapping blindly. Always check the meaning in context. If “it is” fits, use “it’s.” If you are showing possession, use “its.” ❌
🔁 1. BINARY TO DECIMAL (Whole Numbers)
How It Works:
Every binary digit (bit) represents a power of 2, just like every decimal digit represents a power of 10.
Let’s take a binary number:
To convert to decimal:
So, 1011 in binary = 11 in decimal.
🌊 2. BINARY WITH DECIMAL POINTS → DECIMAL (Fractions)
Binary fractions work just like whole numbers, except instead of powers of 2 going up, we go down (negative exponents) after the decimal point.
Example: 101.101
Break it into two parts:
Whole part: 101 → same rules as above = 5
Fractional part: .101
1 × 2⁻¹ = 0.5
0 × 2⁻² = 0
1 × 2⁻³ = 0.125
Adding arrows really helps beginners see how each bit contributes to the total value.
Add it all up:
✅ 101.101 in binary = 5.625 in decimal
🔄 3. DECIMAL TO BINARY (Whole Numbers)
You use successive division by 2, and keep track of the remainders.
Example: Convert 13 to binary
Final Binary (13 in base 10): 1101.
🔬 4. DECIMAL WITH DECIMAL POINTS TO BINARY (Fractions)
Now it’s the reverse of earlier, instead of dividing, you multiply the fractional part by 2, and take the whole number part each time.
Example: Convert 0.625 to binary
Let's Do a Full Example:
Convert 13.625 to Binary:
• Whole part: 13 → 1101
• Fractional part: .625 → .101
Final binary:
✅ 13.625 = 1101.101
Do questions as programming practice, yourself.
⚠️ WHY SOME DECIMALS CAN’T BE EXACTLY REPRESENTED IN BINARY
Quick Fact:
Just like 1/3 = 0.333... goes on forever in decimal, some decimal values (like 0.1) go on forever in binary.
Let’s Build a Table: Convert Decimal Fractions → Binary
💡 What's Going On?
Only numbers that are a sum of powers of 2⁻¹, 2⁻², 2⁻³… will end cleanly in binary.
That means:
0.5 = 2⁻¹ ✅
0.25 = 2⁻² ✅
0.75 = 2⁻¹ + 2⁻² ✅
But 0.1 = ??? → There's no clean combo of powers of 2 to get 0.1
So it becomes a repeating binary fraction.
🔧 Real-World Impact (esp. for C/C++/Python devs like you)
This is why floats/doubles can act weird if you rely on exact equality.
Comparing if (x == 0.1) may fail even if you just set x = 0.1.
You often need to use tolerances, like:
🧪 Want Proof? Let’s Convert 0.1 to Binary
Let’s show just the first few steps of multiplying 0.1 by 2 repeatedly:
Why Some Decimals Repeat Forever in Binary
When a number like 0.2 is converted into binary, it does not have a clean, finite representation. Instead, it becomes a repeating pattern that goes on indefinitely. Since computers have limited space to store numbers, they cut off the pattern after a certain number of bits. This small cutoff introduces tiny inaccuracies, which is why floating-point numbers sometimes behave unexpectedly.
This is not a bug in your program—it is a limitation of how numbers are represented in binary.
Final Insight: Why Floats Feel Inaccurate
Whenever you notice strange rounding errors or precision issues, keep this principle in mind: decimal numbers are designed for human use, while binary numbers are optimized for machines. Because of this mismatch, some values cannot be represented exactly, and small errors are unavoidable.
Binary to Hexadecimal Conversion
Hexadecimal (base 16) is a compact way of representing binary numbers. The key idea is that one hexadecimal digit corresponds exactly to four binary bits. This makes it much easier to read and work with long binary sequences.
When converting from binary to hexadecimal, you group the binary digits into sets of four, starting from the right. Each group is then replaced with its hexadecimal equivalent.
Conversion Table from Binary to Hexadecimal (0–F)
Each hexadecimal digit represents a unique 4-bit binary pattern:
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
1010 = A
1011 = B
1100 = C
1101 = D
1110 = E
1111 = F
This direct mapping is what makes hexadecimal especially useful in computing, as it provides a shorter and more readable form of binary data.
🎨 2. How to Quickly Build the Binary-to-Hex Table (Bit Patterns)
To draw the full binary-to-hex table fast, follow this simple visual trick:
In the first column, write 8 zeros followed by 8 ones (00000000 to 11111111).
In the second column, alternate every 4 bits: 4 zeros, 4 ones, 4 zeros, 4 ones.
In the third column, alternate every 2 bits: 2 zeros, 2 ones, 2 zeros, 2 ones.
In the last column, just repeat 0101 eight times going downward.
Each row represents one 4-bit binary number (0000 to 1111), and this structure helps you quickly match each one to its hex equivalent (0–F).
🧙♂️ Binary to Octal Conversion
This table shows how to convert 3-bit binary chunks into single octal digits. Each 3-bit binary chunk directly corresponds to one octal digit.
🧮 3. How to Quickly Build the Binary-to-Octal Table (Bit Patterns)
To draw the binary-to-octal table easily, break it down into 3-bit chunks. Here's a quick pattern method:
In the first column, alternate every 4 rows: 4 zeros, 4 ones, 4 zeros, 4 ones.
In the second column, alternate every 2 rows: 2 zeros, 2 ones, 2 zeros, 2 ones.
In the third column, simply repeat 01010101 downward.
This gives you all binary numbers from 000 to 111 (that’s 0 to 7 in decimal), which is exactly what octal digits represent. Each 3-bit binary number maps directly to a single octal digit.
💻 For hex conversions:
⚡ For octal conversions:
Final Tips for Number System Conversions
Understanding how different number systems connect becomes much easier when you follow a few consistent rules. These tips help you stay accurate and avoid common mistakes when converting between binary, hexadecimal, and octal.
Tip 1: Use Binary as the Bridge
Binary acts as a universal translator between number systems. When a direct conversion feels confusing, convert the number into binary first.
For example, instead of struggling to go from decimal to hexadecimal in one step, convert decimal to binary, then binary to hexadecimal. This works because binary is the base representation used internally by computers, while hexadecimal and octal are simply grouped versions of binary.
Thinking of binary as the foundation keeps your process structured and reliable.
Tip 2: Always Group from the Right-Hand Side
When converting binary into hexadecimal or octal, you must group the bits into fixed sizes:
Groups of 4 bits for hexadecimal
Groups of 3 bits for octal
These groups must always start from the right-hand side. The rightmost bit is called the Least Significant Bit (LSB), which represents the smallest value (the “ones” place).
If you start grouping from the left, you risk misaligning the values and getting incorrect results. Grouping from the right ensures each chunk correctly represents its place value.
Tip 3: Use Zero-Padding on the Left
Sometimes a binary number does not divide evenly into groups of 3 or 4 bits. When this happens, you add extra zeros to the left side until the groups are complete. This process is called zero-padding.
Zero-padding does not change the value of the number. It only ensures that the binary digits fit neatly into the required group sizes for accurate conversion.
Example: Converting Binary to Hexadecimal
Consider the binary number: 101101
To convert it into hexadecimal, you need groups of 4 bits. Start grouping from the right: 10 1101
The left group is incomplete, so you add zeros: 0010 1101
Now convert each group:
0010 becomes 2
1101 becomes D
The final hexadecimal result is: 2D
Why Zero-Padding Matters
Without zero-padding, the grouping would be incorrect, and the final answer would be wrong. Padding ensures that each group maintains its correct positional value while preserving the original number.
These small rules make a big difference in accuracy and help you build confidence when working across number systems.
MEMORY & STORAGE SIZE MEASUREMENTS
When you hear stuff like "your phone has 128GB storage" or "this file is 5MB", you’re hearing data size measurements — a way to describe how much info is being stored or moved around.
Let’s start with two main styles of measurement:
✅ 1. Decimal System (What manufacturers use):
Based on powers of 10 (1 KB = 1,000 bytes).
This is what’s printed on your USB drive or SSD packaging
⚠️ 2. Binary System (What your computer actually uses):
Let’s get one thing straight: your computer doesn’t count like you do. It doesn't care about 10s. It speaks binary — a language made up of just two symbols: 0 and 1.
Why? Because deep down, all your computer sees is voltage:
1 = electricity flowing (ON)
0 = no electricity (OFF)
So, everything — every video, song, app, or meme — is just trillions of 0s and 1s processed fast as hell.
💡 Why Powers of 2?
Because each binary digit (bit) doubles the number of possible combinations:
So, when you hear:
1 byte = 8 bits
1 KiB (kibibyte) = 1024 bytes
1 KB (kilobyte) = 1000 bytes (SI definition) or 1024 bytes (binary) .
1 kbit (kilobit) = 1000 bits
Let’s address this madness:
⚠️ 2. Binary System (What Your Computer Actually Uses)
💭 “So wait… 1KB is 1000 bytes? Or 1024? Or 8192 in Mars?”
Yep. Welcome to the madness of digital units.
Let’s break this thing down like you’re hearing it for the first time — because most people only pretend they understand this.
📌 Binary: The Language of Computers
At the hardware level, everything is just ON (1) or OFF (0), two voltage states.
That’s why computers use binary (base-2) instead of human-friendly decimal (base-10).
Binary example:
See that? It gets long fast. But it’s perfect for computers because flipping switches (on/off) is fast, cheap, and reliable.
📦 Units in Binary World (the OG Nerd Units)
Now, let’s talk storage units — this is where the confusion starts:
💡 Important:
1 KB = 1 Kilobyte✅ = 1000 bytes
1 KiB = 1 Kibibyte✅ = 1024 bytes
1 kbit = 1 Kilobit✅ = 1000 bits
1 byte = 8 bits✅
1 kilobyte (KB) = 1000 bytes (Decimal, SI standard) ✅
1 kibibyte (KiB) = 1024 bytes (Binary, OS standard) ✅
1 Kilobit (kbit) = 1000 bits (used in networking) ✅
Internet speeds are shown in kilobits per second (kbps), not kilobytes, that’s why 10 Mbps WiFi doesn’t feel that fast.
Why Binary Sizes Even Exist (And Who Uses What)
🧾 Binary Sizes (KiB, MiB, GiB, etc.)
These units are used in computing (especially in operating systems and hardware) and are based on powers of 2:
1 KiB (Kibibyte) = 1024 bytes
It’s 210 (which equals 1024).
1 MiB (Mebibyte) = 1024 KiB (Kibibytes) = 1,048,576 bytes
This is equal to 220 bytes.
1 GiB = 1024 MiB = 1,073,741,824 bytes
1 TiB = 1024 GiB = 1,099,511,627,776 bytes
Each time, you multiply by 1024, which follows the binary system (base 2).
"Megabyte" and "kilobyte" are officially based on the SI standard.
But... when you're working in operating systems, file systems, and even low-level stuff like assembly, those units often use powers of 2.
This is where mebibyte (MiB), kibibyte (KiB), etc., come in.
So, yeah, everyone says “megabyte” (MB), “kilobyte” (KB), and so on, even though technically they often mean MiB or KiB in many contexts.
🏁 Used in:
RAM/Memory.
Operating Systems (Windows File Explorer, Linux ls, etc.)
CPU-level code.
Embedded systems, firmware.
When you see 4 GiB RAM — that’s 4 × 2³⁰ = 4,294,967,296 bytes.
🧾 Decimal Sizes (KB, MB, GB)
Based on powers of 10:
1 KB = 10³ = 1000
1 MB = 10⁶ = 1,000,000
Used in:
Hard drive & SSD marketing (they’ll say “500GB” but that’s 500 × 10⁹ bytes, not GiB)
Internet Service Providers
USB packaging
SD card labels
📉 So your 1TB hard drive is not 1TB in Windows. It shows around 931GiB. Why?
Because marketing uses decimal, but Windows shows binary.
🎯 Real World Example: Where You’ll Meet These
🧪 Quick Quiz to Test You (Mentally)
Q1: If a file is 10 MiB, how many bytes is that?
10 × 220 = 10,485,760 bytes
Q2: Your internet is 100 Mbps. How many megabytes per second can you download?
100 / 8 = 12.5 MBps
(Because 8 bits = 1 byte)
INTEGER STORAGE: HOW THE CPU SEES NUMBERS
The most fundamental storage unit in any modern computer (including x86 architecture) is:
⚙️ 1 byte = 8 bits
But that's just the start. Larger integer sizes are built by combining more bytes:
📊 UNSIGNED INTEGER STORAGE TABLE (RAW BINARY)
When we talk unsigned integers, we’re only representing positive values, including zero. This means the minimum is always 0, and the maximum depends entirely on how many bits are used.
These are the raw binary interpretations, not tied to a programming language (yet). Just what the CPU or memory sees.
⚠️ SIGNED vs. UNSIGNED: THE TWIST
When you introduce signed integers (which include negative numbers), the bit layout changes, usually the most significant bit (MSB) is used to indicate sign:
So, for signed 32-bit (int):
MSB = 1 → negative number
MSB = 0 → positive number
In two's complement format (what modern CPUs use), this makes arithmetic way easier for the hardware.
WHAT THIS MEANS IN PRACTICE (x86 & C/ASM)
✅ Assembly / WinAPI / x86 Systems
mov eax, 1 → eax is a 32-bit register (DWORD)
mov ax, 1 → ax is the 16-bit word part of eax. You're only manipulating the lower half of it.
mov al, 1 → al is the 8-bit low byte of ax.
Where you’ll mostly see these being used (Zoom PDF for clarity):
TLDR - INTEGER STORAGE DECODED
🧱 Byte = 8 bits = max 255 (unsigned)
🔧 Word = 16 bits = max 65,535
🧠 Dword = 32 bits = max ~4.2 billion
👑 Qword = 64 bits = max ~18 quintillion
✅ Unsigned = only positive
⚠️ Signed = supports negatives, via two's complement
🔍 In WinAPI and x86, these terms show up everywhere
NB from the last topic:
✅ KB, MB, GB, TB = marketing numbers (1KB = 1,000 bytes)
💻 KiB, MiB, GiB, TiB = actual memory sizes in your system (1KiB = 1,024 bytes)
Be aware of both — especially if you're doing systems programming, OS work, or comparing file sizes accurately.
WHAT’S THE DEAL WITH “SIGN EXTENSION” AND “ZERO EXTENSION”?
Imagine you’re taking a number written in a smaller box (like 8 bits) and putting it into a bigger box (like 16 or 32 bits). You can’t just copy-paste the bits — the computer needs to preserve the meaning (especially the sign if it’s signed).
🧭 Zero Extension (Used for Unsigned numbers)
What it does:
Just adds 0s to the left (the higher bits).
Why?
Unsigned numbers don’t care about sign. So, filling with zeroes is always safe.
Example (8-bit to 16-bit):
See that? We kept the value exactly the same but just padded it with zeroes on the left.
🧭 Sign Extension (Used for Signed numbers — 2’s complement)
What it does:
Copies the sign bit (leftmost bit) to the new bits on the left.
Why?
To preserve the sign and value of the number in 2’s complement.
Example (8-bit to 16-bit):
See how it copied the sign bit (1)? That's how −1 stays −1 even after "growing".
📍 Key Differences: Zero Extension vs. Sign Extension
💡 Real-Life Analogy
Imagine someone is writing a note on a small piece of paper (8-bit value), and now they need to stick it on a large poster (16-bit register).
If it’s a positive message (unsigned), they just tape it on and fill the background with blank space (zero extension).
If it’s a negative message (signed), they fill the background with angry red ink (1s) to keep the same emotional vibe across the bigger paper (sign extension).
🧪 Common Use Cases in Assembly
Reading bytes from memory and processing them as 32-bit values:
Before arithmetic: Some arithmetic instructions (like IMUL, IDIV) require 16 or 32-bit operands, so you must extend your smaller value first — correctly, based on its sign.
⚠️ Important Reminder
On x86:
If you use MOV directly, no extension happens. Just copy. If you move al into ax, it won’t zero-extend!
Use MOVZX (zero extension) or MOVSX (sign extension) explicitly.
✅ TLDR
Use MOVZX for unsigned values — it adds zeroes.
Use MOVSX for signed values — it replicates the sign bit.
Crucial when extending from 8-bit to 16-bit or 16-bit to 32-bit.
If you mess this up? Your arithmetic gets WILDLY wrong, especially with negatives.💀
TWO'S COMPLEMENT REPRESENTATION pt 2
How your CPU thinks about negative numbers — and still sleeps well at night.
Why Do We Need It?
Computers store everything as 0s and 1s — and binary is naturally positive.
So… how do you store negative integers? 🤔
Option 1: use a “sign bit” — not efficient.
Option 2: use two's complement, the industry standard.
Two’s complement is the system used in almost all CPUs today (x86, ARM, RISC-V, etc.) to store signed integers — i.e., both positive and negative values — using only binary math.
THE RULES (in human words)
📈 For positive numbers:
Just write the binary as usual.
Example:
📉 FOR NEGATIVE NUMBERS:
Use two's complement steps:
Step-by-step for -5:
Start with the binary of +5: 00000101
Invert the bits: 11111010
Add 1: 11111011
So, the two’s complement of -5 is: 11111011
Bonus: the leading 1 shows it’s negative. Always.
💥 WHY TWO'S COMPLEMENT IS AWESOME
You can add and subtract negative numbers just like positives.
The CPU doesn't need separate logic for subtraction.
It simplifies circuitry and is way faster. Example:
We’d done this as the former example.
VALUE RANGE PER SIZE (Signed Integers)
Why is the minimum value bigger than the maximum?
Because zero uses up a positive slot (e.g., 00000000 = 0).
✅ 1. Bit-width Importance (Overflow Awareness)
We briefly mentioned "make sure both have the same number of bits", but we need to hammer that home.
✍️ If you're working with 8-bit, 16-bit, 32-bit systems, the two's complement depends on that width.
Example: Represent -5 in 4 bits vs 8 bits
4-bit:
8-bit:
⚠️ If you try to add or subtract outside the allowed bit-width, you'll get overflow.
Two’s Complement Range and Why the MSB Indicates a Negative Number
In a two’s complement system, the range of signed integers depends on the number of bits used.
For an n-bit number, the range is from −2ⁿ⁻¹ to (2ⁿ⁻¹ − 1).
This means that one more value is allocated to negative numbers than to positive numbers.
For example, in a 4-bit system, the range of values is from −8 to +7.
In an 8-bit system, the range extends from −128 to +127.
This pattern continues for larger bit sizes.
The most significant bit (MSB), which is the leftmost bit in a binary number, plays a special role in two’s complement representation.
It is often referred to as the sign bit because it determines whether the number is positive or negative.
If the MSB is 0, the number is either positive or zero.
If the MSB is 1, the number is negative.
This happens because, in two’s complement, the MSB is assigned a negative weight instead of a positive one.
To understand this better, consider how place values work in binary.
Normally, each bit position represents a power of 2, starting from the rightmost bit: 2⁰, 2¹, 2², and so on.
However, in an n-bit two’s complement number, the MSB (the leftmost bit) represents −2ⁿ⁻¹ instead of +2ⁿ⁻¹.
For example, in an 8-bit number, the bit positions represent the following values:
The rightmost bit represents 2⁰ (1)
The next bit represents 2¹ (2)
Then 2² (4), 2³ (8), 2⁴ (16), 2⁵ (32), 2⁶ (64)
The leftmost bit (MSB) represents −2⁷ (−128)
So, for the binary number 10000000 (8 bits), only the MSB is 1. This means its value is −128, since all other bits are zero.
This design is what makes two’s complement efficient for arithmetic operations.
It allows computers to perform addition and subtraction using the same hardware, without needing separate rules for positive and negative numbers.
For the number 10000000, the leftmost bit (MSB) is 1, and it represents the 128 place:
The first (leftmost) bit is worth -2⁷ = -128 (this is the negative part of the number).
All other bits are 0, so the value is just -128.
Thus, 10000000 in 8-bit two's complement represents -128.
To Summarize:
The MSB in two's complement is treated as a negative value because it corresponds to the most significant bit’s weight, which is a negative power of 2 (specifically, −2n−1).
This is why the MSB = 1 signals a negative number in two's complement representation.
WORKED EXAMPLE: Subtracting 39 - 25 using 2's Complement
Let’s manually walk through it so beginners see the real magic.
✏️ Step 1: Convert numbers to 8-bit binary
39 = 00100111
25 = 00011001
✏️ Step 2: Take the two’s complement of 25 (to make -25)
Invert: 11100110
Add 1: 11100111
So: -25 = 11100111
✏️ Step 3: Add the two values
✏️ Step 4: Convert 00001110 to decimal
Result: 39 + (-25) = 14✅
It just works. No separate subtraction logic needed.✅
Another example:
Example: -5 + (-3) in 8-bit two’s complement.
-5 = 11111011
-3 = 11111101
Even with overflow, we discard extra carry in fixed-width arithmetic. This confuses many new devs.
✅ Why Two’s Complement is Better than 1’s Complement
So yeah, no one really uses 1’s complement anymore — just good to mention it for historical flavor.
One's Complement is where you flip all the bits (0s become 1s, 1s become 0s) to get the negative representation of a number.
Two's Complement is where you flip all the bits (like 1's complement), and then add 1 to the result to get the negative representation of a number.
6. Two’s Complement of Hex Values — The Shortcut, Demystified
⚙️ PART 1: What’s Actually Happening in Two’s Complement?
Two’s complement is a way to store negative numbers using binary.
It’s smart because it allows the same addition circuitry to handle both positive and negative values. No separate subtractor needed.
But you already knew that.
What’s less obvious is how that idea translates into hex math — where people often say:
“Just subtract from 2ⁿ.” Wait... Why? What is 2ⁿ? Why are we subtracting?
⚙️ PART 2: What “Subtract from 2ⁿ” Really Means
Let’s say you’re working in 8 bits, which is very common.
In 8 bits, the total number of possible values is: 2⁸ = 256
So, you can represent:
00000000 → 0
11111111 → 255
Now imagine this like a circular number line that wraps around from 255 back to 0.
⚙️ THE CORE IDEA:
When you want to get the negative version of a number,
you want to find what value would “wrap it around” to 0
in this circular world of 0 to 255.
This “wrapping” is modulo math — specifically mod 256 (because 2⁸ = 256).
So, you’re asking:
What number can I add to 90 to get 256?
Answer:
166 (because 90 + 166 = 256)
In hex:
So clearly, 0xA6 is the two's complement of 0x5A.
You flipped it around the 256 mark. That's it.
🎯 SO THE TRICK WORKS BECAUSE…
In two’s complement:
Negative numbers are stored such that:
X + (-X) = 0 (mod 2ⁿ)
So, if:
X = positive number (e.g. 90)
-X = two’s complement of that number (e.g. 166)
Then:
NOW DO IT STEP BY STEP WITH EXPLANATIONS
Let’s say we want to find -0x5A in 8-bit
Step 1: Understand what 0x5A means
0x5A is hex
5A in hex = 90 in decimal
Step 2: What’s the total possible value in 8 bits?
2⁸ = 256
(because 8 bits can store values from 0 to 255)
Step 3: Subtract 90 from 256
256 - 90 = 166
This means that:
-0x5A = 166 in decimal
166 in hex = 0xA6
✅ Final Answer:
Two’s complement of 0x5A = 0xA6
Another example: What is -0x2F in 8-bit?
Step 1: Convert hex to decimal
0x2F = 47
Step 2: Use the full range of 8 bits
2⁸ = 256
Step 3: Subtract 47 from 256
256 - 47 = 209
Step 4: Convert that back to hex
209 = 0xD1
✅ Final Answer:
-0x2F = 0xD1 in 8-bit two’s complement
✅ Because:
0x2F + 0xD1 = 0x100 = 256 → wraps to 0 → valid
Let’s Try to Visualize It with a Circle (Mod 256)
This is why subtraction works:
You're finding the number that would complete the circle to 256.
⚠️ Two’s Complement Shortcut: Important Conditions
The "subtract from 2n" shortcut for Two's Complement is incredibly powerful, but like any powerful tool, it comes with specific conditions for when it works correctly. Make sure you keep these in mind to avoid unexpected results!
🤖 USING THIS IN REAL LIFE
In C or Assembly:
You're storing something like:
In Malware:
You encode a positive value like 0x2F, but store it as 0xD1 (which looks like junk) to hide meaning.
In File Formats or Debuggers:
You read a hex dump and see 0xA6. What does that mean?
If unsigned: 166
If signed (two’s complement): -90
Now you know how to decode and encode both ways.
📌 TLDR REWRITE — MAKE THIS UNDERSTANDABLE
What is Two’s Complement in Hex?
Two’s complement is how computers represent negative numbers using only binary.
Hex is just a cleaner way to write binary. So to represent -X in hex, we can use math.
The Shortcut
To find the two’s complement of a hex value,
subtract it from 2ⁿ, where n is the number of bits.
In 8 bits, that’s 2⁸ = 256 = 0x100
So:
That means:
0x5A = +90
0xA6 = -90
Because they add up to 0x100, which wraps to 0.
When Should You Use This?
Final Examples
Example 1: -0x2F
Example 2: -0x7A
1. Signed Binary to Decimal — Two’s Complement Style
💡 Problem: How do you convert binary like 10101011 into a negative decimal?
When you're dealing with signed binary (two’s complement), the highest bit (leftmost one) tells you if it’s negative:
0 = positive
1 = negative (so we need to decode it differently)
Example: Converting 10101011 to Decimal (Two’s Complement)
Let us convert the binary number 10101011 into its decimal equivalent, assuming it is an 8-bit signed number in two’s complement form.
First, we check the most significant bit (MSB), which is the leftmost bit. In this case, the MSB is 1, which tells us that the number is negative.
To find its decimal value, we need to determine the magnitude of the number by converting it to its positive equivalent. We do this using the two’s complement process.
We start by inverting all the bits (changing 1s to 0s and 0s to 1s).
So, 10101011 becomes 01010100.
Next, we add 1 to the result:
01010100 + 1 = 01010101
Now we convert 01010101 to decimal.
This binary number equals 85 in decimal.
Since the original number had an MSB of 1, it is negative. Therefore, the final answer is:
10101011 = −85 (in decimal)
Another One: Convert 11010101 (8-bit) to decimal
Leftmost bit is 1 → negative
Invert: 11010101 → 00101010
Add 1: 00101010 + 1 = 00101011
00101011 = 43
✅ So 11010101 = -43
Max and Min Values (8-bit Two’s Complement)
01111111 = 127
10000000 = -128 (the lowest value possible in 8-bit Two's Complement)
✅ 2. Character Sets: ASCII, Extended ASCII and Unicode
ASCII — American Standard Code for Information Interchange
A cheat sheet that assigns specific numbers to each keyboard key and character, making it easier for computers to process and understand text.
ASCII uses a 7-bit system, which allows it to represent 128 unique characters in total.
These characters include English letters (both uppercase and lowercase), digits, punctuation marks, and some control characters (like newline, carriage return).
In memory, each ASCII character is stored as a byte (8 bits).
Although ASCII itself only uses 7 bits for each character, it is typically stored in an 8-bit byte, with the extra bit usually set to 0.
Example:
The ASCII value for the letter "A" is 65. In binary, this is represented as 01000001 (7 bits, with an extra 0 bit for storage).
In memory, this would be stored as the byte 01000001, which is equivalent to 0x41 in hexadecimal.
Extended ASCII
So, the Extended ASCII set uses 8 bits (1 byte), allowing for a total of 256 characters (0-255). It has the ordinary 0 to 127… but also…
The characters in the range 128-255 are typically used for non-English characters and special symbols (See the images and html files) e.g.
0x41 (65 in decimal) = "A" (Standard ASCII)
0xE9 (233 in decimal) = "é" (Extended ASCII)
This extension was useful in environments that needed to support multiple languages or special symbols, but it has limitations, which is why it was eventually superseded by the more powerful Unicode standard.
The range 128 to 255 expands the original set to use the 8th bit, allowing for additional characters. This part includes:
Special symbols, like currency symbols (€, £, ¥)
Characters from other alphabets, such as é, ñ, and other accented characters.
Graphics, like box-drawing characters, and some early emojis (though emojis today are much more advanced in Unicode).
UNICODE — GO GLOBAL OR GO HOME
ASCII wasn’t enough when humans needed:
Arabic.
Chinese.
Emoji.
Mathematical symbols.
So, we got Unicode, which maps over 100,000+ characters.
🔁 Unicode Transformation Formats (See the html and images for Unicode)
Read the Unicode.html and the image for more information.
💡 How Are Strings Stored?
Characters are stored as bytes representing their character code. Example:
When you declare a string like above in C, the characters 'H' and 'i' are converted into their corresponding numerical ASCII (or other encoding) values.
Memory view (ASCII):
'H' is stored as 0x48 (hexadecimal).
'i' is stored as 0x69 (hexadecimal).
Null Terminator: A crucial part of C-style strings is the null terminator, represented as '\0' or 0x00. This byte marks the end of the string in memory.
The string "ABC123" is stored in memory like this:
Every character = 1 byte. Last byte = 00h (null terminator)
So wait… Does 41h mean memory location or character?
🔍 Answer: 41h is not a memory address.
🔍 It’s the numeric value of the ASCII character 'A'.
Memory might look like:
⚠️ Why the Null Terminator?
Because in C, C++, WinAPI, Assembly — a string doesn’t store its length.
So the only way to know where a string ends is to look for the 00h null byte.
In memory:
🔧 Control Characters (ASCII 0–31) – As seen in the ASCII.table.html
ASCII 0–31 = non-printable control characters, like:
0x0A (10d) = \n (newline)
0x08 (8d) = \b (backspace)
0x00 (0d) = \0 (null terminator)
In C/ASM, you’ll see them written using escape sequences:
🔢 Why is 2⁷ - 1 = 127 the max for signed 8-bit integers?
The Core Rule:
If you’re using n bits to store a signed integer in two’s complement, then:
You get 1 bit for the sign (positive or negative)
That leaves (n - 1) bits for the value
So, for 8 bits total:
🎯 Max positive value?
You use all 7 value bits as 1s:
That's why 2⁷ - 1 = 127 is the max positive value in signed 8-bit
🎯 Total number of values?
For n bits, total combinations = 2ⁿ
So:
8-bit → 256 total values
That’s the range of signed 8-bit values: -128 to +127
Because:
Min: 1000 0000 = -128
Max: 0111 1111 = 127
Why 2⁸ - 1 = 255 for unsigned?
If you're not using a sign bit (unsigned), all 8 bits are for value:
🔁 Summary Table
I was mixing unsigned vs signed logic in my head.
🧾 Back to Unicode…
UNICODE ENCODING FORMATS: UTF-8, UTF-16, UTF-32
✨ What is Encoding? (all these are mentioned in the htmls and images)
Encoding = turning characters into binary for storage or transmission.
Decoding = converting the binary back to characters.
Unicode is the global standard that assigns each character (letters, numbers, emoji, symbols, etc.) a code point — a unique number.
But we still need to encode those code points into bytes so computers can store them in memory or send them across the web.
That's where UTF-8, UTF-16, and UTF-32 come in.
UTF-8 (Most Popular)
Variable-length encoding: uses 1 to 4 bytes per character
First 128 characters (ASCII) = 1 byte (so it's backwards compatible with ASCII)
Supports all Unicode characters (up to U+10FFFF)
Efficient for English and common languages — because most characters use only 1 byte
Most widely used on the web, Linux, APIs, and emails
✅ Example
UTF-16
Variable-length encoding: uses 2 or 4 bytes per character
First 65,536 characters (Basic Multilingual Plane) use 2 bytes
Rare characters like emojis and historical scripts use surrogate pairs (4 bytes)
Used in Windows, Java, and .NET
✅ Example
UTF-32
Fixed-length encoding: 4 bytes per character
Every character — no matter how simple or complex — uses exactly 4 bytes
Simple and predictable (no need to deal with variable lengths or surrogate pairs)
Very inefficient in terms of memory/storage
Used mainly in low-level systems, like C/C++ internal handling
✅ Example:
Pick your Unicode Transformation Format
Pro Tip:
UTF-8 is the default for files, web, APIs, and databases.
UTF-16 is mostly for Windows apps or Java-based systems.
UTF-32 is best used when you need fixed-width encoding and don't care about memory (e.g., internal char buffers).
TERMINOLOGY IN DATA REPRESENTATION – FOR BEGINNERS
In assembly language and low-level systems work, you’ve got to be ultra-precise with how you describe numbers, characters, and what’s actually in memory.
Why? Because the same number (like 65) can have different meanings depending on:
⚙️ where it is (memory vs screen).
📺 how it’s interpreted (ASCII vs integer).
💾 how it's formatted (binary vs hex vs string).
Example: The Number 65
Memory Contexts
Let’s break it down in a real-world scenario:
🔠 Number 65: Character vs String in ASCII
When you store the value 65, how it’s interpreted depends on the data type:
If you treat it as a character (like chr(65) in Python), it becomes 'A', because 65 is the ASCII code for 'A'.
If you treat it as a string (like str(65)), it becomes '65', which is literally the two characters '6' and '5', not 'A'.
✅ TLDR:
65 → 'A' if treated as a character
65 → '6' and '5' if treated as a string of digits
They look the same on the outside, but they're totally different under the hood. One is a single byte with value 65 ('A'), the other is two bytes: 0x36 ('6') and 0x35 ('5').
📌 Key Terminology
Let’s define the exact terms you’ll see in docs and assembly manuals:
📦 Data Storage: You Decide the Meaning
What’s wild is — the computer doesn’t care what 01000001 means.
It’s just 8 bits. You — the programmer — decide how to interpret it.
TLDR
Same binary data can be an integer, a character, or a string, context defines the meaning.
A binary integer is raw math data. A digit string is made of ASCII bytes that look like numbers.
Hex (41h) is just another way to write the same data, it’s easier to read for humans.
ASCII 'A' = 65 = 0x41 = 01000001.
🔥 Not important but good to know notes: Hex and ASCII Fast-Lookup Tip
If you're working in low-level code or reading memory:
'A' → 0x41 → 01000001
'0' → 0x30 → 00110000
'9' → 0x39 → 00111001
Once you memorize these ranges (0x30–0x39 for digits, 0x41–0x5A for uppercase letters), you'll read hex dumps like the Matrix.
Let’s go deep, not just on how to read ASCII and hex dumps, but also why it’s super important when you’re inside tools like x64dbg, Ghidra, or IDA.
🔥 WHY YOU NEED TO RECOGNIZE HEX ➡️ ASCII RANGES
When you reverse engineer software, you’re constantly reading memory dumps, disassembly, or binary blobs.
Inside those dumps are:
Strings (like usernames, passwords, commands)
Constants (e.g., 'A', '0', '9', etc.)
File formats (PDF, PE headers, image metadata)
Protocols (HTTP, binary protocols, etc.)
But guess what? Check the html’s and images for more context to be honest.
All of those are just bytes — and those bytes often encode ASCII characters. If you can spot those by eye, you start seeing stuff that’s hidden to normal devs.
💡 ASCII CHEAT TIP
Here’s the gold — memorize these three ASCII hex ranges:
Let’s continue with shifts and rotates from the next docx, cool?