PTR_MANGLE/PTR_DEMANGLE の実装は xor + ror/rol になっていた
マイクロスレッドの実装で、%ESP と %EIP の切り替えに setjmp()/longjmp() を利用しようとしたらハマってしまった。調べてみるとセキュアコーディングの関係で jmp_buf の %EIP, %ESP のポインタがエンコーディングされていた。
で、参考にさせてもらって自分のコードをいじったがまだ動かない…。結局、libc-2.7 の、
/sysdeps/unix/sysv/linux/i386/sysdep.h
あたりのコードをよく見たら、最近は xor だけではなく ror/rol による 9bit のローテーションが追加されていた。以下に抜き出して実験してみた。(0x18 など一部ハードコーディングに置き換えている。0x18 は tcbhead_t の pointer_guard までのオフセット)
#include <stdio.h> #include <setjmp.h> #define PTR_MANGLE(var) asm("xorl %%gs:0x18, %0;" \ "roll $9, %0;" : "=r"(var) : "0"(var)) #define PTR_DEMANGLE(var) asm("rorl $9, %0;" \ "xorl %%gs:0x18, %0;" : "=r"(var) : "0"(var)) int main(int argc, char** argv) { int direct_esp, direct_eip; int setjmp_esp, setjmp_eip; jmp_buf jmpBuf; asm("movl %%esp, %0;" : "=r"(direct_esp)); asm("call label;" "label: popl %0;" : "=r"(direct_eip)); printf("direct_ESP = %X, direct_EIP = %X\n", direct_esp, direct_eip); setjmp(jmpBuf); setjmp_esp = jmpBuf[0].__jmpbuf[4]; // ESP setjmp_eip = jmpBuf[0].__jmpbuf[5]; // EIP PTR_DEMANGLE(setjmp_esp); PTR_DEMANGLE(setjmp_eip); printf("setjmp_ESP = %X, setjmp_EIP = %X\n", setjmp_esp, setjmp_eip); return 0; }
実行結果は以下の通り。(EIP が異なるのは保存しているところが違うから。だいたい合っている、という参考までに)
direct_ESP = BFC930B0, direct_EIP = 8048418 setjmp_ESP = BFC930B0, setjmp_EIP = 8048444