Se ha recopilado Baidu Netdisk. Si necesita revisarlo, puede verlo en la carpeta [colección del banco de preguntas CTF]
Solo ejecútalo primero
Esta es una pregunta tipo crackme, una pregunta de competencia sobre Snow CTF. Utilice OD para analizarla.
Primero utilicé el análisis IDA. Después de analizarlo durante mucho tiempo, no pude encontrar nada. Luego busqué en línea y lo encontré. Levanté la bandera directamente y resolví mi problema urgente. Jaja, miré wp después y lo descubrí. . Para encontrar la solución real, aún debemos resumirla. Después de todo, algunas preguntas no se pueden encontrar...
Pregunta: ¿Por qué utilizar OD en lugar de IDA?
OD puede rastrear dinámicamente el proceso de cambio de variables. El código de desmontaje del OD se puede colorear para hacerlo más llamativo. Preguntas tipo crackme
→La primera opción para sintonización dinámica
IDA puede ver la estructura de datos e incluso desensamblarla en código C, lo que resulta útil para comprender la estructura general.
→La primera opción para un tono tranquilo
Ejecute el programa en OD y descubra que aparece el cuadro de mensaje después de ejecutar la función en la dirección 00401494. Se puede ver que esta es la función clave, F2 establece el punto de interrupción y F7 realiza el seguimiento.
En el proceso de seguir esta función, se producirá un bucle de mensajes en la GUI de Windows y mensajes. Puede consultar este artículo.
Parece que tienes que escribir algo para salir del bucle, luego establecer un punto de interrupción, ejecutar F9 e ingresar caracteres para salir del bucle.
¿Dónde colocar un punto de interrupción? Si establece un punto de interrupción aquí, como se muestra a continuación,
Después de la ejecución, se informará un error directamente porque la instrucción de ensamblaje retn se usa para finalizar el proceso actual y regresar al proceso de llamada anterior.
Por lo tanto, debe establecer un punto de interrupción en la primera instrucción junto a esta instrucción de ensamblaje.
Después de ejecutar con éxito en el punto de interrupción, el siguiente paso es el código clave de desmontaje:
CPU Disasm
地址 十六进制数据 指令 注释 标签
00401225 . 83F8 04 CMP EAX,4
00401228 . 59 POP ECX
00401229 . 0F85 A0000000 JNE 004012CF strlen()函数
0040122F . 6A 30 PUSH 30
00401231 . 59 POP ECX
00401232 . 384D E4 CMP BYTE PTR SS:[EBP-1C],CL 判断key第1个字符是否为“0”
00401235 . 0F84 94000000 JE 004012CF
0040123B . 384D E5 CMP BYTE PTR SS:[EBP-1B],CL 判断key第2个字符是否为“0”
0040123E . 0F84 8B000000 JE 004012CF
00401244 . 384D E6 CMP BYTE PTR SS:[EBP-1A],CL 判断key第3个字符是否为“0”
00401247 . 0F84 82000000 JE 004012CF
0040124D . 384D E7 CMP BYTE PTR SS:[EBP-19],CL 判断key第4个字符是否为“0”
00401250 . 74 7D JE SHORT 004012CF
00401252 . 807D E4 31 CMP BYTE PTR SS:[EBP-1C],31 判断key第1个字符是否等于“1”,不等于则直接跳转弹出“error”
00401256 . 75 77 JNE SHORT 004012CF
00401258 . 807D E5 35 CMP BYTE PTR SS:[EBP-1B],35 判断key第2个字符是否等于“5”,不等于则直接跳转弹出“error”
0040125C . 75 71 JNE SHORT 004012CF
0040125E . 74 03 JE SHORT 00401263 花指令
00401260 . 75 01 JNE SHORT 00401263
00401262 E8 DB E8 CHAR 'è'
00401263 > 66:B8 0800 MOV AX,8
00401267 . 66:35 0700 XOR AX,0007
0040126B . 0FBE45 E6 MOVSX EAX,BYTE PTR SS:[EBP-1A] 取输入key的第3位数
0040126F . 2BC1 SUB EAX,ECX 减去0x30,得到a
00401271 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值保存在[ebp-0x4]中
00401274 . 0FBE45 E4 MOVSX EAX,BYTE PTR SS:[EBP-1C] 取输入key的第1位值“1”
00401278 . DB45 FC FILD DWORD PTR SS:[EBP-4] 把[ebp-0x4]中保存的值压入到ST(0)中
0040127B . 2BC1 SUB EAX,ECX 0x31减去0x30,则为1
0040127D . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值1保存在[ebp-0x4]中
00401280 . 0FBE45 E5 MOVSX EAX,BYTE PTR SS:[EBP-1B] 取输入key的第2位值“5”
00401284 . DB45 FC FILD DWORD PTR SS:[EBP-4] 把[ebp-0x4]中保存的值1压入到ST(0)中
00401287 . 2BC1 SUB EAX,ECX 0x35减去0x30,则为5
00401289 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值5保存在[ebp-0x4]中
0040128C . DA75 FC FIDIV DWORD PTR SS:[EBP-4] st(0)中的值1除以[ebp-0x4]中的值5,得到0.2保存到st(0)中
0040128F . 0FBE45 E7 MOVSX EAX,BYTE PTR SS:[EBP-19] 取输入key的第4位值
00401293 . 2BC1 SUB EAX,ECX 减去0x30,得到b
00401295 . 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 把得到的值b保存在[ebp-0x4]中
00401298 . DEE9 FSUBP ST(1),ST st(1)-st并保存在st(0)中,即(a-0.2)
0040129A . DA4D FC FIMUL DWORD PTR SS:[EBP-4] st(0)乘以[ebp-0x4] 中保存的值b,结果保存在st(0)中
0040129D . D80D 1C714000 FMUL DWORD PTR DS:[40711C] 数据段ds:[0x40711C]值为16,这里则是st(0)乘以16
004012A3 . D95D FC FSTP DWORD PTR SS:[EBP-4] 把上面得到值保存在[ebp-0x4]中
004012A6 . 74 03 JE SHORT 004012AB
004012A8 . 75 01 JNE SHORT 004012AB
004012AA E8 DB E8 CHAR 'è'
004012AB /> 66:B8 0800 MOV AX,8
004012AF |. 66:35 0700 XOR AX,0007
004012B3 |. D945 FC FLD DWORD PTR SS:[EBP-4] 取出[ebp-0x4]中保存的值
004012B6 |. D81D 18714000 FCOMP DWORD PTR DS:[407118] 得出的值与384比较是否相等
004012BC |. 6A 00 PUSH 0
004012BE |. 68 78804000 PUSH OFFSET 00408078 ASCII "CrackMe 2017 CTF"
004012C3 |. DFE0 FSTSW AX
004012C5 |. 9E SAHF
004012C6 |. 75 0E JNE SHORT 004012D6
004012C8 |. 68 5C804000 PUSH OFFSET 0040805C ASCII "Registration successful !"
004012CD \. EB 0C JMP SHORT 004012DB
004012CF /> 6A 00 PUSH 0
004012D1 |. 68 48804000 PUSH OFFSET 00408048 ASCII "CrackMe 2017 CTF v2"
004012D6 |> 68 40804000 PUSH OFFSET 00408040 ASCII "error !"
0x01 determina la longitud del valor de entrada
Puede ver la parte del valor que pasamos después de la entrada y usar strlen para saber si su longitud es 4. Si no es 4, saltará directamente a 004012CF.
Ahora se puede determinar que la longitud de la clave es 4
0x02 Verificar el valor de los primeros 2 dígitos de la clave.
Aquí verificamos si todos los valores clave son la cadena "0". Si otra clave de 4 dígitos es "0", salte directamente al cuadro emergente "error".
Luego continúe verificando el valor de los primeros 2 dígitos de la cadena clave, es decir, los primeros 2 dígitos de la cadena dada son "15",
si el valor de los primeros 2 dígitos de la clave no es "15", salte directamente al cuadro emergente "error"
Aquí obtenemos el valor de las 2 primeras claves como "15".
Algoritmo de análisis 0x03
Así es como funciona:
1. Tome el valor hexadecimal del tercer dígito de la clave y luego reste 0x30. Aquí, se supone que el valor es un
2. Tome el valor hexadecimal del primer bit de la clave como "1", que es 0x31, y luego reste 0x30, 0x31-0x30 =1
3. Tome el valor hexadecimal de "5" en el segundo dígito de la clave, que es 0x35, luego reste 0x30, 0x31-0x30 = 5 y luego divida 1 entre 5 para obtener el número de coma flotante 0,2.
4. Tome el valor hexadecimal del cuarto dígito de la clave y luego reste 0x30. Aquí, se supone que el valor es b
5. Entonces el resultado de multiplicar (a-0.2)*b por 16 es c
6. Determina si cy 384 son iguales. Si son iguales, ¡registro exitoso!, si no son iguales, entonces
fórmula de "error": (a-0.2)*b*16 = 384 Resuelve a y b
0x04 Escribe un script de algoritmo
Según el análisis anterior, escribí un script simple y obtuve dos resultados: "151N" y "1555".
for i in range(126):
for j in range(126):
if(((i-48)-0.2)*(j-48) == 24):
print(i)
print(j)
print("15"+"%s"%(chr(i))+"%s"%(chr(j)))
print("------")