Apakah buffer overflow mengubah tipe data dari variabel yang ditimpa? [Tutup]

8

Katakanlah saya memiliki array C karakter char buf[15]. Say variable int set_me = 0menyimpan datanya di lokasi memori langsung setelahnya char buf[15]. Jika saya dipenuhi bufdengan string "aaabbbcccdddeee\xef\xbe\xad\xde", apakah set_metipe data akan berubah dari integer ke array karakter?

Darien Springer
sumber
3
Tergantung pada siapa yang menafsirkan data. akhirnya semuanya biner. Jadi cara Anda mengartikannya, itu bisa menjadi nilai integer yang valid atau menyebabkan kesalahan pemeran
Ganesh R.

Jawaban:

33

Tidak.

"Tipe data" dari suatu variabel hanya relevan dalam kode sumber (dan itupun hanya dalam beberapa bahasa). Ini memberitahu kompiler bagaimana memperlakukan variabel.

Tipe data tingkat tinggi ini tidak ada dalam kode yang dikompilasi (asli). Mereka dapat mempengaruhi instruksi apa yang dihasilkan oleh kompiler, tetapi instruksi itu sendiri tidak peduli jika data tersebut mewakili karakter atau angka.


Variabel tidak ada di perangkat keras. Di perangkat keras, Anda memiliki lokasi memori dan instruksi yang beroperasi di sana.

Variabel dapat dilihat sebagai tampilan data di lokasi memori - jika Anda menyipitkan mata dan melihat memori yang sama sedikit berbeda (variabel berbeda dengan tipe berbeda merujuk ke lokasi yang sama), nilai biner yang sama dapat memiliki arti yang berbeda .

Sebagai contoh, byte 0x41 dapat diartikan sebagai karakter yang dikodekan oleh UTF-8 A. Bisa juga diartikan sebagai integer byte tunggal 65. Bisa juga diartikan sebagai satu byte dalam integer multi-byte atau angka floating point, atau satu byte dalam pengkodean karakter multi-byte. Itu bisa berupa bitset 0b1000001. Semua dari byte yang sama di lokasi memori yang sama. Dalam bahasa C, Anda dapat melihat efek ini dengan melakukan casting ke tipe yang berbeda ini.

Ketika Anda memiliki "buffer overflow", Anda melakukan sesuatu di luar batas yang mungkin diharapkan oleh kompiler atau bahasa Anda. Tetapi, sejauh menyangkut perangkat keras 1 , Anda menulis byte (baik tunggal atau ganda) ke lokasi memori. Lokasi memori tidak memiliki "tipe". Bahkan, perangkat keras bahkan tidak tahu bahwa set byte tertentu membuat array atau buffer dalam kode Anda.

Di mana pun Anda selanjutnya mengakses lokasi memori dalam kode Anda, instruksi akan berjalan seperti yang didefinisikan sebelumnya. misalnya jika mereka mengharapkan nomor di sana, mereka akan bertindak berdasarkan byte data apa pun seolah-olah mereka nomor.


Untuk menggunakan contoh Anda, anggap Anda intadalah integer 4-byte (32-bit) yang sudah ditandatangani:

+-------------+--------------------------------------------+-----------+
| Source code |                  char[15]                  |    int    |
+-------------+--------------------------------------------------------+
| Memory      |61|61|61|62|62|62|63|63|63|64|64|64|65|65|65|EF|BE|AD|DE|
+-------------+--------------------------------------------------------+

Anda dapat melihat bahwa intlokasi memori sekarang berisi 0xEFBEADDE, dengan asumsi sistem big-endian 2 . Ini adalah int 32-bit yang ditandatangani -272716322. Sekarang, jika Anda mengartikan memori yang sama dengan int ( uint) yang tidak ditandatangani , itu akan menjadi 4022250974sebaliknya. Untuk data yang persis sama dalam memori, artinya sepenuhnya tergantung pada bagaimana Anda melihatnya.


1 Ada beberapa mekanisme yang mencegah Anda dari menulis ke wilayah memori yang dilindungi, dan akan merusak program Anda jika Anda berupaya melakukannya.

2 x86 sebenarnya adalah little-endian, yang berarti Anda mengartikan byte yang membentuk nilai lebih besar ke belakang. Jadi pada x86 Anda malah harus 0xDEADBEEF, memberi yang ditandatangani -559038737atau tidak 3735928559.

Bob
sumber
Jadi 0xdeadbeef, pada arsitektur x86, akan memakan lebih sedikit ruang dalam memori dibandingkan dengan desimalnya , 3735928559?
Darien Springer
2
@DarienSpringer Keduanya membutuhkan 4 byte memori - keduanya adalah urutan 4 byte yang sama. Mereka identik dalam ingatan. Anda dapat menganggap itu semua sebagai basis 2 (biner) dalam memori, jika Anda mau. Kemudian, ketika Anda menampilkannya (mengkonversi ke string untuk output) Anda dapat memilih basis untuk ditampilkan - hex adalah basis 16, dan desimalnya adalah basis 10. Representasi string disimpan di lokasi memori yang berbeda dan dapat menggunakan jumlah yang berbeda memori (karena setiap karakter adalah byte terpisah). The String 0xDEADBEEF disimpan dalam memori sebagai 0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46.
Bob
5
@DarienSpringer Dengan kata lain, angka adalah nomor yang sama tidak peduli apa dasar itu. Hex adalah cara yang nyaman (kompak) untuk melihat biner. Secara fisik, ini biner. Manusia suka desimal, jadi kita lebih sering menampilkan angka sebagai desimal. Tetapi sampai kita sampai pada langkah tampilan, semua operasi numerik (tambah, kurangi, gandakan, dll.) Bekerja pada data biner yang sama dalam memori.
Bob
1
"Anda dapat melihat bahwa lokasi memori int sekarang 0xEFBEADDE" Nitpick: Saya tahu Anda tidak bermaksud ini, tetapi sepertinya Anda mengatakan bahwa int terletak di lokasi memori 0xEFBEADDE. Mungkin menulis ulang sedikit. Kalau tidak, ini adalah jawaban yang luar biasa - Saya terutama menyukai analogi "tampilan" dan ide "menyipitkan mata" :)
Lightness Races in Orbit
@LightnessRacesinOrbit Poin bagus. Diedit.
Bob
2

Dari perspektif C, jawabannya adalah "Siapa yang tahu? Ini Perilaku Tidak Terdefinisi".

Jenis adalah konsep C, bukan perangkat keras. Tetapi aturan C tidak berlaku jika program Anda memiliki Perilaku Tidak Terdefinisi, itulah arti harfiah dari Perilaku Tidak Terdefinisi dalam standar C. Dan buffer overflow adalah salah satu bentuknya.

Saya awalnya menulis "aturan C tidak berlaku lagi", tetapi pada kenyataannya Perilaku Tidak Terdefinisi bersifat retroaktif. Aturan C tidak berlaku untuk program yang akan memiliki Perilaku Tidak Terdefinisi di masa depan.

MSalters
sumber