HelloAssembly: The smallest possible complete Windows application (2021)
github.com
github.com
Set /HEAP:4096,4096 and /STACK:65536,4096, write yourself a simple 100 line growable arena implementation, use that, avoid the heap entirely. Very quick and easy way to get a real windows program up and running that uses about 500kb of commit at baseline.
You end up with only ntdll.dll, kernelbase.dll, and kernel32.dll loaded. Trying to eliminate any of these becomes pretty painful and you venture into the territory of weird tricks that are expensive to maintain.
Dave's approach is a fun exercise though.
Windows 10 makes it literally impossible to write something that uses low memory and uses an actual window.
One trick I know of to make user32 a bit more lightweight is to call ImmDisableIme prior to creating your first window. This disables a lot of the TSF integration, which is notably quite slow. Not sure if it impacts memory footprint but worth a try. It of course does what the name says and disables IME support, so not a viable option if you have users who need IME
It's a bit like 'smallest hello world in assembly' but the code is just setting up the calling convention and then passing the zero-terminated character string into `write`. Cool, but that could be done a bit more straightforwardly in C, too. A lot of assembly (including in the linked repository) is book-keeping for the platform's calling convention.
Since the low-level Windows kernel API is undocumented and non-public, using these system DLLs is your only option on Windows.
It's just like linking against libc.so on any POSIX systems.
but also why would you, not much point except for very niche functionality
I mean officially. Yes, you can find some on the internet, but nothing on the official MSDN.
> but also why would you, not much point except for very niche functionality
Exactly. Using system DLL API is backward and forward compatible, and just as standardized and well-documented as the POSIX API. I see no problem relying on it.
(Sidenote: as a bonus, MSDN is surprisingly good, understandable, well organized, lots of examples. I rarely say this, but well done MS, that's how a dev doc should be.)
> I mean officially. Yes, you can find some on the internet, but nothing on the official MSDN.
It seems that changed. https://learn.microsoft.com/en-us/windows/win32/devnotes/ntq... says
[This function may be changed or removed from Windows without further notice.]
but it on the official MSDN site, and it does document a call in Ntdll.dll.It’s easy to find many more examples such as https://learn.microsoft.com/en-us/windows/win32/api/winternl..., so I don’t think that’s an accident.
> If the call to this function occurs in user mode, you should use the name "NtMapViewOfSection" instead of "ZwMapViewOfSection".
Does it? What's FILE_BASIC_INFORMATION? Link gives me 404. How do you replace kernel32 API with this?
> It’s easy to find many more examples such as https://learn.microsoft.com/en-us/windows/win32/api/winternl..., so I don’t think that’s an accident.
Again, how do you replace kernel32 API with this?
> In addition a bunch are documented in the driver docs, such as https://learn.microsoft.com/en-us/windows-hardware/drivers/d....
This has nothing to do with ntdll at all.
I still don't get it, what's wrong with using the user32 and kernel32 APIs? It's stable, well-documented, and is the official API on Windows. So why not use it?
I can only wonder where `NtMapViewOfSection` could be exported from...
> For calls from kernel-mode drivers, the NtXxx and ZwXxx versions of a Windows Native System Services routine can behave differently in the way that they handle and interpret input parameters.
How "differently" exactly? That's undocumented. And lots of other small (but very important) details are undocumented as well.
2072 80F 001612B0 ZwMapViewOfSection
2073 810 00163160 ZwMapViewOfSectionEx
> PS C:\Program Files\Microsoft Visual Studio\18\Community> dumpbin.exe /EXPORTS C:\Windows\System32\ntdll.dll | rg NtMapViewOfSection 425 1A0 001612B0 NtMapViewOfSection
426 1A1 00163160 NtMapViewOfSectionEx
> How "differently" exactly? That's undocumented.https://learn.microsoft.com/en-us/windows-hardware/drivers/k...
It just causes one big headache that a DLL can't simply return a pointer and have the caller use "free", because malloc/free can be incompatible across modules.
This just led to the COM standard, featuring reference-counted objects that don't care what underlying way was used to allocate the memory. For the situations where you do need memory buffers, COM enforces the use of CoTaskMemAlloc/CoTaskMemFree.
PS. Honest take :)
“Runs a Windows message loop Has a title bar, minimize, maximize, and close buttons, which all work as expected Has a system menu with the same Paints the background and some text centered in the middle, equal to or larger than "Dave's Tiny App"”
That Linux program:
“Let’s take an incredibly simple program, one that does nothing but return a number back to the operating system”
See https://archive.is/w01DO#selection-265.0-265.44 for a fairer comparison (97/133 bytes)
A copy can be found at https://github.com/Dwedit/NoCopilotKey/blob/main/stub.bin
FA F4
That's CLI HLT, which effectively deadlocked the machine. Had to be saved as a .com fule obviously, not as an .exe.And wouldn't a single instruction such as NOP or HLT be simply 1 byte?
> Somewhat more meaningful was "INT 19h" (CD 19) ...
I seem to remember the smallest MS-DOS program to be CD 20h saved as a `.com`.
Putting the search terms "Windows" and "assembly language" turns up all sort of books. The one that got me to initially explore the topic (from 1993).... [0]
For a more up to date treatment of assembly and windows.... comes with source code for the IDE also. Ray Seyfarth's book [1].
[0] Windows Assembly Language & Systems Programming: Object Oriented & Low-Level Systems Programming in Assembly Language for Windows 3.X
[1] Introduction to 64 Bit Windows Assembly Language Programming: Fourth Edition ISBN-13: 978-1543138849, ISBN-10: 1543138845
... the days! :)