ntdll.dllのみに依存するCプログラムを作成
Windowsでは、Windows.hをインクルードすると、KERNEL32.dllにある低レイヤーの関数を使えるようになります。しかしながら、KERNEL32.dllの下にはntdll.dllというさらに低レイヤーなDLLが存在します。このDLLが提供する関数を利用したプログラムをビルド & 実行する方法を調査・学習したので共有します。
1 開発環境
| 用途 | 種類 |
|---|---|
| OS | Windows 11 |
| コンパイラ | MinGW-w64 (gcc) |
| 依存ファイルの調査 | Developer PowerShell for VS 2022 (dumpbin)MinGW-w64 ( objdump) |
MinGW-w64がまだない方は、次の記事を参考にインストールしてみてください。
2 プログラム
ntdll.dllに実装がある次の2つの関数を呼び出し、それ以外に依存関係のないプログラムを作成します。
NtDelayExecutionNtTerminateProcess
_start.cというファイル名で次のプログラムを作成します。このプログラムはSleep関数を呼び出す代わりに、ntdll.dllが提供するNtDelayExecution関数を呼び出して、Sleep関数のようなものを自分で書いた例です。
// declare types
typedef long NTSTATUS;
typedef unsigned long ULONG;
typedef unsigned char BOOLEAN;
typedef long long LONGLONG;
typedef void* HANDLE;
typedef union _LARGE_INTEGER {
struct {
ULONG LowPart;
long HighPart;
};
LONGLONG QuadPart;
} LARGE_INTEGER;
NTSTATUS __stdcall NtDelayExecution(
BOOLEAN Alertable,
LARGE_INTEGER* DelayInterval
);
NTSTATUS __stdcall NtTerminateProcess(
HANDLE ProcessHandle,
NTSTATUS ExitStatus
);
// main関数の代わりのエントリーポイント
void _start(void) {
LARGE_INTEGER interval;
interval.QuadPart = - (LONGLONG)1000 * 10000;
NtDelayExecution(0, &interval);
NtTerminateProcess((HANDLE)-1, 0);
}
3 ビルド
次のgccのバージョンでビルドしました。
gcc --version
# 出力
# gcc (x86_64-posix-seh-rev0, Built by MinGW-Builds project) 15.2.0
# Copyright (C) 2025 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
次のコマンドでビルドします。キャレット^はcmd.exeの行継続コマンドです。
gcc _start.c ^
-nostdlib ^
-Wl,--entry=_start ^
-lntdll ^
-o _start.exe
それぞれのオプションの意味です。
| オプション | 意味 |
|---|---|
-nostdlib |
標準ライブラリを一切リンクしない |
-Wl,--entry=_start |
gccからリンカ(ld)へ関数エントリポイントの通知 |
-lntdll |
ntdll.dllのインポートライブラリをリンク |
4 実行
_start.exe
# 実行結果としては何も表示されません。
5 実行ファイルの依存関係
次に実行ファイル_start.exeの依存関係をVisual Studioのdumpbinコマンドで確認します。dumpbinコマンドはDeveloper PowerShell for VS 2022のターミナル上で実行できます。このターミナルはVisual Studioのインストールが必要です。
dumpbin /dependents _start.exe
# 出力
# Microsoft (R) COFF/PE Dumper Version 14.44.35222.0
# Copyright (C) Microsoft Corporation. All rights reserved.
# Dump of file _start.exe
#
# File Type: EXECUTABLE IMAGE
#
# Image has the following dependencies:
#
# ntdll.dll
#
# Summary
#
# 1000 .idata
# 1000 .pdata
# 1000 .rdata
# 1000 .text
# 1000 .xdata
Image has the following dependencies:のところに、ntdll.dllのみ表示されました。つまりこの実行ファイルはKERNEL32.dllに依存しない実行ファイルです。
おまけ
インポートライブラリ
リンカはビルド時にntdll.dllだけでなく、使用する関数の実装がファイルのどの位置にあるか特定するため、インポートライブラリの情報が必要です。ntdll.dllのインポートライブラリはlibntdll.aというファイルであり、MinGW-w64をインストールしたフォルダにあります。
objdump -t "インストールパス"\MinGW\mingw64\x86_64-w64-mingw32\libntdll.a > file.txt
SYMBOL TABLE:
[ 0](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .text
[ 1](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .data
[ 2](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .bss
[ 3](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .idata$7
[ 4](sec 5)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .idata$5
[ 5](sec 6)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .idata$4
[ 6](sec 7)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x0000000000000000 .idata$6
[ 7](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 NtDelayExecution
[ 8](sec 5)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 __imp_NtDelayExecution
[ 9](sec 0)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 _head_lib64_libntdll_a
⚠️kernel32.dllとntdll.dllの解析⚠️
次の場所に2つのDLLがあります。これらのファイルが破損するとWindows上のアプリのほとんどが起動しなくなるため、作業フォルダにコピーしてから、そのコピーされたdllを解析することを強く推奨します。
C:\Windows\System32\kernel32.dll
C:\Windows\System32\ntdll.dll
dumpbin /dependents /exports kernel32.dll > kernel32.dll.txt
# 出力 >> ファイル kernel32.dll.txt が作成される
dumpbin /dependents /exports ntdll.dll > ntdll.dll.txt
# 出力 >> ファイル ntdll.dll.txt が作成される
dumpbinコマンドのオプション
-
/dependents- 依存関係のあるDLLファイル名一覧を表示します
-
/exports- 実行ファイル・DLLファイルが持つ関数一覧を表示します
kernel32.dllの解析
Dump of file kernel32.dll
File Type: DLL
Image has the following dependencies:
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-2-2.dll
ntdll.dll
KERNELBASE.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-3.dll
############# 省略 #############
Image has the following delay load dependencies:
ext-ms-win-oobe-query-l1-1-0.dll
ext-ms-win-packagevirtualizationcontext-l1-1-0.dll
RPCRT4.dll
############# 省略 #############
Section contains the following exports for KERNEL32.dll
00000000 characteristics
2E35230E time date stamp
0.00 version
1 ordinal base
1671 number of functions
1671 number of names
ordinal hint RVA name
1 0 AcquireSRWLockExclusive (forwarded to NTDLL.RtlAcquireSRWLockExclusive)
2 1 AcquireSRWLockShared (forwarded to NTDLL.RtlAcquireSRWLockShared)
3 2 00018A90 ActivateActCtx
4 3 00014750 ActivateActCtxWorker
############# 省略 #############
197 C4 00020420 CreateDirectoryA
198 C5 00063F50 CreateDirectoryExA
199 C6 0003AF50 CreateDirectoryExW
210 D1 00020440 CreateFile2
211 D2 00020450 CreateFileA
260 103 000144B0 CreateThread
813 32C 00010D60 GetTickCount
814 32D 00010CE0 GetTickCount64
1461 5B4 00018650 Sleep
1553 610 000203D0 WaitForSingleObject
上記の結果より、次のことが確認できます。
-
kernel32.dllはntdll.dllに依存している - 以下の関数は
kernel32.dllに実装があるCreateDirecotryACreateFileACreateThreadGetTickCountSleepWaitForSingleObject
ntdll.dllの解析
Dump of file ntdll.dll
File Type: DLL
Section contains the following exports for ntdll.dll
00000000 characteristics
BCED4B82 time date stamp
0.00 version
8 ordinal base
2486 number of functions
2485 number of names
ordinal hint RVA name
9 0 0000E6F0 A_SHAFinal
10 1 0000E820 A_SHAInit
11 2 0000E860 A_SHAUpdate
12 3 000EB470 AlpcAdjustCompletionListConcurrencyCount
13 4 0007E280 AlpcFreeCompletionListMessage
14 5 000EB4A0 AlpcGetCompletionListLastMessageInformation
15 6 000EB4C0 AlpcGetCompletionListMessageAttributes
############# 省略 #############
337 148 0009F9E0 NtDelayExecution
############# 省略 #############
653 284 0009F8E0 NtTerminateProcess
############# 省略 #############
2421 96C 00092B10 mbstowcs
2422 96D 00092BE0 memchr
2423 96E 00092C20 memcmp
2424 96F 000A5F00 memcpy
2425 970 0009A230 memcpy_s
2426 971 000A5F00 memmove
2427 972 0009A2D0 memmove_s
2428 973 00131010 memset
2429 974 000A51A0 pow
2430 975 00092D00 qsort
2431 976 000930A0 qsort_s
2432 977 00091F90 sin
2433 978 00093470 sprintf
2434 979 0009A330 sprintf_s
2435 97A 00093500 sqrt
2436 97B 00093610 sscanf
2437 97C 0009A3B0 sscanf_s
2438 97D 00093720 strcat
2439 97E 0009A410 strcat_s
2440 97F 000938A0 strchr
2441 980 000938F0 strcmp
2442 981 000937E0 strcpy
2443 982 0009A4A0 strcpy_s
2444 983 000939B0 strcspn
2445 984 00093A70 strlen
2446 985 00093B40 strncat
2447 986 0009A530 strncat_s
2448 987 00093D00 strncmp
2449 988 00093DE0 strncpy
2450 989 0009A630 strncpy_s
2451 98A 00093F60 strnlen
2452 98B 00093F80 strpbrk
2453 98C 00094030 strrchr
2454 98D 00094070 strspn
2455 98E 00094140 strstr
2456 98F 0009A730 strtok_s
2457 990 000943D0 strtol
2458 991 00094430 strtoul
2459 992 000902C0 swprintf
2460 993 0009A8A0 swprintf_s
2461 994 0009A930 swscanf_s
2462 995 00094470 tan
2463 996 00094910 tolower
2464 997 00094950 toupper
2465 998 000949C0 towlower
2466 999 000949F0 towupper
############# 省略 #############
2484 9AB 0009ABD0 wcsncpy_s
2485 9AC 00094C50 wcsnlen
2486 9AD 00094C80 wcspbrk
2487 9AE 00094CC0 wcsrchr
2488 9AF 00094D00 wcsspn
2489 9B0 00094D50 wcsstr
2490 9B1 0009ACE0 wcstok_s
2491 9B2 00094FE0 wcstol
2492 9B3 00095080 wcstombs
2493 9B4 00095040 wcstoul
8 0007F650 [NONAME]
############# 省略 #############
上記の結果を見ると、ntdll.dllはどのDLLファイルにも依存していないことがわかります。またC言語でよく使うような関数名memcpy, memsetなどが確認できます。これらは#include <string.h>によって読み込まれるアプリケーションの利用する関数とは全く別物で、OS自身が利用する関数だと思われます。
