FFI nasıl çalışıyor?

C yi nerdeyse hiç bilmeyince zorladı baya.

Olsun biraz daha araştırmayla öğrenirim.

Sorun yok :smiley:

#include <stdio.h>

int kod2()
{
    int arr[3];
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    int sonuc = 0;
    for (int i = 0;i < 3;i++)
    {
        sonuc += arr[i];
    }
    return sonuc;
}

int kod1()
{
    return 5;
}

int main()
{
    int a = kod1();
    int b = kod2();
    printf("%d\n", a);
    printf("%d", b);
	return 0;
}

Bu kodda çalışmayan ne?

Derleyince çalışıyor ama ctypes ta bu fonksiyonlardan birini çağırmaya çalışınca hata veriyor.

Kodu ve hata mesajini yazmayi unutmussun :slight_smile:

Bunu calistiran kod nerede?
DLL/SO olarak derleyip baska bir executable’da LoadLibrary/dlopen + GetProcAddress/dlsym kullanarak calistirman lazim fonksiyonlari.

Pardon ben sadece C kısmını atmışım :smiley:

Bunu main in içinde çalıştırıyorum zaten, fazladan bir şey mi eklemem gerekiyor ?

DLL olarak derleyememiştim ama tekrar bir deneyeyim.

Pythonda yazdığım kod:

from ctypes import cdll

lib = cdll.LoadLibrary("C:\\Users\\Furkan\\Desktop\\yeni2.dll")
kod2 = lib.kod2

print(kod2)

Hata: OSError: [WinError 193] %1 geçerli bir Win32 uygulaması değil

Birde bir messagebox çıkıyor onda da yazanlar şunlar:
C:\Users\Furkan\Desktop\yeni2.dll programı Windows üzerinde çalışmak üzere tasarlanmadı veya hata içeriyor. Programı özgün yükleme medyasını kullanarak yüklemeyi deneyin veya destek için sistem yöneticinize veya yazılım satıcısına başvurun. Hata durumu: 0xc000012f.

DLL olarak derlerken aynı kodu kullandım belki ondan hata veriyordur bilmiyorum belki de değişiklik yapmam lazımdı. Öyle düşünmemin sebebi şu linkteki yazı:
https://www.codementor.io/@a_hathon/building-and-using-dlls-in-c-d7rrd4caz
Mesela burda void message(void); değilde

#define EXPORT __declspec(dllexport)

EXPORT void message (void);

yapmış. Ama DLL oluşturmayı denemeye devam edicem belki daha kolay bir yol bulurum :smiley:
Birde

Nasıl hem LoadLibrary hem de GetProcAddress olarak çalıştırabilirim ki ? Mesela

lib = cdll.LoadLibrary("C:\\Users\\Furkan\\Desktop\\yeni2.dll")

yerine

lib = cdll.LoadLibrary("C:\\Users\\Furkan\\Desktop\\yeni2.dll") + GetProcAddress("C:\\Users\\Furkan\\Desktop\\yeni2.dll")

gibi mi ?

Python’da degil.

  1. LoadLibraryA function (libloaderapi.h) - Win32 apps | Microsoft Learn
  2. GetProcAddress function (libloaderapi.h) - Win32 apps | Microsoft Learn
  3. C++ Libraryler hakkında sorular(aklıma takılan sorular) - aib tarafından #4

DLL olmamis gibi.

LoadLibraryA ve GetProcAddress in ne işe yaradığını anladım ama bunları c de yazdığım kodda mı kullanmam gerekiyor ?

Sonunda oldu! https://www.cygwin.com/cygwin-ug-net/dll.html adresindeki kodu denedim ve bir DLL oluşturabildim. Ayrıca python da kullanmayı denerken de hata vermiyor.
Kod:

#include <stdio.h>

int
hello()
{
	printf("Hello World!\n");
}

Ayrıca fonksiyonu çağırıp ekrana Hello World! yazdıramamış olsam da en azından fonksiyonun adresini alabildim: <_FuncPtr object at 0x0000020B480BBD40>

Evet, ctypes’in yaptigini yapmis olacaksin.

lib.hello() ?

Valla bende yukardaki kod1/kod2 “cat” diye calisti. Parametre/return’lerini soylemem bile gerekmedi. (Herhalde int(void)'e default ediyor)

0 yazdırıyor.

Peki kodun neresine eklemem gerekiyor ? Ne işe yaradıklarını anladım da nereye eklendiklerini anlamadım.

Kodu terminalde çalıştırın.

Return değeri ve paslanan bütün argümanlar default olarak int.

İşe yaradı! Artık sonuç:
Hello World!
0
print(hello) vardı 0 ı yazdıran o onu kaldırırsam Hello World! kalıcak geriye.

Konu çok güzel.

Satır satır katılımcıları okudum.

Sonra neden ben de iki link paylaşmayayım ki dedim.

mesela ben ctypes nasıl çalışıyor diye merak etsem şöyle yapardım.

Python kaynak koduna bir bakayım sonuçta açık kaynak değil mi?

Ne gerek var efsanelere neyse içine bakıp kendim göreyim dedim…

GitHub - python/cpython: The Python programming language

Adamlar yapmış…

Sonra ctype ı merak ettim…

Nerededir diye baktım lib altında…

cpython/init.py at main · python/cpython · GitHub

Bir kaç klasör var ama en can alıcılarından biri yukarıdaki link.

Kodu kurcalarken

cpython/wintypes.py at main · python/cpython · GitHub

Tip çevrimlerine de bakmadan geçmedim.

Tabi bu arada init içinde:

cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)

if _os.name == "nt":
    pythonapi = PyDLL("python dll", None, _sys.dllhandle)
elif _sys.platform == "cygwin":
    pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
else:
    pythonapi = PyDLL(None)

dll dosyalarına nasıl davrandığını da görme şansım oldu.

Şimdi gelelim işin en başına.

Yukarıdakilerin hiç biri python’ın marifeti değil.

Windows’un marifeti.

Windows gençlik yıllarında OLE (object linking and embeding), COM gibi teknolojiler geliştirdi.

Burada amaç, herhangi bir derlenmiş program parçasına başka programlardan erişim sağlamak ve böyleyece bazı nesneleri ortak kullanarak hem programlar arası iletişimi artırmak hem de bellekten tasarruf sağlamaktı.

Mesela dll içinde duran ve bazı davranışlar sergileyen bir buton nesnesini, o dönemler, hem c, hem visualbasic, hemde delphi gibi üçüncü parti dil ve yazılımlar bu yapı sayesinde paylaşabiliyordu.

Ki hala öyle.

Yani COM tabanlı bir nesne oluşturup, com template ile istediğin programda kullanabilirsin.

The Component Object Model - Win32 apps | Microsoft Docs

Bu com modeli sana componetlerini başka diller ve programlarla paylaşma ve yazdığın bir objeyi derledikten sonra istediğin kadar programdan çağırma ve farklı dillerde kullanmayı sağlar.

Teknolojinin reklamını yapmayacağım, çok da microsoft sever birisi değilim zaten.

Yine windows işletim sisteminin bazı marifetleri, bazı windows çağrılarını doğrudan yapmaya izin vermez.

Güvenlik anlayışı tartışılır ama doğrudan hook apileri çağırmana izin vermez.

Hook, windows un herhangi bir programının herhangi bir mesaj kuyruğuna kanca atmak demektir…

Ne işe yarar, çakma keylogger ları bir kenara koyarsak, keyboardhook ile keyboard olaylarını doğrudan yakalamak, mouse hareketlerini işletim seviyesi takip edebilmek için bir yapıdır.

Böyle anlatılmaz ama sabahın 6 sında benden bu kadar. :slight_smile:

Ve hazin olan şudur, ki bu, api hook işi de dll ler üzerinden yapılmalıdır. Doğrudan yürütülebilir bir process üzerinden hook yapmanıza izin vermez.

Yani dll ler içine nesne (object), kaynak (resource) ve kod gömebileceğiniz, kendiliğinden çalışmayan ama çağrılarak çağrılan programlar üzerinden çalışan enteresan canlılardır.

İşin acı tarafı buraya kadar ki anlattıklarımız, linux ve türevlerini hiç ırgalamaz.

Windows kendi yürütülebilir dosyaları için kendi kurallarını koymuş ve dll ler de bu kuralların bir parçası olarak yaşamına devam etmektedir.

Bir dll oluşturmak ayrı çağırıp çalıştırmak ayrı bir konu.

İkisine de girmek niyetinde değilim aslında

Ama işin sürprizi de aklımda.

Bkz. rundll32.exe

rundll32 | Microsoft Docs

dll dosyaları, aslında program entry pointları olmadığından çalışamayan budanmış exe dosyalarıdır.

Bunlara rundll32.exe ile hayat öpücüğü verebilirsiniz. Rundll32 ile istediğiniz dll dosyasındaki kodu çalıştırabilirsiniz. (istisnalar hariç) yani dll dosylarının çalışması için gerekli exe dosyası rundll32.exe dir.

Garibim python un bunlara yapabilecek veya karışabilecek bir durumu yok.

O sadece, az önce verdiğim windtpes dönüşümü ile windows un istediği veri tiplerini simüle eder, işletim sistemine bu dll leri çalıştırmasını rica eder o da çalıştırır. Ve sonucu python a geri verir.

