Geceler birbirini izliyor. Sırasıyla.. Gündüzlere dair pek bir şey hatırlamıyorum. Geceleri çalıyorum, gündüzleri size bırakıyorum.
Hal böyle olunca daldan dala atlayan ben, kendimi bir anda c++ ile uğraşırken buluverdim.
C++ hakkında patavatsızca konuşarak sistem programcılarını kızdırmak istemem.
Hepinizin de bildiği gibi programlamaya ilk girişenlere genelde c ile başlayıp üzerine c++ ile devam etmesi önerilir.
Benim hikayem pek öyle olmadı. Programlamaya ilk delphi ile başladım. Sonra kendimi her dil ile en az bir "hello world" yazmış olarak buldum : )
Ama algoritma işini bir kere kaptınız mı dil falan önemli değil. Hangi dilin syntax'ını ve ufak trick'lerini kaparsanız gideceğiniz yerin sınırı aslında algoritmanızın ve hayal gücünüzün sınırıdır. O yüzden benim tavsiyem hangi dil olursa olsun tamamen programlamanın mantığını ve algoritmanızı geliştirene kadar o dil ile uğraşın. Sonra hedeflerinize veya ihtiyaçlarınıza göre hatta ve hatta hobilerinize göre başka diller ile ilgilenirsiniz.
C++ öğrenmeye başlamamın sebebi cross platform, native ve performanslı olması. Native ve performanslı oluşuna kimsenin diyeceği yok ama cross işini sonra konuşuruz.
C++ ile ilgilenince, Windows'da low level işlere merak saldım. Özellikle api hooking dikkatimi çekiyordu.
Kısaca api hook işlemini tanımlayacak olursak, programdaki bir function call işlemini yakalayıp onu kendi fonksiyonumuza yönlendirmektir.
Örnek verecek olursak. Programınızda win32 apileri yardımıyla bir "MessageBox" gösteriyorsunuz. Programınızda api hook işlemi yaptığınızda "user32.dll"den ne zaman "MessageBox" fonksiyonunu çağırırsanız çağırın, sizin belirlediğiniz user32.dll ' deki "MessageBox" prototipini kullanan kendi fonksiyonunuz işleme girecektir.
Bu şekilde bakıldığında tek başına api hook işlemi pek zevkli gözükmüyor. Eğer bu işlemleri bir library'de yapar ve bu library'i başka bir programa inject ederseniz, inject ettiğiniz programdaki istediğiniz api'yi hook edebilirsiniz.
Not: Kodlar orta düzey c / c++ ve win32 programlama bilgisi gerektirir
Api hooking için birkaç yöntem bulunmakta. Bu yöntemleri bu yazıda incelemeyeceğim. Ben m-hook adlı bir library buldum. Örnekleri bu library ile anlatacağım. Eğer api hooking hakkında daha detaylı bilgilere ulaşmak isterseniz yazının sonunda linkler vereceğim.
M-Hook adlı library'i buradan indirebilirsiniz.
Sevdiğiniz IDE'niz ve çayınız hazırsa başlayalım.
//Dynamic olarak bind etmek için fonksiyonumuzu tanımlıyoruz
typedef int (WINAPI *_MessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT);
_MessageBoxW TrueMessageBoxW = (_MessageBoxW)GetProcAddress(GetModuleHandle(L"user32"), "MessageBoxW");
Aşağıdaki fonksiyon gerçek MessageBox ile değişecek olan bizim fonksiyonumuz.
int WINAPI HookMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType){
return TrueMessageBoxW(hWnd,L"DENEME",lpCaption,uiType);
}
Dikkat edin 2. parametreyi "DENEME" olarak, diğer parametreleri de olduğu gibi gönderiyoruz.
Mhook-SetHook(HookEdilecekFonksiyon, HookFonksiyon);
M-hook ile yukarıdaki şekilde hook işlemi yapıyoruz. Hook işlemi gerçekleşirse true gerçekleşmez ise false değeri döndürür.
if (Mhook_SetHook((PVOID*)&TrueMessageBoxW, HookMessageBoxW)){
printf("Hooked\n");
}
Buradan sonra eğer MessageBox fonksiyonunu kullanırsak HookMessageBoxW fonksiyonumuz devreye girecek.
MessageBoxW(NULL, L"Bu yazının gozukmemesi lazim", L"..", MB_ICONINFORMATION);
Hook işleminden sonra UnHook işlemi uygulanmalıdır. O da şöyle ki
if(Mhook_Unhook((PVOID*)&TrueMessageBoxW)){
printf("UnHooked\n");
}
Kodları toplarsak.
#include <windows.h>
#include <stdio.h>
#include "mhook-lib/mhook.h"
void Hook();
void UnHook();
typedef int (WINAPI *_MessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT);
_MessageBoxW TrueMessageBoxW = (_MessageBoxW)GetProcAddress(GetModuleHandle(L"user32"), "MessageBoxW");
int WINAPI HookMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType){
return TrueMessageBoxW(hWnd,L"DENEME",lpCaption,uiType);
}
int main(int argc, char *argv[]){
Hook();
MessageBoxW(NULL, L"Bu yazının gozukmemesi lazim", L"..", MB_ICONINFORMATION);
UnHook();
return 0;
}
void Hook(){
if (Mhook_SetHook((PVOID*)&TrueMessageBoxW, HookMessageBoxW)){
printf("Hooked\n");
}
}
void UnHook(){
if(Mhook_Unhook((PVOID*)&TrueMessageBoxW)){
printf("UnHooked\n");
}
}
Buraya kadar ne yaptık, kendi programımızda kullandığımız MessageBoxW fonksiyonunu hook ettik.
Programımızı tekrar library olarak yazalım ve başka bir programa inject edelim.
Library projenizi açın ve int main(...){....} kod bloğunu şununla değiştirin.
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
Hook();
break;
case DLL_PROCESS_DETACH:
UnHook();
}
return TRUE;
}
Yukarıda ki switch statement'ı library'miz başka bir process'e inject olduğunda ki durumları kapsayan kod bloğudur.
Library process'e inject olduğunda Hook() , DLL_PROCESS_DETACH'ta da UnHook() fonksiyonlarımız çağırılır. Ki DETACH koşulu da genelde program sonlandığında oluşan durumdur
Library'i derledikten sonra oluşan dll'mizin adı test.dll olsun.
Inject işlemini yapacak ufak bir program gerekiyor.
Injector.cpp kodları
#undef UNICODE
#include <vector>
#include <string>
#include <windows.h>
#include <Tlhelp32.h>
using std::vector;
using std::string;
#define ProcessToInject "msgbox.exe"
int main(void)
{
vector<string>processNames;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
BOOL bProcess = Process32First(hTool32, &pe32);
if(bProcess == TRUE)
{
while((Process32Next(hTool32, &pe32)) == TRUE)
{
processNames.push_back(pe32.szExeFile);
if(strcmp(pe32.szExeFile, ProcessToInject) == 0)
{
char* DirPath = new char[MAX_PATH];
char* FullPath = new char[MAX_PATH];
GetCurrentDirectory(MAX_PATH, DirPath); //Holds directory for convenience
sprintf_s(FullPath, MAX_PATH, "%s\\test.dll", DirPath); //Copy DLL name in there
LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); //Get LoadLibraryA address
//Open Process
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
if(!hProcess)
{
MessageBox(0, "OP Failed", "Error!", 0);
break;
}
//Allocate space for function
void *pRemoteThread = VirtualAllocEx(hProcess, 0, strlen(FullPath), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!pRemoteThread)
{
MessageBox(0, "RT Failed", "Error!", 0);
break;
}
//Copy function
if (!WriteProcessMemory(hProcess, pRemoteThread, FullPath, strlen(FullPath), 0))
{
MessageBox(0, "WPM Failed", "Error!", 0);
break;
}
//CreateRemoteThread
HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryAddr, pRemoteThread, 0, 0);
if (!hThread)
{
MessageBox(0, "CRT Failed", "Error!", 0);
break;
}
CloseHandle(hProcess);
delete [] DirPath;
delete [] FullPath;
}
}
}
CloseHandle(hTool32);
return 0;
}
Şimdi de MessageBox apisini kullanan örnek bir program lazım
msgbox.cpp
#include "Windows.h"
int main()
{
for(int i=1;i<=5;i++){
MessageBoxW(NULL, L"bunun cikmamasi lazimdi", L"..", MB_ICONINFORMATION);
}
}
test.dll, injector.exe ve msgbox.exe' miz hazır. Hepsinin aynı dizinde olmasına dikkat edelim.
msgbox.exe'i ilk açışımız da
Hook edilmemiş MessageBox'un çalıştığını görüyoruz. OK'a tıklamadan injector.exe'i açıyoruz
Ve OK'a basıyoruz.
Ve içerik olarak daha önce test.dll'de yazdığımız "DENEME" i görüyoruz. Diğer parametreleri aynı şekilde gönderdiğimiz için başlık aynı şekilde kaldı.
Programı kapatmadan task manager'dan bakarsanız injector.exe'nin çalışmadığını görebilirsiniz. Çünkü biz injector.exe aracılığıyla test.dll mizi msgbox.exe mize inject ettik.
OK'a bastıkça hook edilmiş fonksiyonun çağırıldığını göreceksiniz.
5 mesaj da gösterildikten sonra program kapanırken DLL_PROCESS_DETACH koşulu gerçekleştiğinden UnHooked yazısını göreceksiniz.
Yazıda size kaba taslak api hooking işlemlerini anlattım. Yazıda hep MessageBox fonksiyonu ile uğraştık.
Oysa Windows işletim sistemi apilerle içli dışlı bir sistemdir. Her şey arka planda apilerle yürütülmektedir. Microsoft'un bu apileri listelediği bir referans adresi de mevcuttur.
http://msdn.microsoft.com/en-us/library/ff818516%28v=vs.85%29.aspx
MessageBox bizim için pek bir şey ifade etmese de binlerce hook edilebilecek apiyi düşündüğümüzde windows'un art niyetli işlemlere ne kadar açık bir OS olduğunu tekrar anlayabiliriz. Örneğin winsock fonksiyonlarını hook eden bir malware düşünün. Winsock apileri kullanan herhangi bir programa inject edildiğinde programa gelecek gidecek bütün trafik önce malware'ın elinden geçecektir. Örneğin plain text kullanan msn protokolü. Bütün msn trafiğini hook ve dll inject yardımıyla dinlenebilir.
Yazının başında da dediğim gibi yapılabileceklerinizin sınırları aslında algoritmanızın ve hayal gücünüzün sınırlarındadır.
Faydalandığım kaynaklar
http://msdn.microsoft.com/en-us/library/ff818516%28v=vs.85%29.aspx
http://stackoverflow.com/questions/1088139/what-is-the-recommended-way-to-hook-win32-apis-for-a-commmercial-application
http://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours
http://www.codeproject.com/Articles/2082/API-hooking-revealed
http://www.codeproject.com/Articles/30537/Windows-File-Monitoring-System-Using-Windows-API-H