We can invoke FORTRAN code, such as subroutines and functions, from Golang using the cgo
package. This method is by far the cleanest to do so, but is still somewhat tricky and messy to get working. The idea is to compile our FORTRAN code into a shared object with relative memory positioning (-fPIC
) and allow Go to dynamically link it at compilation time. The method follows.
- Write the FORTRAN code in a file, say
fortran.f90
. We need our subroutines and functions to usebind(C)
to make them compatible with C. Optionally, we can useiso_c_binding
to make the code more readable for C types. - Compile the FORTRAN and obtain an object file:
gfortran -c fortran.f90
- In our Goland code, we need to import the
C
package and include the necessary comments to link the FORTRAN code. This helpscgo
to link our object to the Golang code. For example, we could include// #cgo LDFLAGS: fortran.o -L/path/to/gcc/lib/gcc/version -lgfortran
. The start of the path was obtained viabrew --prefix gcc
. - We need to add an additional commend for each subroutine of function we want to use. For example, we could include
// void hello();
to use thehello
subroutine. - To use the subroutine of function, we simply call it as if it were a C function. For example, we could call
C.hello()
. - We can now build and run our Golang code.
Instead of linking to the absolute path of the GCC library, we can create a shared object file from the fortran source using gfortran -shared -fPIC -o libfortran.so fortran.f90
. We can then link to this shared object file using // #cgo LDFLAGS: -L. -lfortran
.
This method is cleaner and more portable, but requires at least the relative path to the shared object file. If we are using multiple fortran files, we can compile them all into a single shared object file using gfortran -shared -fPIC -o libfortran.so fortran1.f90 fortran2.f90 ...
.
There are a few reverse engineering countermeasures that can be taken. The first and most obvious would be to strip
the final Go executeable of anything symbolic. Of course, the architecture (e.g. mach-o arm64
on MacOS) will still be exposed. We can radix/trie our literals as well, although I'm unsure of anyway to completely encrypt or prevent access to these. Compilation of the FORTRAN code with optimization (e.g. -Os
for gfortran
) can also do a number on the reverse engineering process. Lastly, we can do our best to revoke read permissions on the executable, although this is environment-dependent. There are some efforts that can be made on the anti-debugger and obfuscation during build time. I'll be looking into more countermeasures to this end.