שיתוף | יכול להיות שבניתי את התוכנה הכי קטנה בעולם?
-
לא עובד לי

עריכה: זה היה רק במחשב מסויים - במחשב שלי עובד מצויין
@יאיר-דניאל אני בודק את זה
אולי מדובר ב build לא תואם אבל מעניין -
@יאיר-דניאל אני בודק את זה
אולי מדובר ב build לא תואם אבל מעניין@מתכנת-חובב עבד להפליא כבר בפעם הראשונה

-
@מתכנת-חובב מאוד יפה!
אהבתי את הרעיון. -
@מתכנת-חובב עבד להפליא כבר בפעם הראשונה

-
נחשפתי לאחרונה לעולם של התוכנות הזעירות - אמנות שבה דוחסים שדות בקובץ exe אחד על השני ומצמצמים את הקוד עצמו למינימום ו"עובדים" על ה loader של ווינדוס כמה שאפשר
הגודל המינימלי של התוכנות האלו נכון להיום הוא 268 בתים בגלל דרישות יישור ולכאורה מבנה ה struct שה loader של ווינדוס מחפש לקרוא כשהוא פותח קובץ
הקבצים שראיתי ברשת (האמת שלא חקרתי הרבה) - כל מה שהם עושים היה סך הכל לבצע return ל loader או סתם להגדיר ערך כלשהו ב EAX אבל לא באמת משהו מעניין
אז ישבתי להכין תוכנת hello world שתשב באותו גודל מינימלי והצלחתי אפילו יותר - יש לי 2 בתים ריקים בסוף שהשארתי שם 00 בשביל הריפוד לגודל הנדרש ככה שסך כל הגודל של התוכנה הוא 266 בתים!
הבניה של זה הייתה די מסובכת ולקחה לי כמה שעות של מלחמות עם ווינדוס ואסמבלי ובשלב מסויים גם עם הבינארי עצמו (וגיליתי שלא כזה מסובך לעשות patching ידני ל opcodes)
ממה שבדקתי זאת תוכנת ה hello world הכי קטנה בעולם אבל אולי יש משהו שמנצל אפילו פחות או עושה דברים נוספים (ניסיתי לגרום לו גם לצפצף אבל זה דרש כבר שכתוב של כל ה opcodes וסדר הריצה ואין לי זמן \ כוח לזה עכשיו אבל זה נראה אפשרי) - אם מישהו ימצא משהו טוב יותר אשמח אם הוא יוכל ליידע אותי
אם מעניינים פרטים טכניים על הקובץ והבניה שלו - תוכלו לבקש ואשמח לשתף
בדקתי את הקובץ אצלי - גרסת build 26200.7840 אבל יכול להיות שבעדכוני ווינדוס הבאים זה יישבר
מצורף הקובץ וה dump שלו למי שמתעניין
smallest_hello_world.exeעריכה: אחרי ששמעתי ממשתמשים שהתוכנה קרסה אצלם מתברר שיש גרסאות של ווינדוס שבהם מתבצעות בדיקות שונות ולעשות תוכנה אחת שתעבוד אצל כולם זה חתיכת סיפור
אחרי שסידרתי את עניין ה IAT קפץ עלי רוגזה של בדיקת DRM בגלל דגל debugging לא מאופס (הוא נופל אצלי בדיוק באמצע הקוד...) מקווה שאצליח לסדר את זה
עריכה: סודר
אם קורס אצלכם אשמח שתודיעו לי4D 5A 00 00 50 45 00 00 4C 01 00 00 68 65 6C 6C 6F 20 77 6F 72 6C 64 21 00 00 02 01 0B 01 FF FF FF FF FF 75 73 65 72 33 32 00 00 FF 88 00 00 00 6D 69 74 6D 2E 74 6F 70 00 00 40 00 04 00 00 00 04 00 00 00 06 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 0C 01 00 00 6F 00 00 00 00 00 00 00 02 00 00 00 00 00 10 00 00 10 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BF A8 A2 4D BC EB 31 00 00 00 00 00 64 A1 30 00 00 00 8B 40 0C 8B 40 14 8B 00 8B 00 8B 68 10 BF 8E 4E 0E EC E8 23 00 00 00 68 23 00 40 00 FF D0 95 EB CD 90 00 00 00 00 E8 11 00 00 00 6A 00 68 30 00 40 00 68 0C 00 40 00 6A 00 FF D0 C3 8B 55 3C 8B 54 15 78 01 EA 8B 4A 18 8B 5A 20 01 EB 49 8B 34 8B 01 EE 52 31 C0 99 AC 84 C0 74 07 C1 CA 0D 01 C2 EB F4 39 FA 5A 75 E5 8B 5A 24 01 EB 0F B7 0C 4B 8B 5A 1C 01 EB 03 2C 8B 89 E8 C3 00 00
עריכה: יצאה גרסה מעודכנת וסופית
https://mitmachim.top/topic/93863/שיתוף-התוכנה-הכי-קטנה-בעולם-עכשיו-גם-מנגנת@מתכנת-חובב
בבתים ששלחת:
6D 69 74 6D 2E 74 6F 70 מתרגם ל-mitm.top. ! ! !זה מופיע מיד אחרי המחרוזת hello world!, מה שמחזק את ההשערה שמדובר בתוכנית דוגמה קטנה שנכתבה על ידי אחד מחברי הקהילה שם כדי להדגים יכולות תכנות ב-Assembly או מניפולציה של קבצי EXE.
-
@מתכנת-חובב
בבתים ששלחת:
6D 69 74 6D 2E 74 6F 70 מתרגם ל-mitm.top. ! ! !זה מופיע מיד אחרי המחרוזת hello world!, מה שמחזק את ההשערה שמדובר בתוכנית דוגמה קטנה שנכתבה על ידי אחד מחברי הקהילה שם כדי להדגים יכולות תכנות ב-Assembly או מניפולציה של קבצי EXE.
@אביגדור-ברמן מה אתה בא לומר?
די ברור שזה מה שרציתי לעשות -
@אביגדור-ברמן מה אתה בא לומר?
די ברור שזה מה שרציתי לעשות@מתכנת-חובב זה מגניב!
(אני לא מבין בזה, זה הגברת בינה...) -
מ מתכנת חובב התייחס לנושא זה
-
גיפיטי מסביר מה הולך שם בבינארי - בספויילר
הסבר טכני תמציתי, שלב-אחר-שלב, למה שהקובץ עושה בפועל:
- טעינה ע״י ה-Loader
תחילת הקובץ מכילה חתימות MZ ו-PE\0\0.
ה-Loader של Windows מזהה זאת כ-PE, ממפה את ה-Image לזיכרון לפי ה-headers ומקפיץ ל-EntryPoint.
- אין Import Table רגילה
ה-DataDirectory של Imports ריק/לא בשימוש.
לכן אין IAT סטטית.
במקום זאת הקוד פותר APIs בזמן ריצה (manual resolving).
- קבלת כתובת בסיס של מודולים (גישה ל-PEB)
ב-EntryPoint מתבצעת גישה ל-PEB דרך ה-segment register (ב-x86 דרך FS:[0x30]).
מהלך טיפוסי:
קריאה ל-PEB
כניסה ל-PEB_LDR_DATA
מעבר על רשימת InMemoryOrderModuleList
כך מאתרים את:
kernel32.dll (כבר טעון בתהליך)
- מציאת Export Table של kernel32
לאחר שיש BaseAddress של kernel32:
קריאת offset e_lfanew מתוך DOS header
קפיצה ל-NT Headers
גישה ל-DataDirectory → Export Table
חישוב כתובות:
AddressOfNames
AddressOfFunctions
AddressOfNameOrdinals
- לולאת Hash על שמות פונקציות
הקוד עובר על כל שם פונקציה ב-Export Table:
מבנה אופייני שנראה אצלך:
AC
84 C0
74 07
C1 CA 0D
01 C2זו לולאה שמבצעת:
קריאה תו-תו
rotate right
הוספת ערך
יצירת hash
כאשר ה-hash תואם לערך קשיח שמקודד בקוד → נמצאה הפונקציה.
בדרך זו מאתרים:
LoadLibraryA
GetProcAddress
- טעינת user32.dll
אחרי שיש כתובת של LoadLibraryA:
הקוד קורא לה עם המחרוזת "user32"
מתקבלת כתובת בסיס של user32.dll
- מציאת MessageBoxA
שוב מתבצע:
סריקת Export Table של user32
חישוב hash
התאמה ל-MessageBoxA
קבלת ה-function pointer
- קריאה ל-MessageBoxA
ה-stack נבנה ידנית:
סדר הפרמטרים (stdcall):
push 0 ; hWnd
push "hello world!" ; lpText
push "hello world!" ; lpCaption (או דומה)
push 0 ; uType
call MessageBoxAלכן מתקבלת תיבת הודעה עם הטקסט.
- יציאה
לאחר הקריאה:
מתבצע ret או קריאה ל-ExitProcess (גם כן נפתר דינמית או פשוט חזרה ל-loader).
למה זה עובד בלי Import Table?
כי:
הכל מחושב בזמן ריצה.
אין תלות ב-IAT.
ה-Loader רק צריך למפות את ה-image ולהריץ את ה-EntryPoint.
מה זה בפועל?
PE מינימלי עם:
API hashing
Manual export resolving
ללא imports סטטיים
ללא sections מורכבות
זו טכניקה נפוצה בקבצים קומפקטיים מאוד וב-shellcode.
פירוט ממוקד לפי הרצף הבינארי ששלחת, משלב ה-EntryPoint והלאה (x86):
שלב 1 — כניסה וניווט ל-Export Table של kernel32
הרצף:
8B 55 3C
8B 54 15 78
01 EAפירוק:
8B 55 3C
mov edx, [ebp+3Ch]
קריאת e_lfanew (offset ל-NT headers).8B 54 15 78
mov edx, [ebp+edx+78h]
גישה ל-DataDirectory → Export Table.01 EA
add edx, ebp
המרה מ-RVA לכתובת מוחלטת.עכשיו EDX מצביע ל-IMAGE_EXPORT_DIRECTORY.
שלב 2 — שליפת טבלאות ה-Export
הרצף:
8B 4A 18
8B 5A 20
01 EB
49פירוק:
8B 4A 18
mov ecx, [edx+18h]
NumberOfNames.8B 5A 20
mov ebx, [edx+20h]
AddressOfNames (RVA).01 EB
add ebx, ebp
EBX עכשיו מצביע למערך שמות.49
dec ecx
התחלת לולאה.שלב 3 — לולאת hash על שמות פונקציות
הרצף:
8B 34 8B
01 EE
52
31 C0
99
AC
84 C0
74 07
C1 CA 0D
01 C2
EB F4פירוק לוגי:
8B 34 8B
mov esi, [ebx+ecx*4]
קבלת RVA של שם פונקציה.01 EE
add esi, ebp
המרה לכתובת.31 C0
xor eax,eax
hash = 0.לולאת תווים:
AC → lodsb (טעינת תו)
84 C0 → test al,al (סוף מחרוזת?)
74 07 → אם 0 → יציאה
C1 CA 0D → ror edx,13 (rotate)
01 C2 → add edx,eax (עדכון hash)
EB F4 → חזרה ללולאה
זו לולאת hashing טיפוסית לזיהוי פונקציות בלי להשאיר שמות גלויים.
שלב 4 — התאמת hash
הרצף:
39 FA
5A
75 E539 FA → cmp edx, edi (השוואת hash לערך קשיח)
75 E5 → אם לא שווה → המשך לולאה
כאשר נמצא hash תואם → ממשיכים לשליפת הכתובת.
שלב 5 — שליפת כתובת פונקציה
הרצף:
8B 5A 24
01 EB
0F B7 0C 4B
8B 5A 1C
01 EB
03 2C 8Bפירוק:
8B 5A 24
AddressOfNameOrdinals0F B7 0C 4B
movzx ecx, word [ebx+ecx*2]
קבלת ordinal8B 5A 1C
AddressOfFunctions03 2C 8B
הוספת offset של הפונקציהבסיום — מתקבל pointer לפונקציה (למשל LoadLibraryA).
שלב 6 — קריאה ל-LoadLibraryA
בהמשך מופיע:
6A 00
68 30 00 40 00
68 0C 00 40 00
6A 00
FF D0פירוק:
push 0
push offset string
push offset string
push 0
FF D0 → call eax
EAX מכיל pointer לפונקציה שנפתרה.
כאן נטענת "user32".
שלב 7 — פתרון MessageBoxA
אותו תהליך hash מתבצע על export table של user32.dll עד למציאת MessageBoxA.
שלב 8 — קריאה ל-MessageBoxA
Stack נבנה כך:
push 0
push "hello world!"
push "hello world!"
push 0
call MessageBoxAולכן מתקבלת תיבת הודעה עם המחרוזת שמופיעה בקובץ:
68 65 6C 6C 6F 20 77 6F 72 6C 64 21
מה זה בפועל?אין Import Table
אין IAT
כל ה-API נפתר דינמית
hashing כדי להימנע משמות גלויים
PE מינימלי עם loader ידני
זו טכניקת manual export resolving מלאה.
פירוק מבנה ה-PE עצמו — למה ה-Loader עדיין מוכן להריץ אותו למרות שהוא מינימלי מאוד.
- DOS Header
התחלה:
4D 5A ; "MZ"
...
3C ?? ?? ?? ?? ; e_lfanew4D 5A = חתימת DOS תקינה.
ב-offset 0x3C נמצא e_lfanew — מצביע ל-NT Headers.
ה-DOS stub כמעט לא קיים — אבל זה לא קריטי. ה-Loader צריך רק:
חתימה תקינה
offset חוקי ל-PE
- NT Headers
בכתובת שמצביע e_lfanew:
50 45 00 00 ; "PE\0\0"
4C 01 ; Machine = 0x14C (x86)
01 00 ; NumberOfSections = 1זה מספיק כדי להיחשב PE תקני ל-32 ביט.
- Optional Header (PE32)
החתימה:
0B 01 ; PE32 (לא PE32+)
שדות קריטיים שה-Loader חייב:
AddressOfEntryPoint
ImageBase
SectionAlignment
FileAlignment
SizeOfImage
SizeOfHeaders
Subsystem
גם אם הערכים מינימליים מאוד — כל עוד הם עקביים לוגית, ה-Loader ימשיך.
- DataDirectory
Import Directory כאן ריק או לא שמיש.
זה חוקי.
Windows לא מחייב Import Table — רק אם יש אחת, הוא יטפל בה.
במקרה שלך:
אין IAT שימושית
לכן אין צורך ב-relocation imports
הכל נעשה בקוד
- Section Table
מוגדרת Section אחת בלבד (למשל .text או אפילו בלי שם משמעותי).
ה-Loader צריך:
VirtualAddress
VirtualSize
SizeOfRawData
PointerToRawData
Characteristics עם:
IMAGE_SCN_MEM_EXECUTE
IMAGE_SCN_MEM_READ
אם ה-Section מסומנת executable — זה מספיק.
- מיפוי לזיכרון
בעת הרצה:
Windows מקצה זיכרון בגודל SizeOfImage.
מעתיק את ה-Headers.
מעתיק את ה-Section ל-VirtualAddress.
קופץ ל-ImageBase + AddressOfEntryPoint.
אין צורך ב-IAT כי אין Imports לעבד.
- למה אין צורך ב-Relocations?
אם:
ImageBase תואם למה שה-Loader מצליח להקצות
אוהקוד משתמש ב-RVA יחסיים
אז relocation table לא חובה.
ב-PE מינימליים לעיתים:
פשוט מניחים ImageBase סטנדרטי
ואם הוא פנוי — הכל עובד
- למה Windows לא “דורש יותר”?
ה-Loader בודק מינימום:
חתימות תקינות
מבנה NT headers סביר
Section Table חוקית
EntryPoint בתוך טווח section executable
זהו.
כל השאר אופציונלי.
סיכום מבני
הקובץ שלך הוא:
DOS header מינימלי
NT headers תקינים
Section אחת
ללא Import Table
ללא IAT
ללא Relocations משמעותיות
EntryPoint שמבצע manual resolving
לכן:
ה-Loader עושה רק mapping → קפיצה ל-EntryPoint → ומשם הכל קורה בקוד שלך.
@מתכנת-חובב - כמה אחוז ממה שהוא כתב נכון?
נ.ב. אני הבנתי רק 3 אחוז ממה שהוא כתב, (וגם זה גוזמה)
-
גיפיטי מסביר מה הולך שם בבינארי - בספויילר
הסבר טכני תמציתי, שלב-אחר-שלב, למה שהקובץ עושה בפועל:
- טעינה ע״י ה-Loader
תחילת הקובץ מכילה חתימות MZ ו-PE\0\0.
ה-Loader של Windows מזהה זאת כ-PE, ממפה את ה-Image לזיכרון לפי ה-headers ומקפיץ ל-EntryPoint.
- אין Import Table רגילה
ה-DataDirectory של Imports ריק/לא בשימוש.
לכן אין IAT סטטית.
במקום זאת הקוד פותר APIs בזמן ריצה (manual resolving).
- קבלת כתובת בסיס של מודולים (גישה ל-PEB)
ב-EntryPoint מתבצעת גישה ל-PEB דרך ה-segment register (ב-x86 דרך FS:[0x30]).
מהלך טיפוסי:
קריאה ל-PEB
כניסה ל-PEB_LDR_DATA
מעבר על רשימת InMemoryOrderModuleList
כך מאתרים את:
kernel32.dll (כבר טעון בתהליך)
- מציאת Export Table של kernel32
לאחר שיש BaseAddress של kernel32:
קריאת offset e_lfanew מתוך DOS header
קפיצה ל-NT Headers
גישה ל-DataDirectory → Export Table
חישוב כתובות:
AddressOfNames
AddressOfFunctions
AddressOfNameOrdinals
- לולאת Hash על שמות פונקציות
הקוד עובר על כל שם פונקציה ב-Export Table:
מבנה אופייני שנראה אצלך:
AC
84 C0
74 07
C1 CA 0D
01 C2זו לולאה שמבצעת:
קריאה תו-תו
rotate right
הוספת ערך
יצירת hash
כאשר ה-hash תואם לערך קשיח שמקודד בקוד → נמצאה הפונקציה.
בדרך זו מאתרים:
LoadLibraryA
GetProcAddress
- טעינת user32.dll
אחרי שיש כתובת של LoadLibraryA:
הקוד קורא לה עם המחרוזת "user32"
מתקבלת כתובת בסיס של user32.dll
- מציאת MessageBoxA
שוב מתבצע:
סריקת Export Table של user32
חישוב hash
התאמה ל-MessageBoxA
קבלת ה-function pointer
- קריאה ל-MessageBoxA
ה-stack נבנה ידנית:
סדר הפרמטרים (stdcall):
push 0 ; hWnd
push "hello world!" ; lpText
push "hello world!" ; lpCaption (או דומה)
push 0 ; uType
call MessageBoxAלכן מתקבלת תיבת הודעה עם הטקסט.
- יציאה
לאחר הקריאה:
מתבצע ret או קריאה ל-ExitProcess (גם כן נפתר דינמית או פשוט חזרה ל-loader).
למה זה עובד בלי Import Table?
כי:
הכל מחושב בזמן ריצה.
אין תלות ב-IAT.
ה-Loader רק צריך למפות את ה-image ולהריץ את ה-EntryPoint.
מה זה בפועל?
PE מינימלי עם:
API hashing
Manual export resolving
ללא imports סטטיים
ללא sections מורכבות
זו טכניקה נפוצה בקבצים קומפקטיים מאוד וב-shellcode.
פירוט ממוקד לפי הרצף הבינארי ששלחת, משלב ה-EntryPoint והלאה (x86):
שלב 1 — כניסה וניווט ל-Export Table של kernel32
הרצף:
8B 55 3C
8B 54 15 78
01 EAפירוק:
8B 55 3C
mov edx, [ebp+3Ch]
קריאת e_lfanew (offset ל-NT headers).8B 54 15 78
mov edx, [ebp+edx+78h]
גישה ל-DataDirectory → Export Table.01 EA
add edx, ebp
המרה מ-RVA לכתובת מוחלטת.עכשיו EDX מצביע ל-IMAGE_EXPORT_DIRECTORY.
שלב 2 — שליפת טבלאות ה-Export
הרצף:
8B 4A 18
8B 5A 20
01 EB
49פירוק:
8B 4A 18
mov ecx, [edx+18h]
NumberOfNames.8B 5A 20
mov ebx, [edx+20h]
AddressOfNames (RVA).01 EB
add ebx, ebp
EBX עכשיו מצביע למערך שמות.49
dec ecx
התחלת לולאה.שלב 3 — לולאת hash על שמות פונקציות
הרצף:
8B 34 8B
01 EE
52
31 C0
99
AC
84 C0
74 07
C1 CA 0D
01 C2
EB F4פירוק לוגי:
8B 34 8B
mov esi, [ebx+ecx*4]
קבלת RVA של שם פונקציה.01 EE
add esi, ebp
המרה לכתובת.31 C0
xor eax,eax
hash = 0.לולאת תווים:
AC → lodsb (טעינת תו)
84 C0 → test al,al (סוף מחרוזת?)
74 07 → אם 0 → יציאה
C1 CA 0D → ror edx,13 (rotate)
01 C2 → add edx,eax (עדכון hash)
EB F4 → חזרה ללולאה
זו לולאת hashing טיפוסית לזיהוי פונקציות בלי להשאיר שמות גלויים.
שלב 4 — התאמת hash
הרצף:
39 FA
5A
75 E539 FA → cmp edx, edi (השוואת hash לערך קשיח)
75 E5 → אם לא שווה → המשך לולאה
כאשר נמצא hash תואם → ממשיכים לשליפת הכתובת.
שלב 5 — שליפת כתובת פונקציה
הרצף:
8B 5A 24
01 EB
0F B7 0C 4B
8B 5A 1C
01 EB
03 2C 8Bפירוק:
8B 5A 24
AddressOfNameOrdinals0F B7 0C 4B
movzx ecx, word [ebx+ecx*2]
קבלת ordinal8B 5A 1C
AddressOfFunctions03 2C 8B
הוספת offset של הפונקציהבסיום — מתקבל pointer לפונקציה (למשל LoadLibraryA).
שלב 6 — קריאה ל-LoadLibraryA
בהמשך מופיע:
6A 00
68 30 00 40 00
68 0C 00 40 00
6A 00
FF D0פירוק:
push 0
push offset string
push offset string
push 0
FF D0 → call eax
EAX מכיל pointer לפונקציה שנפתרה.
כאן נטענת "user32".
שלב 7 — פתרון MessageBoxA
אותו תהליך hash מתבצע על export table של user32.dll עד למציאת MessageBoxA.
שלב 8 — קריאה ל-MessageBoxA
Stack נבנה כך:
push 0
push "hello world!"
push "hello world!"
push 0
call MessageBoxAולכן מתקבלת תיבת הודעה עם המחרוזת שמופיעה בקובץ:
68 65 6C 6C 6F 20 77 6F 72 6C 64 21
מה זה בפועל?אין Import Table
אין IAT
כל ה-API נפתר דינמית
hashing כדי להימנע משמות גלויים
PE מינימלי עם loader ידני
זו טכניקת manual export resolving מלאה.
פירוק מבנה ה-PE עצמו — למה ה-Loader עדיין מוכן להריץ אותו למרות שהוא מינימלי מאוד.
- DOS Header
התחלה:
4D 5A ; "MZ"
...
3C ?? ?? ?? ?? ; e_lfanew4D 5A = חתימת DOS תקינה.
ב-offset 0x3C נמצא e_lfanew — מצביע ל-NT Headers.
ה-DOS stub כמעט לא קיים — אבל זה לא קריטי. ה-Loader צריך רק:
חתימה תקינה
offset חוקי ל-PE
- NT Headers
בכתובת שמצביע e_lfanew:
50 45 00 00 ; "PE\0\0"
4C 01 ; Machine = 0x14C (x86)
01 00 ; NumberOfSections = 1זה מספיק כדי להיחשב PE תקני ל-32 ביט.
- Optional Header (PE32)
החתימה:
0B 01 ; PE32 (לא PE32+)
שדות קריטיים שה-Loader חייב:
AddressOfEntryPoint
ImageBase
SectionAlignment
FileAlignment
SizeOfImage
SizeOfHeaders
Subsystem
גם אם הערכים מינימליים מאוד — כל עוד הם עקביים לוגית, ה-Loader ימשיך.
- DataDirectory
Import Directory כאן ריק או לא שמיש.
זה חוקי.
Windows לא מחייב Import Table — רק אם יש אחת, הוא יטפל בה.
במקרה שלך:
אין IAT שימושית
לכן אין צורך ב-relocation imports
הכל נעשה בקוד
- Section Table
מוגדרת Section אחת בלבד (למשל .text או אפילו בלי שם משמעותי).
ה-Loader צריך:
VirtualAddress
VirtualSize
SizeOfRawData
PointerToRawData
Characteristics עם:
IMAGE_SCN_MEM_EXECUTE
IMAGE_SCN_MEM_READ
אם ה-Section מסומנת executable — זה מספיק.
- מיפוי לזיכרון
בעת הרצה:
Windows מקצה זיכרון בגודל SizeOfImage.
מעתיק את ה-Headers.
מעתיק את ה-Section ל-VirtualAddress.
קופץ ל-ImageBase + AddressOfEntryPoint.
אין צורך ב-IAT כי אין Imports לעבד.
- למה אין צורך ב-Relocations?
אם:
ImageBase תואם למה שה-Loader מצליח להקצות
אוהקוד משתמש ב-RVA יחסיים
אז relocation table לא חובה.
ב-PE מינימליים לעיתים:
פשוט מניחים ImageBase סטנדרטי
ואם הוא פנוי — הכל עובד
- למה Windows לא “דורש יותר”?
ה-Loader בודק מינימום:
חתימות תקינות
מבנה NT headers סביר
Section Table חוקית
EntryPoint בתוך טווח section executable
זהו.
כל השאר אופציונלי.
סיכום מבני
הקובץ שלך הוא:
DOS header מינימלי
NT headers תקינים
Section אחת
ללא Import Table
ללא IAT
ללא Relocations משמעותיות
EntryPoint שמבצע manual resolving
לכן:
ה-Loader עושה רק mapping → קפיצה ל-EntryPoint → ומשם הכל קורה בקוד שלך.
@מתכנת-חובב - כמה אחוז ממה שהוא כתב נכון?
נ.ב. אני הבנתי רק 3 אחוז ממה שהוא כתב, (וגם זה גוזמה)
@אביגדור-ברמן בגדול נכון אבל הוא חיסר דברים
בכל אופן הוא כתב את זה כל כך לא ברור שלא יודע אם אני הייתי מבין את זה...
תעבור לג'מיני הוא הרבה יותר טוב להסביר דברים מורכבים

