יום שבת, 19 בפברואר 2011

ARP Poisoning and Spoofing With C

אחת ההתקפות הנפוצות ברשתות היא שימוש ב ARP Poisoning , שבעצם הופכת את התוקף לתחנת בניים של התקשורת העוברת בין מחשבים ברשת, ומאפשרת לתוקף איסוף מידע רגיש כמו סיסמאות, חשבונות ובכלל לתפוס את התעבורה ולשנות אותה בכל שלב בדרך, כמו כן לעשות התקפה של Denial Of Service למחשבים ברשת ולכן על מנת להבין איך זה בדיוק עובד צריך להכיר את מודל OSI ואת פרוטוקל ה Arp.

מה זה מודל OSI?
Open Systems Interconnection - נכון שזאת לא הפעם הראשונה שאני נוגע ברשתות אבל מודל ה OSI קיים בכול הקשור ברשתות והוא הבסיס לכל תקשורת שמתבצעת לכן כדאי שנכיר אותו, הוא הומצא ע"י ארגון התקינה הבין לאומי (ISO) בתחילת שנות השמונים, שבתקופה זו לא היו סטנדרטים אחידים בכל הקשור לתקשורת וכל יצרן בנה מנגונני תקשורת משלו, נגרמו המון בעיות תאימות שחייבו הקמת סטנדרט אחיד לתקשורת בין מחשבים.

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


 כאשר החבילה מגיעה למחשב הוא מפרק אותה בסדר הפוך עד לאפליקצה המקבלת.

מה זה Arp?
Address Resolution Protocol - פרוטוקול רשתות שנכנס לשימוש בשנת 1982, מטרת הפרוטוקל הוא לשייך כתובת פיזית לכתובת IP, וניתן לממש אותו במגוון של סוגי רשתות: Internet Protocol ו IEEE 802.11


נניח שיש שני מחשבים שרוצים לתקשר בניהם, לפני שיוצאת החבילה המחשב השולח צריך לודא שהיא נשלחת ליעד המקורי שלה, ולכן מתבצעת שאילתה Arp לרשת על מנת שיקבל את הכתובת הפיזית של המחשב שאליו הוא שולח החבילה, כל מחשב ברשת מחזיק טבלה (Arp Cache) שמשייכת כתובת פיזית לכתובת Ip לזמן מסויים (תלוי במערכת הפעלה) ואח"כ מתבצעת השאילתה פעם נוספת והטבלה מתמלאת מחדש, ע"פ מודל ה OSI שכבת השימוש ב Arp היא בין שכבת 2 (Data Link) לשכבה ה 3 (Network).

מבנה חבילת Arp דחוס  וקטן מאוד סה"כ 4 בתים, ולכן הוא קצת מבולגן בגלל שהכתובות הפיזיות הן 6 בתים, לכן פיצלו אותן לחלקים כפי שניתן לראות בתרשים הבא:



Hardware Type
סוג ה Ethernet מיוצג ע"י מספר.
  • 1 - Ethernet
  • 2 - Experimental Ethernet
  • 3 - X.25
  • 4 - Token Ring
  • 5 - Chaos
  • 6 - IEEE 802.x
  • 7 - ARC network
