*3 Şubat 2012 Cuma

c++ dll injection and win32 api hooking via m-hook

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

*1 Aralık 2011 Perşembe

Mazeret mi ?

    Ben buradayım deme yollarından biridir blog. Hani herkes çevresi tarafından kabul görmeyi ister(*). İster ister. Ya da biz ona ister demeyelim de "İstemem yan cebime koy" olsun. Demek istediğim kimse öylesine bir şeyler karalamaz, yazmaz.  Yazdıktan sonra bekler ki ziyaretçim olsun, okusun. Bunu sadece blog diye daraltamayız. Sanat da öyledir mesela. Sen kral bir sanat eseri yapacaksın da ben egoist değilim diye kimseye göstermeyeceksin, eserin beğenilirse gururun hafiften okşanmayacak. Yok öyle bir dünya. 

Şöyle de bir söz duymuştum aklıma gelmişken söyleyeyim. 

"Mütevazi olmaması gereken yerde mütevazi olan herkesden daha kibirlidir."

Anlaşılan o ki ben buradayım deme ihtiyacı azalmış bizde. Belki sadece o da değildir nedeni. Yeterince ifade edememişizdir kendimizi, becerememişizdir, kelimeler dökülmemiştir.

*14 Ekim 2011 Cuma

Yoklama

Takip eden kaldı mı ki hala ?

*29 Mayıs 2011 Pazar

Remotesms android ile pc üzerinden sms gönderin

Bu aralar rastladığım en güzel şey olsa gerek. Yıllardır sms yazma zorluğundan nefret ederdim. Kaldı ki dokunmatik ekranla sms yazmak daha da işkence haline gelmişti. Neyse ki bu programı keşfettim. 

Program androidinize ufak bir webserver kuruyor. Gelen http requestleri belirli işlemlerden geçirilerek sms'lerinize erişim sağlıyor. Programın client ile iletişimi bu şekilde gerçekleşiyor. Siz de kendi browseriniz ile programın web 2.0 arayüzünden sms gönderebiliyorsunuz. Yeni sms geldiğinde uyarı veriyor, sms göndereceğiniz kişiyi yazarken otomatik tamamlama özelliği var. Sms geçmişini görebiliyorsunuz. Kısaca programın özellikleri bunlar. Daha detaylı bilgiyi yazılımcının sitesinden bulabilirsiniz.

Program ister wifi üzerinden kablosuz, isterseniz sitesinden indirilebilen usb connector adlı aracı yazılımı kullanarak usb üzerinden kullanılabiliyor.

Programın hem ücretli hem de ücretsiz versiyonları bulunuyor. Ücretsiz versiyonunu sitesinden indirebiliyorsunuz. Ücretlisine ben karışmıyorum ama arayan onu da bulur.

Aşağıda programın ekran görüntülerine bakabilirsiniz.



*22 Mayıs 2011 Pazar

Benim de bir Android'im var


Bugüne kadar smartphonelar bir yana Nokia 3100 gibi bir telefonu 7 yıl kullanmış biri olarak yazıyorum bu yazıyı.
Telefon dün elime geldi ve hala sevişiyoruz. Telefon hakkındaki ilk izlenimlerim göze çarpan müthiş hızı. Şarj konusunda diğerlerinden farklı bir yorum yapamayacağım ama henüz bir gün oldu telefonu elime alalı. Şarj kullanımı kullanandan kullanana değişecek bir şey zaten. Android Gingerbread 2.3.3 sürümü kullanıyorum. Daha telefonun tüm numaralarını keşfetmesemde şimdilik bir kaç program yükledim marketten.



  • Opera Browser
  • Winamp
  • Meebo IM
  • Mp3 Music Download
  • Applanet
  • Barcode Scanner
  • Astro File Manager
Android dünyasına katıldığımdan ötürü mutluyum. Bu demektir ki ileride blogda android programlamayla ilgili güzel başlıklar olabilir. Takipte kalın. Yazmadığım zamanları bir kenara atarsak android ile ilgili güzel makaleler artık burada diyebilirim.

