Last active
May 25, 2025 20:16
-
-
Save odzhan/8e3801f4dfb1a1851d79cc8a5bca96c3 to your computer and use it in GitHub Desktop.
Writing Tiny Executables in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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); | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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