标题: shellcode自识别32/64位架构 创建: 2014-12-26 更新: 2017-09-26 17:18 链接: https://scz.617.cn/windows/201412260000.txt 本文为下列文档的意译,仅为收集整理点评,非原创。 -------------------------------------------------------------------------- Architecture Detection (x86 or x64) Assembly Stub - zero sum [2014-12-26] https://zerosum0x0.blogspot.com/2014/12/detect-x86-or-x64-assembly-stub.html Detecting Architecture in Windows - OsandaMalith [2017-09-24] https://osandamalith.com/2017/09/24/detecting-architecture-in-windows/ checking_architecture.cpp https://gist.github.com/hasherezade/0994447e9d3dc184888fb2afd5a57301 The initial values of x86 registers https://github.com/corkami/docs/blob/master/InitialValues.md -------------------------------------------------------------------------- 1) 推荐方案(zero sum) shellcode自识别32/64位架构极其重要,比如Windows的TIB,x86上用FS寻址,x64上 用GS寻址。下面这5字节汇编指令可以自动识别32/64位架构: -------------------------------------------------------------------------- _shellcode: xor ecx,ecx ; set ecx to 0 db 0x41 ; x86 opcode for: inc ecx loop x64_code ; ecx now -1 in x64, we jmp x86_code: ; use fs segment ; ret x64_code: ; use gs segment -------------------------------------------------------------------------- 熟悉x64汇编的人应该知道,[0x40,0x50]经常用作指令前缀,可以利用这点微妙的区 别自动识别32/64位架构。 假设在x86上运行: -------------------------------------------------------------------------- xor ecx,ecx ; 31c9 ecx=0 inc ecx ; 41 ecx=1 loop x64_code ; e201 ecx=0 no jmp -------------------------------------------------------------------------- 假设在x64上运行: -------------------------------------------------------------------------- xor ecx,ecx ; 31c9 ecx=0 rex.B loop x64_code ; 41e201 ecx=-1 jmp -------------------------------------------------------------------------- 这里用"db 0x41",而不是直接写成"inc ecx",因为nasm会采用2字节指令避免这种 歧义,我们恰恰需要这种歧义。 上面给出的机器码只是演示,e201中的01是假设x86_code处只有一条ret指令,占1个 字节。 Eternalblue使用了本质上相同的类似方案: -------------------------------------------------------------------------- 31 C0 xor eax, eax 40 90 xchg eax, eax 0F 84 B5 05 00 00 jz x64_main -------------------------------------------------------------------------- 这是推荐方案,它只与CPU相关,与OS无关,理论上针对Linux也能使用这种技术。后 面其他方案都是针对Windows的。 2) Kronos malware xor eax, eax mov ax, cs shr eax, 5 x86/Win7用户态的CS是0x1B,x64/Win7用户态的CS是0x23或0x33,因此最后的eax为0 时表示x86,为1时表示x64。 上述代码只适用于用户态,且无法区分SysWOW64。 3) 其他段选择子 -------------------------------------------------------------------------- x86/Win7 user cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 x64/Win7 32-bits user cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b x64/Win7 64-bits user cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b -------------------------------------------------------------------------- x86/Win7 kernel cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 x64/Win7 kernel cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b -------------------------------------------------------------------------- OsandaMalith受Kronos启发,用其他段选择子区分32/64位架构: -------------------------------------------------------------------------- xor eax, eax mov ax, es ror ax, 0x3 and eax, 0x1 test eax, eax -------------------------------------------------------------------------- xor eax, eax mov eax, gs test eax, eax -------------------------------------------------------------------------- 上述代码无法区分SysWOW64。当然,不必那么死板,只要存在差异,就可以区分。 4) TEB x86/Win7 user > dt ntdll!_TEB WOW32Reserved @$teb +0x0c0 WOW32Reserved : (null) > ? @$teb Evaluate expression: 2147344384 = 7ffde000 x86用户态FS:0指向ntdll!_TEB,可以用"dg @fs"获取FS段基址。 > dg @fs P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 003B 7ffde000 00000fff Data RW Ac 3 Bg By P Nl 000004f3 x64/Win7 32-bits user > dt ntdll!_TEB WOW32Reserved @$teb +0x0c0 WOW32Reserved : 0x74a92320 Void > u 0x74a92320 l 1 74a92320 ea1e27a9743300 jmp 0033:74A9271E > ? @$teb Evaluate expression: 2130563072 = 7efdd000 > dg @fs P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0053 7efdd000 00000fff Data RW Ac 3 Bg By P Nl 000004f3 x64/Win7 64-bits user > dt ntdll!_TEB WOW32Reserved @$teb +0x100 WOW32Reserved : (null) > ? @$teb Evaluate expression: 8796092882944 = 000007ff`fffde000 x64用户态GS:0指向ntdll!_TEB。对于x64,"dg @gs"无法获取GS段基址。 用WOW32Reserved可以区分SysWOW64,但WOW32Reserved的偏移对于三种情况不统一, 而且访问TEB时涉及FS、GS的选择,本方案意义不大。 xor eax, eax mov eax, [FS:0xc0] test eax, eax