不说前提了,就是想明确知道一个进程是什么语言写的,像Python,Java都可以一眼看出来,但是Go这种编译型语言如何检测呢?
直觉是解析Go编译后文件格式。
最初看到这篇文章:
https://blog.wolfogre.com/posts/mechanism-of-gops/
使用gdb检测:
但是如果线上环境没有gdb命令呢?有没有其他方法
google有gops工具,可以直接查看。
https://github.com/google/gops/blob/master/goprocess/gp.go
一般问题可能就到此为止了,但是我还想继续深入调查,毕竟线上环境一般也没有这个命令,使用这个工具还得手动上传,不符合实际情况。
我们继续查看gops如何实现的
https://github.com/google/gops/blob/master/goprocess/gp.go#L123
https://github.com/google/gops/blob/master/goprocess/gp.go#L123
可以看到使用gops使用 goversion 模块
goversion 模块怎样实现的呢?
https://github.com/rsc/goversion/blob/master/version/read.go#L37
使用 openExe() 函数读取文件并解析的
openExe() 怎样实现的呢?
https://github.com/rsc/goversion/blob/597212e462da05a7902d6cea0ec895a0d9b8b218/version/exe.go#L36
读取文件字节码并解析,分情况:ELF文件格式(Linux),MZ文件格式(windows)
也即:(以Linux举例)
读取文件为ELF格式,遍历,如果出现 .note.go.buildid 则表示该文件为Go编译文件
既然是解析ELF文件,可以直接用readelf命令来解析呀
可以看到红框内的 .note.go.buildid
证明了该文件是go编译后的文件。
其实不止 .note.go.buildid,截图中的其他项也表明了文件的Go身份,比如 .go.buildinfo
所以,我们可以通过readelf命令检测进程是否为Go进程。而几乎所有线上环境都有此命令。
实际上辨别的方式不止这一种,例如 https://github.com/rsc/goversion/blob/master/version/read.go#L37 给出的多种判定方式: