http-equiv=»Content-Type» content=»application/xhtml+xml; charset=utf-8″ />
/ * <[CDATA [* / var asciidoc = {/ / Namespace!. / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / Indice generador / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / * Autor: Mihai Bazon , septiembre de 2002 * http://students.infoiasi.ro/ ~ mishoo ** Tabla de generador de contenido * Versión: 0.4 ** Siéntase libre de utilizar esta secuencia de comandos en los términos de la GNU General Public License *, siempre y cuando lo hace no suprimir o alterar este aviso. * / / * Modificado por Troy D. Hanson, septiembre de 2006. Licencia: GPL * / / * modificado por Stuart Rackham, 2006, 2009. Licencia: GPL * / / / toclevels = 1 .. 4. toc: function (toclevels) {function getText (el) {var text = ""; for (var i = el.firstChild; i = null; i = i.nextSibling!) {if (== i.nodeType 3 / * Node.TEXT_NODE * /) / / IE no habla constantes. texto + = I.Data; else if (i.firstChild = null!) Texto + = getText (i);} texto return;} function TocEntry (el, texto, toclevel) {this.element = el; this.Text = texto; this.toclevel = toclevel;} tocEntries función (EL, toclevels) {var result = new Array; var re = new RegExp ('[HH] ([1 -' + (toclevels 1) + '])') / / Función que escanea el árbol DOM para elementos de encabezado (la API DOM2 / / NodeIterator sería una mejor técnica, pero no con el apoyo de todos / / los navegadores). iterate var = function (el) {for (var i = el.firstChild;! i = null; i = i.nextSibling) {if (== i.nodeType 1 / * Node.ELEMENT_NODE * /) {var = mo re . exec (i.tagName); if (mo && (i.getAttribute ("clase") | | i.getAttribute ("className")) = "float"!) {resultado [result.length] = new TocEntry (i , getText (i), mo [1] -1);} iteración (i);}}} iterate (el); return resultado;} var toc = document.getElementById ("toc"); if (toc) {! vuelta;} / / Eliminar entradas de la TDC existentes en caso de que estamos volviendo a cargar el TOC. var tocEntriesToRemove = []; var i; for (i = 0; i
«; var id = palmos [i] getAttribute («id»);. if (id = nulos!) refs [«#» + id] = n;}} si (n == 0) noteholder.parentNode.removeChild (Bonista); else {/ / Proceso footnoterefs. for (i = 0; i
Recientemente tuve la oportunidad de ayudar a un colega con una base de datos para el iPhone que no recibió el apoyo de sus herramientas automatizadas. La aplicación fue la aplicación TextMe, y como era previsible, la aplicación de mensajes de texto almacena su charla en una base de datos SQLite. . Lo que hizo la base de datos interesante fue el hecho de que no había manera no inmediatamente obvio para identificar a quien se envió un mensaje
Permítanme ilustrar: Un análisis rápido de la base de datos revela algunas de las capacidades de la aplicación: los mensajes de texto (cuadro ZMESSAGE) y llamando al (ZCALL, ZVOICEMAIL)
Comando SQLite Interfaz de línea
$ sqlite3 TextMe2.sqlite tablas.
ZATTACHMENT ZDISCUSSION ZMESSAGEHEIGHT Z_METADATA
ZCALL ZFAVORITE ZVOICEMAIL Z_PRIMARYKEY
• Contacto ZMESSAGE Z_3DISCUSSIONS
$
El objeto de esta investigación fueron los mensajes de texto, así que tenía que ver cómo la tabla se construyó.
SQLite Command Line Interface
$ sqlite3 TextMe2.sqlite ". zmessage esquema"
CREAR ZMESSAGE MESA (Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER,
Z_OPT INTEGER, INTEGER ZSTATUS, ZCALL INTEGER, INTEGER ZDISCUSSION,
ZHEIGHT INTEGER, INTEGER ZSENDER , Z3_SENDER INTEGER, ZTIMESTAMP />
VARCHAR);
... $
El CREATE TABLE declaración nos muestra que hay 14 campos de la tabla, y la mayoría son enteros: Z_PK, Z_ENT, Z_OPT, ZSTATUS, ZCALL, ZDISCUSSION, ZHEIGHT, ZSENDER, Z3_SENDER, ZTIMESTAMP, ZBODY, Zguid, ZLOCATION, ZREMOTEID. Pero, no caer en la trampa de que el tipo declarado de cada columna (por ejemplo INTEGER , TIMESTAMP , VARCHAR ) en realidad restringen los datos a esos tipos, no lo hacen. Tratar el nombre-tipo, ya que sólo informativo, pero verificar los datos antes de formar conclusiones.
Inspección de las columnas, vemos algunos de evidente valor en un forense examen:
- Z_PK (que es la clave principal, un número entero de auto incremento quién principal valor que nos está ayudando a identificar si los mensajes tienen sido borrado de la base de datos)
- ZSTATUS
- ZSENDER
- ZTIMESTAMP
- ZBODY
Otros podrían estar impidiendo su atención, pero yo voy a seguir este debate se centró en estas columnas. Algunos datos de la muestra está en orden:
SQLite Command Line Interface
$ sqlite3-header TextMe2.sqlite "seleccione z_pk, zstatus, zsender, ztimestamp />
Z_PK | ZSTATUS | ZSENDER | ZTIMESTAMP | ZBODY
2 | 2 | 2 | 386362581 |! Hola
3 | 4 | 10 | 386 362 603 | bueno, ¿qué estás haciendo
4 |? 3 | 2 | 386362630 | Estoy comprobando esta nueva aplicación
5 | 3 | 2 | 386362634 | Puede ser que sea un reto para decodificar
6 | 3 | 2 | 386362644 | Pero yo lo averiguaré ...
veo que tenemos un par de problemas de interpretación, aquí: el estado es un número entero que tiene que ser interpretado, y es el remitente. La fecha es alguna forma de tiempo de la época, y mis ojos me dicen su probable Mac Tiempo absoluto. Espero encontrar las interpretaciones en otras tablas de la base de datos. Pero lo que salta de la pantalla a mí es que existe la siguiente pregunta hay una respuesta obvia: ¿A quién está al remitente enviando el mensaje La marca de tiempo nos da una secuencia de mensajes, pero ¿cómo sabemos? ese remitente «2» es el envío de mensajes al remitente «10»? ¿No podría remitente «2» a enviar su mensaje a, por ejemplo, el remitente «5» y en medio, recibe un mensaje del remitente «10»? ¡Por supuesto!
Entonces, ¿cómo rectificamos este tema? Bueno, en cierto modo me maliciosamente dejé la columna de la zdiscussion en mi consulta. Hice esto para llevar la conversación y simular lo que puede suceder cuando un investigador se encuentra con una nueva base de datos por primera vez: pasar por alto una columna importante. Si incluimos la columna, vemos algo interesante:
SQLite Command Line Interface
$ sqlite3-header TextMe2.sqlite "seleccione z_pk, zstatus, zdiscussion, zsender />
Z_PK | ZSTATUS | ZDISCUSSION | ZSENDER | ZTIMESTAMP | ZBODY
2 | 2 | 2 | 2 | 386362581 |! Hola
3 | 4 | 2 | 10 | 386 362 603 | bueno, ¿qué estás haciendo
4 |? 3 | 2 | 2 | 386362630 | Estoy comprobando esta nueva aplicación
5 | 3 | 2 | 2 | 386362634 | Puede ser que sea un reto para decodificar
6 | 3 | 2 | 2 | 386362644 | pero voy a averiguarlo ...
Ahora vemos que la conversación es todo parte de la misma discusión. Y si estudiamos toda la base de datos, que nos gustaría ver en el ejemplo de más de una conversación se estaba produciendo un mismo tiempo, y por la clasificación en el campo de la discusión, le damos sentido a esas conversaciones. Pero el sello de fecha por sí sola no nos pista pulg
Esto podría no parecer una gran cosa, pero la mayoría de las bases de datos de mensajería que he encontrado que la parte remota en el registro de mensaje para mensajes enviados y recibidos. Esto funciona bien y da lugar a una interpretación sencilla, por ejemplo, «enviado a Joe» y «recibido de Joe». Pero esta base de datos sin entender correctamente la columna de la discusión, es el equivalente de «enviado por Joe» y «enviado por Jane», lo que lleva a la pregunta « a quién? »
lugar de desglose del resto del análisis, sólo voy a compartir la consulta solía completar el análisis:
<- Generador: GNU fuente-highlight 3.1.6 por Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite ->
seleccione
m como " Clave " ,
datetime ( + 978307200 , 'unixepoch' , "localtime" ) como " Fecha " ,
caso
cuando style="color: m . ( seleccione de naturales join )
demás " Unknown (" | | z_ent | | ")"
final como "Tipo" ,
caso zstatus
2 "Enviados"
3 "Entregado"
cuando 4 "Recibido"
"Desconocido ( " | | | | ")"
como " Estado " ,
como "DiscussionID" ,
como "Contacto " ,
como "Mensaje"
de como m , como
c en . zsender = .
fin por asc , fecha asc ;
A modo de breve descripción:
- AS declaraciones, como la observada en m.z_pk como "clave" , crear alias, el cambio de nombre de manera efectiva las columnas (o en el FROM declaración, las mesas) para hacer la salida más informativo.
- el primer caso Declaración consulta el z_primarykey interpretar la Z_ENT entero en su valor textual.
- el segundo caso Declaración interpreta el ZSTATUS en su equivalente Inglés, que no se almacena en la base de datos, pero determinado mediante el estudio de la interfaz de usuario de la aplicación. Esto plantea la pregunta, entonces ¿de dónde viene la aplicación recibe la interpretación textual? Probablemente dentro de su código.
- El FROM Declaración consulta dos tablas, y zmessage • Contacto, para interpretar el ZSENDER entero. Pero espere, usted dice, no hay ZSENDER en el estado de selección! (Ver la siguiente viñeta …)
- El ON Declaración es el equivalente de un SQLite SQL INNER JOIN , que es la intersección de las dos tablas, es decir, seleccionar filas de ambas tablas, donde coinciden con las columnas. En este caso, las columnas que se van emparejados son ZSENDER de la ZMESSAGE Mesa y Z_PK de la • Contacto Mesa. El efecto es que la declaración SELECT sabe que ZUSERNAME de • Contacto para volver sobre la base de la ZSENDER en el ZMESSAGE Mesa.
- El ORDER BY Declaración ordena la salida por primera vez por ZDISCUSSION la columna, a continuación, por el ZDATESTAMP , tanto en orden ascendente. Tenga en cuenta que se utilizan los nombres de alias de columna.
Espero que esto da una idea del funcionamiento de las bases de datos TextMe2.sqlite y le ayuda en el futuro con el análisis bases de datos SQLite de nunca antes vistos.