2012-10-05 27 views
2

我知道格式化字符串攻擊發生在格式化I/O函數需要比提供的更多參數時。爲什麼在C中發生格式串攻擊?

在C,

用於讀取存儲位置

一個例子:

printf("%x"); // this prints a memory address location in the stack 

用於重寫存儲器位置又如:

printf("Overwritten%n"); //this prints the number of chars in "Overwritten" 

我的問題是:爲什麼會發生這種情況在兩種情況?爲什麼在沒有提供相應值的情況下只有格式化字符串中的%x會在內存中打印一個地址?那究竟是什麼地址?我知道發生了,但究竟發生了什麼?

與覆蓋相同。

+0

我建議閱讀有關調用約定: http://en.wikipedia.org/wiki/Calling_convention –

+0

按照從[Wikipedia文章]鏈接(http://en.wikipedia.org/wiki/Uncontrolled_format_string),搜索在那裏使用的術語。在YouTube上甚至還有關於此的視頻。 –

回答

4

發生什麼是未定義的行爲。 Printf不知道沒有相應的值。它試圖訪問您的呼叫的第二個參數(您沒有提供),並訪問一些隨機存儲器值。

對於"overwritten%n",在調用%n之前,%n會在內存中存儲寫入的字符數。如果你打電話,如果沒有通過正確的地址,它會隨機寫一些東西,冒着破壞你的記憶的風險。

1

可能對您會有所幫助:
我猜你是在Windows中工作。沒有進行嚴格的檢查。
我在Linux上試過同樣的警告。

int main(){
printf(「%x」);
printf(「Overwritten%n」);
}

給出如下警告:
$ GCC test.c的
test.c的:在函數 '主':
test.c的:4:警告:對格式參數太少
測試.c:5:警告:格式太少的參數

1

這是因爲printf不知道程序員的意圖。當它在格式字符串中看到一個格式標識符時,它在那裏格式化適當的參數。

printf("%x"); 

需要額外的參數(通常存儲在寄存器或堆棧中)。由於程序員沒有告訴編譯器在這個調用中提供額外的參數,無論存儲在哪裏printf預計在那時會找到參數將被打印。

爲了優化原因,編譯器通常在調用下一個函數之前不清除寄存器。

2

鑑於C被命名爲「高級彙編器」,答案在於其編譯器結構。 printf是一個函數,它接受可變數量的參數,而不檢查是否實際提供了所有參數。因此,取決於該函數如何在編譯器級接受參數,以下情況是可能的:

首先,傳遞給printf的字符串被解析,導致後續調用內部函數,該函數會輸出一個字符串在第二種情況下'覆蓋'(在第一種情況下,格式化字符串的第一個符號是表示參數的'%')。然後,當一個參數被要求打印時,調用一個相應的原始數據打印程序,其中下一個應該放入堆棧的參數(偏移量是在編譯時計算的)。在%x的情況下,沒有參數,並且要打印的未更改字符串爲空,因此未分配,因此堆棧中的下一個32位值是當前返回地址,即由EXE上的OS生成的地址加載時間,並通過call printf_hex_address彙編指令實際放入堆棧。這種攻擊顯然是基於這樣一個事實,即如果處理程序實際上在內存中是持久的,並且不會被交換,則該地址是程序地址空間中的可寫內存位置。爲什麼出現「覆蓋」的長度,可以通過設計的內部字符串操作例程來解釋,以便將字符串的實際長度傳遞給它。

+0

我仍然無法得到printf(「%x」)調用顯示的地址。我需要一個簡單的句子來描述這個地址是什麼? –

+0

這取決於printf的本地實現。一個粗略的猜測將是「代碼的地址printf」,儘管它也可能是printf中調用內部打印例程的代碼地址。 – Vesper