Bucle while infinito muy ruidoso para keylogger c++

Iniciado por @XSStringManolo, 3 Junio 2019, 08:17 AM

0 Miembros y 1 Visitante están viendo este tema.

@XSStringManolo

Como puedo hacerlo consumir menos recursos de cpu sin perder pulsaciones de tecla?
No quiero usar delay, wait, sleep ni nada parecido porque se puede saltar pulsaciones de teclas y a parte a pensas baja el uso de cpu.
Alguna solución buena?

El codigo es en plan:

while(true)
{
for (//tamanho maximo del log)
{
if ( teclainput() ) escribelog;
}
}


RayR

Por lo que dices de los recursos de CPU, imagino que en teclainput() iría una función tipo kbhit(), que simplemente verifica si hay datos de teclado. Por lo tanto, cuando no hay tecla presionada, regresa y se vuelve a ejecutar el bucle, ocasionando el alto consumo de recursos. La clave estaría en usar mejor una función bloqueante, es decir, que intente leer una tecla, y si no hay ninguna, simplemente espere, y de esa forma no se usa prácticamente nada de CPU. Todas las funciones estándar de entrada de C y C++ (getchar, cin.get, etc.) ya son bloqueantes, pero un problema es que, de forma predeterminada, stdin usa buffer por línea. Por ejemplo, getchar() lee un caracter, pero el usuario tiene que presionar Enter para que esta función pueda leer lo que escribió. La solución sería cambiar stdin a modo sin buffer. En Windows podría hacerse así:

Código (cpp) [Seleccionar]
// Obtenemos handle a stdin
HANDLE hEntrada = GetStdHandle(STD_INPUT_HANDLE);
DWORD modo;
char c;

// Guardamos la configuracion actual
GetConsoleMode(hEntrada, &modo );
// Desactivamos el buffer por linea
SetConsoleMode(hEntrada, modo & ~(ENABLE_LINE_INPUT) );


Una vez hecho esto, ya podrías hacer algo así:

Código (cpp) [Seleccionar]
while (true) {
    c = cin.get(); // o getchar() o cualquier funcion que lea 1 caracter
    escribelog(c);
}

// Importante devolver stdin a su estado original antes de salir del programa
SetConsoleMode(hEntrada, modo);


De esta manera, el programa simplemente esperará a que se presione alguna tecla, sin consumir apenas CPU, y en cuanto el usuario teclee algo, sin necesidad de que presione Enter, cin.get() lo obtendrá.

Una forma aún mejor sería haciendo que tu aplicación reciba eventos del teclado, pero ahí ya tendrías que usar más cosas de la API de Windows.

Y, claro está, me basé en el seudocódigo que pusiste, pero esto obviamente no funcionaría como keylogger, ya que sólo captura teclas de tu propia aplicación. Si quisieras capturar las del sistema, podrías crear un hook de teclado (WH_KEYBOARD o WH_KEYBOARD_LL). Realmente no es difícil pero tendrías que meterte más de lleno a WinAPI.

@XSStringManolo

Muchas gracias por la respuesta. El problema es el bucle en sí, no la repeticion de instrucciones de dentro. Si no ek propio bucle, si creo un bucle while vacio completamente tengo el mismo problema. La funcion que uso no se parece a kbhit, solo lee las teclas if (KEY_IS_DOWN) mediante eventos. Es decir, cuando una tecla se baje. No cuando encuentre datos en buffer. Si una tecla se pulsó hago comprobaciones en un switch(mapa) con case 0x30: escribeenlog("0"); Usando virtual keywords http://www.kbdedit.com/manual/low_level_vk_list.html


RayR

Sí, un bucle vacío también te va a consumir mucho CPU, debido a que las instrucciones de verificación de la condición y el salto de vuelta al inicio, se van a ejecutar muchos millones de veces por segundo:

while (true) {
}


Aquí, el procesador está constantemente verificando si la condición es true, y saltando de nuevo al inicio del bucle. Esto sucede tan rápido, que ese trozo de código hace que tu procesador ejecute seguramente muchos millones de instrucciones por segundo. En este otro caso:

while (true) {
    if (tecla_presionada()) {
    ....
    }
}


En este caso, estamos llamando a tecla_presionada() en cada repetición, pero dado que lo único que hace es verificar si se presionó una tecla, regresa muy rápido. Ahora, en condiciones normales, la gran mayoría de las veces no habrá tecla presionada (obviamente nadie puede teclear millones de veces por segundo), por lo que ese if evaluará a falso, y volveremos a la siguiente repetición del bucle. Todo esto pasa muy rápido, y no hay nada ahí que le diga al procesador que tiene que detenerse un poco: él hace lo que tiene que hacer, que es ejecutar las instrucciones que tiene delante, tan rápido como sea posible.

Aunque no sé qué librería estás usando, prácticamente todas (por no decir todas) las que funcionan de la forma if (KEY_BLABLA), en Windows llaman internamente a la función GetKeyState o GetAsyncKeyState. Estas funciones únicamente verifican si la tecla especificada está presionada, y en cualquier caso, regresan inmediatamente, por eso estoy seguro de que así funciona también la función que estés llamando.

La única forma de evitar el alto consumo es haciendo que el bucle no se repita tan rápidamente, y eso sólo se puede hacer, o con algo tipo sleep, que no es muy recomendable, o usando funciones bloqueantes, como en el ejemplo que te puse, que no consume prácticamente nada de CPU. Si no te sirven las funciones de entrada estándar, tendrías que ver si la librería que estés usando tiene funciones que verifiquen si hay teclas presionadas, y si no las hay, espere hasta que se presione alguna, es decir, que funcionen de forma bloqueante. De otra manera, es imposible solucionar el problema.

Pero como te mencioné en el otro mensaje, la mejor solución es usar eventos de Windows, es decir, que tu programa reciba mensajes. De esa manera, ni siquiera hay que poner verificaciones if (KEY_IS_DOWN). Tu programa automáticamente será notificado cuando se haya pulsado alguna tecla, y tú únicamente verificas el valor de tecla virtual que recibas. De hecho, así es como suelen funcionar los keyloggers reales (aunque estos, adicionalmente instalan, como te decía, hooks para capturar teclas de todo el sistema).

MCKSys Argentina

Cita de: string Manolo en  3 Junio 2019, 08:17 AM
No quiero usar delay, wait, sleep ni nada parecido porque se puede saltar pulsaciones de teclas y a parte a pensas baja el uso de cpu.
Alguna solución buena?

Usar hooks: https://www.codeproject.com/Articles/1264/KeyBoard-Hooks

Saludos!
MCKSys Argentina

"Si piensas que algo está bien sólo porque todo el mundo lo cree, no estás pensando."


@XSStringManolo

Intentaré usar algun tipo de funcion bloqueante que no haga nada hasta que reciba input.
A parte el keylogger que estoy diseñando va bastante como el culo. Nornalmente pilla todas las teclas pero a veces el for no le da tiempo a pillar teclas. Entonces si escribo HHHOOOLLLAAA en el log se me puede guardar:
HHOAAA

Creo que voy a empezar de 0 mirando por ejemplos para ver varias maneras de hacerlo. El tema es que me gustaría que fuese en C++ puro multiplataforma porque a parte del keylogger se guardan otro tipo de registros y lo quiero usar para pcs que tengan servidor linux y sistema windows. Se que podría hacerlo con un rotkit y varios módulos. Uno de ellos para desplegar otro rotkit desde un sistema a otro y tener 1 en cada sistema según versión etc, pero no me convence. Parece una tarea muy pesada.

Es más que nada para aprender, si no hacia copia y pega de sources y ya.


Mirare los hoocks, pero ne gustaría que fuese multiplataforma sin tener que diseñar un keylogger para windows, otro para linux, otro para mac, otro para android...

La idea es subir el keylogger a un servidor web al cual puedo acceder a archivos de solo lectura para sacar la pass de root. Ya sea windows server, ubuntu server o lo que sea.