Ringkasan singkat tentang apa yang digunakan kompiler Microsoft untuk berbagai bit memori yang tidak dimiliki / tidak diinisialisasi ketika dikompilasi untuk mode debug (dukungan dapat bervariasi menurut versi kompiler):
Value Name Description
------ -------- -------------------------
0xCD Clean Memory Allocated memory via malloc or new but never
written by the application.
0xDD Dead Memory Memory that has been released with delete or free.
It is used to detect writing through dangling pointers.
0xED or Aligned Fence 'No man's land' for aligned allocations. Using a
0xBD different value here than 0xFD allows the runtime
to detect not only writing outside the allocation,
but to also identify mixing alignment-specific
allocation/deallocation routines with the regular
ones.
0xFD Fence Memory Also known as "no mans land." This is used to wrap
the allocated memory (surrounding it with a fence)
and is used to detect indexing arrays out of
bounds or other accesses (especially writes) past
the end (or start) of an allocated block.
0xFD or Buffer slack Used to fill slack space in some memory buffers
0xFE (unused parts of `std::string` or the user buffer
passed to `fread()`). 0xFD is used in VS 2005 (maybe
some prior versions, too), 0xFE is used in VS 2008
and later.
0xCC When the code is compiled with the /GZ option,
uninitialized variables are automatically assigned
to this value (at byte level).
// the following magic values are done by the OS, not the C runtime:
0xAB (Allocated Block?) Memory allocated by LocalAlloc().
0xBAADF00D Bad Food Memory allocated by LocalAlloc() with LMEM_FIXED,but
not yet written to.
0xFEEEFEEE OS fill heap memory, which was marked for usage,
but wasn't allocated by HeapAlloc() or LocalAlloc().
Or that memory just has been freed by HeapFree().
Penafian: tabel ini dari beberapa catatan yang saya miliki - mereka mungkin tidak 100% benar (atau koheren).
Banyak dari nilai-nilai ini didefinisikan dalam vc / crt / src / dbgheap.c:
/*
* The following values are non-zero, constant, odd, large, and atypical
* Non-zero values help find bugs assuming zero filled data.
* Constant values are good, so that memory filling is deterministic
* (to help make bugs reproducible). Of course, it is bad if
* the constant filling of weird values masks a bug.
* Mathematically odd numbers are good for finding bugs assuming a cleared
* lower bit.
* Large numbers (byte values at least) are less typical and are good
* at finding bad addresses.
* Atypical values (i.e. not too often) are good since they typically
* cause early detection in code.
* For the case of no man's land and free blocks, if you store to any
* of these locations, the memory integrity checker will detect it.
*
* _bAlignLandFill has been changed from 0xBD to 0xED, to ensure that
* 4 bytes of that (0xEDEDEDED) would give an inaccessible address under 3gb.
*/
static unsigned char _bNoMansLandFill = 0xFD; /* fill no-man's land with this */
static unsigned char _bAlignLandFill = 0xED; /* fill no-man's land for aligned routines */
static unsigned char _bDeadLandFill = 0xDD; /* fill free objects with this */
static unsigned char _bCleanLandFill = 0xCD; /* fill new objects with this */
Ada juga beberapa kali di mana runtime debug akan mengisi buffer (atau bagian dari buffer) dengan nilai yang diketahui, misalnya, ruang 'kendur' dalam std::string
alokasi atau buffer yang diteruskan fread()
. Kasing tersebut menggunakan nilai yang diberikan nama _SECURECRT_FILL_BUFFER_PATTERN
(didefinisikan dalam crtdefs.h
). Saya tidak yakin kapan tepatnya diperkenalkan, tapi itu di runtime debug oleh setidaknya VS 2005 (VC ++ 8).
Awalnya, nilai yang digunakan untuk mengisi buffer ini adalah 0xFD
- nilai yang sama digunakan untuk tanah tak bertuan. Namun, dalam VS 2008 (VC ++ 9) nilainya diubah menjadi 0xFE
. Saya berasumsi itu karena mungkin ada situasi di mana operasi pengisian akan berjalan melewati akhir buffer, misalnya, jika penelepon meneruskan dalam ukuran buffer yang terlalu besar untuk fread()
. Dalam hal ini, nilainya 0xFD
mungkin tidak memicu deteksi overrun ini karena jika ukuran buffer terlalu besar hanya dengan satu, nilai isian akan sama dengan nilai tanah tak bertuan yang digunakan untuk menginisialisasi kenari itu. Tidak ada perubahan di tanah tak bertuan yang berarti penganiayaan tidak akan diperhatikan.
Jadi nilai isian diubah pada VS 2008 sehingga kasus seperti itu akan mengubah kenari tanah tak bertuan, yang menghasilkan deteksi masalah oleh runtime.
Seperti yang telah dicatat oleh orang lain, salah satu properti kunci dari nilai-nilai ini adalah bahwa jika variabel pointer dengan salah satu dari nilai-nilai ini dide-referensikan, itu akan mengakibatkan pelanggaran akses, karena pada konfigurasi Windows 32-bit standar, alamat mode pengguna tidak akan lebih tinggi dari 0x7fffffff.
Satu properti bagus tentang nilai isian 0xCCCCCCCC adalah dalam x86 assembly, opcode 0xCC adalah int3 opcode, yang merupakan interupsi breakpoint perangkat lunak. Jadi, jika Anda pernah mencoba mengeksekusi kode dalam memori yang tidak diinisialisasi yang telah diisi dengan nilai isian itu, Anda akan segera mencapai breakpoint, dan sistem operasi akan memungkinkan Anda melampirkan debugger (atau mematikan proses).
sumber
int
instruksi, jadi mengeksekusi 0xCD 0xCD akan menghasilkanint CD
, yang juga akan menjebak.VirtualProtect()
ataumprotect()
membuat memori dapat dieksekusi.Ini adalah kompiler dan khusus OS, Visual studio menetapkan berbagai jenis memori ke nilai yang berbeda sehingga dalam debugger Anda dapat dengan mudah melihat apakah Anda telah menyatu lagi ke dalam memori malloced, array tetap atau objek tidak diinisialisasi. Seseorang akan memposting detail sementara saya mencari di Google ...
http://msdn.microsoft.com/en-us/library/974tc9t1.aspx
sumber
Ini bukan OS - melainkan kompiler. Anda dapat memodifikasi perilaku juga - lihat bagian bawah posting ini.
Microsoft Visual Studio menghasilkan (dalam mode Debug) biner yang mengisi memori stack dengan 0xCC. Ini juga menyisipkan ruang antara setiap frame stack untuk mendeteksi buffer overflows. Contoh yang sangat sederhana tentang di mana ini berguna ada di sini (dalam praktiknya Visual Studio akan menemukan masalah ini dan mengeluarkan peringatan):
Jika Visual Studio tidak memprioritaskan variabel ke nilai yang diketahui, maka bug ini berpotensi sulit ditemukan. Dengan variabel yang sudah diinisialisasi (atau lebih tepatnya, memori stack yang sudah diinisialisasi), masalah dapat direproduksi pada setiap proses.
Namun, ada sedikit masalah. Nilai yang digunakan Visual Studio BENAR - apa pun kecuali 0 adalah. Sebenarnya sangat mungkin bahwa ketika Anda menjalankan kode Anda dalam mode Rilis bahwa variabel unitisasi dapat dialokasikan ke sepotong memori stack yang kebetulan mengandung 0, yang berarti Anda dapat memiliki bug variabel unitial yang hanya memanifestasikan dirinya dalam mode Rilis.
Itu mengganggu saya, jadi saya menulis sebuah skrip untuk memodifikasi nilai pra-isi dengan langsung mengedit biner, memungkinkan saya untuk menemukan masalah variabel tidak terinstalasi yang hanya muncul ketika tumpukan berisi nol. Script ini hanya memodifikasi stack pre-fill; Saya tidak pernah bereksperimen dengan heap pre-fill, meskipun itu harus mungkin. Mungkin melibatkan mengedit DLL run-time, mungkin tidak.
sumber
Sebenarnya, ini hampir selalu merupakan fitur dari perpustakaan runtime (seperti perpustakaan C runtime). Runtime biasanya sangat berkorelasi dengan kompiler, tetapi ada beberapa kombinasi yang bisa Anda tukarkan.
Saya percaya pada Windows, tumpukan debug (HeapAlloc, dll.) Juga menggunakan pola isian khusus yang berbeda dari yang berasal dari malloc dan implementasi gratis di perpustakaan runtime debug C. Jadi mungkin juga fitur OS, tetapi sebagian besar waktu, itu hanya perpustakaan runtime bahasa.
Bagian manajemen memori baru dan hapus biasanya diimplementasikan dengan malloc dan gratis, sehingga memori yang dialokasikan dengan baru dan hapus biasanya memiliki fitur yang sama.
Detailnya khusus untuk runtime. Nilai aktual yang digunakan sering dipilih untuk tidak hanya terlihat tidak biasa dan jelas ketika melihat dump hex, tetapi dirancang untuk memiliki properti tertentu yang dapat mengambil keuntungan dari fitur prosesor. Misalnya, nilai ganjil sering digunakan, karena mereka dapat menyebabkan kesalahan pelurusan. Nilai besar digunakan (sebagai lawan 0), karena menyebabkan keterlambatan mengejutkan jika Anda beralih ke penghitung yang tidak diinisialisasi. Pada x86, 0xCC adalah
int 3
instruksi, jadi jika Anda menjalankan memori yang tidak diinisialisasi, itu akan menjebak.Ini sebagian besar tergantung pada pustaka runtime yang Anda gunakan.
Saya mendaftarkan beberapa di atas. Nilai-nilai umumnya dipilih untuk meningkatkan peluang bahwa sesuatu yang tidak biasa terjadi jika Anda melakukan sesuatu dengan bagian memori yang tidak valid: penundaan lama, jebakan, kesalahan penyelarasan, dll. Manajer tumpukan juga terkadang menggunakan nilai pengisian khusus untuk kesenjangan antara alokasi. Jika pola-pola itu pernah berubah, ia tahu ada tulisan buruk (seperti buffer overrun) di suatu tempat.
Menulis Kode Padat (dan mungkin Kode Lengkap ) berbicara tentang hal-hal yang perlu dipertimbangkan ketika memilih pola pengisian. Saya telah menyebutkan beberapa dari mereka di sini, dan artikel Wikipedia tentang Magic Number (pemrograman) juga merangkumnya. Beberapa trik tergantung pada spesifikasi prosesor yang Anda gunakan (seperti apakah itu memerlukan baca dan tulis yang selaras dan nilai apa yang dipetakan ke instruksi yang akan menjebak). Trik lain, seperti menggunakan nilai besar dan nilai tidak biasa yang menonjol di memori dump lebih portabel.
sumber
Artikel ini menjelaskan pola bit memori yang tidak biasa dan berbagai teknik yang dapat Anda gunakan jika Anda menemukan nilai-nilai ini.
sumber
Alasan yang jelas untuk "mengapa" adalah anggaplah Anda memiliki kelas seperti ini:
Dan kemudian Anda instantiate satu
Foo
dan meneleponSomeFunction
, itu akan memberikan pelanggaran akses mencoba membaca0xCDCDCDCD
. Ini berarti Anda lupa menginisialisasi sesuatu. Itulah "bagian mengapa". Jika tidak, maka penunjuk mungkin telah berbaris dengan memori lain, dan akan lebih sulit untuk di-debug. Ini hanya memberi tahu Anda alasan Anda mendapatkan pelanggaran akses. Perhatikan bahwa kasus ini cukup sederhana, tetapi di kelas yang lebih besar mudah untuk melakukan kesalahan itu.AFAIK, ini hanya bekerja pada kompiler Visual Studio ketika dalam mode debug (sebagai lawan melepaskan)
sumber
0x00000000
, yang akan sama bermanfaatnya (atau lebih, sebagai alamat yang buruk). Seperti yang saya tunjukkan dalam komentar lain di halaman ini, alasan sebenarnya untuk0xCD
(dan0xCC
) adalah mereka adalah x86 opcode yang dapat ditafsirkan yang memicu interupsi perangkat lunak, dan ini memungkinkan pemulihan yang baik ke debugger hanya dalam satu jenis kesalahan khusus dan langka. , yaitu, ketika CPU secara keliru mencoba mengeksekusi byte di wilayah non-kode. Selain penggunaan fungsional ini, nilai isian hanyalah petunjuk penasehat, seperti yang Anda perhatikan.Ini untuk dengan mudah melihat bahwa memori telah berubah dari nilai awal awal, umumnya selama debugging tetapi kadang-kadang untuk kode rilis juga, karena Anda dapat melampirkan debugger ke proses saat sedang berjalan.
Ini bukan hanya memori juga, banyak debugger akan mengatur konten register ke nilai sentinel ketika proses dimulai (beberapa versi AIX akan mengatur beberapa register
0xdeadbeef
yang agak lucu).sumber
Kompiler IBM XLC memiliki opsi "initauto" yang akan menetapkan variabel otomatis nilai yang Anda tentukan. Saya menggunakan yang berikut ini untuk build debug saya:
-Wc,'initauto(deadbeef,word)'
Jika saya melihat penyimpanan variabel yang tidak diinisialisasi, itu akan diatur ke 0xdeadbeef
sumber