Skip to content

Instantly share code, notes, and snippets.

@odzhan
Last active May 25, 2025 20:16
Show Gist options
  • Save odzhan/8e3801f4dfb1a1851d79cc8a5bca96c3 to your computer and use it in GitHub Desktop.
Save odzhan/8e3801f4dfb1a1851d79cc8a5bca96c3 to your computer and use it in GitHub Desktop.
Writing Tiny Executables in C
/**
Compile with your C console project.
*/
#include <stdio.h>
#include <windows.h>
#define __UNKNOWN_APP 0
#define __CONSOLE_APP 1
#define __GUI_APP 2
int main(int, char **, char **);
int wmain(int, wchar_t **, wchar_t **);
typedef void (__cdecl * new_handler) ();
typedef struct _startupinfo_t {
int newmode;
new_handler newh;
} _startupinfo;
int __getmainargs(int *argc, char ***argv, char ***penv, int glob, _startupinfo *info);
int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***penv, int glob, _startupinfo *info);
#ifndef _UNICODE
void mainCRTStartup(void)
#else
void wmainCRTStartup(void)
#endif
{
_startupinfo si = {0};
int argc, ret;
__set_app_type(__CONSOLE_APP);
#ifndef _UNICODE
char **argv = NULL;
char **envp = NULL;
__getmainargs(&argc, &argv, &envp, 0, &si);
ret = main(argc, argv, envp);
#else
wchar_t **argv = NULL;
wchar_t **wenvp = NULL;
__wgetmainargs(&argc, &wargv, &wenvp, 0, &si);
ret = wmain(argc, wargv, wenvp);
#endif
ExitProcess(ret);
}
#!/usr/bin/env python3
"""
dll2def.py - Create a module-definition (.def) file from a Windows DLL.
Usage
-----
python dll2def.py library.dll [optional_output.def]
The script writes a .def file next to the DLL (or to the explicitly
supplied output path) and prints a short summary.
Requires
--------
pip install pefile
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
import pefile
def build_def_text(dll_path: Path) -> str:
"""Return the complete .def file text for *dll_path*."""
pe = pefile.PE(dll_path.as_posix(), fast_load=True)
pe.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_EXPORT']])
if not hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
raise ValueError(f"'{dll_path.name}' has no export table.")
lines: list[str] = []
lines.append(f'LIBRARY "{dll_path.name}"')
lines.append('EXPORTS')
for sym in pe.DIRECTORY_ENTRY_EXPORT.symbols:
# Symbol names can be None (export-by-ordinal only)
name = sym.name.decode(errors='replace') if sym.name else f'#{sym.ordinal}'
lines.append(f' {name}')
# A final newline keeps MSVC's LIB.EXE happy
return '\n'.join(lines) + '\n'
def parse_args(argv: list[str]) -> argparse.Namespace:
p = argparse.ArgumentParser(description="Generate a .def file from a DLL's export table.")
p.add_argument('dll', type=Path, help='Path to the input DLL')
p.add_argument('out', nargs='?', type=Path,
help='Optional .def output path (default: DLL name with .def extension)')
return p.parse_args(argv)
def main(argv: list[str] | None = None) -> None:
args = parse_args(argv or sys.argv[1:])
dll_path: Path = args.dll.expanduser().resolve()
if not dll_path.is_file():
sys.exit(f"Error: '{dll_path}' is not a file.")
out_path: Path = (args.out or dll_path.with_suffix('.def')).expanduser().resolve()
try:
def_text = build_def_text(dll_path)
except Exception as exc:
sys.exit(f"Failed to read exports: {exc}")
out_path.write_text(def_text, encoding='utf-8')
print(f"Wrote {out_path} ({len(def_text.splitlines()) - 2} exports)")
if __name__ == '__main__':
main()
// cl /D_NO_CRT_STDIO_INLINE /Os /O1 /GS- hello.c crt.c /link /nodefaultlib /subsystem:console msvcrt.lib kernel32.lib
#include <stdio.h>
int main(int argc, char *argv[]) {
for (int i=0; i<argc; i++) {
printf("argv[%i]: %s\n", i, argv[i]);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment