# tl;dr > **update:** I've used this technique to bypass Cortex XDR on an engagement, and was in the process of creating a full-scale packer for .NET exes, and the day after NimPackt-v1 came out. > > The simplified version of the script I was using (still bypasses Cortex) is available on [gists](https://gist.github.com/zimnyaa/e4a46d35bbd0694e93ea591a44fc71db) This post provides an example of extending Python's offensive capabilities with Nim with a usable `.pyd` port of `inline-executeassembly`. >*note:* Since it really is easy to extend Python with Nim, I am planning to merge my Nim side-projects to a single .pyd for ease of use in Python implants and similar stuff Usage example: ![[pyd_executeassembly.gif]] Code available on https://gist.github.com/zimnyaa/10eca1d805297520c57eb8a7170a4a39 # nimpy Frequently used types are easy to convert between Python and Nim, so nimpy doesn't actually need your help for most of the stuff it does. Creating a Python-exported function is as easy as: >```nim proc myproc(myqrg: openarray[byte]) : string {.exportpy.} = > # code here ... >``` Building it, however, is another matter. The build recommendation on the nimpy repo recommends the following: ```bash nim c --threads:on --app:lib --tlsEmulation:off --out:mymodule.pyd mymodule ``` However, if you try building it like that, the Python will not load the lib due to MinGW runtime dependencies (`libgcc_s_seh-1.dll => /mingw64/bin/libgcc_s_seh-1.dll` and `libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll`): >![[Pasted image 20220112163032.png]] >![[Pasted image 20220113132930.png]] >`python` not finding DLL references So the way to do it is statically linking libgcc and pthreads: ```bash $ nim c --threads:on --app:lib --out:pymodule.pyd --passL:"-static-libgcc -static -lpthread" .\pymodule.nim ``` # winim/clr and execute_assembly `winim/clr` is very easy to use: >```nim >var dotnetargs = toCLRVariant(args, VT_BSTR) >var assembly = load(assembly_bytes) >assembly.EntryPoint.Invoke(nil, toCLRVariant([dotnetargs])) >``` However, capturing the output is a bit harder, and requires to define `dup`/`dup2` in Nim: >```nim proc dup(oldfd: FileHandle): FileHandle {.importc, header: "unistd.h".} proc dup2(oldfd: FileHandle, newfd: FileHandle): cint {.importc, header: "unistd.h".} >``` With those functions, it is possible to redirect stdout to an open file handle in a POSIX-compliant way. >*note:* the obvious next step is using a named pipe instead of a temporary file, but it became increasingly complex for a PoC # links https://github.com/yglukhov/nimpy https://github.com/khchen/winim