exploring the x64
TRANSCRIPT
Exploring the x64
村上 純一 執行役員 先端技術研究部長
(株)フォティーンフォティ技術研究所
自己紹介
• 村上 純一 – (株)フォティーンフォティ技術研究所
– カーネルモードでのWindows、Linuxにおける開発
– セキュリティ脆弱性分析、マルウェア解析、P2P解析等
– 講演活動 • Black Hat 2008 US and Japan, AVAR 2009,
RSA Conference(2009-)
– セキュリティ&プログラミングキャンプ講師(2006-)
2
はじめに
• IA64
• Linux, *BSD, Mac, etc.
3
& 目標
x86で利用される様々なテクニックがx64ではどのようになっているかを明確にする
難易度
環境
• Windows 7 x64 Edition • Visual Studio 2008 • Windbg • IDA Pro Advanced
– Standard Editionは、x64未対応
4
アジェンダ
• Windows x64
• ABI(Application Binary Interface)
• API Hooking
• Code Injection
5
Windows x64
• Native x64 およびWoW64
• 仮想メモリ空間
– 2^64 = 16 Exa Byte ( Exa: 10^18)
–実際には、最大16TBに制限されている
• ファイル・レジストリリフレクション
• 64-bit用の追加API
– IsWow64Process, GetNativeSystemInfo, etc.
6
x86 – プロセスメモリ空間
7
0x0
0xffffffff (4GB)
0x7fffffff (2GB)
カーネル
ユーザー空間
0x7fffffff
0x0
ntdll.dll
kernel32.dll
MSVCR90.dll
実行モジュール 0x00400000
x64 – プロセスメモリ空間
8
0x0
0xfff`ffffffff (16TB)
0x7ff`ffffffff (8TB)
カーネル
ユーザー空間
2GB
・ ・ ・ ・ ・ ・ ・
x 4096(0x7ff`ffffffff / 0x7fffffff )
・ ・ ・ ・ ・ ・ ・
x 4096
2GB
x64 – プロセスメモリ空間
9
0x0
カーネル
ユーザー空間
0x0
KERNELBASE.dll
実行モジュール 0x1`40000000
0x7fffffff
0xfff`ffffffff (16TB)
0x7ff`ffffffff (8TB)
0x7fff`fffffff
ntdll.dll
kernel32.dll
MSVCR90.dll
/DYNAMICBASE:NO
WoW64 – プロセスメモリ空間
10
0x0
0xfff`ffffffff (16TB)
0x7ff`ffffffff (8TB)
カーネル
ユーザープロセス
x 4096
0x7fffffff
0x0
ntdll.dll
kernel32.dll
wow64
実行モジュール 0x00400000
ntdll32.dll
kernelbase.dll
wow64win
wow64cpu C:¥Windows¥System32¥ntdll.dll
C:¥Windows¥SysWOW64¥ntdll.dll
ABI
• バイナリ形式
• レジスタ
• 呼び出し規約
• 例外処理
• システムコール(x64, WoW64)
11
バイナリ形式 = PE32+
• 基本的な構造は、概ねPE32と同様
• IMAGE_NT_HEADERS.FileHeader.Machine
– 0x014c => x86
– 0x8664 => x64
12
バイナリ形式
• 次のフィールドサイズが64-bitsに拡張されている
– IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER
• ImageBase
• SizeOfStackReserve
• SizeOfStackCommit
• SizeOfHeapReserve
• SizeOfHeapCommit
13
レジスタ
x86(32-bits) x64(64-bits)
EAX RAX R8
ECX RCX R9
EDX RDX R10
EBX RBX R11
ESI RSI R12
EDI RDI R13
ESP RSP R14
EBP RBP R15
EIP RIP
14
呼び出し規約
• 始めの4つの引数は、RCX, RDX, R8, R9レジスタを利用して渡される(5つ目以降は、スタック経由)
• 呼び出し側がスタック上にレジスタ・ホーム・スペースを確保
• 返り値は、x86同様RAXレジスタ経由で返却される
• リーフ関数・非リーフ関数 – リーフ関数:スタックを一切利用しない関数
– PE32+は、非リーフ関数の情報を例外ディレクトリに保存している
• レジスタの揮発性 – 揮発レジスタ:RAX, RCX, RDX, R8-R11
– 不揮発レジスタを関数内で変更する場合は、スタックを利用して保存・復元を行う必要がある
15
呼び出し規約
16
int foo(int a, int b, int c, int d, int e) { int x = 0; x = a + b + c + d + e * 2; return x; } int main(void) { int rc; rc = foo(1, 2, 3, 4, 5); printf("%d¥n", rc); return rc; }
rc
r9 (home)
r8 (home)
rdx (home)
rcx (home)
Low
High
retaddr
x
5th parameter
rsp
rsp
rsp
rsp
sub rsp,30h
mov dword ptr [rsp+20h],5 mov r9d,4 mov r8d,3 mov edx,2 mov ecx,1 call foo
mov dword ptr [rsp+20h],r9d mov dword ptr [rsp+18h],r8d mov dword ptr [rsp+10h],edx mov dword ptr [rsp+8h],ecx sub rsp,8h
例外処理
• テーブルベースでの処理 – x86で利用されていたリンクリストでの管理は廃止
17
参考) x86での例外処理
例外ディレクトリ及びRUNTIME_FUNCTION構造体
18
Section A
PE32+
DOS Header
DOS stub
NT FileHeader
NT Optional Header
Section Header
Section B
Section C
Export Table
Import Table
Resource Table
Exception Table
Import Address Table
・ ・ ・
・ ・ ・
Data Directory
RUNTIME_FUNCTION_ENTRY
RUNTIME_FUNCTION_ENTRY
RUNTIME_FUNCTION_ENTRY
・ ・ ・
struct _RUNTIME_FUNCTION { ULONG BeginAddress; ULONG EndAddress; ULONG UnwindData; }
dumpbin /unwindinfo
Begin End Info Function Name
00000000 00001000 00001041 000022D4 foo
Unwind version: 1
Unwind flags: None
Size of prologue: 0x16
Count of codes: 1
Unwind codes:
16: ALLOC_SMALL, size=0x18
0000000C 00001050 00001095 000022DC main
Unwind version: 1
Unwind flags: None
Size of prologue: 0x04
Count of codes: 1
Unwind codes:
04: ALLOC_SMALL, size=0x48
19
RUNTIME_FUNCTION.UnwindData
20
typedef struct _UNWIND_INFO { UBYTE Version : 3; UBYTE Flags : 5; UBYTE SizeOfProlog; UBYTE CountOfCodes; UBYTE FrameRegister : 4; UBYTE FrameOffset : 4; UNWIND_CODE UnwindCode[1]; union { // If (Flags & UNW_FLAG_EHANDLER) OPTIONAL ULONG ExceptionHandler; // Else if (Flags & UNW_FLAG_CHAININFO) OPTIONAL ULONG FunctionEntry; }; // If (Flags & UNW_FLAG_EHANDLER) OPTIONAL ULONG ExceptionData[]; } UNWIND_INFO, *PUNWIND_INFO;
#define UNW_FLAG_NHANDLER 0x0 #define UNW_FLAG_EHANDLER 0x1 #define UNW_FLAG_UHANDLER 0x2 #define UNW_FLAG_CHAININFO 0x4
cf. http://www.osronline.com/article.cfm?article=469
ExceptionData
typedef struct _SCOPE_TABLE { ULONG Count; struct { ULONG BeginAddress; ULONG EndAddress; ULONG HandlerAddress; ULONG JumpTarget; } ScopeRecord[1]; } SCOPE_TABLE, *PSCOPE_TABLE;
21
cf. http://www.osronline.com/article.cfm?article=469
try/except
22
int main(void) { int x = 0; __try { printf("%d¥n", 100/x); printf("foo¥n"); printf("bar¥n"); printf("baz¥n"); } __except(EXCEPTION_EXECUTE_HANDLER) { printf("catch!¥n"); } return 0; }
try/except
23
140001000 sub rsp,28h 140001004 mov eax,64h 140001009 cdq 14000100A xor ecx,ecx 14000100C idiv eax,ecx 14000100E mov edx,eax 140001010 lea rcx,[400021B0h] 140001017 call qword ptr [40002130h] 14000101D lea rcx,[400021B4h] 140001024 call qword ptr [40002130h] 14000102A lea rcx,[400021BCh] 140001031 call qword ptr [40002130h] 140001037 lea rcx,[400021C4h] 14000103E call qword ptr [40002130h] 140001044 jmp 0000000140001054 140001046 lea rcx,[400021D0h] 14000104D call qword ptr [40002130h] 140001053 nop 140001054 xor eax,eax 140001056 add rsp,28h 14000105A ret
Name main Unwind version: 1 Unwind flags: EHANDLER Size of prologue: 0x04 Count of codes: 1 Unwind codes 04: ALLOC_SMALL, size=0x28 Handler:0000165C __C_specific_handler Count of scope table entries: 1 Begin 00001004 End 00001046 Handler 00000001 Target 00001046
例外ディレクトリの効用
• 実行ファイル内の非リーフ関数を列挙可能
• 非リーフ関数それぞれについて:
–例外処理の情報を取得可能
–スタック及び不揮発レジスタの用途を把握可能
24
システムコール x86
25
IDTR
MSR[176h]
SDT (ntoskrnl.exe)
SDT Shadow (win32k.sys)
IDT
・ ・ ・
・ ・ ・
KiSystemService
Nt* APIs
Nt* APIs (User/GDI)
SSDT
SSDT other interrupt handlers
int 0x2e or sysenter
システムコール x64
26
ntdll.dll NtCreateFile
kernel32.dll
CreateFileWImplementation
(CreateFileW)
kernelbase.dll CreateFileW
実行モジュール CreateFileW
mov r10,rcx mov eax,52h syscall ret nop dword ptr [rax+rax]
システムコール WoW64
27
ntdll32.dll NtCreateFile
kernel32.dll
CreateFileWImplementation
(CreateFileW)
kernelbase.dll CreateFileW
実行モジュール CreateFileW
mov eax,52h xor ecx,ecx lea edx,[esp+4] call dword ptr fs:[0C0h] add esp,4 ret 2Ch
fs:[0C0h]
28
0:000:x86> dt _TEB dbgbreak!_TEB +0x000 NtTib : _NT_TIB (snip) +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB +0x034 LastErrorValue : Uint4B +0x038 CountOfOwnedCriticalSections : Uint4B +0x03c CsrClientThread : Ptr32 Void +0x040 Win32ThreadInfo : Ptr32 Void +0x044 User32Reserved : [26] Uint4B +0x0ac UserReserved : [5] Uint4B +0x0c0 WOW32Reserved : Ptr32 Void
• FSレジスタは、TEB(Thread Environment Block) のアドレスを保持
0:000:x86> dd fs:[0C0h] 0053:000000c0 738c2320 00000411 00000000 00000000 ↑ X86SwitchTo64BitMode
Systemcall WoW64
29
wow64cpu.dll
X86SwitchTo64BitMode
CpupReturnFromSimulatedCode
TurboDispatchJumpAddressEnd
wow64.dll
Wow64SystemServiceEx
jmp 0033:CpupReturnFromSimulatedCode
call fs:[0C0h]
GDT (超約)
30
仮想メモリ空間 • 仮想メモリ空間をセグメントとして管理
• カーネルコード、カーネルデータ • ユーザコード、ユーザデータ等 seg. A
seg. B
seg. C
0x0
0xff
ID seg. base limit type
0x00 A 0x0 0x3f RW
0x08 B 0x40 0x7f RE
0x10 C 0x0 0xff RE
セグメントセレクタ
GDT
Windows 7(x64)でのGDTダンプ結果
31
kd> dg 0x00 0x60 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- ----------------- ----------------- ---------- - -- -- -- -- -------- 0000 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000 0008 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000 0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P Lo 0000029b 0018 00000000`00000000 00000000`ffffffff Data RW Ac 0 Bg Pg P Nl 00000c93 0020 00000000`00000000 00000000`ffffffff Code RE 3 Bg Pg P Nl 00000cfa 0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P Nl 00000cf3 0030 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P Lo 000002fb 0038 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000 0040 00000000`00b9b080 00000000`00000067 TSS32 Busy 0 Nb By P Nl 0000008b 0048 00000000`0000ffff 00000000`0000f800 <Reserved> 0 Nb By Np Nl 00000000 0050 ffffffff`fffe0000 00000000`00003c00 Data RW Ac 3 Bg By P Nl 000004f3 0058 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000 0060 00000000`00000000 00000000`ffffffff Code RE 0 Bg Pg P Nl 00000c9a
Kernel CS(x64), Kernel DS User CS(x86), User DS
User CS(x64)
GDT[0x30]の内容
• ベース: 0x000`00000000
• リミット: 0x000`00000000
• タイプ: CODE, Read, Execute and Accessed
• 特権レベル: 3(ユーザーモード)
• L (64-bitコードセグメント) flag: 1
32
システムコール WoW64
33
wow64.dll
Wow64SystemServiceEx
whNtCreateFile
ntdll.dll
NtCreateFile
mov r10,rcx mov eax,52h syscall ret
システムコール WoW64 (return to x86)
34
ntdll.dll
NtCreateFile
wow64.dll
whNtCreateFile
Wow64SystemServiceEx
wow64cpu.dll
TurboDispatchJumpAddressEnd
CpuSimulate
mov dword ptr [r14+4],23h mov r8d,2Bh mov ss,r8w mov esp,dword ptr [r13+0C8h] mov r9d,dword ptr [r13+0BCh] mov dword ptr [r14],r9d jmp fword ptr [r14]
0:000> dd r14 00000000`0008ec70 77330056 00000023 0008ed30 00000000 ↑ ↑ offset User Code(x86)
デモ: WoW64からのx64 APIの直接呼出し
• x86からx64への遷移
– jmp 0033:XXXXXXXX
• API呼び出し
– rax: システムコール番号
– rdx: 引数リストのアドレス
– syscall
• x64からx86への遷移
– call 0023:XXXXXXXX
35
API Hooking
• IAT Hooking
– x86と同様の手法で実現可能
• Code Hooking
36
Code Hooking
• 基本的な方法は、x86と同じ
• ただし実装の詳細に若干の差異有り
37
mov edi,edi mov ebp,esp push ebp sub esp,0xc … …
対象API
mov edi,edi push ebp mov ebp,esp sub esp,8h jmp XXXXXXXX
トランポリンコード
… … … jmp trampoline
フック関数
push hookfunc ret nop nop
REXプレフィックス
• 0x40~0x4E – x86: INC 、DEC 命令
– x64: REX プレフィックス(レジスタ拡張)
• 例) 0x48,0xB8,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88
38
48 B8 11 22 33 44 55 66 77 88 mov rax,8877665544332211h
48 dec eax B8 11 22 33 44 mov eax,44332211h 55 push ebp 66 77 88 ja 00004E9F
x86:
x64:
Code Hooking
39
00000000779811E4 mov rax,7FFFFFA0028h 00000000779811EE push rax 00000000779811EF ret 00000000779811F2 …
000007FFFFFA0034 sub rsp,38h 000007FFFFFA0038 xor r11d,r11d 000007FFFFFA003B cmp dword ptr [7FFFFFC0F8Ch],r11d 000007FFFFFA0042 push rax 000007FFFFFA0043 mov rax,779811F2h 000007FFFFFA004D xchg rax,qword ptr [rsp] 000007FFFFFA0051 ret
フック関数
書換えた元のコード
フックした関数への復帰先
Code Injection
• WoW64 からWoW64ヘのインジェクション
• x64からx64へのインジェクション
• WoW64 から x64へのインジェクション
• x64 からWoW64ヘのインジェクション
40
x64環境は、x86マルウェアへの魔除けになるか?
(Fail CreateRemoteThead API)
まとめ
• Windows x64
• ABI(Application Binary Interface)
• API Hooking
• Code Injection
41
Special thanks
• Toshiaki Ishiyama@FFR
• Satoshi Tanda@FFR
42