Repository: kmaork/pyinjector (language: python)

Issue:
Add support for windows



Discussion / hints:
I tried to compile it with setup.py (with changed src dir "src/windows") but get a "stdio.h no found" error, and I tried nmake injector, and it succeded with several obj/lib/dll, how could I use these file to make accessible pyd for pyinjector? 

Thx!

Fix patch:
diff --git a/README.md b/README.md
index 15c5290..5233bf1 100644
--- a/README.md
+++ b/README.md
@@ -16,12 +16,12 @@ It is implemented as a python wrapper for [kubo/injector](https://github.com/kub
 ```shell script
 pip install pyinjector
 ```
-Both source distributions and `manylinux2010` wheels are upoloaded to pypi for every release.
+Both source distributions, `manylinux2010` wheels and windows wheels are uploaded to Pypi for every release.
 
 ### Usage
 #### CLI
 ```shell script
-inject <pid> <path/to/so/file>
+inject <pid> <path/to/shared/library>
 ```
 
 #### API
diff --git a/libinjector.c b/libinjector.c
new file mode 100644
index 0000000..d58a045
--- /dev/null
+++ b/libinjector.c
@@ -0,0 +1,2 @@
+#include <Python.h>
+PyMODINIT_FUNC PyInit_libinjector(void) { return NULL; }
diff --git a/setup.cfg b/setup.cfg
index 1de0ae3..699b40f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@ packages = pyinjector
 
 [metadata]
 name = pyinjector
-version = 0.1.4
+version = 1.0.0
 description = A tool/library allowing dynamic library injection into running processes
 author = Maor Kleinberger
 author_email = kmaork@gmail.com
diff --git a/setup.py b/setup.py
index 67075f7..2262294 100644
--- a/setup.py
+++ b/setup.py
@@ -1,15 +1,20 @@
+from sys import platform
 from pathlib import Path
 from setuptools import setup, Extension
+from distutils.extension import Extension
 
 PROJECT_ROOT = Path(__file__).parent.resolve()
 LIBINJECTOR_DIR = PROJECT_ROOT / 'injector'
-LIBINJECTOR_SRC = LIBINJECTOR_DIR / 'src' / 'linux'
+LIBINJECTOR_SRC = LIBINJECTOR_DIR / 'src' / ('windows' if platform == 'win32' else 'linux')
+LIBINJECTOR_WRAPPER = PROJECT_ROOT / 'libinjector.c'
 
 libinjector = Extension('pyinjector.libinjector',
-                        sources=[str(c.relative_to(PROJECT_ROOT)) for c in LIBINJECTOR_SRC.iterdir()
+                        sources=[str(c.relative_to(PROJECT_ROOT))
+                                 for c in [LIBINJECTOR_WRAPPER, *LIBINJECTOR_SRC.iterdir()]
                                  if c.suffix == '.c'],
                         include_dirs=[str(LIBINJECTOR_DIR.relative_to(PROJECT_ROOT) / 'include')],
-                        define_macros=[('EM_AARCH64', '183')]) # Needed on CentOS for some reason
+                        export_symbols=['injector_attach', 'injector_inject', 'injector_detach'],
+                        define_macros=[('EM_AARCH64', '183')])  # Needed on CentOS for some reason
 
 setup(
     ext_modules=[libinjector],


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index dbbd66e..238af66 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -6,7 +6,7 @@ on:
   push:
 
 jobs:
-  test:
+  test_linux:
     runs-on: ubuntu-latest
     container: quay.io/pypa/manylinux2014_x86_64 # Need a relatively modern platform for the actions to work
     strategy:
@@ -18,7 +18,7 @@ jobs:
           submodules: true
       - name: Set up Python ${{ matrix.python-version }}
         run: |
-          echo "::add-path::/opt/python/${{ matrix.python-version }}/bin"
+          echo "/opt/python/${{ matrix.python-version }}/bin" >> $GITHUB_PATH
           echo $PATH
       - name: Install dependencies
         run: pip install tox tox-gh-actions tox-wheel
@@ -32,16 +32,47 @@ jobs:
       - name: Test wheel with tox
         run: python -m tox --wheel
       - name: Audit ${{ matrix.python-version }} wheel
-        run: auditwheel repair .tox/dist/* -w wheelhouse${{ matrix.python-version }}
+        run: auditwheel repair .tox/dist/* -w audited_wheels
       - name: Upload ${{ matrix.python-version }} wheel
         uses: actions/upload-artifact@v2
         with:
           name: dist
-          path: wheelhouse${{ matrix.python-version }}/*
+          path: audited_wheels/*
+
+  test_windows:
+    runs-on: windows-latest
+    strategy:
+      matrix:
+        python-version: [3.6, 3.7, 3.8, 3.9]
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          submodules: true
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Install dependencies
+        # virtualenv==20.0.33 because of this https://github.com/ContinuumIO/anaconda-issues/issues/10822#issuecomment-736650629
+        run: pip install tox tox-gh-actions tox-wheel virtualenv==20.0.33
+      - name: Test sdist with tox
+        run: python -m tox
+      - name: Upload ${{ matrix.python-version }} sdist
+        uses: actions/upload-artifact@v2
+        with:
+          name: dist
+          path: .tox/dist/*
+      - name: Test wheel with tox
+        run: python -m tox --wheel
+      - name: Upload ${{ matrix.python-version }} wheel
+        uses: actions/upload-artifact@v2
+        with:
+          name: dist
+          path: .tox/dist/*
 
   publish:
     if: github.event_name == 'release' && github.event.action == 'created'
-    needs: test
+    needs: [test_windows, test_linux]
     runs-on: ubuntu-latest
     steps:
       - name: Download artifacts
diff --git a/tests/injection/injection.c b/tests/injection/injection.c
index 40a8243..b9419ea 100644
--- a/tests/injection/injection.c
+++ b/tests/injection/injection.c
@@ -1,7 +1,26 @@
-static void init(void) __attribute__((constructor));
+#include <Python.h>
+PyMODINIT_FUNC PyInit_injection(void) { return NULL; }
 
-static void init(void) {
-    const char *s = "Hello, world!";
-    write(1, s, strlen(s));
-    close(1);
-}
\ No newline at end of file
+#ifdef _WIN32
+    #include <windows.h>
+    #include <io.h>
+
+    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) {
+        const char *s = "Hello, world!";
+        switch( fdwReason ) {
+            case DLL_PROCESS_ATTACH:
+                _write(1, s, strlen(s));
+                _close(1);
+                break;
+        }
+        return TRUE;
+    }
+#else
+    static void init(void) __attribute__((constructor));
+
+    static void init(void) {
+        const char *s = "Hello, world!";
+        write(1, s, strlen(s));
+        close(1);
+    }
+#endif
diff --git a/tests/test_pyinjector.py b/tests/test_pyinjector.py
index 3fc4a38..b7c3dbe 100644
--- a/tests/test_pyinjector.py
+++ b/tests/test_pyinjector.py
@@ -6,7 +6,8 @@
 
 INJECTION_LIB_PATH = find_spec('injection').origin
 STRING_PRINTED_FROM_LIB = b'Hello, world!'
-TIME_TO_WIT_FOR_PROCESS_TO_INIT = 0.1
+TIME_TO_WIT_FOR_PROCESS_TO_INIT = 1
+TIME_TO_WIT_FOR_INJECTION_TO_RUN = 1
 
 
 def test_inject():
@@ -14,6 +15,7 @@ def test_inject():
         try:
             time.sleep(TIME_TO_WIT_FOR_PROCESS_TO_INIT)
             inject(process.pid, INJECTION_LIB_PATH)
+            time.sleep(TIME_TO_WIT_FOR_INJECTION_TO_RUN)
             assert process.stdout.read() == STRING_PRINTED_FROM_LIB
         finally:
             process.kill()