go 语言逆向技术之 --- 常量字符串解密
【摘要】go 语言编译出来的二进制文件中,字符串数据是如何存放的,逆向时如何快速和准确的识别出源代码中定义的字符串,本文给你解密。
Go 语言源代码编译成二进制文件后,源代码中的字符串存放在哪里?是如何组织的?
以下面 go 语言源代码为例:
package main
import “fmt”
func main() {
fmt.Println(“Hello, World!”)
}
虽然只是打印一个字符串"Hello, World!",生成的二进制文件中字符串却是非常的多:
Go 语言二进制文件中字符串是存放在哪里的呢?其实存放的位置遵循的 elf 格式原则,在.rodata 节中(如上图所示)。
有同学会问 C 语言编译出来的 elf 格式中字符串也是这样存放的,Go 语言的字符串组织方法和 C 语言的字符串组织方法有什么不同的呢?最大的不同点就是 C 语言字符串是以’\x00’结尾的,这样不同字符串之间可以方便的以’\x00’来切割,而 Go 语言的字符串你可以发现是没有’\x00’结尾的,比如上图中"Hello, World!"后面紧接着就是"SIGKILL:"了,没有’\x00’分隔。
Go 语言字符串按以下方法来组织:
字符串按长度从小到大排列
相同长度的字符串按字符比较的方法从小到大排列
非可见字符串先转义再存放
另外 Go 语言字符串一般从 go_string 位置开始存放,如下图所示
逆向时正确切割 Go 语言字符串方法有两种:
进行反汇编,解析汇编指令,确定字符串起始位置和处理长度
直接根据 Go 语言字符串组织原则进行切割
基于 Go 语言字符串组织原则的快速切割算法:
1、 搜索确定 go_string 起始位置
2、 设置字符串搜索起始长度为 1
3、 根据当前字符串长度切割字符串
4、 预切割下一个字符串,和当前字符串进行比较,检查是否违反原则,若符合保存当前字符串,继续第 3 步切割下一个字符串,否则表示字符串有变化进行第 5 步操作
5、 把当前字符串长度加 1,继续第 3 步的搜索,直至全部正确搜索完毕
如下图所示(长度为 13 个字节的字符串):
【总结】go 语言字符串的切割在二进制安全检测中可以真实的还原源代码中引用字符串的信息,提升检测准确率。
评论