Monday, January 23, 2012

Понять лог keylogrecorder

Неплохая статья на Хабре о Meterpreter, способствует желанию все испробовать. Наибольший интерес, конечно, вызывает кейлоггер, - действительно, полезная штука. Проблема только в том, что, как правило, русские люди пишут по-русски, тогда как keylogrecorder, конечно, об этом не догадывается. Как следствие - просмотр логов его работы не дает желанных результатов :-(. Получается что-то типа такого:

$ cat test.txt

Ujybvs dtiybvb kexfvb?

C jrhtcns[ ujh e;t cytuf

C,t;fkb venysvb hexmzvb

Yf gjnjgktyyst keuf

<return> 'nj ntcn <ctrl> Ntcn 'nj <lctrl> <alt> Fktrcfylh Cthuttdbx Geirby<lmenu>


Может кто, возможно, глядя на это поймет что здесь написано, но я подобными способностями не обладаю.


Первое что приходит на ум - Perl-овый tr, что-нибудь типа:

tr/`qwertyuiop[]asdfghjkl;'zxcvbnm,./ёйцукенгшщзхъфывапролджэячсмитьбю/

При этом программка выглядит так:

$ cat tr1.pl



#!/usr/bin/perl -w

while (){
   tr/`qwertyuiop[]asdfghjkl;'zxcvbnm,./ёйцукенгшщзхъфывапролджэячсмитьбю/;
   print;
}


Но не все так просто, к моему глубочайшему сожалению. Русские буквы, бывает, кодируются UTF-8 в 2 байта, а английские - в 1 байт...

Абсолютно рабочим вариантом является recode наш tr (всю Perl-овую программку) в кодировку где русские буквы однобайтовые, например так:

$ recode UTF-8..KOI8r tr-koi8r.pl

Затем, этим tr-koi8r.pl можно уже транслировать продукт keylogrecorder-а.

$ cat test.txt | ./tr-koi8r.pl >test2.txt


Помним, что у нас локаль - UTF-8...

у меня на Debian оно выглядит так:

$ locale

LANG=en_US.utf8

LANGUAGE=

LC_CTYPE="en_US.utf8"

LC_NUMERIC="en_US.utf8"

LC_TIME="en_US.utf8"

LC_COLLATE="en_US.utf8"

LC_MONETARY="en_US.utf8"

LC_MESSAGES="en_US.utf8"

LC_PAPER="en_US.utf8"

LC_NAME="en_US.utf8"

LC_ADDRESS="en_US.utf8"

LC_TELEPHONE="en_US.utf8"

LC_MEASUREMENT="en_US.utf8"

LC_IDENTIFICATION="en_US.utf8"

LC_ALL=


..., поэтому результат, test2.txt, следует вернуть в юникод:

$ recode KOI8r..UTF-8 test2.txt


И..., вуаля, уже что-то:


$ cat test2.txt

Uонимы вешними лучами?

C окрестых гор уже снега

Cбежали мутными ручьями

Yа потопленные луга

<rуегкт> это тест <cекд> Nест это <lcекд> <aде> Fлександр Cергеевич Gушкин<lmутг>


Есть кое-какие артефакты, но это потому, что заглавные буквы я забыл (:-) указать в tr, перевелись и управляющие клавиши, типа <lctrl> <alt> и т.п. Тем, не менее, в целом, такой вариант перевода трудов keylogrecorder-а, также возможен: программка на Perl в три строчки, дважды recode и все!


Но, почему-то этот варинат показался мне неспортивным! Решил тряхнуть стариной, написать транслятор на С. Последний раз я интенсивно писал на С уже как десять лет назад, поэтому не могу похвастаться что получилось все сразу просто и быстро. Но, в целом, ничего сложного в коде нет, поэтому не буду много разглагольствовать, просто приведу исходник. Программа учитывает управляющие последовательности типа (в коде это реализовано двумя способами, один из способов закомментарин, показался также неспортивным, но у него есть определенные преимущества перед вторым способом, поэтому полностью его убивать жаль), заглавные буквы, и пунктуацию в русской раскладке.


$ cat trc.c



#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int checkIfCtrl(char *p);

int main(int argc, char **argv){
   const int n = 512;
   char *buf, *buf2, *ten, *tru, *tb, *tb2;
   char *enl = "`qwertyuiop[]asdfghjkl;'zxcvbnm,.~QWERTYUIOP{}ASDFGHJKL:ZXCVBNM<>\"";
   char *rul = "ёйцукенгшщзхъфывапролджэячсмитьбюЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЯЧСМИТЬБЮЭ";
   char *enl1 = "/?&^$";
   char *rul1 = ".,?:;";
   int b = (int) strlen(rul)/strlen(enl), i;
   //char *words[] = {"<Next>","<Prior>","<Return>","<Ctrl>","<LCtrl>","<Alt>","<LMenu>","<Back>","<Delete>","<N3>","<N0>","<Right>","<Tab>"};
   //int wn = 13;
   int wil;

   buf = (char *) malloc(n);
   memset(buf,0,n);
   buf2 = (char *) malloc(n*b);
   memset(buf2,0,n*b);

   while( 0 != fgets(buf,n,stdin) ){
      tb2 = buf2;
      for(tb = buf; *tb != '\0'; tb++){
         /*for (i=0; i<wn; i++){ //ctrl
            wil = strlen(words[i]);
            if (strncmp(tb,words[i],wil) == 0){
               memcpy(tb2,tb,wil);
               tb += wil;
               tb2 += wil;
            }
         }*/
         if( (wil = checkIfCtrl(tb)) > 0){ //ctrl
            memcpy(tb2,tb,wil);
            tb += wil;
            tb2 += wil;
         }
         if ( (ten = strchr(enl, *tb)) != 0 ){
            tru = rul + b*(ten-enl);
            memcpy(tb2,tru,b);
            tb2 += b;
         }
         else if ( (ten = strchr(enl1, *tb)) != 0 ){
            tru = rul1+(ten-enl1);
            memcpy(tb2,tru,1);
            tb2 += 1;
         }
         else {
            memcpy(tb2,tb,1);
            tb2 += 1;
         }
      }
      printf(buf2);
      memset(buf2,0,n*b);
      memset(buf,0,n);
   }
   
   free(buf2);
   free(buf);
   return 0;
}
/////////////////////////////////////////////////////////////////////////
int checkIfCtrl(char *p){
   int lmax = 10, i, flag=0;
   char b='<', e='>';
   
   if(*p == b){
      for(i=0; i<lmax; i++){
         if (*(p+i) == e){
            flag = 1+i;
            break;
         }
      }
   }
   return flag;
}



Сразу прошу снисхождения к моим навыкам академического программирования. Но, если есть предложения по развитию этой микро-программки (во термин - micro-soft), буду рад их увидеть.

Компилируем:

$ gcc trc.c -o trc


Результат работы:

$ cat test.txt | ./trc

Гонимы вешними лучами,

С окрестых гор уже снега

Сбежали мутными ручьями

На потопленные луга

<return> это тест <ctrl> Тест это <lctrl> <alt> Александр Сергеевич Пушкин<lmenu>




Совсем хорошо!

Кривовато, правда... Более правильным кажется использование штатных С-шных функций для двухбайтовых символов, описанных в wchar.h и wctype.h, но просто и быстро у меня это почему-то не получилось (помню на VC под win пару лет назад получалось), поэтому я эту идею бросил, может, в следующий раз...

Представленные здесь варианты решили мою задачу, надеюсь, могут быть полезны и вам.