Android - Analisis forense
Guía para analisis forense en Android
🔍 Análisis Forense en Android: Retos y Claves para Investigaciones Digitales
Los smartphones son herramientas esenciales en la sociedad europea, usados desde consumidores hasta altos cargos gubernamentales y empresas. Su versatilidad los convierte en monederos digitales, sistemas de navegación, sensores de salud (como monitorización cardíaca remota) y más. Sin embargo, esta riqueza de datos los convierte en fuentes críticas para el análisis forense móvil, que busca recuperar evidencia digital bajo condiciones forenses rigurosas.
🔑 Aspectos Clave en el Análisis Forense Móvil:
- Adquisición de Datos Compleja:
- Los dispositivos suelen analizarse encendidos (live acquisition), ya que acceder a la memoria interna puede ser técnicamente limitado.
- Tarjetas SD y memorias externas pueden contener información vital, pero requieren manejo cuidadoso para preservar pruebas.
- Cadena de Custodia (CoC) Frágil:
- Instalar aplicaciones forenses en el dispositivo puede alterar su estado original.
- La falta de sistemas de archivos de solo lectura aumenta el riesgo de modificar datos, comprometiendo su validez legal.
- Riesgo de Pérdida de Integridad:
- Entornos de prueba o herramientas no especializadas pueden activar mecanismos de defensa del dispositivo (como malware) y borrar pruebas.
- Cualquier error técnico puede invalidar la evidencia en juicios.
Uso de Android Studio para Análisis Forense
Para analizar datos forenses en Android, se puede utilizar Android Studio ya que cuenta con un emulador de dispositivos Google Pixel.
En este caso estaremos usando Android Studio en un sistema host Windows 11.
Instalado el software vamos a crear un emulador.
Si nos pide instalar el hypervisor para el emulador de Android, nosotros lo instalamos.
Como queremos un equipo en el que podamos trabajar como usuario root seleccionaremos el modelo más reciente que no cuente con el soporte de google.
Seleccionamos la API de Google compatible con el sistema host y ajustamos las características del emulador a necesidad.
Una vez iniciado puede que veamos un mensaje como este.
Si es el caso significa que tendremos que descargar el Android Debug Bridge (adb) para poder conectarnos al emulador de forma manual.
Para descargarel paquete de herramientas SDK de Android podemos usar el siguiente enlace y seleccionar el que corresponda a nuestro sistema host.
Una vez descagado y extraido, en el emulador haremos lo siguiente.
Colocamos la ruta al ejecutable de adb.
Activar el modo depuración USB en el emulador
Es igual a un teléfono Android convencional. Iremos a ajustes, información sobre el dispositivo y pulsaremos varias veces sobre el numero de compilación del dispositivo hasta que se nos que hemos activado las opciones de desarrollador.
Ahora en sistema buscaremos las opciones de desarrollador y activamos el modo depuración USB.
Algunos comandos de ADB
1. adb devices
- Uso: Lista todos los dispositivos Android conectados a la computadora y que tienen el modo de depuración USB activado.
- Ejemplo:
1
adb devices
- Resultado: Muestra una lista de dispositivos conectados con sus identificadores únicos (serial numbers) y su estado (por ejemplo,
device
si está listo para usar ounauthorized
si no se ha autorizado la depuración USB).
2. adb shell
- Uso: Inicia una sesión de terminal (shell) en el dispositivo Android, permitiendo ejecutar comandos directamente en el sistema operativo del dispositivo.
- Ejemplo:
1
adb shell
- Resultado: Entras en una línea de comandos dentro del dispositivo, donde puedes ejecutar comandos de Linux (como
ls
,cd
,rm
, etc.) para navegar por el sistema de archivos o realizar tareas avanzadas.
3. adb root
- Uso: Reinicia el servicio ADB con permisos de superusuario (root) en el dispositivo. Esto es útil para acceder a partes restringidas del sistema.
- Ejemplo:
1
adb root
- Nota: Solo funciona si el dispositivo tiene permisos root habilitados. Si no, el comando no tendrá efecto.
4. adb pull
- Uso: Copia archivos o directorios desde el dispositivo Android a la computadora.
- Sintaxis:
1
adb pull <ruta_en_dispositivo> <ruta_en_pc>
- Ejemplo:
1
adb pull /sdcard/Download/mi_archivo.txt ~/Desktop/
- Resultado: Copia el archivo
test.png
desde la carpetaDownload
del dispositivo al escritorio del equipo.
5. adb push
- Uso: Copia archivos o directorios desde la computadora al dispositivo Android.
- Sintaxis:
1
adb push <ruta_en_pc> <ruta_en_dispositivo>
- Ejemplo:
1
adb push ~/Desktop/mi_archivo.txt /sdcard/Download/
- Resultado: Copia el archivo
test.txt
desde el escritorio de la computadora a la carpetaDownload
del dispositivo.
Crear una maquina virtual Android en un entorno de virtualización (Proxmox)
Como alternativa a android studio, podemos utilizar un entorno de virtualización como proxmox para crear una maquina virtual con el sistema operativo android.
Nota : Se podría utilizar cualquier otro virtualizados como VMWare o VirtualBox, pero en este caso vamos a utilizar proxmox.
Para descargar una versión del sistema android compatible con arquitectura x86 podemos utilizar el siguiente enlace.
Una vez creada la maquina virtual, arrancamos y procedemos a instalar el sistema operativo android.
Detectamos y creamos las particiones del sistema.
Si queremos indicamos que use GPT. En principio seleccionaremos que no.
Creamos una nueva.
Seleccionamos primaria y damos enter para dejar el tamaño por defecto del disco.
Hacemos la partición booteable.
Escribimos los cambios y seleccionamos QUIT
para salir del modo de particionado.
Ya nos debería salir la partición correcta por lo que damos en OK.
Formateamos la partición en EXT4.
Indicamos que si.
Instalamos el bootloader GRUB.
Hacemos la que se pueda escribir en /system.
Reiniciamos el sistema y hacemos la configuración inicial.
En la red WiFi seleccionamos más redes y la red virtualizada.
Finalizada la configuración tipica de android ahora activamos como antes el modo depuración USB.
Extracción de datos mediante AFLogical OSE
Ahora que tenemos nuestros posibles entornos de prueba vamos a empezar utilizando una herramienta para extraer datos de los dispositivos Android como registros de llamadas, contanctos, SMS, etc.
Debido a que el software ya es antiguo posiblemente sea dificil encontrar el apk necesario para que funcione aunque a continuación dejo el enlace del apk oficial que encontré y subí a Internet Archive.
Una vez descargado el archivo, lo instalamos en nuestro dispositivo Android.
Para ello vamos a utilizar adb por lo que en nuestra máquina windows donde tenemos descargado ADB descargaremos el apk a esta.
Nota : Para saber la IP de la máquina android y poder conectarnos por ADB podemos utilziar el terminal integrade que viene con el sistema operativo android y el comando
ip a
1
2
3
adb connect 192.168.1.10:5555
adb devices
adb install aflogical-ose-1.5.2.apk
Una vez instalada veremos la aplicación instalada en nuestro dispositivo. Aunque es algo antigua no viene mal probarla.
Una vez ejecutemos la aplicación los datos extraidos deben aparecer en la ruta /sdcard/forensics/
Mediante adb pull podemos extraer los datos.
Extracción de datos mediante Andriller
Andriller es una herramienta de software que ofrece una colección de herramientas forenses para smartphones. Realiza adquisiciones de solo lectura, forenses, seguras y no destructivas desde dispositivos Android. Incluye características como el desbloqueo de pantallas de bloqueo (Patrón, PIN o Contraseña), decodificadores personalizados para datos de aplicaciones desde bases de datos de Android (algunas de Apple iOS y Windows) para decodificar comunicaciones. La extracción y los decodificadores generan informes en formatos HTML y Excel.
Es una herramienta escrita en python por lo que necesitamos este lenguaje para poder utilizarla.
En Windows:
- Descargamos el codigo de gitihub y navegamos a su carpeta.
1
2
3
python -m venv venv
.\venv\Scripts\Activate.ps1
pip install andriller -U
Una vez instalado para ejecutarlo simplemente python -m andriller
.
Este software detecta el dispositvo mediante USB por lo que en este caso para que detecte nuestra máquina virtual android debemos hacer lo siguiente.
En el adb que utiliza este software vamos a conectarnos a la máquina virtual android de forma remota manualmente.
Ahora nos detectará la máquina virtual y podremos utilizarla.
Esta herramienta nos permite extraer los datos básicos que se pueden extraer de los dispositivos Android sin permisos de root y los directorios compartidos, sin embargo si somos usuario root dentro del dispositivo podemos extraer información más detallada haciendo uso de un backup del dispositivo.
Si damos en esta última opción nos mostrará un mensaje de aviso indicando que debemos aceptar el backup del dispositivo de forma manual.
Una vez completado tendremos un pequeño resumen de los datos estos dentro de la carpeta de salida que seleccionamos anteriormente.
Peritajes sobre WhatsApp
Introducción para un Peritaje sobre WhatsApp
Actualmente, las aplicaciones de mensajería instantánea como WhatsApp se han convertido en herramientas esenciales tanto para la comunicación personal como para las interacciones comerciales. Con más de 2.000 millones de usuarios en todo el mundo, WhatsApp no solo facilita el intercambio de mensajes, sino también la transmisión de archivos multimedia, la realización de llamadas de voz y video, y el uso de funcionalidades avanzadas como la geolocalización en tiempo real. Sin embargo, este amplio uso también ha convertido a WhatsApp en una fuente crítica de evidencias digitales en investigaciones judiciales, casos de ciberseguridad y procesos legales.
El análisis forense de WhatsApp tiene como objetivo extraer, preservar y analizar los datos almacenados en la aplicación para responder a preguntas clave, como:
- ¿Quién participó en una conversación?
- ¿Cuándo y cómo se envió o recibió un mensaje?
- ¿Es posible recuperar mensajes borrados?
- ¿Se puede determinar la procedencia de un mensaje (desde un dispositivo móvil o WhatsApp Web)?
- ¿Qué información adicional (metadatos, ubicaciones, archivos) puede ser relevante para el caso?
Este tipo de análisis es especialmente relevante en casos de acoso, fraude, suplantación de identidad, ciberdelitos y otros escenarios donde las conversaciones de WhatsApp pueden ser pruebas fundamentales. Sin embargo, el proceso de peritaje no está exento de desafíos, como el cifrado de los datos, la constante actualización de la aplicación y la necesidad de preservar la integridad de las evidencias para garantizar su validez en un procedimiento judicial.
En este contexto, el peritaje se enfoca en el análisis forense de WhatsApp, abordando tanto las plataformas iOS como Android, y explorando las técnicas y herramientas disponibles para la extracción y análisis de datos. Además, se examinarán las diferencias entre los modelos de datos de ambas plataformas, las funcionalidades de interés forense y las limitaciones técnicas que pueden surgir durante el proceso.
Diferencias entre un peritaje consensuado y un peritaje no consensuado
Consensuado: El profesional cuenta con el permiso del titular de la cuenta y acceso completo al terminal (claves de desbloqueo, datos de la cuenta). Esto permite métodos menos invasivos, como extraer la base de datos mediante copias de seguridad (iTunes en iOS o Google Cloud en Android) o usar herramientas comerciales con el token de WhatsApp Web.
No consensuado: Se realiza sin acceso al terminal, generalmente por orden judicial. Requiere evadir medidas de seguridad (root/jailbreak) para acceder a la memoria interna. En Android, implica obtener la clave de cifrado ubicada en
/data/data/com.whatsapp/files/key
. En iOS, puede ser imposible si el dispositivo está cifrado, a menos que se realice un jailbreak.
Algunas técnicas para peritar conversaciones de WhatsApp
Capturas de pantalla: Menos fiable, pero válida si se verifica la integridad del dispositivo.
Extracción mediante token: Usar WhatsApp Web para simular una sesión y extraer mensajes (no accede a datos borrados o completos).
- Acceso a la base de datos:
- iOS: Extraer copias de seguridad con iTunes y analizar archivos como
ChatStorage.sqlite
. - Android: Acceder a
/data/data/com.whatsapp/databases/msgstore.db
(requiere root) o descifrar copias de seguridad en la nube usando la clave local.
- iOS: Extraer copias de seguridad con iTunes y analizar archivos como
Herramientas forenses comerciales: Oxygen Forensics, MobilEdit o Magnet Axiom para extraer y analizar datos.
- Análisis de registros y metadatos: Revisar logs de llamadas (
call_history.sqlite
), ubicaciones (location.db
) o mensajes borrados mediante técnicas de recuperación de datos.
Ubicación y extracción de claves y bases de datos
- Clave de cifrado (Android):
- Ruta:
/data/data/com.whatsapp/files/key
. - Extracción: Requiere acceso root (por ejemplo, mediante ADB) o downgrade de la versión de WhatsApp para evitar cifrado.
- Ruta:
- Bases de datos:
- iOS:
- Ubicación:
/private/var/mobile/Applications/group.net.whatsapp.WhatsApp.shared/
. - Extracción: Copia de seguridad con iTunes y uso de herramientas como Oxygen Forensics.
- Ubicación:
- Android:
- Ubicación:
/data/data/com.whatsapp/databases/
(ej:msgstore.db
,wa.db
). - Extracción: Root del dispositivo o uso de máquinas virtuales para evitar alterar el original.
- Ubicación:
- iOS:
- Métodos alternativos:
- WhatsApp Web: Simular sesiones para extraer mensajes activos (no incluye datos borrados).
- Copia de seguridad en la nube (Android): Descargar desde Google Drive usando la clave local almacenada en el dispositivo.
Nota : La extracción de datos en iOS es más estructurada pero menos informativa, mientras que Android permite comprobaciones cruzadas debido a redundancia en tablas. Ambos requieren preservar la integridad de los artefactos para su validez judicial.
Ejemplo de análisis forense de WhatsApp en Android
Para este caso tenemos diferentes opciones y es que actualmente las bases de datos de WhatsApp están cifradas siempre y cuando en el dispositivo donde se ha instalado la aplicación tenga una tarjeta SIM insertada. De lo contrario las bases de datos no están cifradas y no existe una clave de cifrado.
Esto podría ocurrir por ejemplo si utilizamos la máquina virtual configurada anteriormente o el emulador por lo que para este caso (si disponemos de ello) lo mejor es realizarlo sobre un terminal con acceso root real, con posibilidad de insetar una tarjeta SIM.
Como vemos ya tenemos nuestro dispositivo listo, en este caso está rooteado por lo que tenemos acceso a la memoria interna y podemos extraer la base de datos de WhatsApp.
- Accedemos al dispositivo como root
Conectamos el dispositivo al PC y permitimos el acceso por adb (previamente activado en las opciones de desarrollador).
1
adb root
Si por algún motivo tenemos un mensaje de error indidcando que el modo root no está disponible en versiones de producción es porque la versión de nuestro dispositivo, aun estando rooteado, es de producción y no de desarrollo, por lo que el modo root mediante ADB no estará disponible.
- Error
1
2
sdksdk@uwuntu:~$ adb root
adbd cannot run as root in production builds
Es por esto que una vez tenemos el dispositivo rooteado podemos hacer lo siguiente.
Vamos a iniciar una shell en nuestro dispositivo y podemos ver que el usuario no es root sino shell, por lo que no tenemos privilegios.
Una vez dentro de la shell ejecutamos su root
para elevar nuestro privilegios a superusuario y, en la pantalla de nuestro dispositivo veremos un aviso de nuestra aplicación que gestiona el acceso root (en este caso Magisk) preguntando si queremos permitirle el acceso.
Si no apareciese el mensaje siempre podemos acceder a nuestra aplicación y permitir el acceso root manualmente.
- Extraer la Clave de Cifrado
1
2
cd /data/data/com.whatsapp/files/
adb pull /data/data/com.whatsapp/files/key /ruta/destino/
El comando pull
solo funcionará si podemos establecer adb como root, en este caso necesitamos acceder como root una vez dentro de la shell por lo que nos indicará que no tenemos permisos para acceder a ese archivo.
Como solución podemos simplemente copiar el contenido.
1
adb exec-out "su -c 'cat /data/data/com.whatsapp/files/key'" > ./key
- Extraer la base de datos
Para este caso el proceso es similar.
1
2
3
cd /data/data/com.whatsapp/databases/
adb pull /data/data/com.whatsapp/databases/msgstore.db /ruta/destino/
adb pull /data/data/com.whatsapp/databases/wa.db /ruta/destino/
Los archivos principales son:
msgstore.db
: Contiene los mensajes.wa.db
: Contiene información de contactos.chatsettings.db
: Almacena configuraciones de chats.
Como tenemos el mismo error de permisos que antes hacemos lo siguiente.
1
2
adb exec-out "su -c 'cat /data/data/com.whatsapp/databases/msgstore.db'" > ./msgstore.db
adb exec-out "su -c 'cat /data/data/com.whatsapp/databases/wa.db'" > ./wa.db
Con todo esto ya tenemos nuestros archivos de bases de datos y clave de cifrado para analizar.
Analizar los datos extraídos con Andriller u otras herramientas forenses.
Para utilizar Andriller hacemos lo mismo que en el apartado de la extracción de datos aunque como en este caso estamos trabajando sobre un ubuntu, los pasos son los siguientes.
1
2
3
4
5
6
git clone https://github.com/den4uk/andriller.git
cd andriller
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 andriller-gui.py
Primero vamos a decodificar las bases de datos con la key.
Seleccionamos en la pestaña app utils
la opción WhatsApp Crypt
.
Indicamos el directorio donde tenemos las bases de datos y la clave de cifrado, y damos click en Decrypt all
.
Si no tenemos encriptadas las bases no es necesario.
Seleccionamos decodificadores.
- Contactos de WhatsApp
Una vez abrimos el reporte podremos ver todos los contactos de WhatsApp.
- Chats de WhatsApp
Como es de esperar la estructura de los datos en la base de datos puede cambiar a lo largo del tiempo y actualizaciones por lo que ahora si intentamos extraer los chats de WhatsApp tendremos un error porque la tabla de chat_list
no existe.
Para solucionar esto podemos abrir la base de datos con SQLiteBrowser
y ver el nombre actual de la tabla. Una vez hemos encontrado la tabla que necesitamos podemos cambiar en el código de Andriller para que la tabla se llame chat
ya que a fecha de escribir este artículo la tabla chat_list
ahora es llamada chat
.
El archivo decoders.py
será el que tendremos que modificar.
Para los mensajes es similar, buscamos como se llama actualmente la tabla messages
y cambiamos el nombre a message
en el código.
En esta aplicación solo he conseguido sacar los contactos por lo que para poder visualizar los chats vamos a utilizar otra herramienta que tendremos que modificar.
Whatsapp Msgstore Viewer
Esta herramienta es algo menos conocida e interpreta la información de forma bastante clara simulando la intergaz de un usuario de WhatsApp.
Una vez tengamos la herramienta descargada y funcionando debemos añadir una nueva estructura de datos ya que la que trae por defecto no es compatible con la actual (a fecha de escribir este artículo).
1
2
3
4
git clone https://github.com/absadiki/whatsapp-msgstore-viewer.git
cd whatsapp-msgstore-viewer
mkdir /db/v2
nano /db/v2/db.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from dbs.abstract_db import AbstractDatabase
class Database(AbstractDatabase):
def __init__(self, msgstore, wa):
# Updated schema to match current WhatsApp database structure
schema = {
'chat_view': {
'name': 'chat_view',
'attributes': [
'_id',
'jid_row_id',
'hidden',
'subject',
'created_timestamp',
'display_message_row_id',
'last_message_row_id',
'last_read_message_row_id',
'last_read_receipt_sent_message_row_id',
'last_important_message_row_id',
'archived',
'sort_timestamp',
'mod_tag',
'gen',
'spam_detection',
'unseen_earliest_message_received_time',
'unseen_message_count',
'unseen_missed_calls_count',
'unseen_row_count',
'plaintext_disabled',
'vcard_ui_dismissed',
'change_number_notified_message_row_id',
'show_group_description',
'ephemeral_expiration',
'last_read_ephemeral_message_row_id',
'ephemeral_setting_timestamp',
'ephemeral_displayed_exemptions',
'ephemeral_disappearing_messages_initiator',
'unseen_important_message_count',
'group_type',
'last_message_reaction_row_id',
'last_seen_message_reaction_row_id',
'unseen_message_reaction_count',
'unseen_comment_message_count',
'growth_lock_level',
'growth_lock_expiration_ts',
'last_read_message_sort_id',
'display_message_sort_id',
'last_message_sort_id',
'last_read_receipt_sent_message_sort_id',
'has_new_community_admin_dialog_been_acknowledged',
'history_sync_progress'
]
},
'message': {
'name': 'message',
'attributes': [
'_id',
'chat_row_id',
'key_id',
'from_me',
'timestamp',
'text_data',
'sort_id' # Added new field
]
},
'message_media': {
'name': 'message_media',
'attributes': [
'message_row_id',
'file_path',
]
},
'message_quoted': {
'name': 'message_quoted',
'attributes': [
'message_row_id',
'text_data',
'from_me',
'key_id'
]
},
'jid': { # Added jid table as it's referenced in the queries
'name': 'jid',
'attributes': [
'_id',
'user',
'raw_string'
]
},
'call_log': { # Added call_log table for fetch_calls method
'name': 'call_log',
'attributes': [
'_id',
'from_me',
'timestamp',
'video_call',
'duration',
'jid_row_id'
]
}
}
super(Database, self).__init__(msgstore, wa, schema=schema)
def fetch_contact_chats(self):
sql_query = """
SELECT
chat_view._id,
jid.user,
jid.raw_string as jid_row_id,
message.text_data,
DATETIME(ROUND(chat_view.sort_timestamp / 1000), 'unixepoch') as timestamp
FROM chat_view
INNER JOIN jid ON chat_view.jid_row_id = jid._id
INNER JOIN message ON chat_view.last_message_row_id = message._id
WHERE jid.raw_string NOT LIKE '%g.us'
ORDER BY timestamp DESC
"""
return self.msgstore_cursor.execute(sql_query).fetchall()
def fetch_group_chats(self):
sql_query = """
SELECT
chat_view._id,
chat_view.subject as user,
jid.raw_string as jid_row_id,
message.text_data,
DATETIME(ROUND(chat_view.sort_timestamp / 1000), 'unixepoch') as timestamp
FROM chat_view
INNER JOIN jid ON chat_view.jid_row_id = jid._id
INNER JOIN message ON chat_view.last_message_row_id = message._id
WHERE jid.raw_string LIKE '%g.us'
ORDER BY timestamp DESC
"""
return self.msgstore_cursor.execute(sql_query).fetchall()
def fetch_calls(self, how_many=None):
sql_query = """
SELECT
call_log._id,
call_log.from_me,
DATETIME(ROUND(call_log.timestamp / 1000), 'unixepoch') as timestamp,
call_log.video_call,
Time(call_log.duration, 'unixepoch') as duration,
jid.user,
jid.raw_string as jid_row_id
FROM call_log
LEFT JOIN jid ON call_log.jid_row_id = jid._id
ORDER BY timestamp DESC
"""
if how_many:
return self.msgstore_cursor.execute(sql_query).fetchmany(how_many)
else:
return self.msgstore_cursor.execute(sql_query).fetchall()
def fetch_chat(self, chat_view_id):
sql_query = f"""
SELECT
message._id,
message.key_id,
message.from_me,
DATETIME(ROUND(message.timestamp / 1000), 'unixepoch') as timestamp,
ifnull(message.text_data, '') as text_data,
message_media.file_path,
message_quoted.text_data as message_quoted_text_data,
message_quoted.from_me as message_quoted_from_me,
message_quoted.key_id as message_quoted_key_id,
message.sort_id
FROM message
LEFT JOIN message_media ON message._id = message_media.message_row_id
LEFT JOIN message_quoted ON message._id = message_quoted.message_row_id
WHERE message.chat_row_id = {chat_view_id}
ORDER BY message.sort_id ASC
"""
return self.msgstore_cursor.execute(sql_query).fetchall()
def fetch_unread_messages(self, chat_view_id):
"""
Fetch unread messages based on last_read_message_row_id or sort_id
"""
sql_query = f"""
SELECT
message._id,
message.key_id,
message.from_me,
DATETIME(ROUND(message.timestamp / 1000), 'unixepoch') as timestamp,
ifnull(message.text_data, '') as text_data,
message.sort_id
FROM message
JOIN chat_view ON message.chat_row_id = chat_view._id
WHERE
chat_view._id = {chat_view_id}
AND (
(chat_view.last_read_message_sort_id IS NOT NULL AND message.sort_id > chat_view.last_read_message_sort_id)
OR
(chat_view.last_read_message_row_id IS NOT NULL AND message._id > chat_view.last_read_message_row_id)
)
ORDER BY message.sort_id ASC
"""
return self.msgstore_cursor.execute(sql_query).fetchall()
def fetch_important_messages(self, chat_view_id):
"""
Fetch important messages from a chat
"""
sql_query = f"""
SELECT
message._id,
message.key_id,
message.from_me,
DATETIME(ROUND(message.timestamp / 1000), 'unixepoch') as timestamp,
ifnull(message.text_data, '') as text_data
FROM message
WHERE
message.chat_row_id = {chat_view_id}
AND message._id IN (
SELECT last_important_message_row_id
FROM chat_view
WHERE _id = {chat_view_id} AND last_important_message_row_id IS NOT NULL
)
"""
return self.msgstore_cursor.execute(sql_query).fetchall()
Si tenemos un fallo en el main_screen podremos arreglarlo modificando lo siguiete.
1
nano view/MainScreen/main_screen.py
Aquí reemplazamos todos los raw_string_jid
por jid_row_id
.
Ahora podemos ejecutarlo y ver los chats de WhatsApp aunque hasta ahora solo he podido listar los chats sin los nombre de contacto ya que existe un error al leer la base de datos WA.db.
- Chats
- Grupos
- Llamadas