Objective

See the Windows API layers on your own PC. You will find ntdll.dll, see which programs use it, call a real Win32 function yourself, translate error numbers, and (optionally) watch a program's file operations live in Process Monitor. You only look and call harmless functions. Nothing here changes a setting, injects code or hooks anything.

Time: 25–30 minutes
You need: A Windows PC. PowerShell and Command Prompt are enough. One free optional tool is named in Part 6.

What to Open

ToolHow to open it
PowerShellPress Win, type PowerShell, press Enter (normal, not admin)
Command PromptPress Win, type cmd, press Enter
Task ManagerPress Ctrl + Shift + Esc
NotepadPress Win, type Notepad, press Enter (used in Part 6)

Part 1: Find the Native API Layer

In Command Prompt:

dir C:\Windows\System32\ntdll.dll
dir C:\Windows\System32\kernel32.dll
dir C:\Windows\System32\kernelbase.dll
dir C:\Windows\System32\user32.dll
  1. Size of ntdll.dll: ________________
  2. Size of kernelbase.dll: ________________
  3. Date of ntdll.dll: ________________

Now ask PowerShell for the version:

(Get-Item C:\Windows\System32\ntdll.dll).VersionInfo.FileVersion
  1. ntdll.dll version: ________________

Is ntdll.dll bigger or smaller than kernelbase.dll? Section 3.5 said it is a thin layer.

Part 2: Who Uses These DLLs?

In Command Prompt:

tasklist /m ntdll.dll
  1. Roughly how many programs are listed? ________________

Now try the other layers:

tasklist /m kernel32.dll
tasklist /m user32.dll
tasklist /m gdi32.dll
  1. Are there programs that use ntdll.dll but not user32.dll? (Hint: background services.) ________________

Also in PowerShell, look inside your own PowerShell process:

Get-Process -Id $PID | Select-Object -ExpandProperty Modules | Where-Object { $_.ModuleName -match "ntdll|kernel32|kernelbase|user32" } | Select-Object ModuleName, FileName
  1. Which of the four modules did you find in PowerShell? ________________

(tasklist /m can be slow, and the exact output depends on your PC. Some protected programs may not list their modules.)

Part 3: Which Module Owns a Command?

PowerShell's Get-Command tells you where a command lives:

Get-Command Get-Process | Select-Object Name, Source
Get-Command notepad.exe | Select-Object Name, Source
  1. What is the Source of Get-Process? ________________
  2. What is the full path of notepad.exe? ________________

Part 4: Call a Win32 Function Yourself (Safe)

This calls GetTickCount64 from kernel32.dll. It only reads the clock. Type both lines:

Add-Type -MemberDefinition '[DllImport("kernel32.dll")] public static extern ulong GetTickCount64();' -Name Native -Namespace Win32
[Win32.Native]::GetTickCount64()
  1. Milliseconds since Windows started: ________________
  2. Convert to hours (divide by 3,600,000): ________________

Run the Add-Type line only once per PowerShell window. If you run it again you will see a "type already exists" message. That is harmless. Just run the second line again.

Compare with Windows' own idea of uptime:

(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
  1. Is that uptime close to your number from step 11? ________________

(If you use Fast Startup, "boot time" can look different from the tick count. That is normal.)

Optional: a harmless pop-up from user32.dll. This shows a message box through the Win32 window API:

Add-Type -MemberDefinition '[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int MessageBoxW(IntPtr h, string text, string caption, uint type);' -Name Msg -Namespace Win32
[Win32.Msg]::MessageBoxW([IntPtr]::Zero, "Hello from user32.dll", "API Lab", 0)

Click OK. That one line travelled application → user32.dll → the window system in the kernel (Section 5.9).

Measure the cost of calls. Measure-Command times a piece of work:

Measure-Command { 1..100000 | ForEach-Object { [Win32.Native]::GetTickCount64() | Out-Null } }
  1. TotalMilliseconds: ________________ (the exact figure depends on your PC)

Each loop passes through PowerShell, Win32 and sometimes the kernel. It shows that calls are cheap, but not free.

Part 5: Translate Error Numbers (Section 2.6)

In Command Prompt:

net helpmsg 2
net helpmsg 3
net helpmsg 5
net helpmsg 32
net helpmsg 87
  1. Write what each number means: ________________

Now trigger a real error safely, and read it. In PowerShell:

Get-Content C:\this-file-does-not-exist.txt
  1. What message do you get? Which of the five numbers above does it match? ________________

Part 6 (Optional): Watch the Calls Live with Process Monitor

Process Monitor is a free tool from Microsoft Sysinternals. It is not part of Windows, so download it only from the official Microsoft Sysinternals site (search "Sysinternals Process Monitor"). It shows each file, registry and process operation a program asks the kernel to do. It only watches. It changes nothing.

  1. Start Process Monitor (it asks for administrator permission, because it needs to watch the kernel).
  2. Process Monitor starts capturing at once. Press Ctrl + E to stop capture, then Ctrl + X to clear the list.
  3. Choose Filter → Filter.... Add: Process Name is notepad.exe, click Add, then OK.
  4. Open Notepad and type a few words.
  5. Press Ctrl + E to start capture again. In Notepad choose File → Save As, name it api-lab.txt and save it in Documents. Then press Ctrl + E to stop capture.
  6. Look for rows whose Operation is CreateFile, WriteFile and CloseFile, with Path ending api-lab.txt.

What the columns mean:

ColumnMeaning
OperationThe file or registry action (CreateFile, ReadFile, RegOpenKey ...)
PathWhat it acted on
ResultSUCCESS, NAME NOT FOUND, ACCESS DENIED ... (NTSTATUS-style names, Section 3.4)
DetailExtra facts such as access type
  1. Which Operation names did you see for api-lab.txt? ________________
  2. Find a row with a Result other than SUCCESS (such as NAME NOT FOUND). What was the path? ________________

See the layer stack. Double-click a CreateFile row and open the Stack tab. You should see frames from top to bottom such as ntdll.dll, KERNELBASE.dll and a Notepad or user32/comdlg32 frame. (Names may show as plain addresses if symbols are not set up. That is fine.)

  1. Name two DLLs in the stack: ________________

When you are done, press Ctrl + E to stop capturing and close Process Monitor.

Windows tip. The operation name CreateFile is shown by Process Monitor for both creating and opening files. It is the I/O request at the kernel level, which your program started through CreateFileW and NtCreateFile.

What Should Happen

  • Part 1 shows ntdll.dll as a modest-sized file in System32.
  • Part 2 shows ntdll.dll in almost every process, and your PowerShell loads all four DLLs.
  • Part 4 gives a tick count that matches your uptime.
  • Part 5 gives plain-English text for each error number.
  • Part 6 shows the file operations and the stack of layers from Section 5.

Interpretation Guide

What you seeWhat it means
ntdll.dll in nearly every processIt is the lowest user-mode layer, used by all programs
Some processes list ntdll but not user32Background programs with no windows do not need the window DLL
Get-Process Source is Microsoft.PowerShell.ManagementA PowerShell module, not a DLL in System32. PowerShell itself calls Win32 underneath
GetTickCount64 matches uptimeYou really called a Win32 function in kernel32.dll
ACCESS DENIED in Process MonitorThe kernel's security check refused. A program would see error 5
NAME NOT FOUND in Process MonitorThe path did not exist. A program would see error 2 or 3
Stack shows ntdll.dll below KERNELBASE.dllThe chain from Section 5: Win32 calls Native

Follow-Up Questions

  1. In Part 6, which DLL sits closest to the kernel in the stack, KERNELBASE.dll or ntdll.dll?
  2. Why does Get-Process have a Source that is a PowerShell module, and not a plain Win32 name?
  3. Why did Process Monitor show a NAME NOT FOUND result even though nothing was wrong?
  4. If a program can only see error number 5, how would you find out the kernel's own status code?
  5. Name three facts from this lab that you could not have learned from just using Notepad.