# 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