Soru:
C ++ uygulamamın tersine mühendislik yapmasını zorlaştırmak için ne tür adımlar atabilirim?
WilliamKF
2013-03-21 16:05:11 UTC
view on stackexchange narkive permalink

Bir C ++ uygulaması oluşturuyorsam ve tersine mühendislik yapmayı zorlaştırmak istiyorsam, bunu yapmak için hangi adımları atabilirim?

  • Derleyici seçimi bunu etkiler mi?
  • Derleyici işaretleri ne olacak, muhtemelen yüksek bir optimizasyon seviyesi yardımcı olacaktır, peki ya diğer bayraklar?
  • Sembolleri sökmek, hata ayıklama sembolleriyle oluşturulmadan yardımcı olur mu? Statik dizeler gibi dahili verileri şifrelerim?
  • Başka hangi adımları atabilirim?
Bir cevap:
#1
+36
Peter Andersson
2013-03-21 17:24:09 UTC
view on stackexchange narkive permalink

Compiler”

Derleyici seçiminin, kodunuzda tersine mühendislik uygulama zorluğu üzerinde minimum etkisi vardır. En aza indirilecek önemli şeylerin tümü, kodunuzdan bilgi sızıntılarıyla ilgilidir. En azından herhangi bir çalışma zamanı türü bilgisini (RTTI) devre dışı bırakmak istiyorsunuz. Tip bilgilerinin sızması ve sanal makinenin komut setinin basitliği, CLR ve JVM kodunun tersine mühendislik işleminin daha kolay olmasının nedenlerinden biridir. Ayrıca, şaşırtmanın gücünü azaltabilecek koda optimizasyonlar uygulayan bir JIT'e sahipler. Gizleme, temelde optimizasyonun tam tersidir ve ilk olarak bir optimizasyon geçişi uygulanarak birçok şaşırtma çözülür.

Bilgilerin hatalarını ayıklama

Size şunu da tavsiye ederim herhangi bir hata ayıklama bilgisini kapatın, bugün çok önemli herhangi bir bilgiyi sızdırmasa bile yarın bunu yapabilir. Hata ayıklama bilgilerinden bilgi sızıntısı miktarı derleyiciden derleyiciye ve ikili biçimden ikili biçime değişir. Örneğin Microsoft Visual C ++, tüm önemli hata ayıklama bilgilerini harici bir veritabanında, genellikle bir PDB biçiminde tutar. Sızdırabileceğiniz en fazla şey, yazılımınızı oluştururken kullandığınız yoldur.

Dizeler

Dizeler söz konusu olduğunda, gerekirse bunları kesinlikle şifrelemelisiniz. hiç. Hata izleme ve hata günlüğü için olanları sayısal numaralandırmalarla değiştirmeyi hedeflerim. İkili dosyanızda şu anda neler olup bittiğine dair her türlü bilgiyi açığa çıkaran dizelerin mevcut olmaması gerekir. Dizeleri şifrelerseniz, şifreleri çözülecektir. Bunlardan mümkün olduğunca kaçınmaya çalışın.

Sistem API'leri

Bir başka güçlü bilgi sızıntısı kaynağı, sistem API'lerinin içe aktarılmasıdır. İmzası bilinen herhangi bir içe aktarılan işlevin iyi gizlendiğinden ve otomatik analiz kullanılarak bulunamayacağından emin olmak istersiniz. Dolayısıyla, LoadLibrary / GetProcAddress gibi bir şeyden bir dizi işlev işaretçisi söz konusu olamaz. İçe aktarılan işlevlere yönelik tüm çağrıların tek yönlü bir işlevden geçmesi ve karmaşık bir bloğun içine yerleştirilmesi gerekir.

Standart çalışma zamanı kitaplıkları

Çok şey var Dikkate almayı unutan insanların oranı, C ++ derleyicinizin çalışma zamanı gibi standart kitaplıklar tarafından sızdırılan bilgilerdir. Tamamen kullanmaktan kaçınırdım. Bunun nedeni, çoğu deneyimli tersine mühendislerin birçok standart kitaplık için hazırlanmış imzaları olmasıdır.

Gizleme

Ayrıca herhangi bir kritik kodu da bir şekilde ele almalısınız ağır gizleme. Şu anda daha ağır ve daha ucuz gizleme yöntemlerinden bazıları CodeVirtualizer / Themida ve VMProtect. Yine de bu paketlerin çok sayıda kusuru olduğunu unutmayın. Bazen kodunuzu orijinalinin eşdeğeri olmayan ve istikrarsızlığa yol açabilecek bir şeye dönüştüreceklerdir. Ayrıca gizlenmiş kodu önemli ölçüde yavaşlatırlar. 10000 kat daha yavaş bir faktör nadir değildir. Ayrıca anti-virüs yazılımıyla daha fazla yanlış pozitif tetikleme sorunu da var. Yazılımınızı saygın bir sertifika yetkilisi kullanarak imzalamanızı tavsiye ederim.

İşlevsel blokların ayrılması

Kodun işlevlere ayrılması, bir programa tersine mühendislik yapmayı kolaylaştıran başka bir şeydir. Bu, özellikle işlevler karmaşık hale getirildiğinde geçerlidir, çünkü tersine mühendisin yazılımınız hakkında gerekçelendirebileceği sınırlar oluşturur. Bu şekilde tersine mühendis, programınızı bölme ve yönetme yöntemiyle çözebilir. İdeal olarak, yazılımınızı tek bir etkili blokta, gizlemenin tüm bloğa tek olarak eşit şekilde uygulanmasını istersiniz. Bu yüzden blok sayısını azaltın, satır içi yazmayı çok cömertçe kullanın ve bunları iyi bir gizleme algoritmasına sarın. Derleyici, bloğun tersine mühendislik yapmayı zorlaştıracak bazı ağır optimizasyonları ve yığın sıralamayı kolayca yapabilir.

Çalışma zamanı

Bilgileri gizlediğinizde bu önemlidir. bilgilerin çalışma zamanında da iyi gizlendiğini. Yetkili bir ters mühendis, programınız çalışırken durumunu inceleyecektir. Bu nedenle, yüklendiğinde şifresini çözen statik değişkenlerin kullanılması veya yükleme sırasında tamamen paketten çıkarılmış paketlerin kullanılması, hızlı bir bulmaya yol açacaktır. Yığın üzerinde ne ayırdığınız konusunda dikkatli olun. Tüm yığın işlemleri API çağrıları üzerinden yapılır ve kolayca bir dosyaya kaydedilebilir ve gerekçelendirilebilir. Yığın işlemlerinin ne sıklıkta olduklarından dolayı takip edilmesi genellikle daha zordur. Dinamik analiz statik kadar önemlidir. Her zaman programınızın durumunun ne olduğu ve hangi bilgilerin nerede yattığının farkında olmanız gerekir.

Hata ayıklamayı önleme

Hata ayıklamayı önleme değersizdir. Bunun üzerinde zaman harcamayın. Yazılımınızın kullanımda olup olmadığına bakılmaksızın, sırlarınızın iyice saklandığından emin olmak için zaman harcayın.

Kod segmentini paketleme ve şifreleme

Şifreleme ve paketlemeyi aynı kategori altında gruplayacağım. İkisi de aynı amaca hizmet ediyor ve ikisinin de sorunları aynı. Kodu çalıştırmak için CPU'nun düz metni görmesi gerekir. Yani ikilideki anahtarı sağlamalısınız. Kod bölümlerini şifrelemenin ve paketlemenin uzaktan etkili tek yolu, bunları işlevsel sınırlarda şifrelemek ve deşifre etmek ve yalnızca şifre çözmenin işlev girişi sırasında gerçekleşmesi ve ardından işlevden çıkarken yeniden şifreleme yapılmasıdır. Bu, ikili programınızın çalışırken atılmasına karşı küçük bir engel oluşturacaktır, ancak güçlü bir şaşkınlıkla birleştirilmelidir.

