4

現在、私は「天国の門」として知られる Windows/WOW64 トリックで遊んでいます。おそらくご存知の方もいらっしゃると思いますが、x86 プログラムであっても x64 モードに入ることができます (テストしたときはとても驚きました)。そしてそれはうまくいきました!)しかし、すべてのWindowsバージョンでサポートされているわけではないことがわかっているので、私のコード(コードがあるため)はsehを使用しています。次のようになります:

start:
  use32
  ;; setup seh...
  call $33:.64bits_code ; specify 0x33 segment, it's that easy
  ;; success in x64 mode, quit seh...
  jmp .exit

.64bits_code:
  use64
  ;; ...
  use32
  retf

.seh_handler:
  use32
  ;; ...
  xor eax,eax ; EXCEPTION_CONTINUE_EXECUTION
  ret

.32bits_code: 
  ; we have been called by a far call (well, indirectly, routed by a seh handler)
  ; HERE IS THE PROBLEM => Should i use a retf since cs and eip are on the stack, 
  ;                        or the exception has been triggered before pushing them???
  ; "retf" or "jmp .exit"?

.exit:
  xor eax,eax
  push eax
  call [ExitProcess] 

単純な「jmp .exit」でうまくいくことは知っていますが、それについて非常に興味があります

4

1 に答える 1

1

OS に割り込みが発生したり、障害が発生したりすると、ユーザー コードが何を実行していたかに関係なく、CPU が必要な状態をカーネル スタックに保存したことを期待するため、実行中の操作IRETが目に見えない形で再開されます。

カーネルスタックのその状態には「魔法」が関与していないことに注意してください。「実行を継続する」とは、 の保存された値を復元し、最終的に を指すコードを実行することのみを意味rflagsします。cs:ripss:rspcs:rip

つまり、SEH を具体的に関与させずに、far 呼び出し中に発生するあらゆる種類の例外について考えるだけで、実際に考慮すべきケースは 2 つだけです。

  1. ジャンプの「前」に例外が発生します。何もプッシュされていません。カーネルスタックの状態は、呼び出し命令を再開して再開する必要があることを示しています。
  2. ジャンプの「後」に例外が発生します。cs:eipプッシュされ、ラベルripまたはその後のどこかを指し.64bits_code、その保存された状態は、再開するには 64 ビット コードにジャンプする必要があることを示しています。

cs:ripCPU が far 呼び出しを「途中で」中断することを許可した場合、OS が実行を継続するときに一貫した結果を生成する可能性のある値はありません。たとえば、例外が発生する前に far 呼び出しの戻りアドレスがプッシュされていたが、保存されたポインターがcs:ripfar 呼び出し命令を指している場合、スタックには戻りアドレスの2 つのコピーが残り、最悪の事態が発生します。

さて、実際にあなたの質問に答えるには、OS が例外が発生したことを通知する rIP の値に依存します。64 ビット コードを指している場合は、スタックに cs:eip が必要です。32 ビット コードを指している場合は、まだプッシュされていないと安全に想定できます。

于 2012-07-22T18:06:05.700 に答える