go语言逆向-基础basic

文章目录

  • go 编译命令 ldflags -w -s的作用和问题
      • 使用 `file` 命令查看文件类型
  • go 语言逆向参考
  • go ID
  • 版本
  • GOROOT和GOPATH
      • GOROOT
      • GOPATH
      • GOROOT和GOPATH的关系
      • 示例
  • go build和 go mod
  • pclntab (Program Counter Line Table 程序计数器行数映射表)
  • Moduledata
  • 程序启动

go 编译命令 ldflags -w -s的作用和问题

https://blog.csdn.net/Kevin_Gates/article/details/130107710
-ldflags 参数可以用来向编译器传递额外的参数。其中,-w 和 -s 是两个常用的参数。

  • w:去掉 dwarf 调试信息。会减小可执行文件的大小。
  • s:去掉符号表信息。会进一步减小可执行文件的大小。

在编译可执行文件时使用了 -ldflags "-w -s" 参数后,你可以通过以下几种方式来检查生成的可执行文件是否去掉了调试信息和符号表信息。

使用 file 命令查看文件类型

file 命令可以显示可执行文件的基本信息,如果去掉了调试信息,file 的输出中应该不会提到调试符号(debugging symbols)。
在这里插入图片描述

go 语言逆向参考

https://www.cnblogs.com/lordtianqiyi/articles/16315905.html
https://forum.butian.net/share/1874
https://jiayu0x.com/2020/09/28/go-binary-reverse-engineering-tips-and-example/
【技术推荐】正向角度看Go逆向
Golang逆向资料

Go 语言设计与实现

go ID

Build ID 是 Go 二进制文件中的元信息之一

llk@ubuntu:~/Desktop/go-reverse/basic$ go tool buildid basic
-VH5aOSX9mVrJNbHxruF/FwnNtemK3U4RER9TE7_8/5x300ikDrpjLHazn79N3/ftLrOMaMAByiPF3chfMM

无论是gccgo还是go编译的,file或者readelf -n都能看到BuildID

版本

一、查看版本号
go version xx.exe
二、查看地址以及依赖库
go version -m xxx.exe

GOROOT和GOPATH

  • GOROOT: 主要是Go语言工具链所在的位置,通常不需要手动修改。
  • GOPATH: 用于管理和组织用户的Go项目,可以根据需要设置和修改,方便管理不同的工作空间。

GOROOT

  • 定义: GOROOT是Go语言的安装目录。它指向Go工具链、标准库源码和编译器等内容所在的目录。
  • 默认值: 通常在安装Go时,GOROOT会自动设置为安装路径。例如,如果你通过官方安装包安装Go,GOROOT可能会是 /usr/local/go(在类Unix系统上)或 C:\Go(在Windows上)。
  • 作用:
    • 存放Go编译器和工具链。
    • 包含标准库源码。
    • Go工具使用GOROOT来找到编译器、链接器等工具,以及标准库的源码。

GOPATH

  • 定义: GOPATH是Go项目的工作目录。它指向开发者的工作空间,可以包含多个目录。
  • 默认值: 如果没有设置GOPATH,默认值通常是用户的主目录下的go目录(如$HOME/go)。
  • 结构: GOPATH目录通常包含三个子目录:
    • src: 存放源代码。
    • pkg: 存放已编译的包对象文件。
    • bin: 存放编译后生成的可执行文件。
  • 作用:
    • 用于存储和组织用户的Go代码。
    • go get 命令会下载依赖包到GOPATHsrc目录中。
    • 编译时,Go工具会从GOPATH中查找包的源码。

GOROOT和GOPATH的关系

  • GOROOT 是Go工具链的安装目录,包含标准库。
  • GOPATH 是用户工作空间的目录,包含用户的代码和第三方库。

示例

假设你在$HOME/go_projects下开发一个项目:

  1. 你可以设置GOPATH$HOME/go_projects

    export GOPATH=$HOME/go_projects
    
  2. 你的项目目录结构可能如下:

    $HOME/go_projects/src/github.com/yourusername/yourproject/main.gopkg/bin/
    
  3. 编译你的项目:

    cd $HOME/go_projects/src/github.com/yourusername/yourproject
    go build
    

编译后的可执行文件将会出现在$HOME/go_projects/bin目录中。

go build和 go mod

go build命令用来启动编译,它可以将Go语言程序与相关依赖编译成一个可执行文件,其语法格式如下。
go build fileName  -o 可执行程序名
其中 fileName 为所需要的参数,可以是一个或者多个 Go 源文件名(当有多个参数时需要使用空格将两个相邻的参数隔开),也可以省略不写。
使用 go build 命令进行编译时,不同参数的执行结果也是不同的。