Son olarak

Yazılımınızı bir konuda inceleyin IDA'nın ücretsiz sürümü gibi. Amacınız, tersine mühendisin sabit bir zihinsel temel bulmasının neredeyse imkansız hale gelmesini sağlamaktır. Ne kadar az bilgi sızdırırsanız ve ortam ne kadar çok değişirse, çalışmak o kadar zor olacaktır. Tecrübeli bir tersine mühendis değilseniz, tersine mühendisliği zor bir şey tasarlamak neredeyse imkansızdır.

Bir kopya koruma sistemi tasarlıyorsanız, zihinsel olarak kırılmasına hazırlanın. Arızayla nasıl başa çıkacağınız ve yazılımınızın bir sonraki sürümünün yükseltmeleri desteklemek için yeterli değer katacağından nasıl emin olacağınız konusunda bir planınız olduğundan emin olun. Sisteminizi kırılamayacak sağlam bir zemin üzerine kurun, yukarıda anlattığım şekilde gizli bazı özel algoritmalar kullanarak kendi lisans anahtarlarınızı oluşturmaya başvurmayın. Mesajların değiştirilemezliği için sistemin sağlam bir kriptografik temel üzerine kurulması gerekiyor.

"satır içi yazmayı çok cömertçe kullanın ve bunları iyi bir gizleme algoritmasına sarın" <- sadece Boost'u ekleyin. Güçlendirme + satır içi + LTCG = tekerleklerde cehennem. Bağımsız değişkenleri ve farklı satır içi alt işlevleri iletmek için kullanılan farklı yazmaçlara sahip aynı işlevlerin onlarca kopyası, yirmi çeşit akıllı işaretçi, argh!
Haha, evet, biraz ücretsiz gizleme elde etmek için kesinlikle karmaşık, ağır şablonlu kodlar seçebilirsiniz. Opak yüklemlerle saf bir C ++ gizleme çerçevesi oluşturmak ve doğrusal bir uyumlu oluşturucu kullanarak rastgele sayılar oluşturmak için şablon meta programlamayı kullanmak için yalnızca şablonların kullanımını gösteren / r / re hakkında bir makale yok muydu? En azından birini hatırlıyorum.
"Dolayısıyla, [..] yüklendiğinde şifresini çözen statik değişkenlerin kullanılması hızlı bir bulmaya yol açacaktır". Alternatif nedir?
@Sosukodo Değişkenleri yerel bir önbelleğe koyardım, muhtemelen yığın üzerinde, şifresini çözerim, kullanırdım, sonra belleği sıfırlardım. Ayrıca şifre çözme algoritmasının, kullanımının ve anahtarının tamamen VM tabanlı gizlemeye gömülü olduğundan emin olurdum. Bazı otomatik yöntemlerle tüm değişkenleri bulmanın ve şifresini çözmenin kolay bir yolu olmaması önemlidir. Anahtarın verilere değil sanallaştırılmış koda gömülmesi, bunu çok daha zor hale getirir. Bunu imkansız kılmak elbette çok zor ama tersine mühendisin işini olabildiğince sıkıcı ve sıkıcı hale getirmeye çalışıyoruz.
Katılıyorum - sadece daha iyi bir kilit yapmaya çalışıyoruz. Bahsettiğiniz bu şeyleri tartışan makalelere bağlantı verebilir misiniz?


Bu Soru-Cevap, otomatik olarak İngilizce dilinden çevrilmiştir.Orijinal içerik, dağıtıldığı cc by-sa 3.0 lisansı için teşekkür ettiğimiz stackexchange'ta mevcuttur.
Loading...