Tugas Anda adalah menulis kode yang akan bocor setidaknya satu byte memori dalam sesedikit mungkin byte. Memori harus bocor bukan hanya dialokasikan .
Memori yang bocor adalah memori yang dialokasikan oleh program tetapi kehilangan kemampuan untuk mengaksesnya sebelum dapat mengalokasikan memori dengan benar. Untuk sebagian besar bahasa tingkat tinggi, memori ini harus dialokasikan pada heap.
Contoh dalam C ++ adalah program berikut:
int main(){new int;}
Ini membuat sebuah new int
heap tanpa pointer ke sana. Memori ini langsung bocor karena kami tidak dapat mengaksesnya.
Berikut ini ringkasan ringkasan dari Valgrind :
LEAK SUMMARY:
definitely lost: 4 bytes in 1 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 0 bytes in 0 blocks
suppressed: 0 bytes in 0 blocks
Banyak bahasa memiliki debugger memori (seperti Valgrind ) jika Anda bisa, Anda harus menyertakan output dari debugger tersebut untuk mengonfirmasi bahwa Anda telah kehabisan memori.
Tujuannya adalah untuk meminimalkan jumlah byte di sumber Anda.
Jawaban:
Perl (5.22.2), 0 byte
Cobalah online!
Saya tahu akan ada beberapa bahasa di luar sana yang membocorkan memori pada program kosong. Saya mengharapkannya menjadi esolang, tetapi ternyata
perl
memori itu bocor pada program apa pun. (Saya berasumsi bahwa ini disengaja, karena membebaskan memori jika Anda tahu Anda akan keluar bagaimanapun juga hanya membuang-buang waktu; dengan demikian, rekomendasi umum saat ini adalah hanya membocorkan memori yang tersisa setelah Anda berada dalam rutinitas keluar program Anda .)Verifikasi
sumber
perl --version
mesin saya , meskipun tidak pernah bisa menjalankan program apa pun, sama sekali.C,
48 3122 bytePeringatan: Jangan jalankan ini terlalu sering.
Terima kasih kepada Dennis untuk banyak bantuan / ide!
Ini selangkah lebih maju.
shmget
mengalokasikan memori bersama yang tidak dialokasikan saat program berakhir. Ia menggunakan kunci untuk mengidentifikasi memori, jadi kami menggunakan int yang tidak diinisialisasi. Ini adalah perilaku yang secara teknis tidak terdefinisi, tetapi secara praktis itu berarti bahwa kami menggunakan nilai yang tepat di atas tumpukan ketika ini disebut. Ini akan ditulis pada waktu berikutnya bahwa apa pun ditambahkan ke tumpukan, jadi kami akan kehilangan kunci.Satu-satunya kasus bahwa ini tidak berhasil adalah jika Anda dapat mengetahui apa yang ada di tumpukan sebelumnya. Untuk tambahan 19 byte, Anda dapat menghindari masalah ini:
Atau, untuk 26 byte:
Tetapi dengan yang ini, memori bocor setelah program keluar. Saat menjalankan program memiliki akses ke memori yang melanggar aturan, tetapi setelah program berakhir kami kehilangan akses ke kunci dan memori masih dialokasikan. Ini memerlukan pengacakan tata letak ruang alamat (ASLR), jika tidak
&k
akan selalu sama. Saat ini ASLR biasanya aktif secara default.Verifikasi:
Anda dapat menggunakan
ipcs -m
untuk melihat apa memori bersama yang ada di sistem Anda. Saya menghapus entri yang sudah ada sebelumnya untuk kejelasan:sumber
Unlambda (
c-refcnt/unlambda
), 1 byteCobalah online!
Ini benar-benar tantangan tentang menemukan juru bahasa yang sudah ada sebelumnya yang bocor memori pada program yang sangat sederhana. Dalam hal ini, saya menggunakan Unlambda. Ada lebih dari satu juru bahasa resmi Unlambda, tetapi
c-refcnt
merupakan salah satu yang paling mudah dibangun, dan memiliki properti yang berguna di sini yang bocor memori ketika sebuah program berjalan dengan sukses. Jadi yang perlu saya berikan di sini adalah program hukum Unlambda yang sesederhana mungkin, sebuah larangan. (Perhatikan bahwa program kosong tidak berfungsi di sini; memori masih dapat dijangkau pada saat penerjemah macet.)Verifikasi
sumber
TI-Basic, 12 byte
"... kebocoran memori adalah tempat Anda menggunakan Goto / Lbl dalam satu lingkaran atau Jika kondisional (apa pun yang memiliki perintah Akhir) untuk melompat keluar dari struktur kontrol sebelum perintah Akhir tercapai ..." (selengkapnya)
sumber
Pause
pada akhirnya? Anda bisa menghemat 2 byte.Python <3.6.5, 23 byte
property.__init__
kebocoran referensi untuk properti tuafget
,fset
,fdel
, dan__doc__
jika Anda menyebutnya pada yang sudah-diinisialisasiproperty
misalnya. Ini adalah bug, akhirnya dilaporkan sebagai bagian dari masalah CPython 31787 dan diperbaiki dalam Python 3.6.5 dan Python 3.7.0 . (Juga, ya,property([])
adalah hal yang dapat Anda lakukan.)sumber
C #, 34 byte
Ini solusi tidak memerlukan Heap. Itu hanya membutuhkan kerja keras yang nyata GC ( Pengumpul Sampah ).
Pada dasarnya itu mengubah GC menjadi musuhnya sendiri.
Penjelasan
Setiap kali destructor dipanggil, ia menciptakan instance baru dari kelas jahat ini selama batas waktu habis dan memberitahu GC untuk hanya membuang objek itu tanpa menunggu destruktor selesai. Pada saat itu ribuan instance baru telah dibuat.
"Kejahatan" ini adalah, semakin keras GC bekerja, semakin banyak ini akan meledak di wajah Anda.
Penafian : GC Anda mungkin lebih pintar dari milik saya. Keadaan lain dalam program dapat menyebabkan GC mengabaikan objek pertama atau destruktornya. Dalam kasus ini, ini tidak akan meledak. Tetapi dalam banyak variasi itu akan terjadi . Menambahkan beberapa byte di sana-sini mungkin memastikan kebocoran untuk setiap keadaan yang memungkinkan. Yah kecuali untuk saklar daya mungkin.
Uji
Berikut ini adalah test suite :
Output setelah 10 menit:
Itu 2 684 476 624 byte. Total
WorkingSet
prosesnya sekitar 4,8 GBJawaban ini telah terinspirasi oleh artikel indah Eric Lippert: Ketika semua yang Anda tahu salah .
sumber
class L{~L(){new L();}}
? AFAIKfor(;;)
satu - satunya membuatnya bocor memori lebih cepat, kan?C (gcc) , 15 byte
Verifikasi
sumber
Javascript, 14 byte
Golf
Mendaftarkan handler interval kosong dengan penundaan default, membuang id timer yang dihasilkan (membuatnya tidak mungkin dibatalkan).
Saya telah menggunakan interval non-default, untuk membuat beberapa juta timer, untuk menggambarkan kebocoran, karena menggunakan interval default memakan CPU seperti mad.
sumber
if(window && window.setInterval && typeof window.setInterval === 'function') { window.setInterval(0); }
clearInterval
dengan ID yang bertambah hingga interval Anda hilang. Sebagai contoh:for(let i=0;i<1e5;i++){try{clearInterval(i);}catch(ex){}}
free()
Java, 10 byte
Akhirnya, jawaban kompetitif di Jawa!
Golf
Ini adalah referensi metode (terhadap konstanta string), yang dapat digunakan seperti itu:
String literal
". "
akan secara otomatis ditambahkan ke kumpulan string global yang diinternir , seperti yang dikelola olehjava.lang.String
kelas, dan saat kami segera memangkasnya, referensi untuk itu tidak dapat digunakan kembali lebih lanjut dalam kode (kecuali jika Anda mendeklarasikan string yang sama persis lagi).https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#intern--
Anda bisa mengubahnya dalam kebocoran memori "tingkat produksi", dengan menambahkan string ke dirinya sendiri dan kemudian memanggil metode intern () secara eksplisit, dalam satu lingkaran.
sumber
("." + " ").intern()
akan dilakukan (jika mereka input pengguna atau w / e, jadi kami mengabaikan optimisasi kompiler).simply by guessing it correctly
, tetapi itu tidak berarti bahwa hal seperti kebocoran memori tidak ada.there's probably some way to use reflection to determine the string's contents too
dapatkah kamu menunjukkan ini? (hint, String.intern () diimplementasikan dalam kode asli ).Karat, 52 byte
Mengalokasikan beberapa byte dengan sistem malloc. Ini mengasumsikan bahwa ABI yang salah dapat diterima.
Karat (dalam teori), 38 byteKami mengalokasikan memori pada heap, mengekstrak pointer mentah, dan kemudian mengabaikannya, membocorkannya secara efektif. (
Box::into_raw
lebih pendek dari itustd::mem::forget
).Namun, Rust secara default menggunakan jemalloc, yang valgrind tidak dapat mendeteksi kebocoran . Kita bisa beralih ke pengalokasi sistem tetapi itu menambahkan 50 byte dan membutuhkan malam. Terima kasih banyak untuk keamanan memori.
Output dari program pertama:
sumber
8086 ASM, 3 byte
Contoh ini mengasumsikan bahwa runtime C terhubung di.
ini berkumpul di
e9 XX XX
manaXX XX
alamat relatif dari_malloc
Ini meminta
malloc
untuk mengalokasikan jumlah memori yang tidak dapat diprediksi dan kemudian segera kembali, mengakhiri proses. Pada beberapa sistem operasi seperti DOS, memori mungkin tidak dapat dipulihkan sama sekali sampai sistem di-boot ulang!sumber
Keempat, 6 byte
Golf
Mengalokasikan string kosong dengan
s" "
, meninggalkan alamat dan panjangnya (0) pada stack, kemudian mengalikannya (menghasilkan alamat memori yang hilang).Valgrind
sumber
lanjutkan 45 byte
ini menciptakan goroutine anonim dengan loop tak terbatas di dalamnya. program dapat terus berjalan seperti biasa, karena memulai goroutine adalah sejenis seperti menelurkan thread kecil yang berjalan bersamaan, tetapi program tidak memiliki cara untuk merebut kembali memori yang dialokasikan untuk goroutine. pemulung tidak akan pernah mengumpulkannya karena masih berjalan. beberapa orang menyebut ini 'bocor goroutine'
sumber
C.malloc(8)
, karena Anda perluimport"C"
Java 1.3, 23 byte
Membuat utas tetapi tidak memulainya. Utas terdaftar di kumpulan utas internal, tetapi tidak akan pernah dimulai, jadi tidak pernah berakhir dan karenanya tidak pernah menjadi kandidat untuk GC. Ini adalah objek yang tidak dapat diperbaiki, terjebak dalam Java limbos.
Ini adalah bug di Java hingga 1.3 yang dimasukkan setelah diperbaiki.
Pengujian
Program berikut memastikan untuk mencemari memori dengan objek utas baru dan menunjukkan ruang memori bebas yang menurun. Demi pengujian kebocoran, saya secara intensif membuat GC berjalan.
sumber
Befunge ( jamur ), 1 byte
Ini mungkin tergantung pada platform dan bergantung pada versi (Saya baru menguji dengan versi 1.0.4 di Windows), tetapi secara historis jamur telah menjadi juru bahasa yang sangat bocor. Perintah
$
(drop) seharusnya tidak melakukan apa-apa pada tumpukan kosong, tetapi mengulangi kode ini entah bagaimana berhasil membocorkan banyak memori dengan sangat cepat. Dalam hitungan detik itu akan menghabiskan beberapa pertunjukan dan akan crash dengan kesalahan "kehabisan memori".Perhatikan bahwa itu tidak harus berupa
$
perintah - apa pun bisa dilakukan. Itu tidak akan bekerja dengan file sumber kosong. Harus ada setidaknya satu operasi.sumber
Swift 3, 38 byte
Versi baru:
x
memiliki referensi yang kuat untuk dirinya sendiri, sehingga tidak akan dialokasikan, menyebabkan kebocoran memori.Versi lama:
x
berisi referensi yang kuat untuky
, dan sebaliknya. Dengan demikian, tidak ada yang akan dialokasikan, menyebabkan kebocoran memori.sumber
x
dany
, jadi ini tidak benar-benar terlihat seperti kebocoran kepada saya (kecuali jika Anda menghancurkannya entah bagaimana).do
blok yang akan memperbaiki masalah yang zeppelin angkat bukan?do
akan bekerja juga. Ide bagus!class X{var x: X!};do{let x=X();x.x=x}
Delphi (Object Pascal) - 33 byte
Membuat objek tanpa variabel, program konsol penuh:
Mengaktifkan FastMM4 di proyek akan menunjukkan kebocoran memori:
sumber
C # - 84bytes
Ini mengalokasikan tepat 1 byte memori yang tidak dikelola, dan kemudian kehilangan
IntPtr
, yang saya percaya adalah satu-satunya cara untuk mendapatkan atau membebaskannya. Anda dapat mengujinya dengan memasukkannya dalam satu lingkaran, dan menunggu aplikasi mogok (mungkin ingin menambahkan beberapa nol untuk mempercepatnya).Saya mempertimbangkan
System.IO.File.Create("a");
dan semacamnya, tetapi saya tidak yakin bahwa ini adalah kebocoran memori, karena aplikasi itu sendiri akan mengumpulkan memori, itu adalah OS di bawahnya yang mungkin bocor (karenaClose
atauDispose
tidak dipanggil). Hal-hal akses file juga memerlukan izin sistem file, dan tidak ada yang mau bergantung pada itu. Dan ternyata ini tidak akan bocor, karena tidak ada yang menghentikan finalis dipanggil (yang membebaskan sumber daya yang mendasarinya adalah mungkin), yang kerangka kerjanya termasuk untuk mengurangi kesalahan penilaian semacam ini (sampai tingkat tertentu), dan untuk membingungkan programmer dengan penguncian file yang tampaknya non-deterministik (jika Anda seorang yang sinis). Terima kasih kepada Jon Hanna karena telah meluruskan hal ini.Saya sedikit kecewa karena saya tidak dapat menemukan cara yang lebih pendek. NET. GC berfungsi, saya tidak bisa memikirkan
IDisposables
mscorlib yang pasti akan bocor (dan memang mereka semua tampaknya memiliki finalis, betapa menjengkelkan) , saya tidak mengetahui cara lain untuk mengalokasikan memori yang tidak dikelola (singkat PInvoke ), dan refleksi memastikan apa pun dengan referensi untuk itu (terlepas dari bahasa semantik (misalnya anggota pribadi atau kelas tanpa pengakses)) dapat ditemukan.sumber
System.IO.File.Create("a")
tidak akan membocorkan apa pun, tetapiGC.SuppressFinalize(System.IO.File.Create("a"))
akan seperti itu secara eksplisit diminta untuk tidak menjalankan finaliser yangFileStream
diproduksi.<!-- language: lang-c# -->
Terima kasih untuk ini & jawaban yang bagus! (Ini C # jadi saya menyukainya)Faktor , 13 byte
Factor memiliki manajemen memori otomatis, tetapi juga memberikan akses ke beberapa fungsi libc:
Secara manual mengalokasikan 1 byte memori, mengembalikan alamatnya, dan menjatuhkannya.
malloc
sebenarnya mendaftar salinan untuk melacak kebocoran memori dan membebaskan ganda, tetapi mengidentifikasi yang Anda bocor bukanlah tugas yang mudah.Jika Anda lebih suka memastikan Anda benar-benar kehilangan referensi itu:
Menguji kebocoran dengan
[ 1 malloc drop ] leaks.
mengatakan:Menguji kebocoran dengan
[ 1 (malloc) drop ] leaks.
mengatakan:Oh tidak! Faktor yang buruk, ia menderita Alzheimer sekarang! D:
sumber
Otomatis , 39 byte
Mengalokasikan satu byte dari heap. Karena pegangan yang dikembalikan oleh
_MemGlobalAlloc
dibuang, tidak ada cara untuk secara eksplisit membebaskan alokasi itu.sumber
Gangguan Umum (hanya SBCL),
2826 byteAnda menjalankannya seperti ini
sbcl --eval 'sb-alien::(make-alien int)'
:; tidak ada yang dicetak atau dikembalikan, tetapi alokasi memori terjadi. Jika saya membungkus formulir di dalam a(print ...)
, pointer ditampilkan di REPL.package::(form)
adalah notasi khusus dalam SBCL untuk sementara mengikat paket saat ini saat membaca formulir. Ini digunakan di sini untuk menghindari awalan baik denganmake-alien
maupunint
dengansb-alien
. Saya pikir akan curang untuk menganggap paket saat ini diatur untuk yang satu ini, karena itu tidak terjadi pada saat startup.make-alien
mengalokasikan memori untuk jenis yang diberikan dan ukuran opsional (menggunakan malloc).Saat menjalankan ini di REPL, tambahkan
0
setelah alokasi sehingga REPL tidak mengembalikan pointer, tetapi nilai itu sebagai gantinya. Jika tidak, bahwa tidak ada akan menjadi kebocoran nyata karena REPL ingat yang terakhir tiga nilai kembali (Lihat*
,**
,***
) dan kami masih bisa memiliki kesempatan untuk membebaskan memori yang dialokasikan.2 byte dihapus berkat PrzemysławP, terima kasih!
sumber
1
(atau2
,3
, dll) bukannya()
sehingga Anda mengembalikan nilai1
? Ini akan menghemat 1 byte. Juga apakah jawaban ini hanya REPL? Mungkin jika Anda memuat kode denganload
Anda tidak dapat memasukkan()
atau apa pun pada akhirnya, karena itu tidak akan dapat diakses?eval
dan ini berfungsi seperti yang Anda katakan. Terima kasih banyak!C ++, 16 byte
Saya tidak punya valgrind untuk memeriksanya, tetapi cukup yakin seharusnya.Kalau tidak, saya akan mencoba:Hasil Valgrind
(Itu memang bocor)
sumber
g++ 4.3.2
(bukan yang terbaru) dan mengkompilasi dengan baik. Tidak ada tipe pengembalianint
secara default saya pikir. Dengan-Wall
saya punya peringatan:plop.cpp:1: warning: ISO C++ forbids declaration of 'main' with no type
[]{new int;}
sebagai fungsi C ++ (tantangannya tidak menentukan keseluruhan program).Java (OpenJDK 9) ,
322220 byteCobalah online!
Ini adalah kebocoran Memori lain yang tidak menggunakan String Cache. Mengalokasikan setengah dari RAM Anda dan Anda tidak dapat melakukan apa-apa dengannya.
Terima kasih kepada zeppelin untuk menyimpan semua byte
sumber
Unsafe
instance dari variabel statis di dalamnya, seperti itu:import sun.misc.*;class M{static void main(String[]a)throws Exception{java.lang.reflect.Field f=Unsafe.class.getDeclaredField("theUnsafe");f.setAccessible(1<2);((Unsafe)f.get(1)).allocateMemory(1);}}
public static void main
dengan initializer statisstatic{try{}catch(Exception e){}}
(yang mungkin sedikit lebih sulit untuk diluncurkan tetapi tetap valid dan dapat dikompilasi).a
alih-alihargs
, dan hapus publik. tio.run/nexus/…c, 9 byte
Bukti:
sumber
gcc
aku s. Ini juga harus bekerja dengan program kosong. Cobagcc src.c && valgrind ./a.out
, yang seharusnya menghasilkan hasil yang bersih.C #, 109 byte
Kami menemukan ide di balik kebocoran ini dalam kode produksi dan meneliti mengarah pada artikel ini. Masalah utama adalah dalam kutipan panjang dari artikel ini (baca untuk info lebih lanjut):
Berjalan dari kompiler di Visual Studio 2015 dan menggunakan Jendela Alat Diagnostik menunjukkan hasil berikut setelah sekitar 38 detik. Perhatikan bahwa memori Proses terus naik dan Garbage Collector (GC) terus berjalan tetapi tidak dapat mengumpulkan apa pun.
sumber
C 30 byte
Hasil Valgrind:
sumber
main(){malloc(1);}
?Dart, 76 byte
Agak seperti jawaban JavaScript. Saat Anda memanggil
.listen
objek stream Dart, Anda diberikan kembali StreamSubscription, yang memungkinkan Anda untuk memutuskan koneksi dari stream. Namun, jika Anda membuangnya, Anda tidak akan pernah dapat berhenti berlangganan dari sungai, menyebabkan kebocoran. Satu-satunya cara kebocoran dapat diperbaiki adalah jika Stream itu sendiri dikumpulkan, tetapi masih dirujuk secara internal oleh kombo StreamController + Timer.Sayangnya, Dart terlalu pintar untuk hal-hal lain yang pernah saya coba.
()async=>await new Completer().future
tidak bekerja karena menggunakan menunggu sama dengan melakukannew Completer().future.then(<continuation>)
, yang memungkinkan penutupan itu sendiri dihancurkan ketika Completer kedua tidak direferensikan (Completer memegang referensi ke Masa Depan dari.future
, Future memegang referensi ke kelanjutan sebagai penutupan).Juga, Isolat (alias utas) dibersihkan oleh GC, jadi menelurkan diri Anda di utas baru dan segera menghentikannya (
import'dart:isolate';main(_)=>Isolate.spawn(main,0,paused:true);
) tidak berfungsi. Bahkan memijahkan Isolate dengan infinite loop (import'dart:isolate';f(_){while(true){print('x');}}main()=>Isolate.spawn(f,0);
) membunuh Isolate dan keluar dari program.Baiklah.
sumber
Cepat, 12 byte
Penjelasan:
Ini adalah kebocoran memori de-facto yang dapat terjadi dalam bahasa apa pun, terlepas dari apakah bahasa tersebut menggunakan manajemen manual memori, penghitungan referensi otomatis (ARC, seperti Swift), atau bahkan pengumpulan sampah yang menyapu.
[3,5]
hanyalah sebuah array literal. Array ini mengalokasikan cukup memori untuk setidaknya 2 elemen ini. The3
dan5
hanya sewenang-wenang.Berlangganan (mengindeks) dan
Array<T>
menghasilkanArraySlice<T>
. AnArraySlice<T>
adalah pandangan ke dalam memori Array tempat ia dibuat.[3,5][0...0]
menghasilkanArraySlice<Int>
, yang nilainya[3]
. Perhatikan bahwa3
dalam irisan ini adalah3
elemen yang sama dengan3
yang asli yangArray
ditunjukkan di atas, bukan salinan.Irisan yang dihasilkan kemudian dapat disimpan ke dalam variabel dan digunakan. Array asli tidak lagi direferensikan, jadi Anda akan berpikir bahwa itu bisa dibatalkan alokasinya. Namun, tidak bisa.
Karena irisan memperlihatkan pandangan ke memori array asalnya, array asli harus tetap hidup selama irisan hidup. Jadi dari
2
memori ukuran elemen-ukuran asli yang dialokasikan, hanya memori ukuran-elemen pertama yang digunakan, dengan yang lain yang diperlukan untuk ada agar tidak mengalokasikan yang pertama. Elemen-ukuran kedua dari memori adalah faktor bocor.Solusi untuk masalah ini adalah tidak menjaga irisan kecil array besar untuk waktu yang lama. Jika Anda perlu mempertahankan konten slice, maka promosikan ke Array, yang akan memicu memori untuk disalin, sehingga menghapus ketergantungan pada memori array asli:
sumber
Solusi 1: C (Mac OS X x86_64), 109 byte
Sumber untuk golf_sol1.c
Program di atas perlu dikompilasi dengan akses eksekusi pada segmen __DATA.
Kemudian untuk menjalankan program jalankan yang berikut:
Hasil:
Sayangnya Valgrind tidak melihat memori yang dialokasikan dari panggilan sistem, jadi saya tidak dapat menunjukkan kebocoran yang terdeteksi dengan baik.
Namun kita dapat melihat vmmap untuk melihat sebagian besar memori yang dialokasikan (MALLOC metadata).
Penjelasan
Jadi saya pikir saya perlu menggambarkan apa yang sebenarnya terjadi di sini, sebelum pindah ke solusi yang ditingkatkan.
Fungsi utama ini adalah menyalahgunakan deklarasi tipe C yang hilang (sehingga default ke int tanpa kita perlu membuang karakter menulisnya), serta bagaimana simbol bekerja. Linker hanya peduli apakah mereka tidak dapat menemukan simbol yang dipanggil
main
untuk dipanggil. Jadi di sini kita membuat array int utama yang kita inisialisasi dengan shellcode kita yang akan dieksekusi. Karena itu, main tidak akan ditambahkan ke segmen __TEXT melainkan segmen __DATA, alasan kami perlu mengkompilasi program dengan segmen __DATA yang dapat dieksekusi.Shellcode yang ditemukan di main adalah sebagai berikut:
Apa yang dilakukan adalah memanggil fungsi syscall untuk mengalokasikan halaman memori (syscall mach_vm_allocate menggunakan internal). RAX harus sama dengan 0x100000a (memberitahu syscall fungsi mana yang kita inginkan), sementara RDI memegang target untuk alokasi (dalam kasus kami kami ingin ini mach_task_self ()), RSI harus memegang alamat untuk menulis pointer ke memori yang baru dibuat (jadi kami hanya mengarahkannya ke bagian pada stack), RDX memegang ukuran alokasi (kami hanya meneruskan dalam RAX atau 0x100000a hanya untuk menghemat byte), R10 memegang bendera (kami menunjukkan itu bisa dialokasikan di mana saja).
Sekarang tidak jelas dari mana RAX dan RDI mendapatkan nilai-nilai mereka. Kami tahu RAX harus 0x100000a, dan RDI harus menjadi nilai mach_task_self () yang dikembalikan. Untungnya mach_task_self () sebenarnya adalah makro untuk variabel (mach_task_self_), yang berada di alamat memori yang sama setiap kali (harus berubah saat reboot). Dalam contoh khusus saya, mach_task_self_ kebetulan berada di 0x00007fff7d578244. Jadi untuk mengurangi instruksi, kami akan meneruskan data ini dari argv. Inilah sebabnya kami menjalankan program dengan ungkapan ini
$(ruby -e 'puts "\xf5\xff\xff\xfe\xff\xff\x44\x82\x57\x7d\xff\x7f"')
untuk argumen pertama. String adalah dua nilai yang digabungkan, di mana nilai RAX (0x100000a) hanya 32 bit dan telah memiliki komplemen seseorang yang diterapkan padanya (jadi tidak ada byte nol; kami hanya BUKAN nilai untuk mendapatkan yang asli), nilai berikutnya adalah RDI (0x00007fff7d578244) yang telah bergeser ke kiri dengan 2 byte sampah tambahan ditambahkan ke akhir (lagi untuk mengecualikan byte nol, kami hanya menggesernya kembali ke kanan untuk mendapatkannya kembali ke aslinya).Setelah syscall, kami menulis ke memori yang baru dialokasikan. Alasannya adalah karena memori yang dialokasikan menggunakan mach_vm_allocate (atau syscall ini) sebenarnya adalah halaman VM, dan tidak secara otomatis dipetakan ke dalam memori. Sebaliknya mereka dicadangkan sampai data dituliskan kepada mereka, dan kemudian halaman-halaman itu dipetakan ke dalam memori. Tidak yakin apakah itu akan memenuhi persyaratan jika itu hanya dicadangkan.
Untuk solusi selanjutnya, kami akan memanfaatkan fakta bahwa shellcode kami tidak memiliki byte nol, sehingga dapat memindahkannya ke luar kode program kami untuk mengurangi ukurannya.
Solusi 2: C (Mac OS X x86_64), 44 byte
Sumber untuk golf_sol2.c
Program di atas perlu dikompilasi dengan akses eksekusi pada segmen __DATA.
Kemudian untuk menjalankan program jalankan yang berikut:
Hasilnya harus sama seperti sebelumnya, karena kami membuat alokasi dengan ukuran yang sama.
Penjelasan
Mengikuti konsep yang sama seperti solusi 1, dengan pengecualian bahwa kami telah memindahkan potongan kode bocor kami di luar program.
Shellcode yang ditemukan di main sekarang adalah sebagai berikut:
Ini pada dasarnya menyalin shellcode yang kami berikan dalam argv untuk menjadi setelah kode ini (jadi setelah itu disalin, itu akan menjalankan shellcode yang dimasukkan). Apa yang menguntungkan kami adalah bahwa segmen __DATA akan berukuran setidaknya satu halaman, jadi meskipun kode kami tidak sebesar itu, kami masih dapat "dengan aman" menulis lebih banyak. Kelemahannya adalah solusi ideal di sini, bahkan tidak perlu salinannya, melainkan hanya akan memanggil dan menjalankan shellcode di argv secara langsung. Namun sayangnya, memori ini tidak memiliki hak eksekusi. Kita dapat mengubah hak memori ini, namun itu membutuhkan lebih banyak kode daripada hanya menyalinnya. Strategi alternatif adalah mengubah hak dari program eksternal (tetapi lebih lanjut tentang itu nanti).
Shellcode yang kami berikan ke argv adalah sebagai berikut:
Ini hampir sama dengan kode kami sebelumnya, hanya perbedaannya adalah kami menyertakan nilai untuk EAX dan RDI secara langsung.
Kemungkinan Solusi 1: C (Mac OS X x86_64), 11 byte
Gagasan memodifikasi program secara eksternal, memberi kita kemungkinan solusi untuk memindahkan leaker ke program eksternal. Di mana program aktual kami (pengiriman) hanyalah program tiruan, dan program leaker akan mengalokasikan sebagian memori dalam program target kami. Sekarang saya tidak yakin apakah ini akan masuk dalam aturan untuk tantangan ini, tetapi tetap membagikannya.
Jadi jika kita menggunakan mach_vm_allocate dalam program eksternal dengan target yang ditetapkan untuk program tantangan kita, itu bisa berarti program tantangan kita hanya perlu menjadi sesuatu seperti:
Di mana shellcode itu hanyalah lompatan pendek ke dirinya sendiri (lompatan / loop tak terbatas), sehingga program tetap terbuka dan kita dapat merujuknya dari program eksternal.
Kemungkinan Solusi 2: C (Mac OS X x86_64), 8 byte
Lucunya ketika saya melihat output valgrind, saya melihat bahwa setidaknya menurut valgrind, memori kebocoran bocor. Jadi secara efektif setiap program membocorkan sejumlah memori. Dengan demikian, kita sebenarnya bisa membuat program yang tidak melakukan apa-apa (hanya keluar), dan itu sebenarnya akan membocorkan memori.
Sumber:
sumber
Bahasa Inggris Polos ,
71705835 byteDihapus 1 byte dengan menghapus garis kosong. Menghapus 12 byte dengan menghilangkan definisi tipe "bogon", dan menggunakan tipe "thing" induk alih-alih subtipe "bogon". Dihapus 23 byte dengan beralih dari program lengkap, menjadi hanya rutin yang bocor memori.
Versi golf:
Versi tidak digabungkan yang merupakan program lengkap, menggunakan definisi subtipe, dan tidak bocor memori:
Jika versi golf "x" dipanggil, itu akan membocorkan memori sebanding dengan berapa kali "x" dipanggil. Dalam versi golf, "Deallocate the thing." akan memperbaiki kebocoran memori.
Bahasa Inggris Biasa memeriksa kebocoran memori secara default. Ketika versi yang bocor memori dijalankan, kotak dialog akan muncul tepat sebelum program dimatikan. Kotak dialog memiliki judul "debug", pesan "1 tetes", dan tombol "OK". Semakin sering fungsi bocor disebut, semakin besar jumlah "tetesan" dalam pesan. Ketika versi yang tidak bocor memori dijalankan, kotak dialog tidak muncul.
Dalam Plain English, "benda" adalah penunjuk ke item dalam daftar yang ditautkan dua kali lipat. "Hal", "untuk memulai", dan "untuk mematikan" didefinisikan dalam modul yang disebut "mie", yang perlu disalin (biasanya sebagai file terpisah) ke dalam setiap proyek. "A", "the", "to", "untuk mengalokasikan memori", dan "untuk menghancurkan" didefinisikan dalam kompiler.
sumber