שיעור זה הוא הבסיס לכל מה שיבוא אחריו. כל נושא בקורס — Assembly, ניתוח זיכרון, Buffer Overflow, ניתוח פרוטוקולים, CTF — נשען על ההבנה שתצבור כאן. לא נניח שאתה יודע כלום מעבר לכך שמחשב קיים.
✓נושאי השיעור
מבנה המחשב — ארכיטקטורת Von Neumann
מערכות ספירה — בינארי, הקסדצימלי, ואוקטלי
CPU ורגיסטרים — EAX, EIP, ESP ועוד
מחזור Fetch-Decode-Execute
היררכיית זיכרון — L1/L2/L3 Cache, RAM, SSD
פעולות ביטוויז — AND, OR, XOR, NOT, SHL, SHR
Endianness — Little Endian לעומת Big Endian
מספרים שליליים — Two's Complement
טיפ ללימוד: ברירת המחדל היא תצוגת תקציר — קרא קודם את עמוד השדרה, ופתח "הרחבה" רק כשרוצים את הפרטים המלאים. למעבר מהיר על הכל, החלף ל‑מלא למעלה.
// פרק 1
למה בכלל קיימים מחשבים?
בשנות ה-40, המילה "computer" הייתה תיאור של תפקיד — לא מכונה. אנשים ישבו כל היום ועשו חישובים בידיים. מתמטיקאים כמו אלן טיורינג הבינו שאפשר לבנות מכונה שתעשה זאת.
💡 הרעיון הבסיסי
מחשב הוא מכונה שמבצעת רצף של הוראות פשוטות, אחת אחרי השנייה. כל תוכנה — WhatsApp, משחק וידאו, מערכת נשק — היא בסופו של דבר רצף של פעולות בסיסיות מאוד.
הרחבה אנלוגיית השף ›
דמיין שף מקצועי במטבח מסעדה. השף (CPU) מקבל פתק עם רשימת הוראות מהמלצר (תוכנה). הוא קורא הוראה אחת בכל פעם, מבצע אותה, ועובר להבאה. המצרכים (נתונים) נמצאים על השיש (RAM) או במחסן מאחורה (דיסק). הכלים שבידיו ממש עכשיו (רגיסטרים) — המהירים ביותר, אבל מוגבלים.
אנלוגיה זו תלווה אותך לאורך כל הקורס.
✏
תרגול עצמי
1 שאלה
שאלה א׳.1
מה הגדרה הנכונה ביותר למחשב?
✓ תשובה נכונה: ב — מחשב אינו חכם. הוא מבצע הוראות בסיסיות מאוד, אחת אחרי השנייה, אבל עושה זאת מהר מאוד. כל תוכנה מורכבת — WhatsApp, AI, משחק — היא בסופו של דבר רצף כזה.
// פרק 2
ארכיטקטורת Von Neumann: המפה הגדולה
ב-1945 פרסם המתמטיקאי ג'ון פון נוימן מסמך שהגדיר את מבנה המחשב שבו אנחנו משתמשים עד היום: שמור הוראות ונתונים באותו זיכרון.
ארבעת המרכיבים
מרכיב
שם
תפקיד
אנלוגיה
CPU
מעבד
מבצע הוראות, מחשב, מקבל החלטות
השף
RAM
זיכרון
שומר נתונים והוראות זמנית בזמן ריצה
השיש במטבח
Input
קלט
מקלדת, עכבר, רשת
ספק המצרכים
Output
פלט
מסך, רמקולים, קובץ
הצלחת ללקוח
! Von Neumann Bottleneck ›
יש בעיה בארכיטקטורה: ה-CPU וה-Memory מחוברים דרך אותו Bus. ה-CPU מהיר בהרבה מהזיכרון — ורוב הזמן הוא ממתין. כשתלמד Assembly ותראה פקודות כמו MOV, זכור: מה שנמצא ברגיסטרים — מגיע בלי המתנה. מה שמגיע מהזיכרון — גורם ל-CPU להמתין עשרות עד מאות מחזורי שעון.
הפתרון: Cache — נדון בזה בפרק 6.
✏
תרגול עצמי
2 שאלות
שאלה א׳.2
Von Neumann Bottleneck נגרם בשל:
✓ תשובה נכונה: ב — ה-CPU עובד מהר, אבל חייב לחכות ל-Bus לכל הוראה ונתון. הפתרון: Cache.
שאלה א׳.3
מה היה החידוש של ארכיטקטורת Von Neumann לעומת מחשבים קודמים?
✓ תשובה נכונה: ג — לפני Von Neumann, "תוכניות" נכתבו לחומרה — היית צריך לשנות כבלים פיזיים. Von Neumann אמר: שמור את ההוראות בזיכרון כמו נתונים רגילים.
// פרק 3
מערכות ספירה: שפת המחשב
מחשבים לא מכירים מספרים כמונו. הם עובדים רק עם שני מצבים: יש חשמל ואין חשמל. כל מחשב מודרני בנוי מטרנזיסטורים — מתגים קטנים: פתוח או סגור, 0 או 1.
3.1 — בינארי (Binary)
מערכת ספירה בבסיס 2 — רק 0 ו-1. כל ספרה בינארית נקראת bit.
הרחבה טבלת ספירה וכוחות 2 ›
דצימלי
בינארי
דצימלי
בינארי
0
0000
8
1000
1
0001
9
1001
2
0010
10
1010
4
0100
15
1111
7
0111
255
11111111
חזקה
ערך
הקס
שימוש נפוץ
2⁰ = 1
1
0x01
ביט יחיד, Flag בסיסי
2⁴ = 16
16
0x10
ספרה הקסדצימלית
2⁷ = 128
128
0x80
ה-MSB (ביט הסימן) ב-byte
2⁸ = 256
256
0x100
כמות ערכים ב-byte
2³² = 4G
4,294,967,296
0x100000000
מרחב כתובות 32 ביט
המרה בינארי → דצימלי: כפל כל ביט בכוח 2 לפי מיקומו (מ-0 בצד ימין), ואחר כך חבר.
✓ תשובה נכונה: א) — CMP EAX,EBX: EAX=EBX=10 → Zero Flag=1. JE קופצת ל-0x2020. ADD EAX,100: EAX=10+100=110.
// פרק 6
היררכיית הזיכרון
אין "זיכרון מושלם". הפיזיקה מכתיבה tradeoff ברור: מהיר = קטן ויקר, איטי = גדול וזול. הפתרון: פירמידה של זיכרונות.
רמה
מהירות
גודל טיפוסי
אנלוגיה למטבח
רגיסטרים
~0.3 ns
< 1 KB
הידיים
L1 Cache
~1 ns
32–64 KB
פינת הכיריים
L2 Cache
~3-10 ns
256 KB–1 MB
השיש
L3 Cache
~10-40 ns
4–32 MB
המדף מעל השיש
RAM
~50-100 ns
4–64 GB
השולחן הגדול
SSD
~0.1 ms
256 GB–4 TB
המדפים
HDD
~10 ms
1–16 TB
המחסן
הרחבה Cache Hit vs Cache Miss ›
כש-CPU צריך נתון, הוא בודק תחילה ב-L1. אם מצא — Cache Hit. אם לא — בודק ב-L2, L3, RAM. Cache Miss (לL3 ו-RAM) הוא יקר מאוד — ה-CPU ממתין מאות מחזורי שעון.
עיקרון המיקום (Locality Principle):
מיקום זמני: אם גשת לנתון עכשיו — סביר שתגיע אליו שוב בקרוב
מיקום מרחבי: אם גשת לכתובת X — סביר שתגש ל-X+1, X+2 בקרוב
✓ תשובה נכונה: א) — Cache קיים כי ה-RAM איטי מדי. ה-CPU מנסה לשמור נתונים שישמשו בקרוב ב-Cache. שניהם נדיפים (מתאפסים בכיבוי).
שאלה ב׳.12 [בינוני]
מדוע תוכנית שעוברת על מערך גדול איטית יותר מאותה תוכנית על מערך קטן?
✓ תשובה נכונה: ב) — Cache Miss = המתנה ל-RAM (50-100ns לעומת 1ns ל-L1). מערך קטן → נכנס ל-L1/L2 → Cache Hits. מערך גדול → Cache Misses × מיליוני גישות = פגיעה ענקית.
// פרק 7
פעולות ביטוויז (Bitwise Operations)
פעולות ביטוויז מבוצעות ישירות על הביטים של מספרים. הן הפעולות הבסיסיות של ה-ALU — מהירות מאוד, ומופיעות בכל מקום בסייבר.
AND — כיבוי ביטים
תוצאה 1 רק אם שני הביטים הם 1. שימוש: Masking, בדיקת ביטים.
📝 דוגמה: 0b11110000 AND 0b10101010
11110000
& 10101010
──────────
10100000 → ה-AND "כיבה" את הביטים שלא רצינו
OR — הדלקת ביטים
תוצאה 1 אם לפחות אחד מהביטים הוא 1. שימוש: הדלקת ביטים, שילוב דגלים.
XOR — הפיכה ↔ הצפנה
תוצאה 1 אם הביטים שונים. תכונה מיוחדת: A XOR K XOR K = A — ניתן לבטל על ידי XOR שוב.
📝 הצפנת XOR
הצפן = data XOR key
פיצוח = cipher XOR key = data ← XOR הפיכה!
NOT — היפוך
הופך כל ביט: 1→0 ו-0→1. שים לב: A + NOT(A) = 255 תמיד (לבייט אחד).
AND עם מסכה = בידוד ביטים, OR = הדלקה, XOR = היפוך (וגם השוואה: a^a=0), הזזה שמאלה ב-n = כפל ב-2 בחזקת n. שאלות דגלים (Flags) במבחן כמעט תמיד נפתרות עם AND למסכה.
// פרק 8
Big Endian ו-Little Endian
כשמאחסנים מספר שגדול מבייט אחד בזיכרון, עולה שאלה: באיזה סדר שומרים את הבייטים? התשובה תלויה בארכיטקטורה.
לדוגמה, המספר 0x12345678 הוא 4 בייטים בכתובות 0x1000–0x1003:
נראה "הפוך" — אבל זה תקין! זה Little Endian בפעולה.
✏
תרגול עצמי
2 שאלות
שאלה ב׳.9 [בינוני]
מחשב Intel x86. המספר 0x12345678 נשמר בכתובת 0x1000. מה הבייט בכתובת 0x1000?
✓ תשובה נכונה: ג) 0x78 — Little Endian = LSB קודם. 0x12345678: LSB=0x78. תשובה א' = Big Endian (שגוי לIntel).
שאלה ו׳5 — Hex Dump
כתובת 0x1010 מכילה: 41 41 41 41 (0x41='A' ב-ASCII). מה ניתן להסיק בהקשר של Buffer Overflow?
✓ תשובה נכונה: א) — 0x41414141 ב-EIP = pattern קלאסי של ניסיון ניצול. כשרואים EIP=0x41414141 ב-crash — זהו ניסיון Buffer Overflow!
🎯 דגש למבחן
x86 הוא Little Endian: הבית הנמוך נשמר ראשון. הערך 0x12345678 יופיע בזיכרון כ-78 56 34 12. בפרוטוקולי רשת ההיפך (Big Endian, Network Order) — ומכאן פונקציות htons/htonl.
// פרק 9
מספרים שליליים: Two's Complement
כיצד מייצגים מספר שלילי ב-0 ו-1? הפתרון: Two's Complement — NOT(המספר) + 1.
מספר שלילי מיוצג כהיפוך כל הביטים ועוד 1. הביט העליון הוא ביט הסימן: ב-8 ביט הטווח הוא 128- עד 127. חיסור במעבד מתבצע כחיבור של המשלים ל-2 — ולכן אין פקודת חיסור נפרדת ברמת החומרה. במבחן: זהו 0xFF כ-1- בטיפוס signed char, ו-255 בטיפוס unsigned.
// תרגול נוסף
תרגול נוסף — בינארי, Hex ו-Endianness
שאלות העשרה נוספות לחיזוק החומר של השיעור — באותו פורמט בחירה של הקורס.
✓ תשובה נכונה: א — 11111111 AND 00001111 = 00001111 = 0x0F. שימוש נפוץ: Masking — חילוץ ה-nibble הנמוך של בית.
// אתגר מעשי
אתגר מעשי — ארכיטקטורה וייצוג בינארי
שיא השיעור: לא לזהות תשובה — לבנות ולתקן. פתרו את משימת החובה, ואז את האתגר שמעליה. הגשה נבדקת אוטומטית מול מקרי-קצה נסתרים.
T1 · מתחיל100 נק'~8 דק'algorithmic
משקל האמינג — ספירת ביטים דלוקים
כל מספר חי בזיכרון כרצף ביטים. נתון מספר שלם אי-שלילי n. החזר את מספר הביטים הדלוקים (1) בייצוגו הבינארי — 'משקל האמינג'. פתרון יעיל אינו סורק את כל 64 הסיביות אלא מדלג ישירות מביט דלוק אחד לבא אחריו.
דוגמאות
count_set_bits(0)→0
count_set_bits(7)→3
count_set_bits(8)→1
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס משקל האמינג — ספירת ביטים דלוקים ›
def count_set_bits(n: int) -> int:
c = 0
while n:
n &= n - 1 # מכבה את הביט הדלוק הנמוך ביותר
c += 1
return c
T2 · בסיסי200 נק'~20 דק'algorithmic
מחבר בינארי Ripple-Carry (O(n))
בנה את פעולת החיבור של ה-ALU במו ידיך. נתונות שתי מחרוזות בינאריות a ו-b (תווי '0'/'1' בלבד, אורכים שרירותיים ואולי שונים, אפסים מובילים אפשריים). החזר את סכומן כמחרוזת בינארית ללא אפסים מובילים (פרט ל-"0" עצמו). חובה O(n): קלט של מיליון ביטים חייב לרוץ בזמן. בנייה תמימה שמשרשרת תו בראש המחרוזת בכל צעד היא O(n²) ותיפסל ב-timeout.
דוגמאות
add_binary('1','1')→'10'
add_binary('101','11')→'1000'
add_binary('0','0')→'0'
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס מחבר בינארי Ripple-Carry (O(n)) ›
def add_binary(a: str, b: str) -> str:
i, j, carry, out = len(a) - 1, len(b) - 1, 0, []
while i >= 0 or j >= 0 or carry:
s = carry
if i >= 0: s += a[i] == '1'; i -= 1
if j >= 0: s += b[j] == '1'; j -= 1
out.append('1' if (s & 1) else '0')
carry = s >> 1
out.reverse() # append+reverse = O(n) (לא שרשור מלפנים!)
res = ''.join(out).lstrip('0')
return res if res else '0'
// סיכום
כל מה שלמדנו: כיצד מופיע בגאמא?
הגענו לסוף השיעור. בואו נסגור מעגל ונראה איך כל נושא מתחבר ישירות לשלבי המיון.
נושא
שלב מיון
כיצד מופיע
בינארי ↔ הקס
שאלון + כנס
'כמה הוא 0x7F?', 'כמה ביטים צריך ל-1000?'
רגיסטרי CPU
מבחן Assembly
כל שאלת Assembly: EAX, EIP, ESP, EBP
Fetch-Decode-Execute
Assembly + Black Box
הבנת זרימת תוכנית, מה EIP מחזיק
היררכיית זיכרון
מבחן C + Assembly
Stack/Heap, עלות גישה לזיכרון, Buffer Overflow
Bitwise
Assembly + פרוטוקול + CTF
TCP flags, הצפנות XOR, masks ב-Assembly
Little Endian
Assembly + Wireshark + CTF
קריאת dump זיכרון, ניתוח packets
Two's Complement
Assembly + מבחן C
signed vs unsigned, overflow bugs, -1 = 0xFFFFFFFF
✓מה למדנו בשיעור 1
מחשב = מכונה לביצוע רצף הוראות. ארכיטקטורת Von Neumann = CPU + זיכרון + I/O
בינארי = בסיס 2. הקסדצימלי = בסיס 16, 4 ביטים לספרה
CPU = Control Unit + ALU + Registers. EIP = כתובת ההוראה הבאה
Little Endian (Intel): LSB בכתובת הנמוכה. Big Endian (רשת): MSB קודם
Two's Complement: -1 = 0xFF, -128 = 0x80 (בבייט)
🎯 השיעור הבא
שיעור 2 — מערכות הפעלה: Kernel, תהליכים ומרחבי זיכרון
✏
תרגול סיום — שאלות אינטגרציה
3 שאלות
שאלה ב׳.18 [קשה]
פקודת ADD EAX, 5 מבוצעת. EAX = 0xFFFFFFFB לפני. מה ערך EAX אחרי?
✓ תשובה נכונה: א) 0x00000000 — 0xFFFFFFFB = -5 (signed). -5+5=0. ב-32 ביטים: carry נופל מחוץ לטווח. תוצאה = 0.
שאלה ב׳.16 [קשה]
מהי תוצאת השרשרת: ((0xFF AND 0x0F) << 2) OR 0b10000000?
✓ תשובה נכונה: א) 0b10111100 — שלב 1: 0xFF AND 0x0F = 0x0F = 0b00001111. שלב 2: <<2 = 0b00111100. שלב 3: OR 0b10000000 = 0b10111100.
שאלה ח׳1 — ניתוח עמוק
מדוע שינוי ה-EIP בזמן ריצה מהווה חולשת אבטחה קריטית?
✓ תשובה נכונה: ג) — Buffer Overflow דורס את ה-Return Address על ה-Stack. כשהפונקציה מסיימת, ה-CPU "חוזר" לכתובת שבחר התוקף — ומריץ את קודו.
✓חוקי ברזל של השיעור
בית = 8 ביט. שני תווי Hex = בית אחד בדיוק
המעבד לא "מבין" משמעות — הפרשנות (signed/unsigned) היא של המתכנת
0xFF = 255 ב-unsigned, ו-1- ב-signed (משלים ל-2)
x86 = Little Endian; רשת = Big Endian. תמיד לוודא מי הצד
XOR עם עצמו מאפס — כלי הבסיס של הצפנה פשוטה ושל ניקוי רגיסטר
הזזה שמאלה/ימינה = כפל/חילוק בחזקות 2, וזול בהרבה מפעולת כפל
מחזור Fetch-Decode-Execute הוא הבסיס לכל ניתוח Assembly בהמשך
שאלות תרגול ותשובות (7)
שאלה 1 · לפי ארכיטקטורת Von Neumann, היכן נשמרות הפקודות של התוכנית?
א. בזיכרון הראשי, יחד עם הנתונים
ב. בזיכרון נפרד מהנתונים
ג. ברגיסטרים של המעבד בלבד
ד. בדיסק בלבד, ולא בזיכרון
תשובה: א
החידוש של Von Neumann: קוד ונתונים חיים באותו זיכרון. מכאן גם החולשה — אם תוקף מזריק נתונים למקום שממנו המעבד קורא פקודות, הנתונים יורצו כקוד. זהו הבסיס ל-Buffer Overflow.
שאלה 2 · מהו סדר השלבים במחזור הפעולה של המעבד?
א. Execute → Fetch → Decode
ב. Fetch → Decode → Execute
ג. Decode → Execute → Fetch
ד. Fetch → Execute → Decode
תשובה: ב
שליפה (Fetch) של הפקודה מהכתובת שב-PC, פענוח (Decode) לזיהוי הפעולה והאופרנדים, ולבסוף ביצוע (Execute). ה-PC מתקדם אוטומטית — וקפיצה היא בסך הכול כתיבה ל-PC.
שאלה 3 · מה מייצג הרגיסטר PC (Program Counter)?
א. את תוצאת הפעולה האחרונה
ב. את כתובת הפקודה הבאה לביצוע
ג. את כמות הזיכרון הפנוי
ד. את מספר הפקודות שבוצעו
תשובה: ב
ה-PC (או RIP ב-64 ביט) מחזיק את כתובת הפקודה הבאה. שליטה ב-PC = שליטה בזרימת התוכנית, ולכן כל מטרת ניצול חולשה קלאסי היא לדרוס אותו.
שאלה 4 · מדוע קיימת היררכיית זיכרון (רגיסטרים → Cache → RAM → דיסק)?
א. כדי לאזן בין מהירות לעלות ולנפח
ב. כדי להצפין את הנתונים בשכבות
ג. כדי לאפשר ריצת כמה מערכות הפעלה
ד. כדי למנוע גישה של תוכניות לזיכרון
תשובה: א
ככל שהזיכרון מהיר יותר הוא יקר וקטן יותר. רגיסטר נגיש תוך מחזור שעון בודד, RAM עשרות עד מאות מחזורים, ודיסק פי אלפים. ההיררכיה מאפשרת מהירות ממוצעת גבוהה בעלות סבירה.
שאלה 5 · מה מבצעת הפעולה x & 0x0F?
א. מאפסת את הערך כולו
ב. משאירה רק את ארבעת הביטים התחתונים
ג. הופכת את כל הביטים
ד. מכפילה את הערך בשש עשרה
תשובה: ב
המסכה 0x0F היא 00001111. פעולת AND מאפסת כל ביט שמולו 0 ומשאירה את מה שמולו 1 — ולכן זו הדרך הסטנדרטית לבודד שדה או דגל מתוך בית.
שאלה 6 · הערך 0x12345678 נכתב לזיכרון במערכת Little Endian. מה סדר הבתים בפועל?
א. 12 34 56 78
ב. 78 56 34 12
ג. 34 12 78 56
ד. 56 78 12 34
תשובה: ב
ב-Little Endian (x86) הבית הנמוך ביותר נשמר בכתובת הנמוכה ביותר, ולכן הסדר מתהפך. בפרוטוקולי רשת משתמשים ב-Big Endian — ולכן צריך המרה עם htons/htonl.
שאלה 7 · מהו הערך העשרוני של 0xFF בטיפוס signed char בן 8 ביט?
א. 255
ב. 1-
ג. 127
ד. 128-
תשובה: ב
ב-signed char הביט העליון הוא ביט הסימן. 0xFF = 11111111, ולפי משלים ל-2 זהו 1-. אותם בתים עצמם ב-unsigned char שווים 255 — ההבדל הוא בפרשנות בלבד.