Advertisement
Guest User

climbo

a guest
Jan 24th, 2009
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.98 KB | None | 0 0
  1. /*
  2.  *    exe2ico.c: Herramienta para sacar iconos de ejecutables y DLL de
  3.  *    Windows para Linux.
  4.  * Copyright (c) BatchDrake 2007 <BatchDrake@gmail.com>
  5.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  *
  21.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <libgen.h>
  26. #include <stdlib.h>
  27. #include <time.h>
  28. #include <errno.h>
  29. #include <string.h>
  30. #include <fcntl.h>
  31. #include <unistd.h>
  32.  
  33. #define DOS_SIGNATURE 0x5a4d /* "MZ" */
  34. #define IMAGE_NT_SIGNATURE 0x4550 /* "PE" */
  35. #define OPTIONAL_HEADER_SIGNATURE 0x10b
  36.  
  37. #define __packed  __attribute__ ((packed))
  38.  
  39. #define _u64 unsigned long long int
  40. #define _u32 unsigned int
  41. #define _u16 unsigned short
  42. #define _u8  unsigned char
  43.  
  44. #define _s64 long long int
  45. #define _s32 int
  46. #define _s16 short
  47. #define _s8  char
  48.  
  49. #define RT_ICON 3
  50.  
  51. #define UNSIG(x) ( (x) & ~0x80000000)
  52. #define error(fmt, arg...) fprintf (stderr, "error: %s: " fmt, name, ##arg)
  53.  
  54. /* Cabecera DOS del ejecutable */
  55. typedef struct _doshdr
  56. {
  57.     _u16 dh_signature __packed;
  58.     _u8  dh_dos_data[22];
  59.     _u32 dh_stub_offset;
  60.     _u8  dh_dos_data2[32];
  61.     _u32 dh_pe_offset;
  62. }
  63. dos_header_t;
  64.  
  65. /* Cabecera PE (COFF) del ejecutable */
  66. typedef struct _pehdr
  67. {
  68.     _u32 pe_signature;
  69.     _u16 pe_arch;
  70.     _u16 pe_sect_count;
  71.     _u32 pe_assembly_time;
  72.     _u32 pe_sym_table_offset;
  73.     _u32 pe_sym_count;
  74.     _u16 pe_ohdr_size __packed;
  75.     _u16 pe_charact __packed;
  76.    
  77. }
  78. pe_header_t;
  79.  
  80. /* Cabecera opcional / NT */
  81. typedef struct _ohdr
  82. {
  83.     _u16 op_magic;
  84.     _u16 op_linker_version;
  85.     _u32 op_size_of_code;
  86.     _u32 op_size_of_data;
  87.     _u32 op_size_of_bss;
  88.     _u32 op_entrypoint;
  89.     _u32 op_codebase;
  90.     _u32 op_database;
  91.     _u32 op_imagebase;
  92.     _u32 op_s_align;
  93.     _u32 op_f_align;
  94.     _u16 op_os_major;
  95.     _u16 op_os_minor;
  96.     _u16 op_image_major;
  97.     _u16 op_image_minor;
  98.     _u16 op_subsystem_major;
  99.     _u16 op_subsystem_minor;
  100.     _u32 op_win32_version;
  101.     _u32 op_image_size;
  102.     _u32 op_headers_size;
  103.     _u32 op_checksum;
  104.     _u16 op_nt_subsystem;
  105.     _u16 op_dll_chars;
  106.     _u32 op_stack_size;
  107.     _u32 op_stack_commit;
  108.     _u32 op_heap_size;
  109.     _u32 op_heap_commit;
  110.     _u32 op_loader_flags;
  111.     _u32 op_rva_count;
  112. }
  113. optional_header_t;
  114.  
  115. /* Entrada del directorio de datos */
  116. typedef struct _rva
  117. {
  118.     _u32 rv_rva;
  119.     _u32 rv_size;
  120. }
  121. rva_directory_entry_t;
  122.  
  123. /* Cabecera de sección. La usamos para saber dónde está .rsrc */
  124. typedef struct _shdr
  125. {
  126.     _u8  sh_name[8];
  127.     union
  128.     {
  129.         _u32 sh_physical;
  130.         _u32 sh_virtualsiz;
  131.     }
  132.     sh_addrdata;
  133.     _u32 sh_virtual_addr;
  134.     _u32 sh_raw_data_size;
  135.     _u32 sh_offset;
  136.     _u32 sh_rel_offset;
  137.     _u32 sh_lns_offset;
  138.     _u16 sh_rel_count;
  139.     _u16 sh_lns_count;
  140.     _u32 sh_chars;
  141. }
  142. section_header_t;
  143.  
  144. /* Cabecera del directorio de recursos */
  145. typedef struct _imrdir
  146. {
  147.     _u32  rd_char;
  148.     _u32  rd_timestamp;
  149.     _u16  rd_major;
  150.     _u16  rd_minor;
  151.     _u16  rd_named;
  152.     _u16  rd_id;
  153. }
  154. image_resource_directory_t;
  155.  
  156. /* Entrada en el directorio de recursos */
  157. typedef struct _imrdirent
  158. {
  159.     _u32   rd_name;
  160.     _u32   rd_off; /* Esto es un offset relativo, y mide desplazamientos
  161.                       desde el inicio de la sección. */
  162. }
  163. image_resource_directory_entry_t;
  164.  
  165. /* Información sobre el icono en el recurso */
  166. typedef struct _ihdrinf
  167. {
  168.     _u32 ih_address; /* OJO: Esto es una RVA sin la dirección base del ejecutable */
  169.     _u32 ih_size;
  170.     _u32 ih_pad[2];
  171. }
  172. icon_header_info_t;
  173.  
  174. /* Estas estructuras ya se corresponden con los ficheros .ICO */
  175. /* Cabecera del icono */
  176. typedef struct _icohdr
  177. {
  178.     _u16 id_reserved;
  179.     _u16 id_type;
  180.     _u16 id_count;
  181. }
  182. icon_header_t;
  183.  
  184. /* Entrada dentro del icono, con información sobre el tamaño del mismo */
  185. typedef struct _icodirent
  186. {
  187.     _u8  ie_width;
  188.     _u8  ie_height;
  189.     _u8  ie_colors;
  190.     _u8  ie_reserved;
  191.     _u16 ie_planes;
  192.     _u16 ie_bits;
  193.     _u32 ie_rsrc_size;
  194.     _u32 ie_offset;
  195. }
  196. icon_entry_t;
  197.  
  198. /* Cabecera DIB (datos del icono per-se) */
  199. typedef struct _bmpinfohdr
  200. {
  201.     _u32  dh_size;
  202.     _u32  dh_width;
  203.     _u32  dh_height;
  204.     _u16  dh_planes;
  205.     _u16  dh_bits;
  206.     _u32  dh_compression;
  207.     _u32  dh_size_image;
  208.     _u32  dh_x_ppm;
  209.     _u32  dh_y_ppm;
  210.     _u32  dh_clr_used;
  211.     _u32  dh_clr_important;
  212. }
  213. dib_header_t;
  214.  
  215. /* Algunas cabeceras globales */
  216. optional_header_t opt_header;
  217. rva_directory_entry_t rva_headers[16];
  218.  
  219. /* Algunas variables necesarias para el comportamiento del programa */
  220. char *name;
  221. int   do_count;
  222. int   dumpcnt;
  223. int   dumptotal;
  224.  
  225. int   specific_width = -1;
  226. int   specific_depth = -1;
  227. char *specific_output;
  228.  
  229. /* Esto nos carga una estructura en cualquier parte del ejecutable sin
  230.    alterar el cursor del fichero */
  231. int load_struct (FILE *fp, _u32 off, void *ptr, _u32 size)
  232. {
  233.     _u32 last_seek;
  234.     int r;
  235.    
  236.     last_seek = ftell (fp);
  237.     fseek (fp, off, SEEK_SET);
  238.    
  239.     r = fread (ptr, size, 1, fp);
  240.    
  241.     fseek (fp, last_seek, SEEK_SET);
  242.    
  243.     return r != 1 ? -1 : 0;
  244. }
  245.  
  246. /* Las siguientes tres funciones son lo más complicado del programa. Son las
  247.   que se encargan de leer el árbol de recursos. La cosa es así:
  248.  
  249.                         .rsrc                                  
  250.                           |
  251.                 image_resource_directory_t: Indica cuántos recursos tenemos
  252.                       RT_DIALOG
  253.                       RT_CURSOR
  254.                        RT_ICON: Esto nos interesa. Offset relativo + offset
  255.                           |     de la propia sección.
  256.                           |     <--- offset@image_resource_directory_entry_t
  257.                           V
  258.                 image_resource_directory_t: Indica cuántos recursos de icono
  259.                        Recurso 1            tenemos.
  260.                        Recurso 2
  261.                        Recurso 3
  262.                           |
  263.                           |     <--- offset@image_resource_directory_entry_t
  264.                           V
  265.                 image_resource_directory_t: Indica cuántos iconos hay dentro
  266.                        Icono 1              de éste recurso.
  267.                        Icono 2
  268.                        Icono 3
  269.                           |
  270.                           |     <--- offset@image_resource_directory_entry_t
  271.                           V
  272.                   icon_header_info_t
  273.                           |
  274.                           V     <--- Offset: RVA sin Imagebase
  275.         *** Datos del icono (sin cabecera .ICO) ***
  276.  
  277. Como véis, es un peñazo leer los recursos de un ejecutable de Windows. Tenemos
  278. que leer TRES directorios de recursos en árbol y luego una cabecera de icono
  279. de la cual tenemos que despejar la maldita dirección física a partir de una
  280. dirección virtual sin el ImageBase.
  281. */
  282.                
  283. /* Esta vuelca el icono a partir del recurso de icono */
  284.  
  285. int dump_this_icon (FILE *fp, _u32 offset, _u32 roff)
  286. {
  287.     image_resource_directory_t dir;
  288.     image_resource_directory_entry_t ent;
  289.     icon_header_info_t hdr;
  290.    
  291.     /* Cabeceras del .ICO */
  292.     icon_header_t ico_hdr;
  293.     icon_entry_t ico_ent;
  294.     dib_header_t *dib_hdr;
  295.    
  296.     char *buff;
  297.     int i;
  298.     FILE *sfp;
  299.    
  300.     char file[256];
  301.    
  302.     if (specific_output && dumpcnt)
  303.         return 0;
  304.    
  305.     load_struct (fp, offset + roff, &dir, sizeof (dir));
  306.    
  307.     for (i = 0; i < dir.rd_named + dir.rd_id; i++)
  308.     {
  309.         load_struct (fp, offset + roff + sizeof (dir) + sizeof (ent) * i, &ent, sizeof (ent));
  310.         load_struct (fp, UNSIG (ent.rd_off) + offset, &hdr, sizeof (hdr));
  311.    
  312.         buff = malloc (hdr.ih_size);
  313.         if (buff == NULL)
  314.         {
  315.             error ("memoria insuficiente para volcar el icono\n");
  316.             exit (1);
  317.         }
  318.    
  319.         /* Despejamos el offset sin el Imagebase */
  320.         load_struct (fp, hdr.ih_address - rva_headers[2].rv_rva + offset, buff, hdr.ih_size);
  321.        
  322.         dib_hdr = (dib_header_t *) buff;
  323.    
  324.         if (specific_width != -1 && specific_width != dib_hdr->dh_width)
  325.             return 0;
  326.    
  327.         if (specific_depth != -1 && specific_depth != dib_hdr->dh_bits)
  328.             return 0;
  329.    
  330.         if (do_count)
  331.         {
  332.             dumpcnt++;
  333.             return 0;
  334.         }
  335.    
  336.         if (specific_output)
  337.             strncpy (file, specific_output, 255);
  338.         else
  339.             sprintf (file, "%s-%04d-%d-%dx%d.ico", name, dumpcnt, ent.rd_name, dib_hdr->dh_width, (unsigned char) dib_hdr->dh_height);    
  340.        
  341.    
  342.         printf ("%s [%d]: icono %d/%d (%dx%d / %d bits) ==>\n    %s... ", name, ent.rd_name, i + 1, dir.rd_named + dir.rd_id, (unsigned char) dib_hdr->dh_width, (unsigned char) dib_hdr->dh_height, dib_hdr->dh_bits, file);
  343.         fflush (stdout);
  344.  
  345.         sfp = fopen (file, "wb");
  346.  
  347.         if (sfp == NULL)
  348.             perror (file);
  349.         else
  350.         {
  351.             /* Inicializamos el icono */
  352.             ico_hdr.id_reserved = 0;
  353.             ico_hdr.id_type = 1;
  354.             ico_hdr.id_count = 1;
  355.             fwrite (&ico_hdr, sizeof (ico_hdr), 1, sfp);
  356.            
  357.             /* Inicializamos la entrada */
  358.             ico_ent.ie_width = ico_ent.ie_height = dib_hdr->dh_width;
  359.             ico_ent.ie_colors = 0;
  360.             ico_ent.ie_reserved = 0;
  361.             ico_ent.ie_planes = 0;
  362.             ico_ent.ie_bits = 0;
  363.             ico_ent.ie_rsrc_size = hdr.ih_size;
  364.             ico_ent.ie_offset = sizeof (icon_header_t) + sizeof (icon_entry_t);
  365.            
  366.             fwrite (&ico_ent, sizeof (ico_ent), 1, sfp);
  367.        
  368.             /* Escribimos todos los datos del icono */
  369.             fwrite (buff, hdr.ih_size, 1, sfp);
  370.             fclose (sfp);
  371.             dumpcnt++;
  372.             dumptotal++;
  373.        
  374.             printf ("hecho (%d bytes escritos)\n\n", hdr.ih_size, sizeof (icon_header_t) + sizeof (icon_entry_t));
  375.         }
  376.    
  377.         free (buff);
  378.        
  379.     }
  380.    
  381.     return 0;
  382. }
  383.  
  384. /* Esto busca recursos de icono en un RT_ICON */
  385. int analyze_icons_in_rsrc (FILE *fp, _u32 offset, _u32 roff)
  386. {
  387.     image_resource_directory_t dir;
  388.     image_resource_directory_entry_t ent;
  389.     int i;
  390.  
  391.    
  392.     load_struct (fp, offset + roff, &dir, sizeof (dir));
  393.    
  394.     for (i = 0; i < dir.rd_named + dir.rd_id; i++)
  395.     {
  396.         load_struct (fp, offset + roff + sizeof (dir) + sizeof (ent) * i, &ent, sizeof (ent));
  397.         dump_this_icon (fp, offset, UNSIG (ent.rd_off));
  398.     }
  399.    
  400.     return 0;
  401. }
  402.  
  403. /* Esto busca el recurso RT_ICON en .rsrc */
  404. int analyze_rsrc_section (FILE *fp, _u32 offset, _u32 size)
  405. {
  406.     image_resource_directory_t dir;
  407.     image_resource_directory_entry_t ent;
  408.  
  409.     int i;
  410.    
  411.     load_struct (fp, offset, &dir, sizeof (dir));
  412.    
  413.     for (i = 0; i < dir.rd_named + dir.rd_id; i++)
  414.     {
  415.         load_struct (fp, offset + sizeof (dir) + sizeof (ent) * i, &ent, sizeof (ent));
  416.         if (ent.rd_name == RT_ICON)
  417.             analyze_icons_in_rsrc (fp, offset, UNSIG (ent.rd_off));
  418.         /* VirtualOffsetYouHave-ImageBase-VirtualOffsetOfSection+RawOffsetOfSection */
  419.        
  420.     }
  421.    
  422.     return 0;
  423. }
  424.  
  425. void parse_exe_file (char *file)
  426. {
  427.     FILE *fp;
  428.     dos_header_t dos_header;
  429.     pe_header_t  pe_header;
  430.     section_header_t      sect_header;
  431.     int i;
  432.    
  433.     dumpcnt = 0;
  434.     fp = fopen (file, "rb");
  435.     name = basename (file);
  436.    
  437.     if (fp == NULL)
  438.     {
  439.         perror (file);
  440.         return;
  441.     }
  442.    
  443.     fread (&dos_header, sizeof (dos_header_t), 1, fp);
  444.     if (dos_header.dh_signature != DOS_SIGNATURE)
  445.     {
  446.         error ("no es un ejecutable MZ válido\n");
  447.         fclose (fp);
  448.         return;
  449.     }
  450.    
  451.     if (!dos_header.dh_pe_offset)
  452.     {
  453.         error ("este ejecutable es de MS-DOS. Los ejecutables de MS-DOS no tienen iconos\n");
  454.         fclose (fp);
  455.         return;
  456.     }
  457.    
  458.     fseek (fp, dos_header.dh_pe_offset, SEEK_SET);
  459.    
  460.     fread (&pe_header, sizeof (pe_header_t), 1, fp);
  461.    
  462.     if (pe_header.pe_signature != IMAGE_NT_SIGNATURE)
  463.     {
  464.         error ("esto no parece ser un ejecutable PE válido\n");
  465.         error ("IMAGE_NT_SIGNATURE inesperado (0x%08x)\n", pe_header.pe_signature);
  466.         fclose (fp);
  467.         return;
  468.     }
  469.  
  470.     if (pe_header.pe_ohdr_size != 224)
  471.     {
  472.         error ("la cabecera opcional del ejecutable no coincide con la esperada\n", pe_header.pe_ohdr_size);
  473.         fclose (fp);
  474.         return;
  475.     }
  476.    
  477.     fread (&opt_header, sizeof (optional_header_t), 1, fp);
  478.     if (opt_header.op_magic != OPTIONAL_HEADER_SIGNATURE)
  479.     {
  480.         error ("este ejecutable no tiene una cabecera opcional válida\n");
  481.         fclose (fp);
  482.         return;
  483.     }
  484.    
  485.    
  486.     if (opt_header.op_rva_count > 16)
  487.     {
  488.         error ("el directorio de datos tiene demasiadas entradas\n");
  489.         fclose (fp);
  490.         return;
  491.     }
  492.    
  493.     for (i = 0; i < opt_header.op_rva_count; i++)
  494.         fread (&rva_headers[i], sizeof (rva_directory_entry_t), 1, fp);
  495.    
  496.     if (pe_header.pe_sect_count)
  497.     {
  498.         for (i = 0; i < pe_header.pe_sect_count; i++)
  499.         {
  500.             fread (&sect_header, sizeof (section_header_t), 1, fp);
  501.            
  502.             if (rva_headers[2].rv_rva == sect_header.sh_virtual_addr)
  503.                 analyze_rsrc_section (fp, sect_header.sh_offset, sect_header.sh_raw_data_size);
  504.         }
  505.     }
  506.    
  507.     if (!dumpcnt)
  508.     {
  509.         if (specific_width != -1 || specific_depth != -1)
  510.             fprintf (stderr, "%s: no hay iconos que sigan el criterio\n", name);
  511.         else
  512.             fprintf (stderr, "%s: el ejecutable no tiene iconos\n", name);
  513.     }
  514.     else
  515.     {
  516.         printf ("%s: %d iconos", name, dumpcnt);
  517.    
  518.         if (do_count)
  519.             printf ("\n");
  520.         else
  521.             printf (", %d volcados\n", dumpcnt);
  522.     }
  523.    
  524.     fclose (fp);
  525. }
  526.  
  527. void help (char *argv0)
  528. {
  529.     fprintf (stderr, "Herramienta de extración de iconos de ejecutables de Windows\n");
  530.     fprintf (stderr, "Por Gonzalo J. Carracedo <BatchDrake@gmail.com>\n\n");
  531.     fprintf (stderr, "FORMA DE USO:\n");
  532.     fprintf (stderr, "    %s [opciones] fichero.exe [fichero2.exe [fichero3.dll [fichero4.scr]]]\n", argv0);
  533.     fprintf (stderr, "\nOPCIONES:\n");
  534.     fprintf (stderr, "    -c, --count:             Sólo cuenta los iconos (no extrae)\n");
  535.     fprintf (stderr, "    -w, --width <tamaño>:    Extrae sólo aquellos iconos de ese ancho\n");
  536.     fprintf (stderr, "    -d, --depth <colores>:   Extrae aquellos iconos que tengan esa profundidad\n");
  537.     fprintf (stderr, "    -o, --output <archivo>:  Extrae el primer icono a <archivo>\n");
  538.     fprintf (stderr, "    --help:                  Esta ayuda\n");
  539.     fprintf (stderr, "\nEste programa es libre y se distribuye bajo los términos de la licencia\n");
  540.     fprintf (stderr, "GNU/GPL versión 2.\n");
  541. }
  542.  
  543. int main (int argc, char **argv)
  544. {
  545.     FILE *fp;
  546.     int i;
  547.     int mul;
  548.    
  549.     mul = 0;
  550.    
  551.     if (argc < 2)
  552.     {
  553.         fprintf (stderr, "%s: Se speraba un argumento\n", argv[0]);
  554.         help (argv[0]);
  555.         exit (1);
  556.     }
  557.    
  558.    
  559.     for (i = 1; i < argc; i++)
  560.     {
  561.         if (strcmp (argv[i], "-c") == 0 || strcmp (argv[i], "--count") == 0)
  562.         {
  563.             do_count = 1;
  564.             continue;
  565.         }
  566.         else if (strcmp (argv[i], "--help") == 0)
  567.         {
  568.             help (argv[0]);
  569.             exit (0);
  570.         }
  571.         else if (strcmp (argv[i], "-w") == 0 || strcmp (argv[i], "--width") == 0)
  572.         {
  573.             if (++i >= argc)
  574.             {
  575.                 fprintf (stderr, "%s: La opción %s espera un valor\n\n", argv[0], argv[i - 1]);
  576.                 help (argv[0]);
  577.                 exit (1);
  578.             }
  579.        
  580.             if (!sscanf (argv[i], "%u", &specific_width))
  581.             {
  582.                 fprintf (stderr, "%s: La opción %s espera un valor numérico\n\n", argv[0], argv[i - 1]);
  583.                 help (argv[0]);
  584.                 exit (1);
  585.             }
  586.        
  587.             continue;
  588.         }
  589.         else if (strcmp (argv[i], "-d") == 0 || strcmp (argv[i], "--depth") == 0)
  590.         {
  591.             if (++i >= argc)
  592.             {
  593.                 fprintf (stderr, "%s: La opción %s espera un valor\n\n", argv[0], argv[i - 1]);
  594.                 help (argv[0]);
  595.                 exit (1);
  596.             }
  597.        
  598.             if (!sscanf (argv[i], "%u", &specific_depth))
  599.             {
  600.                 fprintf (stderr, "%s: La opción %s espera un valor numérico\n\n", argv[0], argv[i - 1]);
  601.                 help (argv[0]);
  602.                 exit (1);
  603.             }
  604.        
  605.             continue;
  606.         }
  607.         else if (strcmp (argv[i], "-o") == 0 || strcmp (argv[i], "--output") == 0)
  608.         {
  609.             if (++i >= argc)
  610.             {
  611.                 fprintf (stderr, "%s: La opción %s espera un valor\n\n", argv[0], argv[i - 1]);
  612.                 help (argv[0]);
  613.                 exit (1);
  614.             }
  615.        
  616.             specific_output = argv[i];
  617.        
  618.             continue;
  619.         }
  620.    
  621.         parse_exe_file (argv[i]);
  622.         mul++;
  623.     }
  624.    
  625.     if (!mul)
  626.     {
  627.         fprintf (stderr, "%s: Se speraba un fichero\n", argv[0]);
  628.         help (argv[0]);
  629.         exit (1);
  630.     }
  631.    
  632.     if (mul > 2)
  633.         printf ("Total: %d iconos volcados en todos los archivos\n", dumptotal);
  634.  
  635.     return 0;
  636. }
  637.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement