Bir programı açtığınızda bir İşletim Sistemi kendi makine kodunu enjekte ediyor mu?


32

CPU'ları inceliyorum ve bellekten bir programı nasıl okuduğunu ve talimatlarını yerine getirdiğini biliyorum. Ayrıca bir işletim sisteminin süreçlerdeki programları ayırdığını ve daha sonra her biri arasında aynı anda çalıştığını düşündüğünüz kadar hızlı bir şekilde geçiş yaptığını anlıyorum, ancak aslında her program CPU'da tek başına çalışıyor. Fakat eğer işletim sistemi CPU'da çalışan bir demet kod ise, süreçleri nasıl yönetebilir?

Düşündüm ve düşünebildiğim tek açıklama şuydu: İşletim sistemi harici bellekten RAM'e bir program yüklediğinde, orijinal talimatların ortasına kendi talimatlarını ekler, böylece program çalıştırılır, program İşletim sistemini arayabilir ve bazı şeyler yapabilir. İşletim sisteminin programa ekleyeceği, işlemcinin işletim sistemi koduna geri dönmesine izin verecek bir talimat olduğuna inanıyorum. Ayrıca, işletim sistemi bir program yüklediğinde, bazı yasaklanmış talimatlar olup olmadığını kontrol eder (bellekteki yasak adreslere atlayacaktır) ve sonra ortadan kaldırır.

Ben dürüst müyüm? Ben bir CS öğrencisi değilim, ama aslında bir matematik öğrencisiyim. Mümkünse, bu konuda iyi bir kitap istiyorum, çünkü işletim sisteminin CPU'da çalışan bir demet kod olması durumunda işletim sisteminin bir işlemi nasıl yönetebileceğini açıklayan birini bulamadım ve aynı anda çalışamaz. programın zamanı. Kitaplar sadece işletim sisteminin işleri yönetebileceğini söylüyor, ama şimdi nasıl.


7
Bkz: İçerik bağlamı İşletim Sistemi uygulamaya bir içerik geçişi yapar. Uygulama daha sonra tekrar işletim sistemine bir içerik yapan işletim sistemi servislerini talep edebilir. Uygulama sona erdiğinde içerik tekrar işletim sistemine geçer.
Guy Coder

4
Ayrıca bkz. "Sistem çağrısı".
Raphael


1
Yorumlar ve cevaplar sorunuzu anlayışınıza veya memnuniyetinize cevap vermezse, lütfen yorum olarak daha fazla bilgi isteyin ve ne düşündüğünüzü veya nerede kaybolduğunuzu ya da özellikle daha fazla ayrıntıya ihtiyacınız olduğunu açıklayın.
Guy Coder

2
Bence kesme , çengel , (Kesme bilgisini) donanım zamanlayıcısı (ile zamanlama -handling kanca) ve sayfalama (yasak belleğe üzerinde tespite kısmi yanıt) gereken temel anahtar kelimelerdir. İşletim sisteminin yalnızca gerektiğinde kodunu çalıştırmak için işlemciyle gerçekten yakın çalışması gerekiyor. Bu nedenle CPU gücünün çoğu yönetimi üzerinde değil gerçek hesaplamada kullanılabilir.
Palec

Yanıtlar:


35

Hayır. İşletim sistemi, programın içine yeni kod enjekte eden kodla uğraşmaz. Bunun bir takım dezavantajları olacaktır.

  1. İşletim sistemi değişikliklerini yapan tüm yürütülebilir dosyayı taramak zorunda kalacağı için zaman alıcı olurdu. Normalde, yürütülebilir dosyanın bir kısmı yalnızca gerektiğinde yüklenir. Ayrıca, bir sürü yükü yoldan çıkarmak zorunda olduğunuz için takma pahalıdır.

  2. Durma sorununun kararsızlığı nedeniyle, "İşletim Sistemine geri dönün" talimatlarını nereye yerleştireceğinizi bilmek imkansızdır. Örneğin, kod gibi bir şey içeriyorsa while (true) {i++;}, kesinlikle bu döngünün içine bir kanca eklemeniz gerekir, ancak döngüdeki ( true, burada) koşul keyfi olarak karmaşık olabilir, bu yüzden ne kadar süre boyunca döneceğine karar veremezsiniz. Öte yandan, kancaları her döngüye yerleştirmek çok verimsiz olacaktır : örneğin, işletim sistemine geri çekilmek for (i=0; i<3; i++) {j=j+i;}işlemi çok yavaşlatır. Ve aynı sebepten dolayı, onları yalnız bırakmak için kısa döngüler tespit edemezsiniz.

  3. Durma sorununun kararsızlığı nedeniyle, kod enjeksiyonlarının programın anlamını değiştirip değiştirmediğini bilmek imkansızdır. Örneğin, C programınızda işlev işaretçileri kullandığınızı varsayalım. Yeni bir kod enjekte etmek, fonksiyonların yerlerini harekete geçirir; böylece, bir işaretçiyi işaretçiden çağırdığınızda yanlış yere atlarsınız. Programcı bilgisayarlı atlama kullanacak kadar hasta olsaydı, bunlar da başarısız olurdu.

  4. Virüs kodunu değiştireceği ve tüm sağlama hesaplarınızı doldurduğu için herhangi bir anti-virüs sistemiyle neşeli bir cehennem oynayacaktı.

Durma probleminin üstesinden gelip, kodu simüle edip, belirli bir sabit sayıdan daha fazlasını yürüten herhangi bir döngüye kancalar takabilirsiniz. Ancak, bu programın yürütülmesine izin verilmeden önce tüm programın oldukça pahalı bir simülasyonunu gerektirir.

Aslında, kodu enjekte etmek istiyorsanız, derleyici bunu yapmak için doğal bir yer olacaktır. Bu şekilde, sadece bir kez yapmanız gerekecek, ancak yine de yukarıda verilen ikinci ve üçüncü nedenlerden dolayı işe yaramayacaktı. (Ve birileri birlikte oynamayan bir derleyici yazabilir.)

İşletim sisteminin kontrollerden elde etmesinin üç ana yolu vardır.

  1. İşbirlikçi (veya önleyici olmayan) sistemlerde, yieldbir işlemin işletim sistemine kontrol vermek için çağırabileceği bir işlev vardır. Elbette, tek mekanizmanız buysa, güzel davranan işlemlere güveniyorsunuz ve vermeyen bir işlem CPU sonlanıncaya kadar çalışacaktır.

  2. Bu sorunu önlemek için, zamanlayıcı kesmesi kullanılır. CPU'lar, işletim sisteminin CPU'nun uyguladığı tüm farklı türde kesintiler için geri aramaları kaydetmesini sağlar. İşletim sistemi bu mekanizmayı periyodik olarak ateşlenen bir zamanlayıcı kesmesi için bir geri çağrısı kaydetmek için kullanır ve bu kendi kodunu çalıştırmasını sağlar.

  3. Bir işlem bir dosyadan okumaya veya donanımla herhangi bir şekilde etkileşime girmeye çalıştığında, işletim sisteminden bunun için çalışmasını ister. İşletim sisteminden bir işlem yapması istendiğinde, bu işlemi beklemeye almaya ve farklı bir işlem başlatmaya karar verebilir. Bu biraz Machiavellian gibi gelebilir, ancak yapılması gereken doğru şey: disk G / Ç yavaş olduğundan B işleminin çalışmasına izin verirken, A işlemi metalin eğrilen topaklarının doğru yere gitmesini bekler. Ağ G / Ç daha yavaş. Klavye G / Ç buzullu çünkü insanlar gigahertz varlıkları değil.


5
Son noktasında daha fazla geliştirebilir misin? Bu soruyu merak ediyorum ve açıklamanın burada atlandığını hissediyorum. Bana öyle geliyor ki, “İşletim Sisteminin İşlemciyi İşlemden Nasıl Geri Aldığı” sorusu ve cevabınız “İşletim Sisteminin İşleyişi” olduğunu söylüyor. ama nasıl? Sonsuz döngüyü ilk örneğinizde ele alalım: bilgisayarı nasıl dondurmaz?
BiAiB

3
Bazı işletim sistemleri, çoğu işletim sistemi en azından "bağlama"
koduyla uğraşır

1
@BiAiB Buradaki anahtar kelime "kesme" dir. CPU sadece belirli bir talimat akışını işleyen bir şey değildir, aynı zamanda ayrı bir kaynaktan asenkronize olarak da kesilebilir - en önemlisi bizim için G / Ç ve saat kesintileri. Yalnızca çekirdek alanı kodu kesintileri kaldırabildiğinden, Windows istediği zaman çalışan herhangi bir işlemden işi "çalabildiğinden" emin olabilir. Kesme işleyicileri, "CPU'nun kayıtlarını bir yerde depolamak ve buradan geri yüklemek (başka bir iş parçacığı)" dahil olmak üzere istedikleri kodu yürütebilir. Son derece basitleştirilmiş, ancak bu bağlam anahtarı.
Luaan

1
Bu cevaba ekleyerek; 2. ve 3. noktalarda belirtilen çoklu görev tarzı "önleyici çoklu görev" olarak adlandırılır, ad, işletim sisteminin çalışan bir süreci önleme yeteneğini ifade eder. Eski işletim sistemlerinde kooperatif çoklu görev sıklığı kullanıldı; Windows'ta en azından önleyici çoklu görev Windows 95'e kadar kullanılmıyordu. Bugün hala kullanımda olan ve yalnızca gerçek zamanlı işbirlikli çoklu görev davranışı için Windows 3.1 kullanan en az bir endüstriyel kontrol sistemi okudum.
Jason C,

3
@ BiAiB Aslında, yanılıyorsunuz. Masaüstü CPU'ları, i486'dan bu yana sıralı ve eşzamanlı olarak kod çalıştırmaz. Bununla birlikte, eski CPU'larda bile hala senkronize olmayan girişler vardı - kesintiler. CPU'nun üzerindeki bir pin gibi bir donanım kesme isteği (IRQ) hayal edin - ne zaman 1olursa olsun, CPU ne yapıyorsa durur ve kesmeyi işlemeye başlar (temelde "durumu koru ve bellekteki bir adrese atla" anlamına gelir). Kesinti işleme kendisi x86ya da ne olursa olsun kodu, kelimenin tam anlamıyla kablolu. Atladıktan sonra (herhangi bir) x86kodu tekrar çalıştırır . İplikler çok daha yüksek bir soyutlamadır.
Luaan

12

David Richerby'nin cevabı iyi bir cevap olsa da, modern işletim sistemlerinin mevcut programları nasıl durdurduğu konusunda bir sır veriyor. Cevabım, masaüstü ve dizüstü bilgisayarlarda yaygın olarak kullanılan tek x86 veya x86_64 mimarisi için doğru olmalı. Diğer mimariler de bunu başarmak için benzer yöntemlere sahip olmalıdır.

İşletim sistemi başlatıldığında, bir kesme tablosu kurar. Tablonun her girişi işletim sisteminin içindeki bir kod parçasına işaret eder. CPU tarafından kontrol edilen kesintiler olduğunda, bu tabloya bakar ve kodu çağırır. Sıfıra bölme, geçersiz kod ve bazı işletim sistemi tanımlı olanlar gibi çeşitli kesintiler vardır.

Bu, kullanıcı işleminin, diske okumak / yazmak ya da işletim sistemi çekirdeğinin denetlediği başka bir şey gibi, çekirdekle nasıl konuştuğunu belirtir. Bir işletim sistemi ayrıca bittiğinde kesmeyi çağıran bir zamanlayıcı ayarlayacaktır, böylece çalışan kod zorla kullanıcı programından işletim sistemi çekirdeğine değiştirilir ve çekirdek çalıştırmak için diğer programları sıraya sokmak gibi başka şeyler yapabilir.

Bellekten, bu gerçekleştiğinde işletim sistemi çekirdeği kodun bulunduğu yeri kaydetmeli ve çekirdek ne gerekiyorsa yapmayı tamamladığında programın önceki durumuna geri dönecektir. Böylece program kesintiye uğradığını bile bilmiyor.

İşlem kesme tablosunu iki nedenden ötürü değiştiremez, ilki korumalı bir ortamda çalışıyor olmasıdır, bu nedenle belirli korumalı montaj kodunu çağırmaya çalışırsa cpu başka bir kesmeyi tetikler. İkinci sebep ise sanal hafıza. Kesme tablosunun konumu gerçek bellekte 0x0 ile 0x3FF arasındadır, ancak kullanıcı bu konumlarla genellikle eşlenmez ve eşlenmemiş belleği okumaya çalışmak başka bir kesmeyi tetikler, böylece korumalı işlev ve gerçek RAM'e yazma yeteneği olmaz , kullanıcı işlemi değiştiremez.


4
Kesmeler işletim sistemi tarafından tanımlanmadı, donanım tarafından verildi. Ve çoğu mevcut mimaride işletim sistemini çağırmak için özel talimatlar var. i386 bunun için bir (oluşturulan yazılım) kesmesi kullandı, ancak halefleri üzerinde artık böyle bir şey yapılmadı.
von

2
Kesintilerin işlemci tarafından tanımlandığını biliyorum, ancak çekirdek işaretçileri ayarlar. Muhtemelen kötü bir şekilde açıkladım. Ayrıca linux’un int 9’u çekirdekle konuşmak için hala kullandığını düşünmüştüm, ancak şimdi daha iyi yollar olabilir.
Programmdude

Önleyici zamanlayıcıların zamanlayıcı kesintileri tarafından yönlendirildiği fikri doğru olsa da, bu oldukça yanıltıcı bir cevaptır. İlk olarak, zamanlayıcının donanımda olduğuna dikkat etmek önemlidir. Ayrıca "kaydet ... geri yükle" işlemine bağlam anahtarı denir ve diğer şeylerin yanı sıra tüm CPU kayıtlarının (komut göstergesini içeren) kaydedilmesini içerir. Ayrıca, işlemler yapabilirsiniz kesme tabloya bir işaretçi yazılabilir kayıt saklanır - etkin bir kesme tabloları değiştirmek, bu da sanal bellek tanımlar ve 286 yana yaklaşık edilmiş olan "korumalı mod" denir.
Jason C,

(Ayrıca gerçek mod kesme tablosu bile yer değiştirebilir hale geldi - 8086'dan beri ilk hafıza sayfasına kilitlenmedi.)
Jason C

1
Bu cevap kritik bir detayı kaçırıyor. Bir kesinti başladığında, CPU doğrudan çekirdeğe geçmez. Bunun yerine, önce varolan kayıtları kaydeder, ardından başka bir yığına geçer ve yalnızca o zaman çekirdek çağrılır. Çekirdeği rastgele bir programdan rastgele bir yığınla çağırmak oldukça kötü bir fikir olabilir. Ayrıca, son kısım yanıltıcıdır. Eşlenmemiş belleği okumak için "denemeyi" kesmezsiniz; bu sadece imkansız. Sanal adreslerden okudunuz ve eşlenmemiş bellekte sadece sanal adres yok.
MSalters

5

İşletim sistemi çekirdeği, işlemin içine kod enjekte etmek yerine CPU saat kesme işleyicisinden dolayı çalışan işlemden tekrar kontrol alır.

Nasıl çalıştıkları ve işletim sistemi çekirdeklerinin bunları nasıl kullandığı ve farklı özellikleri nasıl uyguladıkları hakkında daha fazla açıklama almak için kesintileri okumalısınız .


Sadece saat kesintisi değil: herhangi bir kesinti. Ve ayrıca mod değiştirme talimatları.
Gilles 'SO- kötülük yapmayı bırak'

3

Orada ise : tarif ne benzer bir yöntem işbirlikçi çoklu görev . İşletim sistemi talimatlar eklemiyor, ancak her program başka bir işbirlikli işlemden birini çalıştırmayı seçebilecek işletim sistemi işlevlerini çağırmak için yazılmalıdır. Bunun sizin tarif ettiğiniz dezavantajları var: bir program çökmesi tüm sistemi ele alıyor. 3.0'a kadar ve 3.0 dahil Windows böyle çalıştı; 3.0 "korumalı modda" ve üstü değildi.

Önleyici çoklu görev (bugünlerde normal olan tür) harici bir kesinti kaynağına dayanır. Kesmeler normal kontrol akışını geçersiz kılar ve genellikle kayıtları bir yerden kurtarır, böylece CPU başka bir şey yapabilir ve ardından programı şeffaf bir şekilde devam ettirir. Tabii ki, işletim sistemi "burada kesintileri bıraktığınızda devam eder" kaydını değiştirebilir, bu yüzden farklı bir süreç içinde devam eder.

(Bazı sistemler yapmak "Thunking" olarak adlandırılan programı yüküne sınırlı bir şekilde, yeniden yazma yönergeleri ve Transmeta işlemci dinamik kendi talimat setine yeniden derlenmesi)


AFAICR 3.1 de kooperatifti. Win95, önleyici çoklu görevlerin yapıldığı yerdeydi. Korumalı mod, esas olarak adres alanının yalıtılmasını sağladı (bu, kararlılığı geliştirir, ancak büyük ölçüde alakasız nedenlerle).
cHao

Thunking, uygulamaya tekrar kod yazmıyor veya kod yerleştirmiyor. Değiştirilen yükleyici, işletim sistemine dayanmaktadır ve uygulamanın bir ürünü değildir. JIT derleyicileri kullanmak gibi derlenen yorumlayıcı diller kodu değiştirmez veya koda herhangi bir şey enjekte etmez. Kaynak kodu çalıştırılabilir hale çevirir. Yine, bu bir uygulamaya kod enjekte etmekle aynı değildir.
Dave Gordon

Transmeta, x86 çalıştırılabilir kodunu yorumlayıcı bir dil değil kaynağı olarak aldı. Ve kod sırasında bir olgu düşündüm olduğu bir ayıklayıcı altında çalışan: enjekte. X86 sistemleri genellikle, hata ayıklayıcısına hapseden "INT 03" ile kesme noktasındaki komutun üzerine yazar. Devam ettirildiğinde orijinal opcode yeniden kurulur.
pjc50

Hata ayıklama neredeyse hiç kimse bir uygulamayı nasıl çalıştığını; Uygulamanın geliştiricisinin ötesinde. Bu yüzden OP'ye gerçekten yardım ettiğini sanmıyorum.
Dave Gordon

3

Çoklu görev, kod enjeksiyonu gibi bir şey gerektirmez. Windows gibi bir işletim sisteminde, bir donanım zamanlayıcısı tarafından tetiklenen bir donanım kesintisine dayanan, zamanlayıcı adı verilen bir işletim sistemi kodu bileşeni vardır. Bu, işletim sistemi tarafından farklı programlar ve kendisi arasında geçiş yapmak için kullanılır ve bu, hepsinin aynı anda gerçekleşmesini algıladığımız gibi görünmesini sağlar.

Temel olarak, işletim sistemi donanım zamanlayıcısını her sıklıkta ... belki de saniyede 100 kez çalışacak şekilde programlar. Zamanlayıcı söndüğünde, bir donanım kesintisi oluşturur - CPU'ya ne yaptığını durdurmasını, yığındaki durumunu kaydetmesini, modunu daha ayrıcalıklı bir şeyle değiştirmesini ve özel olarak belirlenmiş bir şekilde bulacağı kodu çalıştırmasını söyleyen bir sinyal hafızaya yerleştirin. Bu kod, daha sonra ne yapılması gerektiğine karar veren zamanlayıcının bir parçası olur. Başka bir işleme devam etmek olabilir, bu durumda “bağlam anahtarı” olarak bilinen şeyi yapmak zorunda kalacaktır - mevcut durumunun tamamını (sanal bellek tabloları dahil) diğer işlemle değiştirir. Bir sürece geri dönerken, bu sürecin içeriğinin tamamını geri yüklemesi gerekir,

Bellekteki "özel olarak belirlenmiş" yer işletim sistemi dışında hiçbir şey tarafından bilinmek zorunda değildir. Uygulamalar değişebilir, ancak bunun temel amacı, CPU'nun bir tablo araması yaparak çeşitli kesintilere cevap vermesidir; tablonun konumu hafızanın belirli bir yerinde (CPU’nun donanım tasarımı tarafından belirlenir), tablonun içeriği işletim sistemi tarafından ayarlanır (genellikle önyükleme zamanında) ve kesmenin "türü" hangi girişi belirler Tabloda "kesme servis rutini" olarak kullanılacaktır.

Bunların hiçbiri "kod enjeksiyonunu" içermez ... işletim sisteminin içerdiği, CPU'nun donanım özellikleri ve destekleyici devresiyle birlikte çalışan koda dayanmaz.


2

Açıkladığın şeye en yakın gerçek dünya örneği VMware tarafından kullanılan tekniklerden biri, ikili çeviri kullanarak tam sanallaştırma .

VMware, aynı donanım üzerinde işletim sistemlerini aynı anda yürüten bir veya daha fazla altında bir katman görevi görür.

Yürütülen talimatların çoğu (örneğin sıradan uygulamalarda) donanım kullanılarak sanallaştırılabilir, ancak bir işletim sistemi çekirdeğinin kendisi sanallaştırılamayan talimatlardan yararlanır, çünkü tahmin edilen işletim sisteminin makine kodu değiştirilmemişse çalıştırılır " "VMware ana bilgisayarının kontrolünün". Örneğin, bir misafir işletim sisteminin en ayrıcalıklı koruma halkasında çalıştırması ve kesme masasını kurması gerekir. Bunu yapmasına izin verilirse, VMware donanımın kontrolünü kaybederdi.

VMware, bu kodu çalıştırmadan önce OS kodunda yeniden yazar ve bunları, istenen efekti simüle eden VMware koduna atlar.

Yani bu teknik, tarif ettiğinize bir nebze benzer.


2

Bir işletim sisteminin bir programa "kod enjekte edebileceği" çeşitli durumlar vardır. Apple Macintosh sisteminin 68000 tabanlı sürümleri, tüm bölüm giriş noktalarının bir tablosunu oluşturur (statik global değişkenlerin hemen önünde bulunan IIRC). Bir program başladığında, tablodaki her giriş bölüm numarası tarafından takip edilen bir tuzak komutundan oluşur ve bölüme dengelenir. Tuzak çalıştırılırsa, sistem hangi kesimin ve ofsetin gerekli olduğunu görmek için tuzak komutundan sonraki kelimelere bakar, kesimi (eğer değilse) yükleyin, kesimin başlangıç ​​adresini ofsete ekleyin ve sonra yeni hesaplanan adrese bir atlama ile tuzağı değiştirin.

Eski PC yazılımlarında, teknik olarak "İşletim Sistemi" tarafından yapılmamasına rağmen, kodun ortak işlemci yönergeleri yerine tuzak talimatlarıyla oluşturulması yaygındı. Hiçbir matematik işlemcisi kurulmamışsa, tuzak tutucu onu taklit eder. Bir işlemcinin kurulu olması durumunda, ilk kez bir tuzak alındığında, işleyici tuzak talimatını bir yardımcı işlem talimatıyla değiştirecektir; Aynı kodun gelecekteki uygulamaları işlemcinin talimatını doğrudan kullanacaktır.


FP yöntemi, x86 işlemcilerin aksine hala FP'siz değişkenleri olan ARM işlemcilerde halen kullanılmaktadır. Ancak çoğu ARM kullanımının özel cihazlarda olması nadirdir. Bu ortamlarda, genellikle CPU'nun FP özelliklerine sahip olup olmadığı bilinmektedir.
MSalters

Bu davaların hiçbirinde işletim sistemi uygulamaya kod girmedi. İşletim sisteminin kod enjekte etmesi için, yazılım satıcısının, almadığı uygulamayı "değiştirmek" için bir lisansa ihtiyacı olacaktır. İşletim sistemi kodunu DOKUNMAYIN.
Dave Gordon

@DaveGordon Sıkışan talimatların, uygulamaya enjekte eden OS kodu olduğu söylenebilir.
Gilles 'SO- kötülük' dur

@ MSalters Sıkışan talimatlar sanal makinelerde yaygın olarak gerçekleşir.
Gilles 'SO- kötülük' dur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.