编译go程序也是编译与链接的一个流程

在这里插入图片描述
golang包管理工具----go mod

一个 Module 中可以包含多个不同的 Package,而每个 Package 中可以包含多个目录和很多的源码文件。

Module :moduledata 里面有pclntab 全名是 Program Counter Line Table

pclntab (Program Counter Line Table 程序计数器行数映射表)

对应到源码为pcHeader结构体,源码路径在src/runtime/symtab.go

// pcHeader 包含 pclntab 查找使用的数据。
type pcHeader struct {magic          uint32  // 0xFFFFFFF1: 用于识别 pcHeader 结构的魔数。pad1, pad2     uint8   // 0,0: 对齐结构在内存中的填充字节。minLC          uint8   // 架构的最小指令大小。ptrSize        uint8   // 指针的字节大小(取决于 32 位或 64 位架构)。nfunc          int     // 模块中的函数数量。nfiles         uint    // 文件表中的条目数量(模块中的源文件数量)。textStart      uintptr // 功能入口 PC 偏移的基地址,等于 moduledata.text。funcnameOffset uintptr // 从 pcHeader 开始到 funcnametab 变量的偏移量,包含函数名。cuOffset       uintptr // 从 pcHeader 开始到 cutab 变量的偏移量,用于编译单元信息。filetabOffset  uintptr // 从 pcHeader 开始到 filetab 变量的偏移量,包含文件名。pctabOffset    uintptr // 从 pcHeader 开始到 pctab 变量的偏移量,用于 PC 数据表。pclnOffset     uintptr // 从 pcHeader 开始到 pclntab 变量的偏移量,用于 PC 到行号的映射。
}

在这里插入图片描述

  1. cu_offset:

    • cu_offset 是编译单元(Compilation Unit)的偏移量。
    • gopclntab 中,编译单元是一个大块,包含了函数信息、行号表等。
    • cu_offset 指的是当前函数在编译单元中的偏移位置。
  2. pctab:

    • pctab 是一个表格,存储了程序计数器(PC)和行号(line number)之间的映射关系。
    • 这种映射关系使得在运行时可以根据PC值找到源代码中的行号,帮助调试和错误处理。
  3. runtime_pclntab:

    • runtime_pclntab 是整个gopclntab的起始点或基地址。
    • 这是一个全局表格,包含了所有函数的PC和函数信息的映射。
  4. dq offset cu_offset - offset runtime_pclntab:

    • 这表示当前函数的 cu_offset 减去全局 runtime_pclntab 的偏移量,得到一个具体的偏移值。
    • 这个偏移值用来定位当前函数在整个 gopclntab 结构中的位置。
  5. dq offset pctab - offset runtime_pclntab:

    • 这表示当前函数的 pctab 减去全局 runtime_pclntab 的偏移量。
    • 这个偏移值用来定位 pctab 在整个 gopclntab 结构中的位置。

函数表
函数地址偏移是和函数表第一个函数地址的偏移
在这里插入图片描述
源码文件表
在这里插入图片描述

Moduledata

Module 是比 Package 更高层次的概念,具体表现在一个 Module 中可以包含多个不同的 Package,而每个 Package 中可以包含多个目录和很多的源码文件。

相应地,Moduledata 在 Go 二进制文件中也是一个更高层次的数据结构,它包含很多其他结构的索引信息

根据 Moduledata 的定义,源码路径在src/runtime/symtab.go

type moduledata struct {sys.NotInHeap // 仅用于静态数据// 指向pcHeader结构的指针,包含程序计数器的头信息pcHeader     *pcHeaderfuncnametab  []byte      // 函数名称表cutab        []uint32    // 编译单元表filetab      []byte      // 文件表pctab        []byte      // 程序计数器表pclntable    []byte      // PC到行号的映射表ftab         []functab   // 函数表findfunctab  uintptr     // findfunctab函数的起始地址minpc, maxpc uintptr     // 代码段的起始和结束地址text, etext           uintptr // 代码段的起始和结束地址noptrdata, enoptrdata uintptr // 不包含指针的数据段的起始和结束地址data, edata           uintptr // 数据段的起始和结束地址bss, ebss             uintptr // BSS段的起始和结束地址noptrbss, enoptrbss   uintptr // 不包含指针的BSS段的起始和结束地址covctrs, ecovctrs     uintptr // 覆盖计数器的起始和结束地址end, gcdata, gcbss    uintptr // 结束地址,GC数据,GC BSStypes, etypes         uintptr // 类型信息的起始和结束地址rodata                uintptr // 只读数据段的起始地址gofunc                uintptr // go.func.*textsectmap []textsect // 文本段映射typelinks   []int32    // 类型链接信息,存储类型偏移itablinks   []*itab    // 接口表链接ptab []ptabEntry // P 表pluginpath string       // 插件路径pkghashes  []modulehash // 包哈希信息// 这个切片记录了启动程序所需的初始化任务。由链接器构建。inittasks []*initTaskmodulename   string       // 模块名modulehashes []modulehash // 模块哈希信息hasmain uint8 // 如果模块包含main函数,则值为1,否则为0gcdatamask, gcbssmask bitvector // GC数据和BSS段的位向量typemap map[typeOff]*_type // 前一个模块中从偏移量到*_rtype的映射bad bool // 模块加载失败,应被忽略next *moduledata // 指向下一个模块的指针
}

Moduledata 是可以串成链表的形式的,而一个完整的可执行 Go 二进制文件中,只有一个 firstmoduledata 包含如上完整的字段

在这里插入图片描述

程序启动

Golang 程序启动过程

rt0_amd64_linux->rt0_amd64->runtime_rt0_go
rt0_go 代码比较长,可分为两个部分,第一部分是系统参数获取和运行时检查。第二部分是 go 程序启动的核心,总体启动流程如下
在这里插入图片描述
执行 runtime.main, 主要进行了
1.启动系统后台监控sysmon 线程
2.执行 runtime 包内 init
3.启动gc
4.用户包依赖 init 的执行
5.执行用户main.mian 方法

  1. rt0_go函数

    • 当程序启动时,Go运行时的入口点是rt0_go函数。这个函数负责初始化运行时环境。
  2. schedinit:初始化运行时组件

    • rt0_go调用runtime_schedinit_0来初始化调度器、内存分配器和垃圾回收器等等。
    • 调度器初始化:初始化调度器,准备管理Goroutines的创建、调度和执行。
    • 内存分配器初始化:初始化堆内存管理,为Goroutines和程序数据分配内存。
    • 垃圾回收器初始化:初始化垃圾回收器,自动管理内存的分配和回收。
  3. newproc:创建主Goroutine

    • rt0_go调用runtime_newproc_0创建主Goroutine。主Goroutine的入口函数是runtime.main,而不是用户的main函数。
    • 创建Goroutinenewproc函数负责创建一个新的Goroutine,并将其加入调度器的队列中。这个Goroutine的入口函数是runtime.main
  4. mstart:启动调度器的调度循环

    • rt0_go调用runtime_mstart启动主线程。主线程会执行runtime.main函数。
    • 调度循环mstart函数启动调度器的调度循环,开始执行队列中的Goroutines。第一个执行的Goroutine是入口方法为runtime.main的G。
  5. runtime.main:执行初始化和用户main函数

    • runtime.main函数首先执行一些必要的初始化操作,例如设置全局变量、初始化标准库等。
    • 然后,runtime.main调用用户的main函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

D2761 适合在个人电脑、便携式音响等系统中作音频限幅用。

概述: D2761是为保护扬声器所设计的音频限幅器,其限幅值可通过外接电阻来调节,适合在个人电脑、便携式音响等系统中作音频限幅用。D2761采用SSOP10、MSOP10、TSSOP14的封装形式封装。 主要特点:  工作电压范围宽:2.7…

【Linux系统】—— 基本指令(四)

【Linux系统】—— 基本指令(三) 1「find」指令2 「grep」指令2.1 初识「grep」指令2.2 「grep」指令 选项 3 打包压缩基本知识4 「zip / unzip」指令5「tar」命令6 文件互传6.1 Linux 与 Windows 互传6.1.1 Linux向Windows传输6.1.2 Windows向Linux传输…

WordCloud去掉停用词(fit_words+generate)的2种用法

-------------词云图集合------------- WordCloud去掉停用词(fit_wordsgenerate)的2种用法 通过词频来绘制词云图(jiebaWordCloud) Python教程95:去掉停用词词频统计jieba.tokenize示例用法 将进酒—李白process_t…

洛谷刷题日记12||图的遍历

反向建边 dfs 按题目来每次考虑每个点可以到达点编号最大的点,不如考虑较大的点可以反向到达哪些点 循环从N到1,则每个点i能访问到的结点的A值都是i 每个点访问一次,这个A值就是最优的,因为之后如果再访问到这个结点那么答案肯…

替代Postman ,17.3K star!

现在,许多人都朝着全栈工程师的方向发展,API 接口的编写和调试已成为许多开发人员必备的技能之一。 工欲善其事,必先利其器。拥有一款优秀的 API 工具对于任何工程师来说都是极为重要的,它能够帮助我们高效地完成各种开发任务。 …

java:拆箱和装箱,缓存池概念简单介绍

1.基本数据类型及其包装类: 举例子: Integer i 10; //装箱int n i; //拆箱 概念: 装箱就是自动将基本数据类型转换为包装器类型; 拆箱就是自动将包装器类型转换为基本数据类型; public class Main {public s…

Node.js的url模块与querystring模块

新书速览|Vue.jsNode.js全栈开发实战-CSDN博客 《Vue.jsNode.js全栈开发实战(第2版)(Web前端技术丛书)》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 4.3.1 http模块——创建HTTP服务器、客户端 要使用http模块&#xff0…

【Reinforcement Learning】强化学习下的多级反馈队列(MFQ)算法

📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…

【linux】服务器加装硬盘后如何将其设置为独立硬盘使用

【linux】服务器加装硬盘后如何将其设置为独立硬盘使用 问题描述:本服务器原本使用了两个硬盘作为存储硬盘,同时对这两个硬盘设置了raid1阵列。现在内存不足要进行加载硬盘,新加载的硬盘不设置为raid1,而是将新加装的两个硬盘作为…

亚信安全与飞书达成深度合作

近日,亚信安全联合飞书举办的“走近先进”系列活动正式走进亚信。活动以“安全护航信息化 共筑数字未来路”为主题,吸引了众多数字化转型前沿企业的近百位领导参会。作为“走近先进”系列的第二场活动,本场活动更加深入挖掘了数字化转型的基础…

TMS FNC UI Pack 5.4.0 for Delphi 12

TMS FNC UI Pack是适用于 Delphi 和 C Builder 的多功能 UI 控件的综合集合,提供跨 VCL、FMX、LCL 和 TMS WEB Core 等平台的强大功能。这个统一的组件集包括基本工具,如网格、规划器、树视图、功能区和丰富的编辑器,确保兼容性和简化的开发。…

Transformer详解及衍生模型GPT|T5|LLaMa

简介 Transformer 是一种革命性的神经网络架构,首次出现在2017年的论文《Attention Is All You Need》中,由Google的研究团队提出。与传统的RNN和LSTM模型不同,Transformer完全依赖于自注意力(Self-Attention)机制来捕…

Git(一)基本使用

目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件,并使用 git init 在该目录下创建一个本地仓库, 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数 微信公众平台添加配置 微信公众平台 > 开发管理 > 开发设置 > 扫普通链接二维码打开小程序 配置链接规则需要下载校验文档给后端存入服务器中,保存配置的时候会校验一次,确定当前的配…

Vercel 设置自动部署 GitHub 项目

Vercel 设置自动部署 GitHub 项目 问题背景 最近 Vercel 调整了其部署政策,免费版用户无法继续使用自动部署功能,除非升级到 Pro 计划。但是,我们可以通过配置 Deploy Hooks 来实现同样的自动部署效果。 解决方案 通过设置 Vercel 的 Dep…

商业物联网:拥抱生产力的未来

在现代商业格局中,数据占据至高无上的地位。物联网(IoT)站在这场数字革命的前沿,将以往模糊不清的不确定因素转变为可衡量、可付诸行动的深刻见解。物联网技术为日常物品配备传感器与连接功能,使其能够实时收集并传输数…

金融租赁系统助力企业升级与风险管理的新篇章

内容概要 在当今的商业环境中,“金融租赁系统”可谓是企业成功的秘密武器。简单来说,这个系统就像一位聪明的财务顾问,帮助企业在资金和资源的运用上达到最优化。从设备采购到项目融资,它提供了一种灵活的方式,让企业…

java版CRM客户关系管理系统crm管理系统+客户+营销管理CRM平台

项目名称:CRM客户关系管理系统 功能模块及描述: 一、待办事项 今日需联系客户:显示当日需跟进的客户列表,支持查询和筛选。 分配给我的线索:管理分配给用户的线索,包括线索列表和查询功能。 分配给我的客…

【K8S问题系列 |18 】如何解决 imagePullSecrets配置正确,但docker pull仍然失败问题

如果 imagePullSecrets 配置正确,但在执行 docker pull 命令时仍然失败,可能存在以下几种原因。以下是详细的排查步骤和解决方案。 1. 检查 Docker 登录凭证 确保你使用的是与 imagePullSecrets 中相同的凭证进行 Docker 登录: 1.1 直接登录…

基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功

基于FPGA的2FSK调制 前言一、2FSK储备知识二、代码分析1.模块分析2.波形分析 总结 前言 设计实现连续相位 2FSK 调制器,2FSK 的两个频率为:fI15KHz,f23KHz,波特率为 1500 bps,比特0映射为f 载波,比特1映射为 载波。 1&#xff09…