本文介绍: Go作为编译语言,天然存在跨平台属性我们编译完成后,可以再不暴露源代码的情况下,运行对应平台中,但是还是架不住有逆向工程师反编译、反汇编的情形;(当然我们写的都不希望被别人偷了,以下内容简单做个攻防介绍,起个引导作用,不到之处,多多留言探讨)

在这里插入图片描述

Go作为编译语言,天然存在跨平台属性我们编译完成后,可以再不暴露源代码的情况下,运行对应平台中,但是
还是架不住有逆向工程师反编译、反汇编的情形;(当然我们写的都不希望被别人偷了,以下内容简单做个攻防介绍,起个引导作用,不到之处,多多留言探讨)

逆向工程(反汇编反编译

逆向工程(Reverse Engineering)是指将现有二进制程序或者系统进行分析,还原出其设计运行机制的一种技术手段

下面是一些逆向工程的常见技术

  1. 汇编技术通过二进制程序转化为汇编代码,以还原程序的运行过程指令执行情况。Go语言提供了反汇编工具可以通过命令行输入go tool compile -S可执行文件名”来实现汇编
  2. 反编译技术:将已经编译好的程序进行还原,得到其源代码。Go语言的反编译工具是“go tool compile -S 源文件名”,生成代码需要通过代码分析修改才能重新编译成可执行程序
  3. 动态调试技术:通过调试器对程序进行分析,观察程序的运行情况和变量值的变化。Go语言的调试器是“dlv”,可以使用命令行对程序进行单步调试
  4. 内存分析技术:通过对程序运行时的内存进行分析,以了解程序的行为数据结构。Go语言的内存分析工具是“pprof”,可以对程序进行CPU、内存goroutine的分析。

1、破解方案

谈到防破解,首先得知道怎么破解,才能更好防护

将Go二进制文件转换为与原始源代码结构相同高级语言源代码是一项非常困难且不可靠的任务。Go是一种静态编译语言,编译器将Go源代码转换为机器码,优化并去除高级语言结构。因此,反向转换机器码到原始源代码是一个复杂问题

虽然有一些工具可以进行反汇编和逆向工程,但这些工具通常无法提供与原始Go源代码结构完全相同的高级语言代码。
这是因为编译器进行了各种优化,同时丢失了一些高级语言结构的信息

以下是一些可能用到的工具:

IDA Pro: IDA Pro一款反汇编和逆向工程工具,但它通常只能提供汇编级别的代码,并不能还原为原始的高级语言源代码。

Ghidra: Ghidra一款开源的逆向工程工具,它提供反汇编和分析二进制文件功能。与IDA Pro类似,Ghidra也更倾向于提供汇编级别的代码。

汇编代码还原: 逆向工程师可能尝试还原机器码为汇编代码,但这通常只是一个近似的过程,并不会得到原始的高级语言源代码。

2、防破解方式

破解一直是个很常见需求,特别是不能做成服务的、或者需要二进制部署场景,Go 的编译特性天然就比脚本类语言更好防逆向,脚本类代码是藏不住的。

当然防破解这个事情主要看投入产出比。Go 在这里的优势主要是省心,同时提高了破解的技术门槛。多数时候,写一个时间检查、或者 MAC 比对就很够用了。

举例:比如可以分离功能逻辑校验逻辑校验失败并不会立即触发异常,而是会正常执行功能逻辑,但附加一个随机延迟取消机制,使得功能完成之前就异常退出

上述逻辑用 Go 代码写出来大概就是 contextWithCancel 几行代码的事情。这样产生的程序无论静态反编译还是静态调试都会很令人迷惑,静态方面难以定位校验逻辑动态方面上下文切换缺少规律,实际运行表现又是难以稳定复现的,大幅增加了逆向难度

除此之外还可以配合 burrowers/garble 之类的自动化混淆工具。

以下是常规的增加破解难度方式

  1. 删除调试符号

正常情况,我们go代码,部署完成,如果出现报错日志等,会有暴露目录内容风险

go build -ldflags "-s -w" [<your/package] (go version > 1.7 )
  1. 删除trace文件信息

    放到自己的.bash_profile或.zshrc即可

     ACTUAL_GOPATH="~/Programming/go"
     export GOPATH='/tmp/go'
     export GOROOT_FINAL=$GOPATH
     [ ! -d $GOPATH ] && ln -s "$ACTUAL_GOPATH" "$GOPATH"
     [[ ! $PATH =~ $GOPATH ]] && export PATH=$PATH:$GOPATH/bin
    
  1. 代码混淆
  1. 静态编译: 使用静态编译将依赖嵌入到二进制文件中,以减少对外部文件的依赖。这可以增加分析和替换难度

  2. 加密关键部分

  1. 代码分割
  1. 使用硬编码密钥
    将密钥硬编码:在代码中直接将密钥硬编码,而不是存储配置文件或其他地方
package main

var encryptionKey = []byte{0x01, 0x02, 0x03, 0x04, 0x05}

  1. 调试技术:
    使用防调试技术,防止二进制文件在调试器中运行。这可以增加对抗性,使得破解变得更加困难。
    使用runtime/debug包:通过runtime/debug包的ReadBuildInfo函数检查二进制文件是否构建,从而检测是否调试模式下运行。
package main

import (
   "fmt"
   "runtime/debug"
)

func main() {
   if info := debug.ReadBuildInfo(); info != nil {
      fmt.Println("Debug information found:", info)
      // Take appropriate action if running in debug mode
   }
}

  1. 使用代码签名 对二进制文件进行数字签名,以确保它的完整性和来源。这可以防止恶意篡改替换

  2. 运行时检测 在运行时检测二进制文件是否修改。这可以通过计算文件哈希值等方式来实现

  3. 虚拟化技术: 使用虚拟化技术将关键代码片段放在虚拟机执行,增加攻击者分析的难度

  4. 动态链接库 将一些关键逻辑放入动态链接库,并在运行时动态加载。这可以减少整个二进制文件的复杂性。

参考

原文地址:https://blog.csdn.net/hmx224_2014/article/details/134745331

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45762.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注