インポートなしでアセンブリで Windows API 呼び出しを行うことに (教育的な演習として) 興味があったので、NtDll!NtCreateFile が行うことを行うために、次の FASM アセンブリを作成しました。これは私の 64 ビット バージョンの Windows (Win10 1803 バージョン 10.0.17134) での大まかなデモであり、呼び出し後にクラッシュしますが、syscall の戻り値はゼロなので成功しています。すべてが Windows x64 呼び出し規約に従ってセットアップされ、次にシステム コール番号が RAX に読み込まれ、呼び出しを実行するための syscall アセンブリ命令になります。私の例ではファイル c:\HelloWorldFile_FASM が作成されるため、「管理者として」実行する必要があります。
format PE64 GUI 4.0
entry start
section '.text' code readable executable
start:
;puting the first four parameters into the right registers
mov rcx, _Handle
mov rdx, [_access_mask]
mov r8, objectAttributes
mov r9, ioStatusBlock
;I think we need 1 stack word of padding:
push 0x0DF0AD8B
;pushing the other params in reverse order:
push [_eaLength]
push [_eaBuffer]
push [_createOptions]
push [_createDisposition]
push [_shareAcceses]
push [_fileAttributes]
push [_pLargeInterger]
;adding the shadow space (4x8)
; push 0x0
; push 0x0
; push 0x0
; push 0x0
;pushing the 4 register params into the shadow space for ease of debugging
push r9
push r8
push rdx
push rcx
;now pushing the return address to the stack:
push endOfProgram
mov r10, rcx ;copied from ntdll!NtCreateFile, not sure of the reason for this
mov eax, 0x55
syscall
endOfProgram:
retn
section '.data' data readable writeable
;parameters------------------------------------------------------------------------------------------------
_Handle dq 0x0
_access_mask dq 0x00000000c0100080
_pObjectAttributes dq objectAttributes ; at 00402058
_pIoStatusBlock dq ioStatusBlock
_pLargeInterger dq 0x0
_fileAttributes dq 0x0000000000000080
_shareAcceses dq 0x0000000000000002
_createDisposition dq 0x0000000000000005
_createOptions dq 0x0000000000000060
_eaBuffer dq 0x0000000000000000 ; "optional" param
_eaLength dq 0x0000000000000000
;----------------------------------------------------------------------------------------------------------
align 16
objectAttributes:
_oalength dq 0x30
_rootDirectory dq 0x0
_objectName dq unicodeString
_attributes dq 0x40
_pSecurityDescriptor dq 0x0
_pSecurityQualityOfService dq securityQualityOfService
unicodeString:
_unicodeStringLength dw 0x34
_unicodeStringMaxumiumLength dw 0x34, 0x0, 0x0
_pUnicodeStringBuffer dq _unicodeStringBuffer
_unicodeStringBuffer du '\??\c:\HelloWorldFile_FASM' ; may need to "run as adinistrator" for the file create to work.
ioStatusBlock:
_status_pointer dq 0x0
_information dq 0x0
securityQualityOfService:
_sqlength dd 0xC
_impersonationLevel dd 0x2
_contextTrackingMode db 0x1
_effectiveOnly db 0x1, 0x0, 0x0
Ntdll!NtCreateFile のドキュメントを使用し、カーネル デバッガーを使用して多くのパラメーターを参照およびコピーしました。
__kernel_entry NTSTATUS NtCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);
Windows でアセンブリ プログラミングを行っている場合、手動の syscall は行いません。 NTDLL とネイティブ API を使用してそれを行います。
ネイティブ API は、単なるカーネル モード側のラッパーです。正しい API のシステムコールを実行するだけです。
質問全体が冗長になるように、手動で syscall する必要はありません。
Linux syscall コードは変更されませんが、Windows は変更されます。そのため、追加の抽象化レイヤー (別名 NTDLL) を介して作業する必要があります。
編集:
また、アセンブリ レベルで作業している場合でも、Win32 API に完全にアクセスできます。最初から NT API を使用する必要はありません。アセンブリ プログラムでは、インポート、エクスポートなどはすべて正常に機能します。
EDIT2:
本当に手動で syscall を実行したい場合は、関連する Windows バージョンごとに NTDLL をリバースし、(PEB を介して) バージョン検出を追加し、呼び出しごとに syscall ルックアップを実行する必要があります。
しかし、それはばかげているでしょう。 NTDLL には理由があります。
リバース エンジニアリングの部分は既に行われています。各 Windows カーネルのシステム コール番号の表については、https://j00ru.vexillium.org/syscalls/nt/64/ を参照してください。 (以降の行は、Windows 10 のバージョン間でも変更されることに注意してください。) 繰り返しますが、これは、自分のマシンで asm や Windows 内部について詳しく学ぶための個人使用のみの実験以外では、悪い考えです。他の人に配布するコードにシステム コールをインライン化しないでください。
Windows syscall 規則について知っておく必要があるもう 1 つのことは、私が理解しているように、ビルド プロセスの一部として syscall テーブルが生成されるということです。これは、それらが単純に変更できることを意味します-誰もそれらを追跡しません.誰かがリストの一番上に新しいものを追加したとしても、それは問題ではありません。 NTDLL は引き続き機能するため、NTDLL を呼び出す他のすべてのユーザーは引き続き機能します。
システムコール (int または sysenter) を実行するために使用されるメカニズムでさえ、固定されておらず、過去に変更されています。マシンの CPU。
Windows システム コールは、kernel32.dll
などのシステム DLL を呼び出すことによって実行されます。 または gdi32.dll
、通常のサブルーチン呼び出しで行われます。 OS 特権レイヤーにトラップするメカニズムは文書化されていませんが、DLL は kernel32.dll
のようなものなので問題ありません。
システム コールによって、CreateProcess()
のような文書化された Windows API エントリ ポイントを参照しています。 または GetWindowText()
.通常、デバイス ドライバーは Windows DDK とは異なる API を使用します。