Recientemente, recibí una solicitud para modificar la función de cierta dll para que pueda leer los archivos en el directorio especificado por el cliente en lugar de la ruta original de la dll
La ruta para leer el archivo está ubicada por ida y ensamblada por sprintf. El uso de ida para desensamblar el código de la máquina es el siguiente:
.text:00000001800042AD 4C 8B 05 5C 5B 5F 00 mov r8, cs:qword_1805F9E10
.text:00000001800042B4 8B F5 mov esi, ebp
.text:00000001800042B6 48 69 F6 08 EA 2B 00 imul rsi, 2BEA08h
.text:00000001800042BD 48 8D 15 4C C6 0F 00 lea rdx, aSSIni ; "%s\\%s.ini"
.text:00000001800042C4 48 8D 8C 24 30 01 00 00 lea rcx, [rsp+918h+Source] ; Buffer
.text:00000001800042CC 4C 8D 8C 3E 80 E8 23 00 lea r9, [rsi+rdi+23E880h]
.text:00000001800042D4 E8 D7 9F 0B 00 call sprintf
El código C desmontado es el siguiente:
sprintf(Source, "%s\\%s.ini", (const char *)qword_1805F9E10, (const char *)qword_1805F96D8 + v7 + 2353280);
Nuestro objetivo es reemplazar el nombre del directorio. Mirando el código anterior, podemos saber que el nombre del directorio es el puntero qword_1805f9e10. Necesitamos reemplazarlo con otro nombre. Saltando, podemos encontrar la cadena %s\\%s .ini en Bajo .rdata:
.rdata:000000018010090E 00 00 align 10h
.rdata:0000000180100910 ; const char aSSIni[]
.rdata:0000000180100910 25 73 5C 25 73 2E 69 6E 69 00 aSSIni db '%s\%s.ini',0 ; DATA XREF: sub_180004150+16D↑o
.rdata:000000018010091A 00 00 align 4
.rdata:000000018010091C 00 00 7F 43 dword_18010091C dd 437F0000h ; DATA XREF: sub_180004150+F7↑r
.rdata:000000018010091C
Puedes ver que 25 73 5c 25 73 2e 69 63 69 representa el código ascii de %s\%s.ini
Acabamos de ver que todavía hay 4 bytes de espacio detrás de la cadena para reproducir
Lo cambiamos a ice\%s.ini, el código ascii es 69 63 65 25 73 2e 69 63 69
Al modificar, tenga cuidado de no cambiar la longitud de estos caracteres a voluntad, solo para reemplazar bytes diferentes
Como el original es 25 73 5C 25 73 2E 69 6E 69 00
Después de la modificación, es 69 63 65 5C 25 73 2e 69 63 69
Puede acortarlo y reemplazar todos los extras con 00. Si hay 0 adicionales detrás y es un espacio reservado, puede alargar la cadena original, al igual que las dos líneas anteriores. Tenga en cuenta que debe dejarse al menos un 0 en el end, como el final de la cadena, como el nuestro, solo hay más bytes, uso uno más
Desde 18010910-1801091a, es el área que operamos a voluntad, un total de 10 bytes
Después de modificar esta cadena, la configuración en el directorio ice no se puede leer y los parámetros de sprintf deben modificarse
Del código anterior, sabemos que %s\%s se usó para hacer coincidir dos parámetros. Ahora que lo hemos cambiado a ice\%s, necesitamos ajustar el último parámetro del código original al frente.
Al aprender el conocimiento de ensamblaje de x64, podemos saber que el orden de pasar parámetros de una función es transferir datos a los cuatro registros rcx rdx r8 r9
En comparación con el código anterior, puede saber fácilmente qué parámetro está almacenado en qué dirección. Solo necesitamos modificar el registro de almacenamiento de datos para modificar el orden de paso de los parámetros.
Necesitamos ajustar el orden de r8 y r9, 4C 8B 05 5C 5B 5F 00 significa transferir la cadena al registro r8, entre ellos,
4C 8B es el movimiento de datos a r8, seguido de 05 5c 5B 5F es el puntero del directorio original
4C 8D 8C 3E 80 E8 23 00 es mover datos a r9, reemplazaremos este 4C 8D con el 4C 8B en la oración anterior,
Es decir, el cuarto parámetro es r9, lo guardamos en r8, y el tercer parámetro lo guardamos en r9, ya que cambiamos la cadena a ice\%s.ini, luego el programa usa r8, y r9 se le da a Discarded, realizando así la sustitución del directorio
Después de la modificación anterior, el programa leerá el archivo ini en el directorio ice en lugar de la ruta empalmada anteriormente
Alguien preguntó, ¿cómo modificarlo? Mi método es usar vim -b xxx, y luego usar el comando:%!xxd para obtener binario, y luego buscar el número hexadecimal correspondiente para modificar. De nuevo: guarde con wq, como para como se hace funcionar en windows, no se...
El contenido anterior se basa en mi propia exploración y resumen, después de la operación práctica, pero la interpretación del código de la máquina aún es algo inexacta.
El siguiente paso es analizar completamente el significado representado por el código de la máquina. Cuando pueda analizar completamente el significado del código de la máquina, podré reescribir fácilmente la lógica del programa, jajajaja
En cuanto a cómo analizar el código de la máquina, no he encontrado la información correspondiente... No sé si tiene alguna buena recomendación.