Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The NOPs You Don't Know
Search
herumi
October 03, 2024
560
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
The NOPs You Don't Know
herumi
October 03, 2024
More Decks by herumi
See All by herumi
Constant Integer Division and Modulo Optimization Revisited (English)
herumi
0
75
定数整数除算・剰余算最適化再考
herumi
1
120
Constant integer division faster than compiler-generated code
herumi
2
1.1k
Batch Processing Algorithm for Elliptic Curve Operations and Its AVX-512 Implementation
herumi
0
270
Mathematics used in cryptography around us
herumi
2
1.1k
Xbyak Internals and Hacks
herumi
1
800
LLVM/ASMを使った有限体の高速実装
herumi
0
320
署名とゼロ知識証明の初歩
herumi
6
5.7k
Lifted-ElGamal 暗号による,Argmax とベクトルの内積近似計算の二者間秘匿計算プロトコルとその応用
herumi
0
610
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.2k
Done Done
chrislema
186
16k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
240
How to make the Groovebox
asonas
2
2.2k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
Context Engineering - Making Every Token Count
addyosmani
9
960
ラッコキーワード サービス紹介資料
rakko
1
3.6M
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
250
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
380
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
Abbi's Birthday
coloredviolet
2
8.1k
Transcript
あなたの知らないnopたち @ラボユース合宿(2024年版) 2024/8/21 光成滋生
• よく使われるループの先頭アドレスは 16byteアライメントされているとよいことが多い • そろえるために隙間を埋める • 隙間の命令は何もして欲しくない 何もしない(no operation)は何のため? アドレス
命令コード 命令コード 命令1 命令2 LP: 0000xx11h 0000xx20h jnz LP 命令1 命令2 LP: jnz LP 何もしない アライメント 2 / 14
• 何もしない1byteの命令 • xchg eax, eaxのalias(32bit時代) • AArch64 • NOP
= hint #0 • 昔のArmはmov x0, x0だったことも • RISC-V • nop = addi x0, x0, 0 # x0はゼロレジスタ 90h(=0x90) 3 / 14
• 何もしない2byte命令(32bit) • lea eax, [eax] • 1byte nopを2個実行するより効率がよい(よかった) •
89 c0h • 別の何もしない2byte命令 • mov eax, eax • 8d 04 05 00 00 00 00h • 何もしない7byte命令 • lea eax, [eax * 1 + 0x00000000] • ... 8d 00h 4 / 14
• これらのnopたちは何もしないわけではなくなった • 32bitレジスタ操作命令は64bitレジスタの上位を クリアする • パーシャルレジスタストールを避けるために 値を保持する戦略はとらなかった(推測) • xchg
eax, eax / lea eax, [eax]などもnopでなくなった • mov eax, eaxはxxxxxxxxを0にする • movzx rax, eaxと同じ(というかこの命令は存在しない) 64bit環境では rax(64) eax(32) ax(16) xxxxxxxx 5 / 14
• 90hは本当のnopになった • xchg eax, eaxではない • それではxchg eax, eaxはどうなった?
• 87, c0h ; xchgの冗長表現 • xchg rax, raxは48 90h • 意味的には32bitのnopに対応するが内部的にはnopではない 64bitでのnop 6 / 14
• いつからnopが拡張された(2000年頃?) • nop r/m • nopがレジスタやメモリアドレッシングを引数に取る • 32/64bit両対応で同一コード •
AMD CPUでも公式にサポートされてるので安心 • 大昔はIntelとAMDで異なる長いnopを準備したことも multi byte nop 66 nop 66 90h nop dword ptr [eax] 0f 1f 00h nop dword ptr [eax + 00h] 0f 1f 40 00h nop dword ptr [eax + eax*1 + 00h] 0f 1f 44 00 00h 66 nop dword ptr [eax + eax*1 + 00h] 66 0f 1f 44 00 00h nop dword ptr [eax + 00000000h] 0f 1f 80 00 00 00 00h nop dword ptr [eax + eax*1 + 00000000h] 0f 1f 84 00 00 00 00 00h 66 nop dword ptr [eax + eax*1 + 00000000h] 66 0f 1f 84 00 00 00 00 00h 7 / 14
• multi byte nopはeax以外の引数も取れる • nop ecx, eax ; 0f
1f c1h • nop esp, [rax + rax] ; 0f 1a 04 00h • Intelはこの余ってるnopを拡張した multi byte nopの拡張 8 / 14
• バッファオーバーフローをOS/libレベルでチェック • 4個の128bit boundレジスタbnd0, bnd1, bnd2, bnd3 • 上位64bitは境界の上限,
下位64bitは境界の下限の値が入る • bndmk bnd, mem • memの値をbndレジスタに設定する • bndcl bnd, r/m • r/mの値がbndの下限より大きいかを確認 • bndcu bnd, r/m • r/mの値がbndの上限より小さいかを確認 • 範囲外ならbounds violationが発生 MPX(Memory Protection Extensions) 9 / 14
• MPX非対応CPU/OSで影響が出ないように拡張 • 対応していないとこう見える MPXエンコーディング bndmk bnd0, [rax] ; f3
0f 1b 00h bndcl bnd0, rax ; f3 0f 1a c0h bndcu bnd0, rax ; f2 0f 1a c0h bndldx bnd0, [rax+rax] ; 0f 1a 04 00h bndstx [rax+rax], bnd0 ; 0f 1b 04 00h nop eax, [rax] nop eax, eax nop eax, eax nop esp, [rax+rax] nop esp, [rax+rax] [rax*2]と等しくない 省略可能な3引数オペランド の一部としてSIBを利用 10 / 14
• コンパイラが対応してくれなかった • 2024年Intel APX登場! • 3op/32レジスタ拡張 add, r20, r21,
r23 (まるでRISC-V) • xsave/xsaveopt • ユーザモードでレジスタの退避・復元をするための命令 • MPXのための領域128バイトがあった • 4個の128bitレジスタ+状態 • これはもう使われることはない • それを拡張レジスタの保存に使うことになった 2019年MPXはremoved 11 / 14
• 単純な関数で見てみる • endbr64って何? 関数の先頭のnop id: endbr64 mov eax, edi
# eax = x; ret 12 / 14 int id(int x) { return x; } gcc –O2 –S t.c
• Control-flow Enforcement Technology • ROP攻撃を防ぐ • 実行ファイルの中にある細切れの命令列を実行する攻撃手法 • バイト列の途中にジャンプしてくる
• CETが有効だと • 正しいコードの先頭にはendbr64を入れてマークしておく • マークされたバイト列にしかジャンプできない • おかしなところにジャンプできない • CETが無効の古い環境では長いnopと解釈される • バイトコード F3 0F 1E FB = rep nop ebx • F3 : 大昔は繰り返し(rep)を意味することが多かったが 今はなんでもあり CET 13 / 14
• キャッシュ制御命令 • 指定された領域をL1やL2キャッシュからL3などの下位のレベ ルに移動する • 近い将来に使われないと分かっているメモリを下位のレベル に移行することでL1やL2キャッシュの領域を広げる • AlderLakeなどの比較的新しいCPUなどで利用可能
• バイトコード 0F 1C ... • やっぱり古いCPUではNOPに見える cldemote 14 / 14