2

For educational purposes, I am trying to create a (32-bit) exe on Windows from assembly code that does not rely on the standard C library or Windows DLLs.

I can create a program that starts to run (and that I am able to debug with gdb) however I am not sure how to cleanly exit the program. All tutorials either link to the standard C library and define a main function or use the ExitProcess WinAPI call which is defined in a DLL.

On 32-Bit Linux, I'd use the int 0x80 instruction with the exit syscall. Apparently, Windows does not meaningfully implement these interrupts.

So, is there a way to cleanly return from my program?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293
  • 2
    `ExitProcess` is defined in `Kernel32.dll` which is *always* loaded into the process. You cannot have a Win32 process without `Kernel32.dll`. – Richard Aug 08 '18 at 07:19
  • 1
    Not portably. Windows doesn't have a *stable* `int 0x??` or `sysenter` ABI. The DLLs that provide the stable ABIs do use that internally, but the call numbers and function signatures can change with different Windows versions, or even with patches. – Peter Cordes Aug 08 '18 at 07:19
  • @Richard. I understand. But how would I find the address of `ExitProcess` so that I can transfer control to it? – René Nyffenegger Aug 08 '18 at 07:23
  • Maybe a duplicate of [System Calls in windows & Native API?](https://stackoverflow.com/q/2489889). Not going to duphammer it right away, since there's also the part about trying to make a static executable (no DLLs) that @Richard says is impossible. But yes you can of make a program that invokes the kernel side of ExitProcess without going through a DLL, if you reverse engineer or look up the call numbers for a specific Windows version. – Peter Cordes Aug 08 '18 at 07:24
  • Found an exact duplicate that does mention the `int 0x2e` ABI used on NT/2000 in 32-bit mode, and `sysenter` on XP and later if CPUs support it. And with a link in the question to http://j00ru.vexillium.org/ntapi_64/, which lists the call numbers and params for various Windows versions. For 32-bit: https://j00ru.vexillium.org/syscalls/nt/32/ – Peter Cordes Aug 08 '18 at 07:31
  • @Richard - *kernel32.dll* not always load to process. simply example - *smss.exe* – RbMm Aug 08 '18 at 07:43
  • *But how would I find the address of ExitProcess so that I can transfer control to it?* - why not use link with *kernel32.lib* ? – RbMm Aug 08 '18 at 07:45
  • @RbMm 1) because I believe that I can learn more about assembly and Windows in general if I try to do certain things in a "non standard" way. I don't mean to put the result of this question into productive use, it's just for my own educational improvement. 2) It seems somehow pointless to link to a library that is mapped into my address space anyway. – René Nyffenegger Aug 08 '18 at 07:52
  • 1
    @RbMm OK, I should have said *user* process,. The kernel has "processes" with different rules (eg. `ssms` doesn't load any images ... but clearly there is code there). – Richard Aug 08 '18 at 07:52
  • 1
    @Richard - more correct say gui (`IMAGE_SUBSYSTEM_WINDOWS_GUI`) and console (`IMAGE_SUBSYSTEM_WINDOWS_CUI`) subsystem always load *kernel32.dll* but `IMAGE_SUBSYSTEM_NATIVE` does not. *smss.exe* example of this - only *ntdll.dll* loaded here. exist so called boot execute apps, which use this subsystem. example *chkdsk.exe* – RbMm Aug 08 '18 at 08:05
  • @RbMm: I can reopen this question if you want to post an answer about avoiding having DLLs linked at all. I guess you can't make a Windows equivalent of a static executable (no dynamic linker at all)? Let me know if you want to expand that comment into an answer. – Peter Cordes Aug 08 '18 at 08:08
  • @RenéNyffenegger - use *kernel32.lib* in build, for have static import from *kernel32.dll* not point less from my view. if you build gui or console exe, *kernel32.dll* anyway will be loaded to your process, but if you import from it - loader auto resolve import functions for you. otherwise you will be need do this yourself. you really need declare `extern __imp__ExitProcess@4 : DWORD` in your asm (for x86) and `call [__imp__ExitProcess@4]`. and add `kernel32.lib` to linker input – RbMm Aug 08 '18 at 08:10
  • 1
    @PeterCordes - in windows not hard (for me) build executable which have no import at all. possible yourself resolve import functions. exist different ways do this. even possible use delay load imports (for this need little patch standard *link.exe*). but question here - not use import table in exe or not call any api from windows dlls at all. second is much more restriction and not portable – RbMm Aug 08 '18 at 08:15
  • *does not rely on Windows DLLs.* - what this is mean ? **1** not import from any DLL in exe or **2** not call any api from DLL ? the **1** is possible - we can found addresses of needed api yourself in runtime and call it. the **2** - not call any windows DLL code at all - absolute another. in practice impossible (we restrict self may be to only system (Zw) calls and even in this case not portable ) – RbMm Aug 08 '18 at 08:21

1 Answers1

1

Windows has some system calls like all (traditional) operating systems. Read Operating Systems: Three Easy Pieces to learn more about OS.

But Microsoft Windows is proprietary software. The system call interface is undocumented by Microsoft, could be specific to a particular version, and you need time-consuming efforts to reverse engineer it. See also this.

People have already done the reverse engineering and published the results at https://j00ru.vexillium.org/syscalls/nt/32/.

So making system calls directly is possible, but very unpractical except as a learning experiment on your own desktop (not for executables you distribute).

The other part of what you want, avoiding having any DLLs loaded/mapped into your process's virtual address space, may actually be impossible.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    People have published the results of such reverse engineering. I think there's a link in one of the SO Q&As about invoking Windows system calls directly. So it's easily possible in practice, but only if you want to make an executable that only works on *your* desktop, not necessarily someone else's. The part of this question about trying to make a static executable that doesn't even link DLLs at all is interesting. IDK if Windows executables can do that, or if the DLL would still get mapped into their virtual address space even if they avoided calling any functions from it. – Peter Cordes Aug 08 '18 at 07:26