Código de incrustación y el peligro del software pirateado

Acerca de cómo puede incrustar código sin jmp en la sección de código y permanecer invisible si no estudia a fondo el código desensamblado. A quién le importa, por favor, debajo del gato.

Estoy desarrollando un desensamblador C para Linux. Sobre mí, no diría que soy un programador profesional. No trabajo como programador, pero lo que aprendí es leer libros o inventarlo yo mismo o estudiar el código fuente de otros programas. Por lo tanto, si el código te parece infantil, no lo jures.

Para empezar, hice un desensamblador y mi código ahora se ve así, es decir, se lee un byte y se pasa a la función deseada.

void disasm_intel ( unsigned char *ptr, int size, int byte_order, int show ) { show_asm = show; virt = global_virt_text; unsigned char *start = ptr; start_op = ptr; for ( int index = 0; index < size; index++ ) { if ( show_asm == TRUE ) printf ( "%lx: ", virt ); switch ( *ptr ) { case 0x30: intel_opcode_1_0x30 ( &ptr, &index, byte_order ); break; case 0x31: intel_opcode_1_0x31 ( &ptr, &index, byte_order ); break; case 0x66: intel_opcode_1_0x66 ( &ptr, &index, byte_order ); break; case 0x67: intel_opcode_1_0x67 ( &ptr, &index, byte_order ); break; case 0x83: intel_opcode_1_0x83 ( &ptr, &index, byte_order ); break; case 0x88: intel_opcode_1_0x88 ( &ptr, &index, byte_order ); break; // mov register to register byte case 0x89: intel_opcode_1_0x89 ( &ptr, &index, byte_order ); break; case 0x8a: intel_opcode_1_0x8a ( &ptr, &index, byte_order ); break; case 0x8b: intel_opcode_1_0x8b ( &ptr, &index, byte_order ); break; // mov esp, %x : mov ebp, %x case 0x8d: intel_opcode_1_0x8d ( &ptr, &index, byte_order ); break; // lea case 0xb0: intel_opcode_1_0xb0 ( &ptr, &index ); break; // mov al, %x case 0xb1: intel_opcode_1_0xb1 ( &ptr, &index ); break; // mov cl, %x case 0xb2: intel_opcode_1_0xb2 ( &ptr, &index ); break; // mov dl, %x case 0xb3: intel_opcode_1_0xb3 ( &ptr, &index ); break; // mov bl, %x case 0xb4: intel_opcode_1_0xb4 ( &ptr, &index ); break; // mov ah, %x case 0xb5: intel_opcode_1_0xb5 ( &ptr, &index ); break; // mov ch, %x case 0xb6: intel_opcode_1_0xb6 ( &ptr, &index ); break; // mov dh, %x case 0xb7: intel_opcode_1_0xb7 ( &ptr, &index ); break; // mov bh, %x case 0xb8: intel_opcode_1_0xb8 ( &ptr, &index, byte_order ); break; // mov eax, %x case 0xb9: intel_opcode_1_0xb9 ( &ptr, &index, byte_order ); break; // mov ecx, %x case 0xba: intel_opcode_1_0xba ( &ptr, &index, byte_order ); break; // mov edx, %x case 0xbb: intel_opcode_1_0xbb ( &ptr, &index, byte_order ); break; // mov ebx, %x case 0xbe: intel_opcode_1_0xbe ( &ptr, &index, byte_order ); break; // mov esi, %x case 0xbf: intel_opcode_1_0xbf ( &ptr, &index, byte_order ); break; // mov edi, %x case 0xc3: intel_opcode_1_0xc3 ( ); break; // ret case 0xcd: intel_opcode_1_0xcd ( &ptr, &index ); break; // int 0x%x } ptr++; virt += ptr - start; start = ptr; start_op = ptr; } show_asm = FALSE; } 

Y tales funciones ya son un montón. En algunos lugares hice comentarios para captar la interconexión de las instrucciones de la máquina, y tal vez más tarde para hacer un desensamblador más competente. Pero de esta forma, en la que tengo el código ahora, puedo establecer fácilmente cualquier condición para cada operador.

Entonces, mientras hacía esto, tuve una idea, ¿es posible agregar código en el medio de la sección de códigos? Resulta que puedes, pero en todos los casos? Hasta ahora, para agregar código, uso códigos de máquina ya preparados. Si puedo más tarde, haré que el traductor del ensamblador en el código de la máquina para agregar el código sea más conveniente. En mi caso, debe especificar el desplazamiento en la sección de código y los bytes se copian en el lugar correcto. También había un cierto problema: direccionamiento en memoria. Agregué un código al comando lea que guarda los datos necesarios en la estructura, y si inserta nuevos operadores en la sección de código, todos los desplazamientos se alinean para que indiquen datos en los nuevos desplazamientos. Bueno, no es muy difícil, si inserta el código, la sección de código aumentará en la misma cantidad de bytes y todas las demás secciones después de que la sección de código ya contenga nuevas compensaciones. Lo hice para que haya diferencias en el lugar donde pega el código, todos los desplazamientos funcionan correctamente. Entonces surgió el problema de que al abordar tales

 mov eax, [eax + eax + 0x100] 

El hecho es que en dicho direccionamiento puede haber ebp y apuntar a la pila, y no a otra sección. Decidí hacerlo de modo que si la dirección apunta a la sección de datos, considere los desplazamientos al insertar el código, si apunta a la pila, es decir, no la dirección en la sección de datos, entonces no tenga en cuenta los desplazamientos.

Y de esta manera los atacantes pueden aprovechar. Después de todo, se puede insertar código malicioso al comienzo de alguna función en el programa, por ejemplo, para que se cree un niño fork y se descargue un archivo especial. En Linux, esto se puede hacer sin ningún problema. De hecho, en / usr / include hay un archivo con todas las funciones del sistema operativo. Es decir, puede usar la parte de red, incluso si el programa no tiene funciones de red. No sé cómo en Windows, pero más adelante intentaré agregar trabajo con formato PE. Puede llegar a hacer lo mismo que en Linux. Hasta ahora tengo una versión de consola. Pero luego planeo hacerlo en GTK.

Gracias por dedicar tu tiempo a mi artículo.

Source: https://habr.com/ru/post/477590/


All Articles