31-10-2016, Saat: 14:56
Bilgisayarımızda internete bağlı olan programları nasıl tespit ederiz?
Aşağıda tümü verilecek olan kod örneği ile bilgisayarımızdan internete çıkış yapan programların listesini form üzerindeki bir TMemo'ya yazdıracağız.
Bunun için yapılması gereken;
Internet erişimi için genelde TCP kullanıldığı için ben burada sadece TCP için örnek göstereceğim. UDP için de hemen hemen aynı yöntem kullanılabilir. (En basitinden bir web sayfasına erişmenin aslında basit bir TCP bağlantısı olduğunu hatırlatmakta fayda var)
TCP bağlantıları tespit etmek için iphlpapi.dll içindeki GetExtendedTcpTable APIsini kullanabiliriz.
Bu API sayesinde hangi process'lerin bir TCP bağlantı oluşturdukları bulunabilir.
APIyi kullanabilmek için bazı tip tanımları yapılmalı:
Kodun mümkün olduğunca basit olması için tüm işlemleri bir butonun OnClick olayı içinde yapmaya çalıştım.
GetExtendedTcpTable APIsi bize processlerin IDlerini (PID - Process Identifier) verir. Yukarıdaki kod bloğunda PID'den programın ismini tespit etmek için GetPidName adında bir fonksiyon kullandım. Fonksiyon şu şekildedir:
Kendi programımızın da internet erişimi olabileceği düşünülerek, tespit edilen PID'lerin bizim programımıza ait olup olmadığının kontrolü için FCurrentPid kullanılmıştır. FCurrentPid, GetCurrentProcessId APIsi sayesinde bizim programımızın PID'sini gösterir.
Memo1 içinde program ismini atarken IndexOf kontrolü yaptık. Çünkü internete bağlı bir program birden fazla TCP/UDP bağlantı kurmuş olabilir. Böyle bir durumda aynı ismi birkaç kez Memo1'e atmamak için IndexOf ile daha önceden listeye eklenip eklenmediğini kontrol etmiş olduk.
Not 1: Yukarıdaki işlemler IPv4 için yapılmıştır. IPv6 için de aynı APIler kullanılabilir.
Not 2: Kullanmak isteyenler için; kod içerisinde bulunan dwRemoteAddr değeri aslında bize bağlantı yapılan IP adresini verir (Yani internete çıkan programın hangi IPye bağlandığı). 4 byte unsigned bu değerden bildiğimiz formattaki IP adresi tespit etmeyi meraklılarına bırakıyorum
Delphi XE ile yazılmış örnek bir program ektedir.
Ekran görüntüsü:
Aşağıda tümü verilecek olan kod örneği ile bilgisayarımızdan internete çıkış yapan programların listesini form üzerindeki bir TMemo'ya yazdıracağız.
Bunun için yapılması gereken;
- Bilgisayarda mevcut TCP ve UDP bağlantılarını tespit etmek
- Bu bağlantılardan hangilerinin başka bir bilgisayara bağlı olduğunu tespit etmek.
- Tespit edilen bağlantıların hangi process'lere ait olduğunu bulmak.
- Process'lerin isimlerini(Program ismi) tespit etmek
Internet erişimi için genelde TCP kullanıldığı için ben burada sadece TCP için örnek göstereceğim. UDP için de hemen hemen aynı yöntem kullanılabilir. (En basitinden bir web sayfasına erişmenin aslında basit bir TCP bağlantısı olduğunu hatırlatmakta fayda var)
TCP bağlantıları tespit etmek için iphlpapi.dll içindeki GetExtendedTcpTable APIsini kullanabiliriz.
Bu API sayesinde hangi process'lerin bir TCP bağlantı oluşturdukları bulunabilir.
APIyi kullanabilmek için bazı tip tanımları yapılmalı:
type TCP_TABLE_CLASS = Integer; PMibTcpRowOwnerPid = ^TMibTcpRowOwnerPid; TMibTcpRowOwnerPid = packed record dwState : DWORD; dwLocalAddr : DWORD; dwLocalPort : DWORD; dwRemoteAddr: DWORD; dwRemotePort: DWORD; dwOwningPid : DWORD; end; PMIB_TCPTABLE_OWNER_PID = ^MIB_TCPTABLE_OWNER_PID; MIB_TCPTABLE_OWNER_PID = packed record dwNumEntries: DWord; table: array [0..0] OF TMibTcpRowOwnerPid; end;
Kodun mümkün olduğunca basit olması için tüm işlemleri bir butonun OnClick olayı içinde yapmaya çalıştım.
procedure TForm1.Button1Click(Sender: TObject); var i: integer; dllHandle : THandle; GetExtendedTcpTable: function(pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall; PID, TableSize: DWORD; Snapshot: THandle; FCurrentPid: Cardinal; FExtendedTcpTable : PMIB_TCPTABLE_OWNER_PID; AppName: string; begin dllHandle := LoadLibrary('iphlpapi.dll'); //DLL'i hafızaya yükle if dllHandle = 0 then Exit; GetExtendedTcpTable := GetProcAddress(dllHandle, 'GetExtendedTcpTable'); if not Assigned(GetExtendedTcpTable) then Exit; // Kullanmak istediğimiz API bu DLLde yok ise çık Memo1.Lines.BeginUpdate; Memo1.Lines.Clear; try FCurrentPid := GetCurrentProcessId(); TableSize := 0; if GetExtendedTcpTable(nil, @TableSize, False, AF_INET, 5, 0) <> ERROR_INSUFFICIENT_BUFFER then //API'yi kullanmak için hafızada ne kadar yere ihtiyaç duyacağız? TableSize bunu bize verecek Exit; // Hafızada yeterli yer yok ise çık try GetMem(FExtendedTcpTable, TableSize); SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if GetExtendedTcpTable(FExtendedTcpTable, @TableSize, TRUE, AF_INET, 5, 0) = NO_ERROR then for i := 0 to FExtendedTcpTable.dwNumEntries - 1 do begin PID := FExtendedTcpTable.Table[i].dwOwningPid; if (PID<>0) and (PID<>FCurrentPid) and (FExtendedTcpTable.Table[i].dwRemoteAddr<>0) then begin AppName := GetPidName(SnapShot, PID); if Memo1.Lines.IndexOf(AppName) = -1 then Memo1.Lines.Add(AppName); end; end; finally FreeMem(FExtendedTcpTable); end; finally Memo1.Lines.EndUpdate; end; end;
GetExtendedTcpTable APIsi bize processlerin IDlerini (PID - Process Identifier) verir. Yukarıdaki kod bloğunda PID'den programın ismini tespit etmek için GetPidName adında bir fonksiyon kullandım. Fonksiyon şu şekildedir:
function GetPIDName(hSnapShot: THandle; PID: DWORD): string; var ProcInfo: TProcessEntry32; begin ProcInfo.dwSize := SizeOf(ProcInfo); if not Process32First(hSnapShot, ProcInfo) then Result := 'Bilinmiyor' else repeat if ProcInfo.th32ProcessID = PID then Result := ProcInfo.szExeFile; until not Process32Next(hSnapShot, ProcInfo); end;
Kendi programımızın da internet erişimi olabileceği düşünülerek, tespit edilen PID'lerin bizim programımıza ait olup olmadığının kontrolü için FCurrentPid kullanılmıştır. FCurrentPid, GetCurrentProcessId APIsi sayesinde bizim programımızın PID'sini gösterir.
Memo1 içinde program ismini atarken IndexOf kontrolü yaptık. Çünkü internete bağlı bir program birden fazla TCP/UDP bağlantı kurmuş olabilir. Böyle bir durumda aynı ismi birkaç kez Memo1'e atmamak için IndexOf ile daha önceden listeye eklenip eklenmediğini kontrol etmiş olduk.
Not 1: Yukarıdaki işlemler IPv4 için yapılmıştır. IPv6 için de aynı APIler kullanılabilir.
Not 2: Kullanmak isteyenler için; kod içerisinde bulunan dwRemoteAddr değeri aslında bize bağlantı yapılan IP adresini verir (Yani internete çıkan programın hangi IPye bağlandığı). 4 byte unsigned bu değerden bildiğimiz formattaki IP adresi tespit etmeyi meraklılarına bırakıyorum
Delphi XE ile yazılmış örnek bir program ektedir.
Ekran görüntüsü:
There's no place like 127.0.0.1