A range of different x86/x86-64 assembly examples across Linux, macOS and Windows. I started this project after some basic Linux shellcoding and then attempting to do the same in Windows and wondering why all the tutorials were fundamentally different - instead of using direct syscalls, they all made calls through the Win32 API.
The assembly snippets also become useful for learning reverse engineering by creating minimal executable files to better understand tools and executable formats without any extra overhead generated by compilation.
in general the files can be assembled using the assembler scripts included in each sub directory.
$ ./assemble64.sh hello64
$ ./hello.out
Hello from asm
Note: do not use the file extension for the selected assembly file when running the script.
The linux examples will require binutils and nasm to be installed.
All of the examples with networking functionality use a hardcoded address of 127.0.0.1:1337 and at least one file has a hardcoded filename which will need to be modified.
The macOS examples will require nasm to be installed. I also have Xcode installed which may or may not also be a requirement.
The Windows examples require Visual studio to be installed for both the Windows SDK and use of masm and the linker. I used Visual Studio Community 2019 which is free. Note that the assembler scripts have hardcoded filepaths to my specific install of Visual Studio and will need to be modified for your specific install.
The examples which use direct syscalls worked for my version of Windows 10 1909 (build 18363.535) but may not work for other versions due to changes in syscall numbers.
Based on my limited understanding of these things, it appears that the differences in shellcoding methodology between *nix and Windows comes down to differences in architecture and what is considered a stable interface to the OS.
In *nix the syscall numbers are stable across releases and libc generally just provides wrappers to these syscalls, whereas in Windows the Win32 API as exported across the standard DLLs is considered to be the stable interface to the OS, with syscall numbers changing between versions.
This means that for shellcode to reliably work across Windows versions it is easier to interface with the Win32 API than use direct syscalls.