El acelerómetro, también conocido como sensor G, es uno de los sensores más comunes en la actualidad. Puedes encontrarlo en casi todos los aparatos modernos. El acelerómetro realiza una tarea bastante simple: mide la aceleración del dispositivo. Veamos cómo lo hace: analicemos los mecanismos de los sensores API de Android utilizando el ejemplo de la tarea No. 7 de la etapa en línea de NeoQUEST-2019.
Según la leyenda, nos dieron 2 archivos:
7.apk y
7.txt . Las siguientes conclusiones pueden extraerse del texto de la tarea (y todas las tareas aún están disponibles
aquí ):
7.apk : un programa de
cifrado que de alguna manera usa la configuración del acelerómetro del dispositivo;
7.txt : criptograma generado por el codificador. Lo siguiente está escrito en él:
[1749054104147639] [2.07154922] [10.001905] [4.5387093] [1749056073889025] [5.7193284] [8.221763] [0.01391537] [1749058029180773] [4.684068] [12.05614] [0,0377285] [1749060105291613] [4,6900544] [6,9307165] [4,7094293] [1749062123327502 ] [4.4682417] [7.512769] [6.037215] [1749067640096818] [1.0396843] [8.798672] [4.9335976] [1749070016073380] [2.3173676] [10.180047] [4.948362] [1749072343679582] [126060] 2.48394698] [10.834006] [6.306282] [1749075827770391] [0.2795044] [13.279829] [0.19391555]Vemos que el texto es un grupo repetitivo de 4 valores, uno de los cuales es entero, y los 3 restantes son números de coma flotante. Por conveniencia, los ponemos en líneas separadas:
[1749054104147639] [- 2.07154922] [10.001905] [4.5387093]
[1749056073889025] [5.7193284] [8.221763] [0.01391537]
[1749058029180773] [- 4.684068] [12.05614] [0.0377285]
[1749060105291613] [4.6900544] [6.9307165] [- 4.7094293]
[1749062123327502] [4.4682417] [7.512769] [6.037215]
[1749067640096818] [1.0396843] [8.798672] [- 4.9335976]
[1749070016073380] [- 2.3173676] [10.180047] [4.948362]
[1749072343679582] [- 4.3660607] [12.218135] [0.5312999]
[1749073674459611] [- 2.48394698] [10.834006] [- 6.306282]
[1749075827770391] [0.2795044] [13.279829] [- 0.19391555]El formato del criptograma se resolvió, pero se desconocen cuáles son estos valores. Algunos parámetros del acelerómetro del dispositivo, sin ningún detalle. Y vamos al sitio de desarrolladores de Android y
veamos qué puede mostrar el acelerómetro en general.
Vemos la siguiente descripción:
Descubrimos de qué son responsables los parámetros de coma flotante: esta es la aceleración del dispositivo a lo largo de los ejes X, Y y Z. Pero, ¿cómo entender de qué eje es responsable cada uno de ellos? Es hora de lanzar la aplicación. Se ve así:
Hay 2 opciones para determinar el comportamiento de la aplicación: descompilar
.apk y analizar los valores resultantes. A continuación, consideramos el segundo método y damos la inserción del código descompilado que es responsable de las acciones consideradas de la aplicación.
El criptograma contiene valores positivos y negativos (sabemos que estas son aceleraciones a lo largo de diferentes ejes), por lo que podemos suponer: si los vectores de inclinación del dispositivo a lo largo del eje son opuestos, entonces las aceleraciones serán aproximadamente iguales en valor absoluto, y la diferencia solo será en signo.
La siguiente es una lista de códigos para almacenar información de aceleración:
public class MotionSnapshot { public final float angle_alpha; public final float angle_beta; public final float angle_gamma; public final long event_time; ... }
En base a estas consideraciones, nos enfrentamos a las siguientes tareas:
- Determine qué valor en el criptograma corresponde a la pendiente del dispositivo
- Definir patrón de desviación
- A cada dígito para asociar un patrón de desviación para descifrar
Las 2 primeras tareas se realizarán en paralelo. En el teléfono podemos probar 2 tipos de inclinación:
- De mí mismo / a mí mismo
- Izquierda / derecha
El código responsable de manejar eventos desde el acelerómetro public class SensorListener implements SensorEventListener { private MotionTrace Trace; public SensorListener(MotionTrace trace, MainActivity activity) { Trace = trace; } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { Trace.addSnaphot(new MotionSnapshot(event.values, event.timestamp)); } }
El código responsable de generar la pendiente del dispositivo con solo hacer clic en un botón public class MotionTrace { private ArrayList<MotionSnapshot> Deltas; private long Length; private MotionSnapshot LastSnapshot; public MotionTrace(long len) { LastSnapshot = new MotionSnapshot(0,0,0,0); Deltas = new ArrayList<>(); Length = len; } public void addSnaphot(MotionSnapshot snapshot) { if (Deltas.size() >= Length) { Deltas.remove(0); } MotionSnapshot delta = new MotionSnapshot(0,0,0,0); if (Deltas.size() > 0) { delta = snapshot; } Deltas.add(delta); } public ArrayList<MotionSnapshot> getDeltas() { return new ArrayList<>(Deltas); } }
El código responsable de generar el criptograma. public void SaveCiphertext() { Log.d(Config.MAIN_TAG, "SAVING - {{" + Ciphertext + "}}"); try { File root = new File(Environment.getExternalStorageDirectory(), Config.DIRNAME); if (!root.exists()) { Log.d(Config.MAIN_TAG, "Creating directory - [" + root + "]"); if (!root.mkdirs()) { Log.d(Config.MAIN_TAG, "Error creating directory"); } } File out_file = new File(root, Config.FILENAME); Log.d(Config.MAIN_TAG, "Out - [" + out_file + "]"); PrintWriter writer = new PrintWriter(out_file, "UTF-8"); writer.println(Ciphertext); writer.close(); Toast.makeText(this, "Saved to - [" + out_file + "]", Toast.LENGTH_LONG).show(); } catch (IOException ex) { Toast.makeText(this, "Error saving data", Toast.LENGTH_SHORT).show(); } Ciphertext = ""; }
Comencemos en orden. Para probar las pendientes del primer tipo, seleccionamos los números 2 y 8. Haga clic en cada 3 veces con un esfuerzo creciente. Obtenemos el siguiente resultado:
[2687418463227102] [- 0.23700714] [10.764615] [- 0.9759079]
[2687419411042043] [- 3.5834892] [13.591138] [- 1.7036858]
[2687420383026907] [- 5.575793] [13.533228] [- 1.3104248]
[2687421461360546] [0.6850295] [6.0002656] [0.5568123]
[2687422317256542] [4.1720495] [1.8675026] [1.545407]
[2687423250514599] [7.9689393] [- 3.600097] [0.33846742]Bueno, las diferencias en el parámetro 2 son visibles a simple vista. Comencemos a completar la plantilla.
Representamos la plantilla en forma de rangos de valores de los campos correspondientes en la línea del criptograma. Marcamos con un signo de interrogación lo que aún no sabemos.
[? ]
[(<0) - desviación de uno mismo; (> 0) - autorrechazo]
[?]
[?]Del mismo modo, realizaremos pruebas con los botones 4 y 6. Resultados:
[2688019191605386] [1.7270225] [9.541045] [0.0397171]
[2688020247971353] [1.0615791] [9.794326] [4.9135437]
[2688021887957875] [1.0974716] [7.5535636] [7.8307548]
[2688023749896352] [1.3328063] [9.43923] [- 0.27600938]
[2688024849688832] [1.1357567] [9.9313135] [- 2.4410355]
[2688026002520864] [0.30400848] [6.4610033] [- 8.0956335]Actualice la plantilla teniendo en cuenta el patrón estudiado:
[? ]
[(<0) - desviación de uno mismo; (> 0) - autorrechazo]
[?]
[(<0) - desviación a la derecha; (> 0) - desviación a la izquierda]Obviamente, el tercer valor es la desviación arriba / abajo, ya que este es el único vector restante. Y realmente no necesitamos verificarlo, porque para la determinación inequívoca del botón presionado, ya tenemos la plantilla conocida.
Ahora crearemos una plantilla para cada dígito en el teclado, basada en la posición de los botones y la plantilla desarrollada (* - el parámetro no nos interesa):
1 - [*] [<0] [*] [> 0]
2 - [*] [<0] [*] [cerca de 0]
3 - [*] [<0] [*] [<0]
4 - [*] [] [*] []
5 - [*] [cerca de 0] [*] [cerca de 0]
6 - [*] [cerca de 0] [*] [<0]
7 - [*] [> 0] [*] [> 0]
8 - [*] [> 0] [*] [cerca de 0]
9 - [*] [> 0] [*] [<0]
0 - [*] [> 0] [*] [cerca de 0]Como se puede ver en la figura, los botones 8 y 0 tienen los mismos parámetros, por lo que su descifrado puede ser ambiguo: cuando encuentre tal combinación en un criptograma, debe probar ambas opciones. Ahora aplicamos las plantillas obtenidas al criptograma y obtenemos 2 respuestas: 1029761235 y 1829761235, de las cuales
1829761235 es
cierto . Asignación completada!
Muy pronto, el 26 de junio, ¡se llevará a cabo la competencia cara a cara NeoQUEST 2019! Date prisa para
registrarte en el sitio web del evento. En un futuro cercano habrastatya se lanzará con el anuncio del programa, ¡no te lo pierdas!