2010-05-18 26 views
14

我已經對jmp指令瞭解了一段時間,但它從來沒有讓我感到甚至是遠程不安全。我最近有理由檢查CIL規格和was very surprised to discover jmp is considered unverifiable爲什麼CLR的jmp指令無法驗證?

+0

請問這是因爲它無法驗證當前部分代碼塊,然後縫合到目的地代碼塊的執行的影響...... 一些關於堆棧/堆跟蹤似乎國旗在我的小夢境.. 。不是我確實知道這一點,但是,這是由這裏的信息立即抵消... http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.jmp .aspx ...明確指出沒有堆棧信息被跟蹤/傳輸。 也許在微軟隱藏的「前端」下面有一些東西。 – War 2010-05-18 14:19:14

+0

我不知道爲什麼它是無法驗證的,但我確實有一個有趣的信息。我們的EQATEC Profiler收集關於所有代碼的匿名統計信息(使用EQATEC Analytics,順便說一句)。因爲jmp非常棘手,並且沒有通過輪廓儀進行最佳處理,所以我們決定跟蹤實際發生的頻率。我們現在有兩年的數據,從超過100萬個異形裝配中收集,共計200億CIL指令。非常多。 jmp有多少?沒有!是的,jmp在我們的任何應用程序(NETCF,SL,WP7,F#等)中都沒有發生過。非常驚喜。 – 2010-10-10 00:59:18

+1

其實我並不太驚訝。沒有編譯器我知道除了可能託管的C++發出jmp指令,因爲它是無法驗證的。 jmp的任何用法都可能在可信類庫中被鬆動。 – naasking 2010-10-12 15:44:27

回答

4

,因爲不同於callcallvirt,或者calli,在調用者的堆棧幀將保持在堆棧上通過未來的代碼訪問安全stackwalks可以看到觸發(可能是間接的)由被叫方,一個jmp指令眼淚就下來了來電者的堆棧幀在轉換到被呼叫者之前並因此對被呼叫者可能觸發的任何CAS棧道不可見。

編輯:我認爲naasking是正確的關於上述錯誤的答案。我現在認爲(可驗證的)tail.call序列和(不可驗證的)jmp序列之間的區別可能在於尾部調用需要將參數推送到評估堆棧上,以便能夠以正常方式對其進行驗證,而一個jmp要求評估堆棧爲空,並使跳轉ee繼承跳轉者的參數。可能沒有理由使驗證者檢查jmp指令變得複雜,但是可能在類似於tail.call序列的條件下這樣做(其中之一是調用者和被調用者必須在相同的程序集中),這些規則在我的CAS猜測之上,至少達到明確的.Deny()調用)。

如果是這樣,這將是該規範的相關部分:(分區III,第3.37)

的當前參數被傳輸 到目的地的方法。

執行此指令時,評估堆棧必須爲空 。 調用約定,目標地址爲 的參數 的數量和類型必須與當前方法的參數匹配。

+0

儘管第一眼看起來很合理,但這並沒有經過仔細審查。這個。tailcall前綴具有大致相同的行爲,儘管更一般,但.tailcall是可驗證的。該文檔簡單地說明。從不可信到可信的代碼調用時,.tailcall被忽略。如果這是jmp無法驗證的原因,我不明白爲什麼他們不會爲jmp使用相同的行爲。 – naasking 2010-05-19 14:37:52

+0

非常好的一點,謝謝naasking。 – 2010-05-19 16:20:48

+0

我認爲在鏈接的博客頁面上發佈的「Rodrigo Kumpera」是正確的:如果任何參數都是by-ref,那麼您可以存儲對本地的引用,然後執行jmp。需要進行控制流分析以確保不會發生這種情況,儘管這種分析比較簡單。我敢打賭,他們只是不想打擾,因爲jmp主要是爲了支持C++而添加的。 .tailcall存在同樣的危險,所以我不確定如何處理,即。不可驗證的,或.tailcall忽略。我必須在某個時候測試它。 – naasking 2010-06-29 23:03:56