欢迎进入UG环球官网(环球UG)!

usdt支付接口(www.caibao.it):【手艺推荐】正向角度看Go逆向

admin9个月前420

正向角度看Go逆向

Go语言具有开发效率高,运行速度快,跨平台等优点,因此正越来越多的被攻击者所使用,其天生的是可直接运行的二进制文件,因此对它的剖析类似于通俗C语言可执行文件剖析,然则又有所差别,本文将会使用正向与逆向连系的方式形貌这些区别与特征。

一、语言特征

Ⅰ. Compile与Runtime

Go语言类似于C语言,目的是一个二进制文件,逆向的也是native代码,它有如下特征:

  1. 强类型检查的编译型语言,靠近C但拥有原生的包治理,内建的网络包,协程等使其成为一款开发效率更高的工程级语言。
  2. 作为编译型语言它有运行速度快的优点,然则它又能通过内置的运行时符号信息实现反射这种动态特征。
  3. 作为一种内存平安的语言,它不仅有内建的垃圾接纳,还在编译与运行时提供了大量的平安检查。

可见只管它像C编译的可执行文件然则拥有更庞大的运行时库,Go通常也是直接将这些库统一打包成一个文件的,即使用静态链接,因此其程序体积较大,且三方库、尺度库与用户代码混在一起,需要区分,这可以用类似flirt方式做区分(特别是对于做了混淆的程序)。在剖析Go语言编写的二进制程序前,需要弄清楚某一操作是发生在编译时代照样运行时代,能在编译时做的事就在编译时做,这能实现错误前移并提高运行效率等,而为了语言的灵活性引入的某些功效又必须在运行时才气确定,在这时就需要想到运行时它应该怎么做,又需要为它提供哪些数据,例如:

func main() {
    s := [...]string{"hello", "world"}
    fmt.Printf("%s %s\n", s[0], s[1])  // func Printf(format string, a ...interface{}) (n int, err error)
}

在第二行界说了一个字符串数组,第三行将其输出,编译阶段就能确定元素接见的指令以及下标接见是否越界,于是就可以去除s的类型信息。然则由于Printf的输入是interface{}类型,因此在编译时它无法得知传入的数据现实为什么类型,然则作为一个输出函数,希望传入数字时直接输出,传入数组时遍历输出每个元素,那么在传入参数时,就需要在编译时把现实参数的类型与参数绑定后再传入Printf,在运行时它就能凭据参数绑定的信息确定是什么类型了。其实在编译时,编译器做的事还许多,从逆向看只需要注意它会将许多操作转换为runtime的内建函数挪用,这些函数界说在cmd/compile/internal/gc/builtin/runtime.go,并且在src/runtime目录下对应文件中实现,例如:

a := "123" + b + "321"

将被转换为concatstring3函数挪用:

0x0038 00056 (str.go:4) LEAQ    go.string."123"(SB), AX
0x003f 00063 (str.go:4) MOVQ    AX, 8(SP)
0x0044 00068 (str.go:4) MOVQ    $3, 16(SP)
0x004d 00077 (str.go:4) MOVQ    "".b+104(SP), AX
0x0052 00082 (str.go:4) MOVQ    "".b+112(SP), CX
0x0057 00087 (str.go:4) MOVQ    AX, 24(SP)
0x005c 00092 (str.go:4) MOVQ    CX, 32(SP)
0x0061 00097 (str.go:4) LEAQ    go.string."321"(SB), AX
0x0068 00104 (str.go:4) MOVQ    AX, 40(SP)
0x006d 00109 (str.go:4) MOVQ    $3, 48(SP)
0x0076 00118 (str.go:4) PCDATA  $1, $1
0x0076 00118 (str.go:4) CALL    runtime.concatstring3(SB)

我们将在汇编中看到大量这类函数挪用,本文将在对应章节先容最常见的一些函数。若需要考察某语法最终编译后的汇编代码,除了使用ida等也可以直接使用如下三种方式:

go tool compile -N -l -S once.go
go tool compile -N -l once.go ; go tool objdump -gnu -s Do once.o
go build -gcflags -S once.go

Ⅱ. 动态与类型系统

只管是编译型语言,Go仍然提供了一定的动态能力,这主要表现在接口与反射上,而这些能力离不开类型系统,它需要保留需要的类型界说以及工具和类型之间的关联,这部门内容无法在二进制文件中被去除,否则会影响程序运行,因此在Go逆向时能获取到大量的符号信息,大大简化了逆向的难度,对此类信息已有大量文章先容并有许多优异的的工具可供使用,例如go_parser与redress,因此本文不再赘述此内容,此处推荐《Go二进制文件逆向剖析从基础到进阶——综述》。

本文将从语言特征上先容Go语言编写的二进制文件在汇编下的种种结构,为了表述利便此处界说一些约定:

  1. 只管Go并非面向工具语言,然则本文将Go的类型形貌为类,将类型对应的变量形貌为类型的实例工具。
  2. 本文剖析的样例是x64上的样本,通篇会对应该平台叙述,一个机器字以为是64bit。
  3. 本文会涉及到Go的参数和汇编层面的参数形貌,好比一个复数在Go层面是一个参数,然则它占16字节,在汇编上将会分成两部门通报(不使用xmm时),就以为汇编层面是两个参数。
  4. 一个庞大的实例工具可以分为索引头和数据部门,它们在内存中涣散存储,下文提到一种数据所占内存巨细是指索引头的巨细,由于这部门是逆向关注的点,详见下文字符串结构。

