על כלבים, חתולים וכלבים וחתולים: איך אילפתי כלבות רוצחות חתולים לאהוב חתול: פושקין בתקופת הטיפוס על העץ... יש לנו בבית שלוש כלבות שרוצחות חתולים. יותר מפעם אחת הרמתי גופות של חתולים אומללים שנקלעו לחצר המגודרת שלנ...
הבלוג של מיכאל האפרתי
החיים, אבטחת מידע, ומה שבינהם
יום שלישי, 24 ביוני 2014
יום חמישי, 20 במרץ 2014
יום שלישי, 25 בספטמבר 2012
נפרצו 50 אתרים בישראל
קבוצת האקרים טורקיים הפילה לאחרונה 50 אתרים ישראלים.
הם כתבו על כך בדף הפייסבוק שלהם
בעליו של אחד האתרים פנה אלי בבקשת עזרה דחופה אותה נתתי בשמחה. רוב האתרים ברשימה (אם לא כולם) מאוכסנים בשרתים של נט ויזיון. בשל סיבות טכניות (ואחרות) לא ניתן היה לקבל מהם סיוע ממשי. הם שינו את הסיסמה אולם לא עלה בידם לשחזר את תוכן האתר לפני הפריצה. האתר הפרוץ הוביל לדף בודד ובו התוכן והתמונות הבאות:
ברור ש-50 האתרים נפרצו בהעדר אמצעי אבטחה מינימליים. לאחר הפריצה, הקשיחה חברת נט ויזיון את הכניסה לשרת, וכך הפך כל נסיון לסייע לקשה יותר. על מנת להכנס לשרת נדרש ממני לתת את כתובת ה-IP שלי, לקבל אישור לכניסה מכתובת זו, ורק אז להכנס. למה חושבים על זה רק אחרי שאתרים נפרצים? (על זה נאמר: too little. Too late). הגבלה כזו הייתה מונעת את הפריצה, ולאחר הפריצה האטה את הסרת דברי הנאצה.
לעומת זאת, לא נראה פתרון מהכיוון הישראלי. זה היה מתסכל. חשבתי שזה עניין של דקות. כבר נראה יותר הגיוני לפרוץ מחדש לאתר כדי להחליף פריצה אחת (של הטורקים) בפריצה חדשה (שלנו).... בסופו של דבר (יום למחרת) לא היה צורך לפרוץ. נט ויזיון הצליחו לסגור את האתר (אם כי לא לשחזר אותו), וזה מוביל לחלק החשוב: איך למנוע פריצה.
2. החליפו את הסיסמאות אחת לחודש.
3. השתמשו בסטנדרטי קידוד שימנעו ככל האפשר פריצה באמצעות SQL Injection .
4. הגדירו את הכניסה לאתר באופן שמתיר כניסה אך ורק מכתובת (או מספר כתובות) IP, וחוסמת את הכניסה מכתובות אחרות. לחליפין, ניתן לחסום גישה ממדינות מסויימות אולם האקרים יכולים להשתמש בProxie שיתחזה לכתובת מישראל. לעומת זאת, בלתי אפשרי להתחזות לכתובת IP ספציפית.
5. בצעו גיבוי על בסיס קבוע והשתמשו בשירותי אכסון הכוללים גיבוי יומי של השרת.
6. הפעילו Firewall ו-Antivirus על השרת, ובצעו עדכונים באופן קבוע (Windows Update).
הם כתבו על כך בדף הפייסבוק שלהם
בעליו של אחד האתרים פנה אלי בבקשת עזרה דחופה אותה נתתי בשמחה. רוב האתרים ברשימה (אם לא כולם) מאוכסנים בשרתים של נט ויזיון. בשל סיבות טכניות (ואחרות) לא ניתן היה לקבל מהם סיוע ממשי. הם שינו את הסיסמה אולם לא עלה בידם לשחזר את תוכן האתר לפני הפריצה. האתר הפרוץ הוביל לדף בודד ובו התוכן והתמונות הבאות:
ברור ש-50 האתרים נפרצו בהעדר אמצעי אבטחה מינימליים. לאחר הפריצה, הקשיחה חברת נט ויזיון את הכניסה לשרת, וכך הפך כל נסיון לסייע לקשה יותר. על מנת להכנס לשרת נדרש ממני לתת את כתובת ה-IP שלי, לקבל אישור לכניסה מכתובת זו, ורק אז להכנס. למה חושבים על זה רק אחרי שאתרים נפרצים? (על זה נאמר: too little. Too late). הגבלה כזו הייתה מונעת את הפריצה, ולאחר הפריצה האטה את הסרת דברי הנאצה.
הסעודים שיתפו פעולה
בשלב מסויים חשבתי להסיר את התמונות, ובדקתי היכן הן מאוכסנות. לא הפתיע לגלות שהם מאוכסנות בחברה היושבת בסעודיה. לא היו לי הרבה ציפיות אולם פניתי לאותה חברה בבקשה להסיר תמונות אלה, בשל היותן מסיתות ופוגעות. התשובה לא אחרה לבוא. למען האמת, תגובת הסעודים הייתה מהירה מתגובת נט ויזיון... וכך נראה האתר אחרי ההסרה:לעומת זאת, לא נראה פתרון מהכיוון הישראלי. זה היה מתסכל. חשבתי שזה עניין של דקות. כבר נראה יותר הגיוני לפרוץ מחדש לאתר כדי להחליף פריצה אחת (של הטורקים) בפריצה חדשה (שלנו).... בסופו של דבר (יום למחרת) לא היה צורך לפרוץ. נט ויזיון הצליחו לסגור את האתר (אם כי לא לשחזר אותו), וזה מוביל לחלק החשוב: איך למנוע פריצה.
איך להגן על אתר בפני פריצה
1. להשתמש בסיסמאות חזקות לממשק עריכת האתר, העלאת תכנים באמצעות FTP (סיסמה נפרדת), התחברות מרחוק לשרת (Remote Desktop) - גם כאן, סיסמה נפרדת.2. החליפו את הסיסמאות אחת לחודש.
3. השתמשו בסטנדרטי קידוד שימנעו ככל האפשר פריצה באמצעות SQL Injection .
4. הגדירו את הכניסה לאתר באופן שמתיר כניסה אך ורק מכתובת (או מספר כתובות) IP, וחוסמת את הכניסה מכתובות אחרות. לחליפין, ניתן לחסום גישה ממדינות מסויימות אולם האקרים יכולים להשתמש בProxie שיתחזה לכתובת מישראל. לעומת זאת, בלתי אפשרי להתחזות לכתובת IP ספציפית.
5. בצעו גיבוי על בסיס קבוע והשתמשו בשירותי אכסון הכוללים גיבוי יומי של השרת.
6. הפעילו Firewall ו-Antivirus על השרת, ובצעו עדכונים באופן קבוע (Windows Update).
תוויות:
האפרתי,
האקינג,
הגנה,
מיכאל האפרתי,
מיכאל ורות האפרתי,
פריצה לאתרים,
רות ומיכאל האפרתי,
Hack,
Haephrati,
netvision
יום שבת, 2 ביוני 2012
סודות הדוקו
תוכנת Target Eye
בשנת 2000 הקמתי מיזם בשם Target Eye במסגרתו פותחה תוכנת ניטור וריגול בשם Target Eye Monitoring System למטרות שימושי ביון ואכיפת חוק. בין השאר הוצעה התוכנה לגופי מערכת הביטחון במדינה, בשנת 2005 נעשו בתוכנה שימושים לא חוקיים למטרות ריגול עסקי, על ידי 3 משרדי חקירות שרכשו את התוכנה מחברת Target Eye (אז כונתה התוכנה "הסוס הטרויאני"). בינתיים, נמשך פיתוח התוכנה, וכיום יש לה היתרי יצוא למספר מדינות בעולם, והיא משווקת אך ורק לגופי אכיפת חוק וביון בארץ ובעולם. מדובר בפיתוח ראשון מסוגו שלאחריו פותחו מוצרים דומים (חלקם אף טובים ומשוכללים לא פחות), וגם ה"דוקו" (כמו גם ה-Stuxnet וה-Flame) דומים במידה רבה לאותו אב טיפוס, באופן איסוף האינפורמציה הסלקטיבי באופן שמוגדר מראש על ידי המפעיל, וכך למעשה מיושם מודל שמיישם מודיעין אנושי (יומינט) באופן ממוחשב, והתוכנה הופכת להיות "סוכן חשאי" ממוכן. ניתן להגדיר היכן יפעל, והיכן ישמיד את עצמו, ואיזה מידע ייאסף, מתי יישלח ובאיזה תדירות ועוד כהנה וכהנה.
הצצה על הטכנולוגיה מאחורי הדוקו
עוד לפני הפרסומים האחרונים אודות וירוס הFlame המתוחכם, נחשפו קיומם של כלי ריגול אחרים, והמפורסם שבהם התגלה אף הוא במקרה, וזמן רב אחרי שכבר הספיק לבצע עבודה רבה עבור מפעיליו העלומים. חוקרים במעבדת המחקר לקריפטוגרפיה ואבטחת מידע במכון הטכנולוגי של בודפשט שפשפו את עינהם בתדהמה, כאשר גילו בתום חודשים של מחקר מאומץ, את אופן הפעולה של אחת הרוגלות המתקדמות בעולם – הדוקו (Doqu). מאמר זה נועד לשפוך אור על כמה מהמסקנות והתובנות ולנסות לשפוך ולו מעט אור על הרוגלה המסתורית שלפי מקורות זרים עשתה (ועדיין עושה) שמות במערכות גרעין ושיגור טילים ארוכי טווח באיראן (אבל לא רק...). קוראיי הנאמנים (והספורים) יבחינו עת יקראו במאמר, שאני קופץ מנושא לנושא. מטכנולוגיה לטכנולוגיה. זה לא אני. זה הדוקו! מדובר בסבך של טריקים וטכנולוגיה שזורים זה בזה, ופועלים לפי תסריט מותח אשר משאיר את הצופה פעור פה. אוכל לסקור במאמר זה כמה מאבני הבניין, שניתן לדמותם למספר שחקני משנה בעלילה, ודי בהם כדי להצביע על מורכבות הפרוייקט, ומשניותם אינה מפחיתה את ייחודם ועצומתם, וכאן המקום לומר שכל שחקן משנה כזה, היה יכול להיות כוכב ראשי בעלילה אחרת. מדובר בכלי שלפי מיטב הבנתי, הפיתוח שלו הסתיים בשנת 2006, וניתן רק לנחש מתי החל.... ועכשיו לא נותר לי אלא לקפוץ הישר אל הקסם.האם מסוכן לפתוח מסמך Word מצורף להודעת מייל
אם מאמר זה יתפרסם, אוכל להניח שהעורך פתח את מסמך ה-Word ששלחתי, ואני כמובן מעריך את האמון... וממתי מסמכי וורד מהווים סיכון? בעבר הרחוק (לפני 15 שנה) הופיעו וירוסים תוך מסמכי וורד, תוך ניצול היכולת ליצור "מאקרו" ולשמור אותו כחלק מהמסמך. כך גם היה במקרה של הוירוס הראשון – "I love you". מאז הוטמע מנגנון החוסם מאקרו כברירת מחדל. למעשה, מי שרוצה לשלב מאקרו לגיטימי במסמך, נתקל בקושי רב לעשות זאת. אלא שהפעם מדובר במנגנון מתוחכם בהרבה אשר מנצל פירצה במערכת ההפעלה. תודות לפירצה זו, נכנס מנגנון התקנה ייחודי לפעולה כאשר מסמך הוורד נפתח. מנגנון התקנה זה גובר על אחת ההגנות היעילות של גירסאות Windows החדשות (ויסטה ואילך). מנגנון הUser Access Control. מנגנון זה אינו מאפשר ביצוע אוטומטי של פעולות רבות, מבלי שמשתמש הקצה יאשר את הפעולה. החלון שקופץ כאשר מפעילים תוכנות רבות, או מפעילים תוכנות כלשהם במוד Administrator נועד להבטיח שמישהו שיושב מול המחשב אכן יאשר את הפעולה. מצד שני, פעולות אשר עלולות לחשוף את המחשב לסיכונים, מצריכות אישור כזה.מספר מילים על דרייברים
דרייברים הם רכיבי תוכנה אשר נועדו לספק תמיכה ותאימות לרכיבי חומרה ותוספים מסוגים אחרים למחשב. פיתוח דרייבר מצריך כלים ייחודיים אשר מאפשרים גישה לבסיס העמוק ביותר של מערכת ההפעלה, הKernel. הגרעין, אשר שליטה בו פירושה שליטה מלאה במחשב, שליטה חשאית ובלתי ניתנת כמעט לגילוי. על מנת להסביר מדוע נדרשת גישה מוחלטת ושקופה, ניקח מוצר תמים ובלתי מזיק. מדפסת או צג מחשב. כאשר אלה מחוברים למחשב, שורה של פעולות מתבצעות על מנת לאפשר שימוש בהתקן שהוכנס. משתמש הקצה לא היה רוצה להתחיל ללחוץ על כפתורים בכל עת שהוא מחבר את המדפסת או צג מחשב, ומכאן כל הפעולות מתבצעות ברקע. ישנם מנגנונים "גרעיניים" עוד יותר, כמו מנגנון המאפשר הצגת פונטים כאשר אלה כלולים בטקסט כזהט או אחר, ובמידה ופונט חסר, להוריד אותו או לקרוא אותו כאשר זה מוטמע במסמך. לכן ניתן לומר שדרייברים מאפשרים להינות משורה של תכונות ופוקציונליות, באופן שקוף שאינו דורש התערבות המשתמש, וכן באופן אוטומטי שאינו מצריך הפעלת כל דרייבר בכל פעם שמבצעים ריסט למחשב. אליה וקוץ בה, עוצמתם של הדרייברים פותחים פתח לפעולות פחות רצויות ויותר מסוכנות, וזה הבסיס (או אחד הבסיסים) לפעולת הדוקו. בשל עוצמתו של הדרייבר, נוקטת מערכת ההפעלה במשנה זהירות כשמדובר בהתקנת דרייבר חדש. דרייברים צריכים להיחתם על ידי רשות מוסמכת כגון CA או Symantec (אשר רכשו את Verisign), והתקנתו דורשת אישור משתמש מסוג Admin. מפתחי הדוקו חיפשו דרך לאפשר התקנה של דרייבר מבלי לקבל את אישור משתמש הקצה. התקנה של דרייבר מבטיחה מקסימום שליטה על המחשב המנוטר, ועם זאת, קושי עצום לגלות את דבר קיומו של הדרייבר, או את ההפעלה האוטומטית שלו עם הדלקת המחשב. דרייברים, במיוחד אלה שמוגדרים כKernel, מופעלים אוטומטית מבלי שצריך להגדיר דבר מה בRegistry. למעשה, הסרה של דרייבר Kernel בדרך של מחיקה (לרבות מחיקה על ידי אנטי וירוס), תביא לשיתוק של המחשב ללא יכולת לתקן אותו (אלא אם מתקינים את Windows מחדש). על תופעה זו כתבתי את המאמר הבא.פירצה בגוף הפונט
כיצד הושחל מנגנון התקנה כה מתקדם למסמך וורד? התשובה היא בפונט. כאשר מסמך אופיס כולל פונט לא סטנדרטי (כזה שאינו חלק מובנה במערכת ההפעלה), ניתן לצרף אותו למסמך וכך יודעת מערכת ההפעלה לשלוף אותו ולהתקין אותו. הפורמט הנפוץ לפונטים הנו True Type. לWindow מנגנון מובנה לקריאת הגדרות הפונט ותרגומם בזמן ריצה לbitmap על מנת להציג את הפונט על המסך (ומנגנון נפרד להדפסתו באיכות גבוהה יותר בזמן ההדפסה). מפתחי הרוגלה עלו על פירצה במנגנון זה, אשר מאפשר להטמיע בקובץ הTrue Type אשר הסיומת שלו TTF, קוד זדוני בעל יכולות לבצע פעולות במחשב מעבר לייעוד המקורי והוא הצגת הטקסט בפונט הנבחר. לקבצי הTTF ישנה הפריווילגיה לעבור חופשי מבלי להיחסם, שכן עד היום לא נחשבו איום. בניגוד לתוכנה כלשהי השמורה בפורמט הנפוץ EXE, אשר תיחסם אם תישלח במייל, ומשתמש הקצה יקפל אזהרות והתראות אם יפעיל תוכנה כלשהי אשר הורדה מהאינטרנט, הרי שמסמכי וורד וקבצי פונט לא נחסמים ולא מסוננים. כדי לדייק, הפירצה האמורה באה לידי ביטוי במסמך הוורד עצמו, בחלק המיועד להגדיר פונט לא מוכר למערכת, על מנת שזה ישולב במסמך גם אם נפתח אצל משתמשים שאין ברשותם פונט זה. לא ידוע על מקרים בהם הוטמע קוד זדוני בקובץ הפונט עצמו (TTF), אם כי אפשרות כזו קיימת ויש לנקוט משנה זהירות. ניתן לומר שאם אינך סטודיו לגראפיקה העוסק בשילוב פונטים ייחודיים בעבודה, ושלחו לך פונט במייל, אל תפתח...אז איך גוברים על הUAC
הUAC אינו שם נרדף לאיחוד האמירויות אלא ראשי תיבות של User Access Control, שכאמור נועד להבטיח שפעולות מסויימות יוכלו להתבצע רק אם המשתמש במחשב מאשר אותן, מה שאמור למנוע ביצוע פעולות אלה ללא ידיעת המשתמש. הרוגלה עצמה, מתוחכמת ביותר ומנגנון ההתקנה הוא רק פורץ הדרך אשר נותן לרוגלה דריסת רגל במחשב המותקף. מנגנון זה מתקין שורה של קבצים מסוג DLL, קבצי קונפיגורציה (הגדרות) וקבצי דרייבר אשר נחזים כאילו יוצרו על ידי חברת Intel על אף שאינם כאלה. למעשה, מתוך 13 קבצי דרייבר אשר נוטלים חלק בפעולת ה"דוקו", רק 6 נבדקו על ידי מעבדות כאלה ואחרות, וה-7 האחרים חמקו ונעלמו. לפי פירסומים זרים, נעשה שימוש ב"דוקו" באירן, ואגב, גם בסודאן. מדובר בכלי ממוקד אשר הוגדרו בו זמני הפעולה (כאשר מחוץ למסגרת הזמן שהוגדרה, הכלי מנוטרל) והיעד אשר היה במערכות ספציפיות הקשורות לתוכנית הגרעין של איראן. למרות שחלק מהדרייברים והקבצים אשר נוטלים חלק במבצע מורכב זה נחשפו, הרי שבאופן מסתורי, מספר קבצים בעלי תפקיד מפתח, חמקו מכל חוקרי הוירוסים באשר הם. דוגמה לכך הנה הקובץ bpmsg.sys. ה"דוקו" אינו וירוס, ואף אף לא רוגלה במובן הקלאסי של המילה, אלא פלטפורמה רחבה (סוג של מיני מערכת הפעלה) אשר ניתן להשתמש בה לכל מטרה ולכל ייעד, תוך קסטומיזציה מלאה של הדרישות והייעדים. ה"דוקו" מסוגל להתעדכן בכל עת. כל הפעולות המתבצעות על ידו, לרבות עדכון כזה, מתבצעות באופן חשאי לחלוטין ללא ידיעת המשתמש. לפי מספר פירסומים, ביותר ממקרה אחד של התקפה על מערכות מחשב במתקני גרעין באיראן, המידע שנאסף נשלח לכתובת ה-IP הבאה: 63.87.255.149 בדיקת כתובת זו מגלה כי היא שייך לחברת Verizon בארה"ב. http://www.ip-adress.com/ip_tracer/63.87.255.149 שרתים נוספים אליהם נשלח המידע נמצאים בויאטנם. מדובר בשרת Linux אשר מריץ CentOS 5.5. חוקרים במעבדת Kespersky אשר גילו שרת זה, לא הצליחו לאתר ולו קובץ אחד אשר אוכסן, ונראה היה שזמן מה לפני כן, בוצעה מחיקה מאסיבית של כל הקבצים (סימן לכך היה שהתיקיות עצמן, בהן נשמרו הקבצים, לא נמחקו, ואלה נשאו גם חתימת תאריך יצירה ותאריך שינוי אחרון). חוקרי מעבדת Kaspersky גילו שמפעילי ה"דוקו" הפעילו את השרת הויאטנמי דרך שרת אחר, בגרמניה, אשר אוכסן בחברת אחסון בולגרית. בגדול, ניתן לומר שה"דוקו" הופעל ממספר כתובות באירופה (גרמניה, שוויץ, בריטניה), תוך גישה מרחוק לשרת הויאטנמי אשר שלט בייעדי ההתקנה באירן וסודן. לפי חתימות תאריכי קבצים ותיקיות בשרתים אלה, ניתן להעריך שמדובר במבצע רחב היקף אשר נכנס לשלב האופרטיבי שלו כבר בשנת 2009 (כלומר ה"דוקו" פותח עוד לפני 2009).פריצה בדרך של Brute Force
חלק מהשרתים הופעלו ללא ידיעת בעליהם, בדרך של פריצה. עדות לכך נמצאת למשל בקובץ לוג של אחד השרתים, ממנו עולה כי בתאריך 18.11.2009 ניסה גורם אלמוני בסינגפור לגלות את סיסמת הגישה בדרך של Brute Force עד שהצליח. שיטת הBrute Force מבוססת על ניסוי כל הקומבינציות האפשריות של כל צירוף של אותיות מספרים וסימנים מיוחדים עד לאיתור הסיסמה הנכונה. שיטה זו יעילה מאד לאיתור סיסמאות למסמכים (למשל מסמך וורד ממוצע המוגן בסיסמה יכול להפרץ בתוך מספר שעות ויש כלים כמו CrackPassword אשר נוסדו בשנת 1990 והכלים שלהם זולים ויעילים). עם זאת ככל שמדובר בשרת או אתר אינטרנט, לרובם יש מנגנון אשר חוסם כתובת IP ממנה מתבצע מספר רב של נסיונות להקליד סיסמה לא נכונה. ועם זאת, הפורצים מצאו את הדרך שלא להיחסם.מבצע טשטוש ראיות רחב היקף
ב-20.10.2011 התקיים מבצע רחב היקף של טשטוש ומחיקת ראיות, או אז הושמדו רוב הקבצים אשר נטלו חלק בהחדרת ה"דוקו". אמנם שירשור של שרתים במיקומים שונים, חוצי מדינות ויבשות, נראה כהופך את איתור מקור התוכנה לקשה יותר, אולם אם חושבים על כך, אין זה ממש משנה אם כדי להגיע אל המקור, צריך לעבור שני שרתים או 200 שרתים אלא שאלת המפתח היא האם ניתן להגיע בסופו של דבר למקור התוכנה. פעולת טשטוש ומחיקת הראיות, והעובדה שהקבצים החשובים באמת אשר נוטלים חלק בפעולתה המורכבת של התוכנה לא התגלו עד היום (על אף שיש עדות לעצם קיומם), מוכיחה שגוף ביון בעל יכולות עומד מאחורי התוכנה.יום שישי, 18 במאי 2012
Target Eye Source Code Revealed
Introduction
Auto Update mechanism doesn't have to be based on the actual version number (kept in the Version String), but can also base on the Last Modified Date Stamp
of the newer version compared to the old one. Target Eye Monitoring System, developed starting of 2000, had such mechanism.
Background
Target Eye Monitoring System, which I have developed 12 years ago, was one of the
first surveillance and monitoring tools for capturing activity of remote computers. The following description is taken from the original Business Plan of this venture:
Target Eye Monitogin System
Target Eye is a start-up company whose
mission is to develop integrated software solutions for real-time monitoring of
remote PCs, which are based on the company’s patent pending technologies
(60/204,084 and 60/203,832). Our major product, Target Eye Monitoring System,
is a software product that can continuously track, record, playback, analyze
and report any activity performed on one or multiple remote PCs, in a way which
is undetectable by their users. The software relies on a stream of rapidly
captured, compressed full-screen images and continuous keystroke capturing to
provide a comprehensive and accurate account of user activities, including
local activities which do not generate any network traffic. In this way, the
software can track and record activities, which are undetectable by systems
relying on network traffic analysis. A smart agent module running on the
monitored PCs uses a rule base to send alerts to the monitoring location(s) or
perform pre-defined local operations. Monitoring can be performed from multiple
locations. Major markets are law-enforcement.
Target
Eye Monitoring System was developed with an auto update mechanism. This
mechanism allows smooth and silent (un-attendant) execution of the new
version instead of the current one.
An historical image: The first version of Target Eye (Apr 2000)
A more recent version (Target Eye 2007)
This article focuses only in one aspect of this product, which is the Auto Update mechanism.
Creating and Marking Incremental Versions
In
order to be able to determine a newer version over the current one, there must
be a mechanism to mark the various versions, to increment the version number,
and to examine the version of a given executable.
The
most common way of doing so is using the "Version String" resource,
and to use a prebuild automated tool to promote this string each time the application
is built.
I
used another method which is based on the list modification date of the executable
file. This method has its pros and cons, but can be useful for most cases,
since it will allow your end users to get any version of your application that
was built after the one that is currently installed.
Before I explain, it is important
to mention 2 global variables which are used to build at start:
strRegularLocation
The location and full path of the
application when it runs normally (i.e. c:\program files\your app name\your
app.exe),
and…
strTemporaryLocation
Another full path to be used for the
temporary version downloaded when there is an update.
The reason for doing so it because since the
application downloads it's new version, the new version can't be downloaded to
its current location, and can't replace itself because while a file is used (or
an application is running) the file is locked and can't be moved, deleted or
renamed.
char strRegularLocation[256];
char strTemporaryLocation[256];
Filling
strRegularLocation
and strTemporaryLocation
with real valuesstrRegularLocation
is taken simply from __argv[0]
, provided that we are sure that we aren't
running already from the temporary location. We ensure that by using a
parameter named "INSTALL" which will be explained later. strTemporaryLocaiton
is built using a common folder and a temporary name combined. We use
GetSpecialFolder()
to find the path name of this folder in any computer running
the application. Getting the date stamp of current version
To
do so,
TEGetVersion()
, the first building block, is used and returns a CString
containing the last modification date of a given file.
//
TEGetVersion returns the last modification date / time of a given file
CString
TEGetVersion (CString FileName)
{
Time1;
if( CFile::Ge
CFileStatus status1;
CTime
tStatus( FileName, status1) )
{
return (Time1.Format("%d%m%M%S")
Time1 = status1.m_mtime;
);
}
// Failed
return ((CString)"");
}
//
When my application starts, I store the date / time stamp of it somewhere.
TE_Options.Version=TEGetVersion((CString)__argv[0]);
// here we keep the date/time stamp of the current version
Now we need to get the date / time stamp of the file online, preferably, without having to download it first, so we only download when we need to update to a newer version.
HINTERNET FileHandle=NULL;
ND_DATA ftpFileData;
//find
WIN32_F
Ithe file on the ftp server
ndle, FTP_NEWVERSION, &ftpFileData,
INTERNET_FLAG_RELOAD, 0 );
if( NULL
FileHandle= FtpFindFirstFile( m_ftpH
a!= FileHandle )
{
// get the write time of the ftp file
FileTimeToSystemTime( &ftpFileData.ftL
SYSTEMTIME ftpFileWriteTime, stUTC1;
FILETIME ftp;
astWriteTime, &stUTC1 );
SystemTimeToTzSpecificLocalTime( NULL, &stUTC1, &ftpFileWriteTime );
}
We need to define how old should be the current
version in order to update it. Again, this approach can be very useful in some
cases and less useful in other. For example, if your application involves a
database, you might be interested to ensure that the database is always most
recent and never older than 3 days.
#define UPDATEEVERY 60*24*7 // 7 days
#define APP_EXE_NAME "TargetEyeTest.exe"
#define FTP_NEWVERSION "NewVersion.exe"
\"
#define APP_REGULAR_FOLDER "\\TargetEye
\
The next step is to compare the date / time
stamp of each file.
CFileStatus
statusOld;
ld;
if( CFile:
CTime Time
O:GetStatus( FileHandle, statusOld ) )
{
CTime ct,OldTime;
d.m_mtime;
hFindFile.GetLastWr
OldTime=statusO
liteTime(ct);
LONG Diff;
Y %H:%M %Z");
oldver=OldTime.FormatGmt
ver=ct.FormatGmt("%d %m
%("%d %m %Y %H:%M %Z");
-OldTime)).GetTotalMinutes();
hFindFile.Close();
Diff = ((CTimeSpan)(c
tif (Diff>UPDATEEVERY || resultSpecific)
{
// download the newer version
}
}
Downloading the new version
Downloading the newer version is performed using
TE_DownladLoad()
which is listed here. We make several attempts in case there is a temporary block or communication problem.
#define FTPRETRIES 5 // number of retries
BOOL TE_DownloadLoad(char *FtpFileName,char *LocalFileName)
{
int DoTry=FTPRETRIES;
int result;
t = MyConnection
TryAgain:;
try
{
resu
l.m_FtpConn->GetFile(FtpFileName, LocalFileName, FALSE);
}
4];
pEx->GetErrorMessage(sz
catch (CInternetException* pEx)
{
TCHAR sz[10
2,1024);
WriteToLog("Error %s\n", sz);
6 - TE_Load",MB_OK);
pEx->Delete();
}
if (!resul
if(TE_DEBUG) MessageBox(NULL,sz,"Error
t)
{
if(DoTry-- >0) goto TryAgain;
return(FALSE);
}
else
{
return (TRUE);
}
}
Now we are ready to switch between the currently running version (the
old one) with the newer one.
Executing the newer version
BOOL ExecuteNewVersion(char *ExeName,char *Param)
{
STARTUPINFO sinfo;
pinfo;
ZeroMemory(&sinfo, s
PROCESS_INFORMATION
izeof(sinfo));
sinfo.cb = sizeof(sinfo);
info.dwFlags=STARTF_USESHOWWINDOW ;
sinfo.lpDesktop= "WinSta0\\Default";
ssinfo.wShowWindow=SW_SHOW;
(char*)(LPCTSTR)((CString)(ExeName)+(CString)"
"+(CString)(Param)
if(!CreateProcess(NULL
,), NULL, NULL,FALSE,NORMAL_PRIORITY_CLASS |
CREATE_NEW_CONSOLE, NULL, NULL, &sinfo, &pinfo))
);
{
char s[256];
sprintf(s,"Can't execute program: %s params %s",ExeName,Para
m // ERROR LOG
TELog.LogError("Execute New Version",s,0);
return FALSE;
}
else
{
return TRUE;
}
}
So if we put all the code together we get:
CFileStatus statusOld;
CTime TimeOld;
atus( FileHandle, statusOld ) )
{
CTime c
if(CFile::GetS
tt,OldTime;
OldTime=statusOld.m_mtime;
NG Diff;
ver=ct.FormatGmt("%d %
hFindFile.GetLastWriteTime(ct);
L
Om %Y %H:%M %Z");
oldver=OldTime.FormatGmt("%d %m %Y %H:%M %Z");
e.Close();
if (Diff>UPDATEEVERY || resultSp
Diff = ((CTimeSpan)(ct-OldTime)).GetTotalMinutes();
hFindFi
lecific)
{
// downloading the newer version
MPPLACE))
{
// We have successfully downloade
if(TE_DownLoad((resultGeneric)?NEWEXESTR:NEWEXE,T
Ed the newer version
if(ExecuteNewVersion(TEMPPLACE,"INSTALL"))
{
rent version can now quit
}
// We have successfully executed the
// newer version. Cu
r else
// Failed to execute new version
}
else
{
TELog.LogError("New Ftp version found","Can't download",0);
}
}
}
The TE_Init() function
TE_Init() is used to determine the parameters
used when application was executed (Unlike the full version of Target Eye
Monitoring System, which is much more complex, in our example, there is one
optional parameter – "INSTALL").
if(__argc>1)
{
if(strcmp(__argv[1],"INSTALL")==0)
{
// TE_FirstTime(); -> here you can place code you wish to
//be executed only during the first run
}
}
else
xists at the tem
// No parameters
{
// Delete a temporary version if
eporary location
}
Replacing old with new
In order to quit in a normal fashion, without missing anything we wish
to do before quitting, the main even loop contains a check for the value of
NeedToQuit, which would normally be FALSE.
BOOL NeedToQuit=FALSE;
When NeedToQuit becomes TRUE, the application will perform any routine
required before quitting (for example, saving unsaved work). For example:
if(NeedToQuit)
{
if(TE_DEBUG)
MessageBox(NULL,"Terminating Targe Eye",
"Target Eye Monitoring System",NULL);
return FALSE;
}
Further, the application expects to be executed either with the
"INSTALL" parameter as part of the command line, or without it. The
following scheme illustrates the flow of an installation of a newer version to
a temporary location (the Desktop folder, in our example), up to the moment the
temporary file used for it is deleted. This requires several stages:
The Target Eye Cycle
Stage
|
Ran
with Parameter
|
Ran
from location
|
Description
|
1
|
None
|
Regular
|
The
current (old) version is running before the newer version is available
|
2
|
The
newer version checks if there is a temporary copy of itself at the temporary
location, but there isn't any
|
||
3
|
A
newer version is found
|
||
4
|
Newer
version is downloaded to a temporary location
|
||
5
|
Newer
version runs from the temporary location with the "INSTALL"
parameter.
|
||
6
|
Current
version quits
|
||
7
|
INSTALL
|
Temporary
|
The
newer application ran from the temporary location copies itself to the
regular location, replacing the old version which quitted (5)
|
8
|
The
newer version runs the copy located in the regular location and quits.
|
||
9
|
None
|
Regular
|
The
newer version checks if there is a temporary copy of itself at the temporary
location, and deletes it.
|
Choosing an FTP server for this demo
In order to use the source code that attached to this article, there are
predefined settings of a public Secured FTP server available to the public by Chilkat Software, Inc.
The details of this server are:
Secure FTP Server
Details
Type | FileZilla |
Address | ftp.secureftp-test.com |
Login | Test |
Password | Test |
There is a file there named hamlet.xml which can be used for testing a
remote file date stamp.
Internationalization
To comply with scenarios in which there
are users worldwide, and yet we wish to release a version to be available at
the same moment to all of them regardless of their local time, we use
FormatGmt
GMT is an absolute time reference and doesn't
change regardless of the season or the location. FormatGmt is used like that:
CTime t( 1999, 3, 19, 22, 15, 0 );
// 10:15 PM March 19, 1999
%B %d, %Y" );
ATLASSERT( s == "Friday, M
CString s = t.Format( "%A,
arch 19, 1999" );
Limiting to a single instance
The mechanism described in this article can only work if we limit our application to run only once at any given moment.
To do so, several methods can be used, such as CreateMutex().
Target Eye Monitoring System uses a different and a bit "brutal" approach, which will be explain in details over another article. Basically, Target Eye Monitoring System searches
for other instances currently running in memory, and when found, does one of the two following options:
- If the instance found is newer, the current running instance quits.
- If the instance found is older, the current running instance kills it.
To explain, let's consider the following
scenario. An end user had his current copy of software updated to a newer one.
A day after, this end user runs the original CD of the software. The version
that resides on the original CD, will search for new updates at the FTP server,
which is unnecessary. Further, if the application runs constantly (like a
monitoring application should), then probably when the CD version is ran, there
is also another newer version already running. To address such scenario and other
scenarios, we should take the necessary measures to ensure that an application
will always be up to date.
Published at www.codeproject.com
חבילת הסמסים שלי
התחרות בענף הסלולר, אשר תפסה תאוצה בשבוע האחרון לאחר כניסת שתי שחקניות חדשות לשוק: גולן טלקום והוט מובייל, מהווה אמתלה טובה להביא סקירה קצרה של הטכנולוגיה שמאחורי הסלולר, ובמקרה זה, משלוח הודעות SMS.
נניח שאתם רוצים להציע מוצר או שירות אשר כולל במסגרתו גם משלוח הודעות SMS. ההודעות עשויות להיות מקומיות (בארץ בלבד), או בינלאומיות (מכל מדינה לכל מדינה).
חברה בריטית ותיקה בשם CardBoardFish, מציעה תשתית טכנולוגית כזו, המקיפה את רוב מדינות העולם, ותעריף משלוח SMS בישראל (לצורך הדוגמה) יעלה כמחצית האגורה.
החברה מספקת תשתית אשר מנתבת את ההודעות על פני רוב חברות הסלולר בעולם כולו.
הדרך לצרוך שירות כזה הוא באמצעות התממשקות. זה יכול להיות אתר אינטרנט שמציע שירות הכולל משלוח SMS, או תוכנה (Desktop Applition), כאשר הדרכים להתממשק למערכת הנן:
נניח שאתם רוצים להציע מוצר או שירות אשר כולל במסגרתו גם משלוח הודעות SMS. ההודעות עשויות להיות מקומיות (בארץ בלבד), או בינלאומיות (מכל מדינה לכל מדינה).
חברה בריטית ותיקה בשם CardBoardFish, מציעה תשתית טכנולוגית כזו, המקיפה את רוב מדינות העולם, ותעריף משלוח SMS בישראל (לצורך הדוגמה) יעלה כמחצית האגורה.
החברה מספקת תשתית אשר מנתבת את ההודעות על פני רוב חברות הסלולר בעולם כולו.
הדרך לצרוך שירות כזה הוא באמצעות התממשקות. זה יכול להיות אתר אינטרנט שמציע שירות הכולל משלוח SMS, או תוכנה (Desktop Applition), כאשר הדרכים להתממשק למערכת הנן:
- המרת מייל לסמס. שיטת Mail2SMS.
- פנייה לשרת HTTP באמצעות פקודת GET.
הטכנולוגיות הנתמכות על ידי החברה הן:
SMPP 3.3 ו-3.4
CIMD2
OIS
שפות התכנות הנתמכות כוללות: Soap, XML, Java, Visual Basic, PHP ו-Pearl.
שפת ++C אינה נתמכת ישירות. פניתי לחברה וקיבלתי תשובה שאין להם תמיכה או דוגמאות קוד לשפה זו, שכנראה הולכת ונעלמת מן העולם. למרות זאת, כתבתי בעצמי תוכנה קטנה שעושה שימוש בשפה זו ובMFC אשר שולחת SMS לכל יעד בארץ ובעולם, ואף נידבתי את קוד התוכנה (עכשיו יש להם תמיכה ב++C ... ).
התוכנה נראית כך:
והקסם מאחוריה הוא בהתממשקות שנעשית באופן הבא:
כל משתמש (כולל משתמש Trial כמו במקרה שלי), מקבל שם משתמש וסיסמה אשר הופכים לחלק מקוד התוכנה.
התוכנה שלי עושה שימוש בClass קוד פתוח בשם WinHTTPClient אשר חיבר תוכניתן סיני בשם Sheng Chi.
כתבתי רוטינה בשם SendSMS אשר משמשת ה"מנוע" של התוכנה.
כפי שתראו יש צורך לקבוע פרמטר בשם DC עם ערך "4" ולקדד את ההודעה כHexadecimal, זאת על מנת שתתמוך בתווים בעברית (ובשפות נוספות), ולצורך כך כתבתי פונקציה נוספת בשם ConvertHex:
שם השולח יכול להיות מספר טלפון, או שם (באותיות לטיניות בלבד, וללא רווחים).
כתובת הנמען כוללת קידומת מדינה, ומספר טלפון (ללא ה"0" בהתחלה).
והעלות, כאמור, חינם לתקופת נסיון ולאחר מכן 0.006 יורו (כ-2 אגורות) להודעה.
תוויות:
אבטחת מידע,
אורנג',
גולן טלקום,
האפרתי,
הוט מובייל,
מיכאל אפרתי,
מיכאל האפרתי,
סלולר,
סלקום,
סמס,
פלאפון,
Cellular,
Haephrati,
Michael Haephrati,
Mobile,
sms
יום שני, 19 במרץ 2012
אפשר גם וגם
לפני מספר חודשים נחשפה פעילות ה"האקר הסעודי" והיקפה, אשר התבטאה בין השאר בגנבת פרטי אזרחים ישראלים לרבות מספרי כרטיסי אשראי שלהם ומספרי תעודות זהות, וכן פרטי חשבונות מייל ואינטרנט שונים שהם מחזיקים (שם משתמש וסיסמה). פעילות ההאקר הסעודי וחבורתו לא נפסקה וניתן לקרוא עליה ולהתעדכן בבלוג הבא.
אחד הכשלים שנחשפים מהפרשה נוגע לעובדה שפרטי מידע רגישים כגון מספרי כרטיסי אשראי ותעודות זהות, נשמרים על ידי אתרים רבים, ויש בכך פירצה הקוראת לגנב.
ביום ראשון האחרון הודיע משרד המשפטים כי הוא בכוונתו לאסור על אתרי אינטרנט לאסוף מספרי זהות של משתמשים ללא הצדקה ממשית. משמעות הדבר היא שאתרים יעברו להשתמש במספר לקוח שהם ייצרו לכל לקוח ולקוח. מספר הלקוח ישמש כמזהה חד ערכי לכל אחד מלקוחות האתר באופן שיאפשר להבדיל בין לקוחות הנושאים, לדוגמה, את אותו שם, וכך משה כהן מתל אביב הנושא מספר לקוח X יזוהה כלקוח שונה ממשה כהן מתל אביב הנושא מספר לקוח Y.
יש לתת את הדעת לכך שאופרטיבית אין דרך טובה יותר ממספר תעודת הזהות לזהות משתמש או לקוח. מספר הזהות מלווה כל אזרח בכל מקום ובכל חנות או אתר, בעוד שלפי השינוי המוצע, כל אדם יצטרך להחזיק במספר רב של "מספרי לקוח", לכל אתר ואתר. לעומת זאת אם היו כל אתרי ה e-commerse מתאגדים ומנפיקים מספר לקוח אחיד, אזי הבעיה של מספרי הזהות הייתה צצה מחדש שכן האקרים היו מתלבשים על מספר הלקוח הגלובאלי בהיותו מספר בעל ערך ומשמעות כמעט זהה לזו של מספר הזהות...
הפתרון המוצע
ניתן לפתור את הבעיה בדרך הבאה. באמצעות מנגנון של checksum, שבאמצעותו בצד של משתמש הקצה, מספר הזהות ימשיך להיות אמצעי הזיהוי באתרים, אולם בצד של האתר, ויותר חשוב, בדטה בייס שלו, יישמר נתון אחר שהוא תולדה של פונקציית הchecksum.
המייחד תהליכים אלה, בהם הופך נתון אחד לנתון אחר באמצעות פונקציות ההמרה האלה הוא שמדובר בתהליך חד כיווני. לא ניתן באמצעים סבירים ונגישים להמיר בחזרה את הנתון שיתקבל ממספר הזהות וישמר בדטה בייס, חזרה למספר הזהות, ומכאן שמספר הזהות יוגן, לא יוחזק בשום מקום, ועם זאת, ישמש במזהה חד ערכי.
בשבועות האחרונים פרסם האקר המוכר בשם עומאר ("ההאקר הסעודי") פרטים אישיים של גולשים ישראלים, שנגנבו בפריצות לאתרי אינטרנט מקומיים. אלו כללו שמות, כתובות מייל, מספרי כרטיסי אשראי ובפרט מספרי תעודות זהות. כמו כן נערכו בתקופה האחרונה דיונים בוועדת המדע והטכנולוגיה של הכנסת, לאור תלונות שהתקבלו על איסוף גורף של מספרי תעודות זהות מצד עסקים שונים.
כיצד יתבצע זיהוי של לקוח חוזר
כאשר לקוח יקליד את מספר הזהות שלו, מספר הזהות יומר לchecksum שלו. המערכת תחפש נתון זה בדטה בייס ובמידה ונתון זה נמצא, יזוהה הלקוח כלקוח חוזר וניתן יהיה לשלוף את נתוניו שנשמרו (ואשר כמובן לא יכללו מספר זהות).
האם הCheckSum לא יהפוך למזהה הייחודי החדש?
לא. משום שניתן להפיק מזהים אלה בדרכים רבות ותוך שקלול פרמטרים רבים. כל עוד משתמשים באלגוריתם ופרמרטים זהים בכל פעם שמקלידים מספר זהות באתר מסוים, השיטה תעבוד. פרמטרים ייחודיים יכולים להיות שם האתר, כתובתו, וכל פרט נוסף שניתן לבקש מהלקוח כאמצעי אבטחת מידע. לדוגמה: 4 ספרות אחרונות של כרטיס האשראי. כך גם שליפת checksum מדטה בייס אחד לא תועיל במאום מול דטה בייס אחר.
ומה קורה למספר תעודת הזהות בכל התהליך
מספר תעודת הזהות משמש ככרטיס הכניסה, אולם משול הדבר לאדם שמציג תעודת זהות בכניסה לבניין, ולאחר שהוא מזוהה, תעודת הזהות מוחזרת לו ופרטיה אינם נשמרים. כך גם בתהליך זה. מספר הזהות נדרש לצורך האימות / רישום אולם הוא נזרק ולא נשמר.
אחד הכשלים שנחשפים מהפרשה נוגע לעובדה שפרטי מידע רגישים כגון מספרי כרטיסי אשראי ותעודות זהות, נשמרים על ידי אתרים רבים, ויש בכך פירצה הקוראת לגנב.
ביום ראשון האחרון הודיע משרד המשפטים כי הוא בכוונתו לאסור על אתרי אינטרנט לאסוף מספרי זהות של משתמשים ללא הצדקה ממשית. משמעות הדבר היא שאתרים יעברו להשתמש במספר לקוח שהם ייצרו לכל לקוח ולקוח. מספר הלקוח ישמש כמזהה חד ערכי לכל אחד מלקוחות האתר באופן שיאפשר להבדיל בין לקוחות הנושאים, לדוגמה, את אותו שם, וכך משה כהן מתל אביב הנושא מספר לקוח X יזוהה כלקוח שונה ממשה כהן מתל אביב הנושא מספר לקוח Y.
יש לתת את הדעת לכך שאופרטיבית אין דרך טובה יותר ממספר תעודת הזהות לזהות משתמש או לקוח. מספר הזהות מלווה כל אזרח בכל מקום ובכל חנות או אתר, בעוד שלפי השינוי המוצע, כל אדם יצטרך להחזיק במספר רב של "מספרי לקוח", לכל אתר ואתר. לעומת זאת אם היו כל אתרי ה e-commerse מתאגדים ומנפיקים מספר לקוח אחיד, אזי הבעיה של מספרי הזהות הייתה צצה מחדש שכן האקרים היו מתלבשים על מספר הלקוח הגלובאלי בהיותו מספר בעל ערך ומשמעות כמעט זהה לזו של מספר הזהות...
הפתרון המוצע
ניתן לפתור את הבעיה בדרך הבאה. באמצעות מנגנון של checksum, שבאמצעותו בצד של משתמש הקצה, מספר הזהות ימשיך להיות אמצעי הזיהוי באתרים, אולם בצד של האתר, ויותר חשוב, בדטה בייס שלו, יישמר נתון אחר שהוא תולדה של פונקציית הchecksum.
המייחד תהליכים אלה, בהם הופך נתון אחד לנתון אחר באמצעות פונקציות ההמרה האלה הוא שמדובר בתהליך חד כיווני. לא ניתן באמצעים סבירים ונגישים להמיר בחזרה את הנתון שיתקבל ממספר הזהות וישמר בדטה בייס, חזרה למספר הזהות, ומכאן שמספר הזהות יוגן, לא יוחזק בשום מקום, ועם זאת, ישמש במזהה חד ערכי.
בשבועות האחרונים פרסם האקר המוכר בשם עומאר ("ההאקר הסעודי") פרטים אישיים של גולשים ישראלים, שנגנבו בפריצות לאתרי אינטרנט מקומיים. אלו כללו שמות, כתובות מייל, מספרי כרטיסי אשראי ובפרט מספרי תעודות זהות. כמו כן נערכו בתקופה האחרונה דיונים בוועדת המדע והטכנולוגיה של הכנסת, לאור תלונות שהתקבלו על איסוף גורף של מספרי תעודות זהות מצד עסקים שונים.
כיצד יתבצע זיהוי של לקוח חוזר
כאשר לקוח יקליד את מספר הזהות שלו, מספר הזהות יומר לchecksum שלו. המערכת תחפש נתון זה בדטה בייס ובמידה ונתון זה נמצא, יזוהה הלקוח כלקוח חוזר וניתן יהיה לשלוף את נתוניו שנשמרו (ואשר כמובן לא יכללו מספר זהות).
האם הCheckSum לא יהפוך למזהה הייחודי החדש?
לא. משום שניתן להפיק מזהים אלה בדרכים רבות ותוך שקלול פרמטרים רבים. כל עוד משתמשים באלגוריתם ופרמרטים זהים בכל פעם שמקלידים מספר זהות באתר מסוים, השיטה תעבוד. פרמטרים ייחודיים יכולים להיות שם האתר, כתובתו, וכל פרט נוסף שניתן לבקש מהלקוח כאמצעי אבטחת מידע. לדוגמה: 4 ספרות אחרונות של כרטיס האשראי. כך גם שליפת checksum מדטה בייס אחד לא תועיל במאום מול דטה בייס אחר.
ומה קורה למספר תעודת הזהות בכל התהליך
מספר תעודת הזהות משמש ככרטיס הכניסה, אולם משול הדבר לאדם שמציג תעודת זהות בכניסה לבניין, ולאחר שהוא מזוהה, תעודת הזהות מוחזרת לו ופרטיה אינם נשמרים. כך גם בתהליך זה. מספר הזהות נדרש לצורך האימות / רישום אולם הוא נזרק ולא נשמר.
הירשם ל-
רשומות (Atom)