*25 Mart 2011 Cuma

Virtualbox dan VmWare'a Doğru (*.vdi to *.vmdk)

Uzun zamandır virtualization işlemleri için VirtualBox kullanıyordum. Hem ücretsiz hem de çok sadeydi. Yani kısacası işimi görüyordu. Ama virtualization konusunda her daim adından söz ettiren bir de VmWare vardı tabi ki. Daha önce kullanmadığımdan test etmek istedim. Ne var ki 20 gb' lik *.vdi formatındaki VirtualBox hard disk'lerini VmWare'ın açabileceği *.vmdk formatına çevirmem gerekiyordu. Uzun araştırmalar sonucu en sağlıklı yolun: Önce *.vdi hard disk imajını VBoxManage aracı ile raw formata çevirip sonra da qemu aracı ile *.vmdk formatına çevirmek olduğunu buldum ve işlemleri sırasıyla yaptım.
Not: Denemek isteyenleri şimdiden uyarmış olayım. İşlemler toplamda yaklaşık 10 saat sürdü.

Önce raw formatına çeviriyoruz:

VBoxManage internalcommands converttoraw win7.vdi win7.raw
Qemu yüklü değilse yüklüyoruz. Debian paket sistemi kullananlar için
sudo apt-get install qemu
Raw hard disk'imizi *.vmdk formatına çeviriyoruz.
qemu-img convert -O vmdk win7.raw win7.vmdk
İşlemler bittikten sonra VmWare'da yeni bir makine oluşturuyoruz. Resimde gördüğünüz gibi "I will install operating system later" ı seçiyoruz "Store virtual disk as single file" ı seçiyoruz. Bu iki seçenek dışında herşeyi isteğinize göre seçebilirsiniz. Makineyi oluşturduktan sonra makineye sağ tıklayıp "Settings" kısmını açıyoruz. Burada hardware bölümünde harddiski seçip siliyoruz. Sonra "Add" butonuna basıyoruz. Buradan hard disk i seçip "Next"'e tıklıyoruz. Aşağıdaki resimdeki gibi "Use an existing virtual disk" ile daha önceden qemu ile oluşturduğumuz *.vmdk formatlı hard disk imajını seçiyoruz. Eğer size hard disk imajını VmWare'ın yeni versiyonları ile uyumlu hale getirmek için convert etmek isteyip istemediğinizi sorarsa evet deyin. Dip Not: Bütün bu işkenceleri yapıp VmWare'a pek ısınamadığım için VirtualBox kullanmaya devam ediyorum.

*24 Mart 2011 Perşembe

Bleachbit Command Line - Bash alias ile Temizlik

Geçici, kullanılmayan, bilgisayarımda 5 kb olsa dahi işe yaramayıp yer kaplayan verilerden hep rahatsız olmuşumdur. Windowsda iken çoğunuzun bildiği ccleaner kullanıyordum. Linux dünyasında ccleaner muadili bleachbit adlı programımız var. Bleachbit hem gui hem de command line üzerinden çalışabilen bir uygulama. Sürekli gui açmaktan rahatsız olduğumdan aşağıdaki bash aliaslarını oluşturdum ve arada bir uyguluyorum. Bleachbit command line kullanımına güzel bir örnek. Siz de ~/.bashrc dosyanıza alias olarak ekleyebilirsiniz.
nano ~/.bashrc # düzenlemek için nano ile açıyoruz ve aşağıdaki aliaslarımızı ekliyoruz.
alias temizlik='bleachbit_cli -d chromium.cache chromium.vacuum easytag.logs firefox.cache firefox.download_history firefox.session_restore firefox.vacuum flash.* gnome.run java.cache nexuiz.cache openofficeorg.* opera.cache opera.download_history screenlets.* skype.chat_logs x11.debug_logs xchat.logs xine.cache'

alias rtemizlik='sudo bleachbit_cli -d apt.* system.desktop_entry system.clipboard system.localizations system.tmp system.trash'
Bleachbit command line daha fazla seçenek için: http://bleachbit.sourceforge.net/documentation/command-line