Acceder a la caché de Internet Explorer (II)

ie

:-/
Hola de nuevo,

Siento haber tardado más de lo previsto en publicar este post, pero hemos tenido un fallecimiento en la familia este fin de semana y todavía andamos un poco descolocados. De todos modos, siguiendo con el hilo del primer post de esta serie, vamos a ver como leer los valores de los archivos temporales de Internet (imágenes que son almacenadas en caché, cookies, sitios visitados, etc.). Para acceder al contenido de esta caché vamos a usar un par de llamadas al API de windows y vamos a guardar el contenido de estas consultas en un medio persistente para su posterior análisis.

El objetivo de todo esto:

Nuestro objetivo va a consistir en recoger información de la caché cada X tiempo (supongamos cada hora), y mediante serialización persistirla en ficheros XML en una ubicación remota. Además, para complicarlo un poquito más vamos a hacer que esta ubicación no sea accesible desde el usuario actual, de modo que debamos impersonar otro inicio de sesión que si tenga permisos sobre esta ubicación. Todo esto, lo encapsularemos como un servicio de Windows y crearemos un proyecto de instalación que podremos distribuir en los clientes que deseamos inspeccionar.

Una vez terminado este ejercicio habremos mostrado varias cosas como:

  • Acceder a la caché de Internet Explorer
  • Serializar objetos a ficheros XML
  • Impersonar la ejecución de nuestra aplicación con otro usuario
  • Crear un servicio de Windows que ejecute un proceso cada X tiempo

De todos modos me gustaría dejar clara una cosa, para que nadie me malinterprete:

** El objetivo de todo esto no es ni mucho menos crear una herramienta para espiar a nadie, si no que lo he considerado más bien como un projecto que reune varias cosillas interesantes a explicar, un modo de reunirlas bajo un mismo ejercicio **


Preparando el terreno:

El primer paso va a ser declarar una clase que almacene la información de las entradas devueltas por las funciones FindFirstUrlCacheEntry y FindNextUrlCacheEntry.

[Serializable]
public class IECacheEntry
{
    public string url;
    public string size;
    public string lastAccessTime;
    public string lastModifiedTime;
    public string expireTime;
    public string filename;
 
    public IECacheEntry()
    {
    }
 
    public IECacheEntry(
        string _url,
        string _size,
        string _lastAccessTime,
        string _lastModifiedTime,
        string _expireTime, 
        string _filename)
    {
        url = _url;
        size = _size;
        lastAccessTime = _lastAccessTime;
        lastModifiedTime = _lastModifiedTime;
        expireTime = _expireTime;
        filename = _filename;
    }
}

Esta clase la vamos a usar conjuntamente con esta clase, que identifica la consulta y recoge los datos que se guardarán cada vez que se ejecute la consulta a la caché. Esta clase también la decoraremos con el atributo serializable para posteriormante poder persistirla a un fichero XML:

[Serializable]
public class IECacheQuery
{
    public IECacheQuery() { }
 
    public string hostname = string.Empty;
    public string username = string.Empty;
    public DateTime date = DateTime.Now;
    public List<IECacheEntry> results;
}

Empezando a ensamblar las piezas:

EL corazón de este ejercicio consiste en esta pequeña función “getResults”, que a partir de una cadena que contiene el patrón de búsqueda devuelve todas las instancias de la caché que coinciden con ésta. Este patrón de búsqueda puede contener el valor “cookies”, “visited”, una URL en concreto o bien NULL (que devuelve todos los valores de la caché). A continuación estos resultados se almacenan en una lista genérica que se devuelve como valor de retorno de la función.

Nota 1: Este código se ha realizado con compatibilidad con estaciones Windows 2000 que admiten versiones del Framework hasta la 2.0, de modo lamentablemente que no se han podido utilizar las bondades del Framework 3.5 (en particular he echado mucho de menos a LINQ to objects).

Nota 2 : En el código pueden observarse llamadas a funciones que no han sido descritas en el artículo (como el método ToStringFromFileTime en el código siguiente). Sin embargo estas funciones si pueden encontrarse en el código completo del ejemplo que se podrá descargar al final de la serie.

private List<IECacheEntry> getResults(string patternText)
{
    List<IECacheEntry> listresults = new List<IECacheEntry>();
    List<IECacheAPI.INTERNET_CACHE_ENTRY_INFO> results =
        IECacheAPI.FindUrlCacheEntries(patternText);
 
    foreach (IECacheAPI.INTERNET_CACHE_ENTRY_INFO result in results)
    {
        IECacheEntry entry = new IECacheEntry();
 
        listresults.Add(
            new IECacheEntry
                (
                    result.lpszSourceUrlName,
                    ((((Int64)result.dwSizeHigh) << 32) + result.dwSizeLow).ToString(),
                    Win32API.ToStringFromFileTime(result.LastAccessTime),
                    Win32API.ToStringFromFileTime(result.LastModifiedTime),
                    Win32API.ToStringFromFileTime(result.ExpireTime),
                    result.lpszLocalFileName
                )
            );
    }
    return listresults;
}

Bien, de momento ya tenemos la función encargada de devolver los resultados de la caché, ahora ¿que hacemos con ellos?


Persistir objetos, que facil es con .NET!

Serializar objetos a XML es muy pero que muy sencillo. De hecho en nuestro caso ni siquiera vamos a aplicar un formateador SOAP ni binario, y tampoco vamos a aplicar atributos para serializar miembros de clases como nodos o atributos. En este caso vamos a usar la serialización del siguiente modo:

public sealed class Manager
    {
        public static void Save(IECacheQuery query, string pfilename)
        {
            try
            {
                XmlSerializer xmlDoc = new XmlSerializer(typeof(IECacheQuery));
                StreamWriter sw = new StreamWriter(pfilename);
                xmlDoc.Serialize(sw, query);
                sw.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

A esta función se le pasan dos argumentos, el objeto que deseamos persistir i el nombre del archivo XML en el que se quiere persistir. En ella se crea un objeto XmlSerializer preparado para el tipo de objeto IECacheQuery, a continuación se crea un Stream al fichero XML para serializar el objeto. A continuación se cierra el Stream y se acabó lo que se daba.

Qué? Facil verdad? Esta es una de las maravillas que me cautivaron cuando empecé con .NET (y es que con anterioridad había que hacer maravillas para poder realizar este tipo de cosas).

xml


Próximos pasos:

De momento ya tenemos la función que devuelve resultados de la caché y tenemos un modo de persistir un objeto en un fichero XML. A continuación, después de la publicidad (o más bien en el próximo post), mostraremos como Impersonar nuestra aplicación para que se ejecute como otro usuario, a fin de tener acceso a una supuesta ubicación de red en la que gusrdar los ficheros de resultados.

Hasta el próximo post.

** crossposting desde el blog de Lluís Franco en geeks.ms **

3 thoughts on “Acceder a la caché de Internet Explorer (II)

  1. Hola!

    Gracias por tú información, me ha parecido un artículo estupendo. Siento mi falta de conocimientos para poder comprender el código y cómo podría aplicarlo por mí cuenta, ya que no tengo muchos conocimientos sobre .Net ni sobre Xml.

    Serías tan amable de recomendarme algunas web para comenzar con mi formación.

    Gracias de nuevo y un Saludo.

Leave a Reply

Your email address will not be published. Required fields are marked *


*