二、数据结构

Ⅰ. 数值类型

数值类型很简单只需要注意其巨细即可:

,

AllbetGmaing下载

欢迎进入AllbetGmaing下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

,
类型 32位平台 64位平台
bool、int8、uint8 8bit 8bit
int16、uint16 16bit 16bit
int32、uint32、float32 32bit 32bit
int64、uint64、float64、complex64 64bit 64bit
int、uint、uintptr 32bit 64bit
complex128 128bit 1238bit

Ⅱ. 字符串string

Go语言中字符串是二进制平安的,它不以\0作为终止符,一个字符串工具在内存中分为两部门,一部门为如下结构,占两个机器字用于索引数据:

type StringHeader struct {
    Data uintptr            // 字符串首地址
    Len  int                // 字符串长度
}

而它的另一部门才存放真正的数据,它的巨细由字符串长度决议,在逆向中重点关注的是如上结构,因此说一个string占两个机器字,后文其他结构也按这种约定。例如下图使用printf输出一个字符串"hello world",它会将上述结构入栈,由于没有终止符ida无法正常识别字符串竣事因此输出了许多信息,我们需要依赖它的第二个域(此处的长度0x0b)决议它的竣事位置:

字符串常见的操作是字符串拼接,若拼接的个数不跨越5个会挪用concatstringN,否则会直接挪用concatstrings,它们声明如下,可见在多个字符串拼接时参数形式差别:

func concatstring2(*[32]byte, string, string) string
func concatstring3(*[32]byte, string, string, string) string
func concatstring4(*[32]byte, string, string, string, string) string
func concatstring5(*[32]byte, string, string, string, string, string) string
func concatstrings(*[32]byte, []string) string

因此在遇到concatstringN时可以跳过第一个参数,随后入栈的参数即为字符串,而遇到concatstrings时,跳过第一个参数后汇编层面还剩三个参数,其中后两个一样平常相同且指明字符串个数,第一个参数则指明字符串数组的首地址,另外经常出现的是string与[]byte之间的转换,详见下文slice部门。提醒一下,可能是优化导致一样平常来说在栈内一个纯字符串的两部门在物理上并没有延续存放,例如下图挪用macaroncontext.Query("username")获取到的应该是一个代表username的字符串,然则它们并没有被延续存放:

因此ida中通过界说内陆结构体去剖析string会遇到困难,其他结构也存在这类情形,气。

Ⅲ. 数组array

类似C把字符串看作char数组,Go类比知array和string的结构类似,其真实数据也是在内存里延续存放,而使用如下结构索引数据,对数组里的元素接见其地址偏移在编译时就能确定,总之逆向角度看它也是占两个机器字:

type arrayHeader struct {
    Data uintptr        
    Len int
}

数组有三种存储位置,当数组内元素较少时可以直接存于栈上,较多时存于数据区,而当数据会被返回时会存于堆上。如下界说了三个局部变量,然则它们将在底层表现出差别的形态:

func ArrDemo() *[3]int {
    a := [...]int{1, 2, 3}
    b := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7}
    c := [...]int{1, 2, 3}
    if len(a) < len(b) {return &c}
    return nil
}

变量a的汇编如下,它直接在栈上界说并初始化:

变量b的汇编如下,它的初始值被界说在了数据段并举行拷贝初始化:

事实上更常见的拷贝操作会被界说为如下这类函数,因此若符号信息完整遇到无法识别出的函数一样平常也就是数据拷贝函数:

变量c的汇编如下,只管它和a的值一样,然则它的地址会被返回,如果在C语言中这种写法会造成严重的结果,不外Go作为内存平安的语言在编译时就识别出了该问题(指针逃逸)并将其放在了堆上,此处引出了runtime.newobject函数,该函数传入的是数据的类型指针,它将在堆上申请空间存放工具实例,返回的是新的工具指针:

经常会遇到的情形是返回一个结构体变量,然后将其赋值给newobject申请的新变量上

Ⅳ. 切片slice

类似数组,切片的实例工具数据结构如下,可知它占用了三个机器字,与它相关的函数是growslice示意扩容,逆向时可忽略:

go

登录并阅读全文
上一篇 下一篇

猜你喜欢

网友评论

  • 2021-01-17 00:00:24

      1月6日早间,*ST天夏开盘即跌停,下跌5.33%,报0.71元。而这已是其延续第15个交易日股价低于1元,若今日无法打开跌停并封至涨停板,*ST天夏将成为新规下首只1元退市股。很好嘛

    • 2021-01-20 05:04:49

      @皇冠官网平台 Usdt支付接口菜包钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,自动充提平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜包Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。我也想写这么好的

  • 2021-02-13 00:01:34

    菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。姐妹们快看神仙

随机文章
热门文章
热评文章
热门标签