Skip to content

Instantly share code, notes, and snippets.

@gvanem
Last active April 5, 2023 07:42
Show Gist options
  • Save gvanem/d63ab3ad81883c9c5f757bb7e62a0606 to your computer and use it in GitHub Desktop.
Save gvanem/d63ab3ad81883c9c5f757bb7e62a0606 to your computer and use it in GitHub Desktop.
GNU-makefile for NPcap's NPF.sys driver
#
# GNU Makefile for the 'NPcap driver'.
# For MSVC + clang-cl, 32/64 bits.
#
# By <[email protected]> 2023.
#
TARGETS := NPcap.sys
THIS_FILE := Makefile.Windows
MAKEFLAGS += --warn-undefined-variables
USE_ASTYLE ?= 1
PYTHON ?= py -3
ifeq ($(CPU),x86)
BITS = 32
else ifeq ($(CPU),x64)
BITS = 64
else
$(error Unsupported CPU=$(CPU))
endif
export CL=
GENERATED = $(OBJ_DIR)/NPcap_hacks.h
NPF_DIR = packetWin7/npf/npf
#
# The default install location for the 'Windows Device Driver Kit' is
# alongside the user-mode Windows-Kit:
# Kernel-mode ('KM') headers under:
#
# $(WindowsSdkDir)/Include/$(WindowsSdkVer)/km
#
# and libraries under:
#
# $(WindowsSdkDir)/Lib/$(WindowsSdkVer)/km/$(CPU)
#
KM_INCDIR = $(realpath $(WindowsSdkDir))/Include/$(WindowsSdkVer)/km
KM_LIBDIR = $(realpath $(WindowsSdkDir))/Lib/$(WindowsSdkVer)/km
TOOLS_ROOT = $(realpath $(VCToolkitInstallDir))
UCRT_LIBDIR = $(realpath $(WindowsSdkDir))/Lib/$(WindowsSdkVer)/ucrt/$(CPU)
UM_LIBDIR = $(realpath $(WindowsSdkDir))/Lib/$(WindowsSdkVer)/um/$(CPU)
CRT_LIBDIR = $(TOOLS_ROOT)/lib/$(CPU)
define Usage
Usage: "make -f $(THIS_FILE) <CPU=x86|x64> CC=[cl | clang-cl] [all | clean | realclean | depend]"
Specify CC=cl - use MSVC
Specify CC=clang-cl - use clang-cl
endef
CFLAGS = -nologo -MT -Ot -GS- \
-Gz -Zi -Zo -Oy- \
-I$(KM_INCDIR) \
-I. \
-FI./$(OBJ_DIR)/NPcap_hacks.h
LDFLAGS = -nologo -verbose -incremental:no \
-map -debug -machine:$(CPU) \
-nodefaultlib:oldnames.lib \
-libpath:$(UCRT_LIBDIR) \
-libpath:$(CRT_LIBDIR)
OBJ_DIR = objects
ifeq ($(CC),cl)
_CC = $(TOOLS_ROOT)/bin/HostX86/$(CPU)/cl.exe
CFLAGS += -W4
else ifeq ($(CC),clang-cl)
#
# The 'clang-cl.bat' (on PATH) should look like this:
# @echo off
# setlocal
# set CL_32=f:\ProgramFiler\LLVM-15-32bit << install base of your 32-bit Clang
# set CL_64=f:\ProgramFiler\LLVM-15-64bit << ditto for 64-bit
# if %1. == -m32. (
# shift
# %CL_32%\bin\clang-cl.exe %*
# ) else if %1. == -m64. (
# shift
# %CL_64%\bin\clang-cl.exe %*
# ) else (
# clang-cl.exe %*
# )
#
_CC = clang-cl.bat -m$(BITS)
CFLAGS += -Wall \
-ferror-limit=5 \
-fms-compatibility
else
$(error $(Usage))
endif
vpath %.c $(NPF_DIR)
C_SOURCES = $(addprefix $(NPF_DIR)/, \
Loopback.c \
Openclos.c \
Packet.c \
Read.c \
Write.c \
win_bpf_filter.c)
C_OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(C_SOURCES:.c=.obj)))
all: $(GENERATED) $(TARGETS) epilogue
epilogue:
$(call green_msg, Welcome to $(BRIGHT_WHITE)$(TARGETS))
WDK_LIBS = $(KM_LIBDIR)/$(CPU)/fwpkclnt.lib \
$(KM_LIBDIR)/$(CPU)/ndis.lib \
$(KM_LIBDIR)/$(CPU)/wdm.lib \
$(KM_LIBDIR)/$(CPU)/wdmsec.lib \
$(UM_LIBDIR)/kernel32.lib \
$(UM_LIBDIR)/uuid.lib
SYS_LDFLAGS = -entry:DriverEntry \
-integritycheck \
-brepro \
-dependentloadflag:0x800 \
-subsystem:native
NPcap.sys: $(C_OBJECTS) $(OBJ_DIR)/npcap.res $(WDK_LIBS) | check-for-unused-libs.py
$(call link_SYS, $@, $(SYS_LDFLAGS) $^)
$(OBJ_DIR)/NPcap_hacks.h: $(THIS_FILE) | $(OBJ_DIR)
$(call generate_c, $@,$(NPcap_hacks_H))
$(OBJ_DIR):
- mkdir $@
$(OBJ_DIR)/%.obj: %.c | $(CC).args
$(call C_compile, $@, $<)
$(OBJ_DIR)/%.res: $(NPF_DIR)/%.rc
$(call make_res, $@, $<)
clean:
rm -f vc1*.pdb link.tmp link.args cl.args clang-cl.args \
NPcap.{map,pdb} cpp-filter.py check-for-unused-libs.py
rm -fr $(OBJ_DIR)
$(CC).args: $(THIS_FILE)
$(call green_msg, All CFLAGS are in $(BRIGHT_WHITE)$@)
$(call create_resp_file, $@, -c $(call put_D_CFLAGS_first, $(CFLAGS)))
realclean vclean: clean
rm -f .depend.Windows $(sort $(TARGETS) $(TARGETS:.sys=.{map,pdb,exp}))
%.i: %.c FORCE cpp-filter.py $(GENERATED) $(CC).args
$(call C_preprocess, $@, $<)
FORCE:
cpp-filter.py: $(THIS_FILE)
$(call generate_py, $@, $(CPP_FILTER_PY))
check-for-unused-libs.py: $(THIS_FILE)
$(call generate_py, $@, $(CHECK_FOR_UNUSED_LIBS_PY))
#
# GNU-make macros:
#
put_D_CFLAGS_first = $(filter -D%, $(1)) \
$(filter-out -D%, $(1))
BRIGHT_GREEN = \e[1;32m
BRIGHT_WHITE = \e[1;37m
green_msg = @echo -e "$(BRIGHT_GREEN)$(strip $(1))\e[0m"
define C_compile
$(_CC) @$(CC).args -Fo./$(strip $(1)) $(2)
@echo
endef
define link_SYS
$(call green_msg, Linking $(1))
$(call create_resp_file, link.args, $(LDFLAGS) $(2))
link -out:$(strip $(1)) @link.args > link.tmp
@cat link.tmp >> $(1:.sys=.map)
@$(PYTHON) check-for-unused-libs.py link.tmp
endef
define make_res
rc -nologo -fo $(1) $(2)
@echo
endef
define create_resp_file
$(file > $(1))
$(foreach f, $(2), $(file >> $(1),$(strip $(f))) )
endef
define generate
$(call green_msg, Generating $(1).)
$(call Warning, $(1),$(2))
endef
define generate_c
$(call generate, $(1), //)
$(file >> $(1),$(2))
endef
define generate_py
$(call generate, $(1), #)
$(file >> $(1),if 1:)
$(file >> $(1),$(2))
endef
define Warning
$(file > $(1),$(2))
$(file >> $(1),$(2) This file was generated at $(shell date +%d-%B-%Y) from)
$(file >> $(1),$(2) $(realpath $(THIS_FILE)).)
$(file >> $(1),$(2) DO NOT EDIT!)
$(file >> $(1),$(2))
endef
#
# clang-cl: /d1PP Retain macro definitions in /E mode
#
ifeq ($(CC),clang-cl)
d1PP = -d1PP
else
d1PP =
endif
ifeq ($(USE_ASTYLE),1)
C_preprocess_filter = | astyle
C_preprocess_comment = and AStyle'd
else
C_preprocess_filter =
C_preprocess_comment = raw
endif
define C_preprocess
$(file > $(1),/* The preprocessed $(C_preprocess_comment) output of '$(filter %.c, $(strip $(2)))':)
$(foreach f, $(_CC) -E $(CFLAGS) $(d1PP), $(file >> $(1), * $(f)))
$(file >> $(1), *)
$(file >> $(1), * Try compiling it with '$(strip $(_CC) -c -Tc $(1))')
$(file >> $(1), *---------------------------------------------------------------------)
$(file >> $(1), */)
$(_CC) -E @$(CC).args $(d1PP) $(2) | $(PYTHON) cpp-filter.py $(C_preprocess_filter) >> $(1)
endef
define NPcap_hacks_H
#ifndef NPcap_hacks_H
#define NPcap_hacks_H
#if defined(__clang__)
#define NDIS_FILTER_MAJOR_VERSION 6
#define NDIS_FILTER_MINOR_VERSION 0
#define NDIS_WRAPPER 1
#define EXPORT
/*
* 'clang-cl -Wall' generates tons of warnings.
* Especially from the Windows DDK.
*/
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wcomment"
#pragma clang diagnostic ignored "-Wcast-align"
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wcast-function-type-strict"
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
#pragma clang diagnostic ignored "-Wbad-function-cast"
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
#pragma clang diagnostic ignored "-Wreserved-identifier"
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#pragma clang diagnostic ignored "-Wvisibility"
#pragma clang diagnostic ignored "-Wsizeof-array-div"
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wpragma-pack"
#pragma clang diagnostic ignored "-Wfour-char-constants"
#pragma clang diagnostic ignored "-Wflexible-array-extensions"
#pragma clang diagnostic ignored "-Wdocumentation"
#pragma clang diagnostic ignored "-Wswitch-enum"
#pragma clang diagnostic ignored "-Wextra-tokens"
#pragma clang diagnostic ignored "-Wextra-semi"
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
#pragma clang diagnostic ignored "-Wredundant-parens"
#pragma clang diagnostic ignored "-Wpointer-sign"
#pragma clang diagnostic ignored "-Wunused-macros"
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wunused-value"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#pragma clang diagnostic ignored "-Wunreachable-code-break"
#pragma clang diagnostic ignored "-Wint-conversion"
#pragma clang diagnostic ignored "-Wduplicate-enum"
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#pragma clang diagnostic ignored "-Wignored-attributes"
#pragma clang diagnostic ignored "-Wignored-pragma-intrinsic"
#pragma clang diagnostic ignored "-Wmicrosoft-anon-tag"
#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
#pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference"
#pragma clang diagnostic ignored "-Wmicrosoft-flexible-array"
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#if defined(i386)
#pragma clang diagnostic ignored "-Wmissing-prototype-for-cc"
#endif
#elif defined(_MSC_VER)
#pragma warning (disable:4024 4047 4057 4100 4189 4306 4324 4389)
#endif
#define HAVE_DOT11_SUPPORT 1
#define HAVE_WFP_LOOPBACK_SUPPORT 1
#define HAVE_RX_SUPPORT 1
#define NDIS630 1
#define WINVER 0x0602
#define _WIN32_WINNT 0x0602
#define NTDDI_VERSION 0x06020000
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_NONSTDC_NO_DEPRECATE 1
//#define UNICODE
//#define _UNICODE
//#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0
//#define RELOCATABLE_USER_SHARED_DATA 1
#define _KERNEL_MODE 1
#define POOL_NX_OPTIN 1
#define POOL_ZERO_DOWN_LEVEL_SUPPORT 1
#define BITS $(BITS)
#if (BITS == 32)
#define _X86_ 1
#define i386 1
#define STD_CALL 1
#elif (BITS == 64)
#define _WIN64 1
#define _AMD64_ 1
#define AMD64 1
#else
#error "Define 'BITS' to either '32' or '64'."
#endif
#endif /* NPcap_hacks_H */
endef
define CPP_FILTER_PY
import sys, os
empty_lines = 0
while True:
line = sys.stdin.readline()
if not line:
break
line = line.rstrip()
if line == "":
empty_lines += 1
continue
if line.lstrip().startswith("# "):
line = line.replace (r"# ", "#line ")
if line.lstrip().startswith("#line"):
line = line.replace (r"\\", "/")
print (line)
if line == "}" or line == "};":
print ("")
print ("Removed %d empty lines." % empty_lines, file=sys.stderr)
endef
define CHECK_FOR_UNUSED_LIBS_PY
import os, sys
map_file = sys.argv[1]
class State():
IDLE = 0
UNUSED = 1
class Color():
RESET = RED = WHITE = ""
try:
from colorama import init, Fore, Style
init()
Color.RESET = Style.RESET_ALL
Color.RED = Fore.RED + Style.BRIGHT
Color.WHITE = Fore.WHITE + Style.BRIGHT
except:
pass
def cprint (color, s):
print ("%s%s%s" % (color, s, Color.RESET))
def report (unused):
num = len(unused)
plural = [ "library", "libraries" ]
if num > 0:
cprint (Color.RED, "%d unused %s in %s:" % (num, plural[num > 1], map_file))
for u in unused:
print (" " + u)
cprint (Color.WHITE, "Done.\n")
def process (state):
unused_libs = []
f = open (map_file, "rt")
lines = f.readlines()
f.close()
for l in lines:
l = l.strip()
if l == "Unused libraries:":
state = State.UNUSED
continue
if state == State.UNUSED:
if l == "":
break
unused_libs.append (l)
return unused_libs
report (process(State.IDLE))
endef
DEP_CFLAGS = -MM $(filter -D% -I%, $(CFLAGS)) \
-DNDIS_SUPPORT_NDIS620=1 \
-D_NDIS_ \
-D_NTDDK_ \
-D_NTIFS_ \
-D_WDMDDK_ \
-DFWPSX_H
DEP_REPLACE = -e 's@\(.*\)\.o: @\n$$(OBJ_DIR)\/\1.obj: @' \
-e 's@$(OBJ_DIR)@$$(OBJ_DIR)@' \
-e 's@$(KM_INCDIR)@$$(KM_INCDIR)@' \
-e 's@$(NPF_DIR)@$$(NPF_DIR)@'
depend: $(GENERATED)
$(call green_msg, Generating dependencies for $(words $(C_SOURCES)) .c-files...)
$(call Warning, .depend.Windows, #)
gcc $(DEP_CFLAGS) $(C_SOURCES) | sed $(DEP_REPLACE) >> .depend.Windows
-include .depend.Windows
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment