4

ntdll.dll を介さずにシステム コールを直接呼び出すプログラムを作成しようとしています。

私のコード(Visual Studio構文...):

#include <windows.h>

int main()
{
   _asm{
        push arg1
        push arg2
        push arg3
        mov eax,syscall_id
        mov edx,esp
        _emit 0xf
        _emit 0x34 //sysenter opcodes...
       }

プログラムが sysenter 命令を実行しようとすると、次のアクセス違反でプログラムがクラッシュします。

CALL DWORD PTR DS:[EAX+EDX*4] // Access Violation when reading [00000128]

EAX == 0x00000000
EDX == 0x0000004D

カーネル デバッガーを使用して目的のシステム コールに hw ブレークポイントを設定しようとしましたが、実行フローがそこに到達しません...

問題はスタックの順序/深さに関係していると思います。

どうもありがとう!

解決済み:

問題は、user32 および gdi32 dll をロードせずに win32k システム コールを実行しようとしたことだと思います。

追加したばかりです:

LoadLibraryW(L"user32.dll");
LoadLibraryW(L"gdi32.dll");

そして問題解決..

これらのdllをロードせずになぜこれが起こるのか、誰かがより良い考えを持っているなら、私は喜んで知っています:)

4

1 に答える 1

5

SYSENTER および SYSEXIT オペコードは、通常の call/ret オペコードとして動作しません。

SYSENTER と SYSEXIT は両方とも、事前定義されたアドレス (一方はカーネル空間、もう一方はユーザー空間) にジャンプします。

具体的には、SYSEXIT は ntdll の KiFastSystemCallRet にジャンプするように設定されています。通常、ntdll にエクスポートされたシステム プロシージャは、SYSENTER を直接使用する代わりに、KiFastSystemCall を呼び出します。ntdll の KiFastSystemCall と KiFastSystemCallRet を見てみましょう。

KiFastSystemCall:     mov edx, esp
                      sysenter
KiFastSystemCallRet:  retn

あなたのコードは、システム プロシージャがカーネルから RETN 命令に戻ることになります。つまり、arg3 にあるアドレスに戻ります。user32 と gdi32 をロードすると何かが変わる理由がわかりません。おそらく arg3 の値に関係しているのでしょう。

とにかく、自分でカーネル システム プロシージャを呼び出す最も安全な方法は、KiFastSystemCall を使用することです。カーネル モードから戻るときの最初のオペコードは RETN になるため、コードはスタックの一番上に戻りアドレスを持つ必要があることを念頭に置いて、独自のコードを記述することもできます。

于 2014-09-05T07:05:55.547 に答える