Çok daha gelişmiş araçlar olsa da

ihtiyar pe explorer sevdiklerimden dir. Maalesef 64 bit desteği yapamadan gittiler ama,

PE Explorer: EXE File Editor, Resource Editor, DLL View Scan Tool, Disassembler. (heaventools.com)

kurup dll ve exe dosyalarını dump ettiğinde, program entry poinlerini, içindeki cdecl olarak tanımlanan fonksiyonları görebilirsin.

Örnek resim de atacaktım ama nasıl becerdiysem elimde birtane 32 bit program görüp de decompile edemedim sabah sabah.

Muhtemelen katılımcılar da bu konuya değinmişlerdir.

Yani yukarıda anlattıklarımın hepsi windows un halt yemesi.

Linux dünyası buna .o dosyasıyla tam olmasa da karşılık vermiş olmakla beraber. Bir yürütülebilir dosyayı linux ile çalıştırmak için uzantısı bile olması gerekmez.

Her neyse oralara girmeyim şimdilik.

Özetle.

Bu işin ana müsebbibi windows. Herhangi bir windows derleyicisi alıp, lib ve include altında bulunan, windows.h dosyalarını incelersen zaten windows tiplerini nerelerde kullanıldığını görebilirsin.

PE formatını da araştırdığında zaten yürütlebilir dosyaları derledikten sonra neden linkere bağladıklarını da anlayabilirsin.

Tabi araştırırsan.

Sonuç en baştaki linklerden kodu incelemen çok yere götür.

Ama windows üzerinden c gibi bir dille bu işi yaparsan daha iyi kavrarsın Python sadece arayüzü verebilir sana.

Kolay gelsin.

2 Beğeni

Soyle diyelim: Fonksiyonun int dondurdugunu, ve pasladigin arguman kadar int parametresi aldigini varsayiyor. Burada otorite fonksiyonun kendisi, ctypes veya baska bir kutuphane fonksiyonun ne alip dondurdugunu sadece tahmin edebilir.

Modulun cogu surada:

Isletim sisteminin marifeti.

Microsoft’un “developer’larin islerini kolaylastiralim ama sadece Microsoft ekosisteminde yasayip Microsoft aletleri kullandiklari surece” teknolojileri… Diger ornekleri icin—aslinda butun diger MS teknolojilerine bakabilirsiniz.

Ne yalan soyliyim, Microsoft vizyonu icinde dahice, ve bilisim tarihinde mutlaka denenmesi gereken fikirlerdi.

*Istedigin Windows programinda. Su aralar olusturdugumuz nesneler baskalarinin bilgisayarinda, VM, container, web aplikasyonu, browser veya ciplak bir *nix altinda kullanilmak isteniyor cogunlukla.

Burada hook mekanizmasinin calisma detaylarina degiliniyor. Bu mekanizmanin dynamic loading (DLL) kullanmasi kaza eseri, programla hook’un ayni address space icinde yasamasi gerektigi icin. (Cunku 16-bit Windows’ta oyleydi.)

Linux’teki (ve aslinda Windows’daki diger) onlarca trace/probe/hook mekanizmasina bakarsan, hemen hic biri boyle calismiyor.

Yaptigi sey LoadLibrary+GetProcAddress+cagridan cok fazlasi degil. Ve (ben de yanlis biliyormusum, ama) sadece ozel programlari calistirmak icin kullanilan bir program, yani bizim DLL’lerle bir alakasi yok.

Terminalde calisabiliyorsan objdump (ve bilumum binutils programi) 'dan iyisine hic denk gelmedim. Zorda kalinca herhangi bir debugger da ayni bilgileri (tek tek bakmak gerekse bile) gosterir.

.o → .obj
.so → .dll

Kesinlikle. Konsept diller arasi iletisim oldugu icin en az 2-3 dille calismak lazim. Cumlenin “Windows uzerinden” kismini ozellikle sildim.

3 Beğeni

Teşekkürler, hepinizin destekleriyle bilgilendirici bir konu haline geldiğini düşünüyorum.

Bunu bende incelemiştim.

Yani aslında her dll çağırdığımızda rundll32.exe yi mi çalıştırıyorduk.

Yani derlediğimiz c koduna main eklemessek hiç bir şeyin çalışmaması gibi mi ? DLL ler de başlangıç için bir nokta (main fonksiyonu) olmadığından hiç bir şey başlamıyor.

İllaki bir video falan bulurum hem kullanımını hem de bahsettiğin entry point ve fonksiyonları görürüm.

Windows derleyicisi ?

Araştırırım tabii.