Protocol Type
 היצוג הפרוטוקול במקרה שלנו הוא (IP (0x0800
Hardware Length
 אורך כתובת הפיזית - 6
Protocol Length
 אורך כתובת הפרוטוקול - 4
Opertation
 סוג פעולת החבילה.
  • 1 - ARP Request
  • 2 - ARP Reply
  • 3 - RARP Requset
  • 4 - RARP Reply
Source Hardware Address
 כתובת מקור פיזית
Source Protocol Address
 כתובת מקור IP
Target Protocol Address
כתובת יעד IP


אחרי שהבנו מזה Arp ולמה הוא נועד נעבור לשלב ההתקפה, אז בעצם לכל IP יש כתובת פיזית ולפני כל תקשורת המחשב השולח מוודא את הכתובת הפיזית ,אבל מה אם ההינו יכולים לחקות את הכתובת הפיזית לכתובת IP ובכך ההינו גורמים למחשב השואל לחשוב שאנחנו המחשב שהוא מחפש, אנחנו נתקוף את Host A בכך שנגרום לו לחשוב שאנחנו בעצם ה Default Gateway שלו ממקום ה Router של הרשת.

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


את רוב ההתקפה כבר עשינו כלומר כל התקשורת שתצא מ Host A תעבור דרך ה Attacker והוא אבחר אם להעביר אותה הלאה ליעד או להפיל אותה ולגרום ל Denial Of Service.
לפני שניכנס לקוד חשוב לדעת איך מפעילים או מפסיקים את ה IP Forward בעזרת ה Terminal ב Linux:
הסטאטוס של ה Ip Forward של המערכת:
#: sysctl net.ipv4.ip_forward
אם נרצה Ip Forward נסמן 1 אם לא נסמן 0
#: sysctl -w net.ipv4.ip_forward = 1
רכיבים נחוצים:
Linux - במקרה שלי החלטתי להשתמש ב OpenSuse

ניצור פרויקט חדש של C ANSI ב Eclipse , נשתמש במספר פנוקציות מהמאמר הקודם בנושא
CreateRawSocket(int protocol_to_sniff)
BindRawSocketToInterface(char *device, int rawsock, int protocol)
SendRawPacket(int rawsock, unsigned char *pkt, int pkt_len)
CreateEthernetHeader(char *src_mac, char *dst_mac, int protocol)

הפונקציות והמבנים שנוספו לנו על הפונקציות הקיימות

typedef struct ArpHeader{
  unsigned short hardware_type;
  unsigned short protocol_type;
  unsigned char hard_addr_len;
  unsigned char prot_addr_len;
  unsigned short opcode;
  unsigned char source_hardware[6];
  unsigned char source_ip[4];
  unsigned char dest_hardware[6];
  unsigned char dest_ip[4];
}ArpHeader;
מבנה ה Arp Header.
 
ArpHeader * CreateArpHeader(void)
יצירת Header עבור ה Arp.


סרטון הדגמה:

קוד להורדה:

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

Packet Injection With C

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

אז מה זה בדיוק Packet Injection?

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

אז הדרך הכי פשוטה לעשות זאת דרך Linux שם יש לי גישה ישירה למחלקות ה Ethernet בניגוד ל Windows , האמת שכל הנושא הזה קצת מלוכלך מתחילתו ו Microsoft מעולם לא נתנו לך ספריות ניהול כמו שצריך בכל הקשור Packets עד Windows 7 שבו הכניסו מנגנון WFP - windows filtering platform.

רכיבים נחוצים:
Linux - במקרה שלי החלטתי להשתמש ב OpenSuse

קצת רקע:
אנחנו שולחים חבילה והחבילה שלנו מחולקת לחלקים (Headers), והיא נשלחת ישירות דרך RawSocket, אז קודם יש להכין את המידע לרשום אותו לחבילה בצורה מסויימת ואח"כ להעביר אותה ל Raw Socket.

מה זה  Raw Socket? 
Raw Socket זאת שיטה לשליחת חבילות מידע דרך ה Ethernet ללא התערבות של מערכת ההפעלה, מרבית ה Api של Sockets מבוססים על Berkeley sockets.

קיימות 2 דרכים כיצד להכין את החבילה שלנו, וההבדל העיקרי איך מכינים את ה Packet וכמות הזיכרון שאנו מקצים.

הדרך הראשונה אומרת קודם נבנה כל אובייקט בנפרד (Ethernet,Ip,Tcp,Data ) אח"כ נקצה את זיכרון החבילה בחישוב של הגדלים של כל האובייקטים ביחד ונשלח ל Raw Socket - שיטה שמבזבזת יותר זיכרון כי אנחנו יוצרים אובייקטים נפרדים ואח"כ מקצים שטח נוסף בגודל כל האובייקטים שלנו.



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




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

Ethernet Header


מכיל את נתוני ה Mac Address, ואת סוג החבילה: Arp, Ip וכו' (הרשימה המלאה).
מבנה (Struct) שמוגדר בקובץ linux/if_ether.h בגודל של 14 בתים.

Ip Header


מכיל את נתוני ה IP של החבילה, את כתובת המקור והיעד ומספר פרמטרים (לפרטים נוספים).
מבנה (Struct) שמוגדר בקובץ linux/ip.h בגודל של 6 כפול 32 בתים.
Tcp Header


מכיל את נתוני ה Tcp של החבילה, פורטים, דגלים ואת המידע (לפרטים נוספים).
מבנה (Struct) שמוגדר ב linux/tcp.h בגודל של 6 כפול 32 בתים, ול Data נקצה גודל משלו.

ספריות מערכת שבהן נשתמש:
#include sys/socket.h

#include features.h

#include linux/if_packet.h 

#include linux/if_ether.h

#include errno.h  

#include sys/ioctl.h  

#include net/if.h  

#include net/ethernet.h  

#include linux/ip.h

#include arpa/inet.h  

#include string.h
string.h - string operations

 הספריות ,הן חלק מספריות המערכת של Linux, הן אחראיות על הגדרת מבנים של אובייקטים שונים כמו Packet,Header, התחברות אל ממשקי ה Ethernet וטיפול בשגיאות.

עכשיו אחרי התאוריה נעבור לשלב המעשי בכל הסיפור הזה , דבר ראשון נעשה לנו פרוייקט חדש של Ansi C  ב Eclipse ונעשה include לכל הספריות הרשומות למעלה אח"כ נגדיר לנו את הפוקנציות שקשורות ל Raw Socket.

int CreateRawSocket(int protocol_to_sniff)
{
   int rawsock;
   if((rawsock = socket(PF_PACKET, SOCK_RAW, htons(protocol_to_sniff)))== -1
   {
     perror("Error creating raw socket: ");
     exit(-1);
    }
    return rawsock;
}
יצירת ה Socket ע"י יצוג הפרוטוקול ETH_P_ALL כלומר כל סוג של Packet, בדרך כלל מגדירים זאת כך אבל אפשר להגדיר את סוג החבילה באופן ספציפי כמו ETH_P_IP , ETH_P_ARP וכו'. 

int BindRawSocketToInterface(char *device, int rawsock, int protocol)
{
   struct sockaddr_ll sll;
   struct ifreq ifr;
   bzero(&sll, sizeof(sll));
   bzero(&ifr, sizeof(ifr));
   strncpy((char *)ifr.ifr_name, device, IFNAMSIZ);
   if((ioctl(rawsock, SIOCGIFINDEX, &ifr)) == -1)
  {
    printf("Error getting Interface index !\n");
    exit(-1);
  }

  sll.sll_family = AF_PACKET;
  sll.sll_ifindex = ifr.ifr_ifindex;
  sll.sll_protocol = htons(protocol);
  if((bind(rawsock, (struct sockaddr *)&sll, sizeof(sll)))== -1)
  {
    perror("Error binding raw socket to interface\n");
    exit(-1);
  }
  return 1;
}

בפונקציה הזאת אנחנו מחברים את ה Raw Socket ל Interface שלנו, אנחנו שולחים את שם ה Device במקרה שלי Eth0 ואח"כ את ה Raw שיצרנו עם הפרוטוקול שהעברנו (ETH_P_ALL).

int SendRawPacket(int rawsock, unsigned char *pkt, int pkt_len)
{
   int sent= 0;
   if((sent = write(rawsock, pkt, pkt_len)) != pkt_len)
  {
   printf("Could only send %d bytes of packet of length %d\n", sent, pkt_len);
   return 0;
  }
  return 1;
}

רושמים את החבילה ל Socket, מעבירים את ה Socket, מצביע (Pointer) עבור החבילה ואת גודל החבילה.

עכשיו יש לנו תקשורת עם ה Raw Socket שלנו, מה שנשאר לנו הוא לבנות את החבילה:

struct ethhdr* CreateEthernetHeader(char *src_mac, char *dst_mac, int protocol)
{
  struct ethhdr *ethernet_header;
  ethernet_header = (struct ethhdr *)malloc(sizeof(struct ethhdr));
  memcpy(ethernet_header->h_source, (void *)ether_aton(src_mac), 6);
  memcpy(ethernet_header->h_dest, (void *)ether_aton(dst_mac), 6);
  ethernet_header->h_proto = htons(protocol);
  return (ethernet_header);
}
יוצרים מבנה (Struct) מסוג ethhdr ורושמים אליו את ה Mac Address של המקור והיעד, בנוסף אנחנו מוסיפים את הפרוטוקול שהוא ETHERTYPE_IP אך יש גם פרוטוקלים נוספים (לרשימה המלאה).


struct iphdr *CreateIPHeader()
{
   struct iphdr *ip_header;
   ip_header = (struct iphdr *)malloc(sizeof(struct iphdr));
   ip_header->version = 4;
   ip_header->ihl = (sizeof(struct iphdr))/4 ;
   ip_header->tos = 0;
   ip_header->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + DATA_SIZE);
   ip_header->id = htons(111);
   ip_header->frag_off = 0;
   ip_header->ttl = 111;
   ip_header->protocol = IPPROTO_TCP;
   ip_header->check = 0; 
   ip_header->saddr = inet_addr(SRC_IP);
   ip_header->daddr = inet_addr(DST_IP);
  
   ip_header->check = ComputeChecksum((unsigned char *)ip_header, ip_header->ihl*4); 
    return (ip_header);
}
יוצרים מבנה (Struct) מסוג Iphdr , מקצים זיכרון בגודל Iphdr רושמים לתוכו את הפרמטרים: כתובת מקור ויעד, גרסאת ה IP, גודל ה Header, פרוטוקול במקרה שלנו TCP, את ה TTL במקרה שלנו 111 וכו', אנחנו שולחים את ה Header לפונקצית ComputeCheckSum שבודקת אם יש תקלה ב Iphdr שלנו על מנת שלא נשלח מידע שהוא corruption ולסיום מחזרים את ה Iphdr בחזרה.

struct tcphdr *CreateTcpHeader()
{
  struct tcphdr *tcp_header;
  tcp_header = (struct tcphdr *)malloc(sizeof(struct tcphdr));
  tcp_header->source = htons(SRC_PORT);
  tcp_header->dest = htons(DST_PORT);
  tcp_header->seq = htonl(111);
  tcp_header->ack_seq = htonl(111);
  tcp_header->res1 = 0;
  tcp_header->doff = (sizeof(struct tcphdr))/4;
  tcp_header->syn = 1;
  tcp_header->window = htons(100);
  tcp_header->check = 0;
  tcp_header->urg_ptr = 0;
  return (tcp_header);
}

יוצרים מבנה (Struct) מסוג tcphdr , מקצים זיכרון בגודל tcphdr רושמים לתוכו פרמטרים: פורט יעד,פורט מקור,דגל וכו', אנחנו שולחים אותו גם לבדיקה אבל שונה מהבדיקה של ה CheckSum שעשינו ל Iphdr פה הבדיקה של ה CheckSum יותר מורכבת ועליה אני אפרט:
Pseudo Header

מבנה (Struct) שנוצר עבור בדיקת ה CheckSum של ה Tcpheader, האובייקט מכיל נתונים מה Iphdr ובעצם נשתל בזיכרון לפני Tcphdr ואחרי ה Iphdr, החישוב של ה Checksum הוא גודל ה tcphdr + data + pseudohdr ,התוצאה נרשמת ב Checksum של ה tcphdr ומשחררים את ה pseudo header ,כאשר החבילה תגיע ליעד המכונה המקבלת תפתח את החבילה ותבנה לעצמה pseudo header ותבדוק אם הוא שווה לגודל של ה checksum שמופיע ב tcphdr.         




 
CreatePseudoHeaderAndComputeTcpChecksum(struct tcphdr *tcp_header, struct iphdr *ip_header, unsigned char *data)
{
  /*The TCP Checksum is calculated over the PseudoHeader + TCP header +Data*/
  /* Find the size of the TCP Header + Data */
  int segment_len = ntohs(ip_header->tot_len) - ip_header->ihl*4;

 /* Total length over which TCP checksum will be computed */
  int header_len = sizeof(PseudoHeader) + segment_len;

  /* Allocate the memory */
  unsigned char *hdr = (unsigned char *)malloc(header_len);

 /* Fill in the pseudo header first */
  PseudoHeader *pseudo_header = (PseudoHeader *)hdr;
  pseudo_header->source_ip = ip_header->saddr;
  pseudo_header->dest_ip = ip_header->daddr;
  pseudo_header->reserved = 0;
  pseudo_header->protocol = ip_header->protocol;
  pseudo_header->tcp_length = htons(segment_len);
 
/* copy TCP */
  memcpy((hdr + sizeof(PseudoHeader)), (void *)tcp_header, tcp_header->doff*4);

/* copy the Data */
  memcpy((hdr + sizeof(PseudoHeader) + tcp_header->doff*4), data, DATA_SIZE);

 /* Calculate the Checksum */
  tcp_header->check = ComputeChecksum(hdr, header_len);

/* Free the PseudoHeader */
 free(hdr);

return ;
}

הדוגמה הבאה מראה שליחה של Packet מכתובת שלא קיימת עם Mac Address מזוייפים.


קוד להורדה

בהצלחה...

יום רביעי, 9 בפברואר 2011

Command Line With C#


בחרתי לכתוב תוכנית שמבוססת על תוכניות של ה Command Line - Console שקשורות לרשתות, כלי אבחון פשוט שמראה לנו את הנתונים של הרשת - משתמשים, ספריות, מחשבים וחיבורים, מצד אחד כלי מאוד לגיטימי כל אחד רוצה לנתר את הרשת שלו, אבל מצד שני ניתן לבצע פקודות ללא צורך במשתמש... לשתול אותן בוירוסים או בתולעים.
התוכניות שאיתן נעבוד קיימות בכל הגרסאות של מערכת ההפעלה מסוג Windows, לכן אני לא צריך לדאוג לעדכן אותן בכל גרסה והן תמיד יעבדו, בסופו של דבר אנחנו מפעילים Process שמריץ את התוכנית ומחזיר את הפלט שלה בסיומה.

תחילה נעבור על הפקודות שבחרתי:
Netstat
Ping
Arp
Net
     User
     Share
     Start
     View
      Use



על מנת להריץ את הפקודה נשתמש ב Process שנעמיס עליו אובייקט מסוג ProcessStartInfo שמכיל את הפקודה והתנאים שהתוכנית מקבלת.

private void running_process()

{
   Process process = new Process();
 הצהרה על Process חדש.
  ProcessStartInfo info = new ProcessStartInfo("Command");
 שם התוכנית והמיקום שלה במקרה שלנו היא ב System32 ולכן זמינה בכל מקום.
  info.Arguments = "Command Args";
 התנאים של התוכנית.
  info.UseShellExecute = false;
האם להפעיל את התוכנית דרך ה Shell או ישירות מהקובץ.
   info.RedirectStandardOutput = true;
קבלת Output בצורה סינכרונית או א-סינכרונית מהתוכנית.
   info.CreateNoWindow = true;
האם ליצור חלון?
   process.StartInfo = info;
   process.Start();
ריצת התוכנית.
   string mystring = process.StandardOutput.ReadToEnd();
קבלת הפלט מהתוכנית
}
 
דוגמה:
 

יום שבת, 5 בפברואר 2011

Json Starting Guide C#

JavaScript Object Notation - Json

היא שיטה להעברת נתונים בין מחשבים , היא נכנסה לשימוש בשנת 1999  עם כניסת סטנדרטים חדשים ב Javascript ומאפשרת שליחה של אובייקטים מסוגים שונים בצורה נוחה וברורה , היא בעצם מתחרה ב XML כי היא יותר דומה ושימושית כשפת תוכנה כחלק משפות הפיתוח הקיימות, בנוסף היא תומכת ב Xml ומאפשרת המרה בניהם, אין ספק שהשפה תפסה תאוצה בשנים האחרונות במיוחד בכל הקשור למידע משתנה, Api ו Ajax , ומאפשרת עבודה נוחה במיוחד ב Framework 3 ומעלה עם  Linq, עצם העובדה שיש לה תמיכה מרובה בשפות שכמעט זהה ל Xml מאפשרת המרה נוחה לאובייקטים בשפות שונות וחוסכת לנו תהליכי המרה מסורבלים.



המבנה של Json הוא פשוט ומורכב מ 2 אובייקטים מרכזיים : אובייקט של מידע, ומערכי מידע.

 אובייקט:
{"name":"value"}
כל אובייקט מידע מתחיל ונסגר עם סוגריים מסולסלים וגרשיים, אח"כ יש את שם האובייקט יש הפרדה בעזרת נקודתיים ואח"כ את ערך האובייקט, הערך יכול להיות בצורות של String,Boolean,Number,Null

מערך:
{"data":[{"name":"value"},{"name":"value"}]}
מערך של אובייקטים מתחיל ונסגר בסוגריים מרובעיים, הוא מכיל אובייקטים , ובין כל אובייקט חייב שהיה פסיק.

{"data": [
 {
   "id": "2132232",
   "name":
             {
               "firstname":"proxytype",
               "lastname":"blog"
              },
  "location":
              {
                "zipcode", "43823",
                 "address": "blogger.com"
               },
    "vip":"true",
    "birthday":"2010-03-24T11:16:02+0000"
  }
]}
 קיימות מחלקות רבות לעבודה עם Json ותמיכה בשפות רבות:
Java,Python,Perl,.Net
המחלקה המפורסמת ל .Net היא Json.Net וניתנת להורדה:
תחילה יש לבצע Reference עבור המחלקה ואח"כ נתחיל בבניית האובייקט שנעבוד איתו עם ה Json , ניסיתי לבנות אובייקט יחסית מורכב שיכיל בתוכו מספר אספקטים שונים בסביבת .Net הוא מכיל בתוכו הורשה מאובייקט אחר ובנוסף קיים בו מופע של אובייקט נוסף ומספר פרמטרים נוספים במטרה לסבך את העניינים.

Person
הוא יורש את אובייקט Name שמכיל בתוכו 2 מחרוזות אחת של שם פרטי ואחת של שם משפחה, בנוסף יש בו מופע של אובייקט Location שמכיל Integer של Zipcode ומחרוזות של Address, בתוך אובייקט Person יש שדות נוספים כמו Integer של ID, תאריך עבור Birthday וערך Boolean עבור Vip.

public class name
{
  [JsonProperty]
  public string Firstname;
  [JsonProperty]
  public string Lastname;
}

public class location
{
  [JsonProperty]
  public int ZipCode;
  [JsonProperty]
  public string Address;
}

public class person : name
{
  [JsonProperty]
  public location mylocation = new location();

  [JsonProperty]
  public int Id;

  [JsonProperty]
  public bool Vip;
 
  [JsonProperty]
  [JsonConverter(typeof(IsoDateTimeConverter))]
  public DateTime Birthday;

}

 [JsonProperty]
חובה להוסיף מעל כל ערך שאנו רוצים להשתמש בו עם Json.

[JsonConverter(typeof(IsoDateTimeConverter))]
המרה של תאריכים ע"י JsonConverter.

ועכשיו אחרי שיש לנו את האובייקט נבנה לנו מחלקה שקורא וממירה ל Json , תהליך העבודה עם Json מחולק ל 2 קבוצות , קבוצת כתיבה אובייקט ל Json וקבוצת המרה בין Json לאובייקט.

פונקציות ממירות:
public person json_reader()
{
   person myperson = new person();
   string json = @"{ ""mylocation"": { ""ZipCode"": 34434, ""Address"": ""blooger.com"" }, ""Id"": 0
   , ""Vip"":   true, ""Birthday"": ""2011-02-05T00:00:00+02:00"", ""Firstname"": ""proxytype"", ""Lastname"":
   ""blog"" }";
   myperson = (person)JsonConvert.DeserializeObject(json,typeof(person));
   return myperson;
}
הפונקציה קוראת את המחרוזת json וממירה אותו ל Person.

public person[] json_array_reader()
{
   person[] myperson = new person[3];
   string json = @"[ { ""mylocation"": { ""ZipCode"": 34434, ""Address"": ""blooger.com"" }, ""Id"": 0,
   ""Vip"": true, ""Birthday"": ""2011-02-05T00:00:00+02:00"", ""Firstname"": ""proxytype"", ""Lastname"":
   ""blog"" }, { ""mylocation"": { ""ZipCode"": 34434, ""Address"": ""blooger.com"" }, ""Id"": 1, ""Vip"": true,
   ""Birthday"": ""2011-02-05T00:00:00+02:00"", ""Firstname"": ""proxytype"", ""Lastname"": ""blog"" },  
   { ""mylocation"": { ""ZipCode"": 34434, ""Address"": ""blooger.com"" }, ""Id"": 2, ""Vip"": true, 
   ""Birthday"": ""2011-02-05T00:00:00+02:00"", ""Firstname"": ""proxytype"", ""Lastname"": ""blog"" } ] ";
  
   myperson = (person[])JsonConvert.DeserializeObject(json, typeof(person[]));
   return myperson;
}
הפונקציה קוראת את המחרוזת json ומחזירה מערך של 3 Person.
 
פונקציות כתיבה:
public string json_Writer()

{
   myperson = new person();
   myperson.Firstname = "proxytype";
   myperson.Lastname = "blog";
   myperson.mylocation.Address = "blooger.com";
   myperson.mylocation.ZipCode = 34434;
   myperson.Vip = true;
   myperson.Birthday = DateTime.Now.Date;
   string json = JsonConvert.SerializeObject(myperson, Formatting.Indented);
   return json;
}
הפונקציה ממירה את האובייקט Person למחרוזת Json.

public string json_array_writer()
{
   person[] myarray = new person[3];
   for (int i = 0; i < myarray.Length; i++)
   {
      myarray[i] = new person();
      myarray[i].Firstname = "proxytype";
      myarray[i].Lastname = "blog";
      myarray[i].Id = i;
      myarray[i].mylocation.Address = "blooger.com";
      myarray[i].mylocation.ZipCode = 34434;
      myarray[i].Vip = true;
      myarray[i].Birthday = DateTime.Now.Date;
    }

    string json = JsonConvert.SerializeObject(myarray, Formatting.Indented);
    return json;
}

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