C yi pek bilmiyorum ama denerim (eğer C# ile de oluyorsa C# bilgim var C# ta denerim)

:heart:

Keşke her (en azından çoğu) işletim sisteminde çalışabilecek şekilde tasarlasalarmış.

Önemli değil, burası öğrenmek için var zaten.

Bildiğim diller ile deneme yapayım o zaman.

Ben tek tek alıntılarayarak cevaplamaya üşeniyorum kusura bakma.

rundll32.exe sadece windows ( aib e göre işletim sisteminin) 'un çağırdığına benzer şekilde dll leri çağırıyor.

Ama bir programı yürütmek demek farklı bir şey, detaylarına ayrıca bakmak istersen uzunca yazarım.

dll ler’in entry point ı yok diyemem.

Bir tane exe dosya benim dijital mikroskopun yazılımı.

Adress of entry point.

Import listesine bakasak.

Bu durumda bu fonksiyonları aşağıdaki şekilde export edebildiğimizi görürüz.

Aynı şekilde bir de dll dosyası ekleyim.

Bunda da bir entry point var.

Yukarı da da export örnekleri var.

Aslında PE dosya formatında önce bir ön DOS programı var. Bu, eğer windows PE yi eski windows sistemlerinde çalıştırmaya çalışınca bu bir DOS programı diyecek kadar bir kod ekler ve her türlü oraya gider.

Arkasından eğer işletim sistemi PE yürütebiliyorsa yeni bir entry point a zıplar.

Yani dll lerinde bir giriş noktası var ama, yürütmek için ikinci bir yürütülecek kod adres tablosu yerine direkt kod tablosu var.

Yani yürütülmesine izin vermez ama bellek üzerinde bu kod parçalarının adreslenerek yürütülmesine olanak sağlar.

Biliyorum, anlatma kabiliyetim yok, ama elimden bu kadarı geliyor.

Aslında dll çağırdığımızda, windows un win.exe, dahil bir çok exe ve dll ve servis bir arada çalışıyor.

İstersen o konuda da uzunca yazarım.

Yani konu çekirdek seviyesi işletim sistemi ve çağrılara dönüşür.

Aslen rundll32.exe bunun bir örneği.

1 Beğeni

Önemli değil.

Olur tabii.

Yani bizim giriş noktası yazmamıza gerek yok zaten yazılmış bir tane var.

Gayet iyi anlatıyorsun.

İstediğiniz konuda yazabilirsiniz yeni bir şeyler öğreniyoruz sonuçta, bana başka konularda da uzunca yazdığınızı hatırlıyorum (sanırım C# ile ilgili bir soruydu) ve epey bilgilendirici oluyor.

run32dll.exe dll leri çağırmak için mecbur değil anladığım kadarıyla.

Linker demiştim. Linker işte bu işe yarıyor. Kaynakları, icon, resim, string gibi, kod ile birleştiriyor.

Dosya başlıklarını hazırlıyor, windows’un istediği PE formatında hepsini bir paket halinde bağlıyor.

Entry point i belirleyip adresini başlığa yazıyor, hatta check sum hesabı yazıp onu da dosyaya yazıyor ki dosya üzerinde oynama olursa check sum hatası versin. Tabi virüs yazarken, zaten check sum ı yeniden hesaplıyorsun, sonra eğer araya kod gireceksen bu entry point i önce kendi virüs koduna oradan da tekrar normal koda atlatıyorsun (jump, jnz vs gibi komutlarla).

Burada adresleri değiştirip istediğin kodu çalıştırabilirsin. Checksum ı da yeniden hesaplatıp kaydedersen. İçindeki virüs imzasını antivirüs tanımıyorsa, dosyada bir tuhaflık olduğunu anlamaz.

Evet rundll32.exe sadece dll nasıl çağırılır denemek istersen diye gündemde.

Aslında onunla da eğer kodun tablosunu biliyorsan, kod çağırıp dönüş alabilirsin.

1 Beğeni

Sanırım DLL i programa ekledikten sonra da DLL den yüklenen fonksiyonların adresleri ile onları çağırabiliyoruz. Entry point te de main yerine başka bir fonksiyonun adresini yazsam o fonksiyon en başta çalışacak.

Aslında öyle değil.

Bir kod yazalım mı?

PE header file okumak için.

Orada zaten çok şey öğrenirsin.

GitHub - erocarrera/pefile: pefile is a Python module to read and work with PE (Portable Executable) files

Şuna benzer bir şey yada bunu da deneyebilirsin.

Bir dll de export table vardır.

Bu export edebileceğin kodların adreslerini gösterir. exe lerde nadiren export table olur.

Yani export edilebilen her fonksiyonun kendisi bir entry point.

2 Beğeni