吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5984|回复: 29
收起左侧

[原创] 第一次尝试粗浅的逆向破解golang程序

  [复制链接]
蚯蚓翔龙 发表于 2022-9-4 17:36

前言

这几天在我无聊逛 github 的时候,发现了一个写着能导出微信数据库密码和聊天记录的仓库,就想下载运行看看效果如何。

image app.zip (2.05 MB, 下载次数: 32)

然而启动后且报错 pass error,显然是需要个正确密码。

image

之后试用了下确实能用,但我很好奇 dump 个微信密钥就这为什么还得需要传个密码才能启动,而且 git 上也没源码只放了 release,第一想法以为可能是暗藏了根据电脑时间来做运行限制之类的暗桩,比如超过某段时间后算法会计算要提供新的密码才能用,也可能是这程序本来是在 shell 上用的,为了防止被蓝队拿了然后去分析或者二次利用。(其实我也经常想给自己的程序加个启动密码。另外 README 本有写要传密码,刚开始没注意)

所以想看看是为什么要这么搞,能不能把密码限制给去掉。

初步分析

用 exeinfope 查了目标程序,无壳,64 位程序,用 go 语言写的。可以直接上 IDA 分析,或者用 x64dbg。

image.png

之前没分析过编译后的 go 程序,大概知道 golang 是静态链接的,封装层次高,有多返回值特点,gc、协程实现,标准库第三方库等等都嵌入了,文件体积贼大。

载入 IDA,能看到一大坨的函数,不可能一个个都去看的。后面干啃去调试时,函数间的跳转比较饶,加上有异步,容易跑飞。

image

像这种应该就是被 strip 掉了符号,go build 本身有命令可以去掉

go build ldflags="-s -w" main.go

也没找到 .gopclntab 区段

开局,搜索字符串

按老套路,最简单的搜索字符串,定位关键代码

image

然而可惜的是,这并没有什么用,都找不到。这时猜测要么就是故意加密了,要么就是 go 字符串结构比较特殊。只能采取其他方法。

还原符号

由于启动密码的判断都写在程序的开头,如果能找到入口点,分析起来就简单不少,虽然这个程序没有调试符号,但一般情况就算 go 编译时去掉了,也还会包含一定量的信息,能还原出一些函数符号和源码文件路径。

我借助了 IDAPython 运行 go_parseIDAGolangHelper 那些脚本来解析,希望能方便后续分析。

然而可惜的是,不是有报错就是解析不全面,字符串也没解析出来,没有看到 main_init main_main 入口函数,当然可能是 go 版本较高,pclntab 结构有变化,一些工具还不支持。

不过至少还原了部分 runtime,这总比干啃好。

image

有些奇怪的是,解析之后不少函数名都是随机字符串。我也不确定这程序是经过了混淆保护了,还是 golang 本身有其他什么设置就能导致如此。

image

额外说一下:有时候 go 版本号可以在 ida string 列表找到。(虽然这个找不到)

image

go 的汇编代码底部会有个 jmp 到函数头,用这个特征可以识别出函数体,IDA 有时识别不出来,手动按 c 可以强制分析成代码

image

IDA rebase 一下基址或导出 map 方便在调试时候对着看

image

动态调试 API 断点回溯

接着尝试从 API 下断入手,逼近关键代码,首先很容易想到获取启动参数的 API 会用到 GetCommandLineW,go 用 fmt.println 写出到控制台的 API 则可能是 WriteFileWriteConsoleW(64 位一般直接断 W),载入程序后下断点运行。

image

返回用户模块空间,接下来每一次返回提前在 ret 处下好断点,很容易跟飞

image

image

中间遇到循环不用管,一直专注回溯

image

同时注意堆栈字符串的变化,println 是分成时间和 pass error 两段。

看到这里再往后一两次 ret 差不多就到了。

image

这地方就差不多到了,在函数头下断点,,如果不确定就多下 F2,重载运行,输入参数。

0000000000DE5F60  | 4C:8D6424 E8             | lea r12,qword ptr ss:[rsp-18]                             |

image

这种方法还是比较绕的,尤其是没有符号和不熟悉的情况,下面还有其他方法。

跟踪数据读写

命令行参数值始终是要判断的,用 go 写个 demo,大概写法就是:

package main

import (
        "fmt"
        "os"
)

func main() {
        if len(os.Args) > 2 {
                if os.Args[1] == "123456" {
                        fmt.Printf("os.Args[1]: %v\n", os.Args[1])
                } else {
                        fmt.Println("pass error")
                }
        } else {
                fmt.Println("error 1")
        }
}

在没有符号的情况下,可以通过对比自己写的 demo 汇编结构和 go 源码来人肉识别某些库函数。

// These routines end in 'ln', do not take a format string,
// always add spaces between operands, and add a newline
// after the last operand.

// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...any) (n int, err error) {
        p := newPrinter()
        p.doPrintln(a)
        n, err = w.Write(p.buf)
        p.free()
        return
}
...
......

os.Args 是一个全局切面变量,找到这个也可以定位。os.Args 是在 os.init 中初始化的。

image

启动后对 GetCommandLineW 下段,单步往下,对 rax 的第一个参数下硬件访问断点

1662194220046

F9 运行来到这里,看起来只是在计算长度,继续运行

1662194314120

循环取值到 edi,然后赋值转移到 [rax+rbx*4],那也在这里下个硬件断点

image

接着运行

image

这些地方大概是在将 unicode 的 string 转换编码,单步往下走,末尾 ret 下断,eax 有有新生成的字符串地址

image

继续单步下去,观察 eax 用到哪

image

可以发现赋给了一个值

image

image

mov qword ptr ds:[0x0000000000F0F300], rax 这里就是 os.Args,这应该是个通用特征,可以通过搜索常量引用或者硬件下断都可以定位到校验方法

0000000000DE5F60  | 4C:8D6424 E8             | lea r12,qword ptr ss:[rsp-18]                             |

image

patch 代码

很简单了,有字符串比较,跟一遍,只要 nop 掉两处跳转即可

image

另外字符串是用这些方法移位解密的,怪不得搜不到。

0000000000DE58C0  | 49:3B66 10               | cmp rsp,qword ptr ds:[r14+10]           |
0000000000DE58C4  | 0F86 EE010000            | jbe target.DE5AB8                       |
0000000000DE58CA  | 48:83EC 70               | sub rsp,70                              |
0000000000DE58CE  | 48:896C24 68             | mov qword ptr ss:[rsp+68],rbp           | [rsp+68]:"袩\r"
0000000000DE58D3  | 48:8D6C24 68             | lea rbp,qword ptr ss:[rsp+68]           | [rsp+68]:"袩\r"
0000000000DE58D8  | 48:BA E4E18554A2A332C3   | mov rdx,C332A3A25485E1E4                |
0000000000DE58E2  | 48:895424 54             | mov qword ptr ss:[rsp+54],rdx           |
0000000000DE58E7  | 48:BA A2A332C3BFD17EA1   | mov rdx,A17ED1BFC332A3A2                |
0000000000DE58F1  | 48:895424 58             | mov qword ptr ss:[rsp+58],rdx           |
0000000000DE58F6  | 48:BA C5CDCF5350E17134   | mov rdx,3471E15053CFCDC5                |
0000000000DE5900  | 48:895424 60             | mov qword ptr ss:[rsp+60],rdx           |
0000000000DE5905  | 0FB65424 55              | movzx edx,byte ptr ss:[rsp+55]          |
0000000000DE590A  | 885424 53                | mov byte ptr ss:[rsp+53],dl             |
0000000000DE590E  | 44:0FB64424 66           | movzx r8d,byte ptr ss:[rsp+66]          |
0000000000DE5914  | 44:884424 52             | mov byte ptr ss:[rsp+52],r8b            |
0000000000DE5919  | 44:0FB64C24 54           | movzx r9d,byte ptr ss:[rsp+54]          |
0000000000DE591F  | 44:884C24 51             | mov byte ptr ss:[rsp+51],r9b            |
0000000000DE5924  | 44:0FB65424 56           | movzx r10d,byte ptr ss:[rsp+56]         |
0000000000DE592A  | 44:885424 50             | mov byte ptr ss:[rsp+50],r10b           |
0000000000DE592F  | 44:0FB65C24 5B           | movzx r11d,byte ptr ss:[rsp+5B]         |
0000000000DE5935  | 44:885C24 4F             | mov byte ptr ss:[rsp+4F],r11b           |
0000000000DE593A  | 44:0FB66424 64           | movzx r12d,byte ptr ss:[rsp+64]         |
0000000000DE5940  | 44:886424 4E             | mov byte ptr ss:[rsp+4E],r12b           |
0000000000DE5945  | 44:0FB66C24 57           | movzx r13d,byte ptr ss:[rsp+57]         |
0000000000DE594B  | 44:886C24 4D             | mov byte ptr ss:[rsp+4D],r13b           |
0000000000DE5950  | 44:0FB67C24 65           | movzx r15d,byte ptr ss:[rsp+65]         |
0000000000DE5956  | 44:887C24 4C             | mov byte ptr ss:[rsp+4C],r15b           |
0000000000DE595B  | 44:0FB66C24 58           | movzx r13d,byte ptr ss:[rsp+58]         |
0000000000DE5961  | 44:886C24 4B             | mov byte ptr ss:[rsp+4B],r13b           |
0000000000DE5966  | 44:0FB66C24 5E           | movzx r13d,byte ptr ss:[rsp+5E]         |
0000000000DE596C  | 44:886C24 4A             | mov byte ptr ss:[rsp+4A],r13b           |
0000000000DE5971  | 44:0FB66C24 67           | movzx r13d,byte ptr ss:[rsp+67]         |
0000000000DE5977  | 44:886C24 49             | mov byte ptr ss:[rsp+49],r13b           |
0000000000DE597C  | 44:0FB66C24 62           | movzx r13d,byte ptr ss:[rsp+62]         |
0000000000DE5982  | 44:886C24 48             | mov byte ptr ss:[rsp+48],r13b           |
0000000000DE5987  | 44:0FB66C24 61           | movzx r13d,byte ptr ss:[rsp+61]         |
0000000000DE598D  | 44:886C24 47             | mov byte ptr ss:[rsp+47],r13b           |
0000000000DE5992  | 44:0FB66C24 5C           | movzx r13d,byte ptr ss:[rsp+5C]         |
0000000000DE5998  | 44:886C24 46             | mov byte ptr ss:[rsp+46],r13b           |
0000000000DE599D  | 44:0FB66C24 60           | movzx r13d,byte ptr ss:[rsp+60]         |
0000000000DE59A3  | 44:886C24 45             | mov byte ptr ss:[rsp+45],r13b           |
0000000000DE59A8  | 44:0FB66C24 63           | movzx r13d,byte ptr ss:[rsp+63]         |
0000000000DE59AE  | 44:886C24 44             | mov byte ptr ss:[rsp+44],r13b           |
0000000000DE59B3  | 44:0FB66C24 5F           | movzx r13d,byte ptr ss:[rsp+5F]         |
0000000000DE59B9  | 44:886C24 43             | mov byte ptr ss:[rsp+43],r13b           |
0000000000DE59BE  | 44:0FB66C24 59           | movzx r13d,byte ptr ss:[rsp+59]         |
0000000000DE59C4  | 44:886C24 42             | mov byte ptr ss:[rsp+42],r13b           |
0000000000DE59C9  | 44:0FB66C24 5A           | movzx r13d,byte ptr ss:[rsp+5A]         |
0000000000DE59CF  | 44:886C24 41             | mov byte ptr ss:[rsp+41],r13b           |
0000000000DE59D4  | 44:0FB66C24 5D           | movzx r13d,byte ptr ss:[rsp+5D]         |
0000000000DE59DA  | 44:886C24 40             | mov byte ptr ss:[rsp+40],r13b           |
0000000000DE59DF  | 48:8D05 5AAE0000         | lea rax,qword ptr ds:[DF0840]           | rax:"pass er"
0000000000DE59E6  | 31DB                     | xor ebx,ebx                             |
0000000000DE59E8  | 31C9                     | xor ecx,ecx                             |
0000000000DE59EA  | 48:89CF                  | mov rdi,rcx                             | rdi:"pass er"
0000000000DE59ED  | BE 0A000000              | mov esi,A                               | A:'\n'
0000000000DE59F2  | E8 89A4E9FF              | call target.C7FE80                      |
0000000000DE59F7  | 0FB65424 53              | movzx edx,byte ptr ss:[rsp+53]          |
0000000000DE59FC  | 44:0FB64424 52           | movzx r8d,byte ptr ss:[rsp+52]          |
0000000000DE5A02  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A05  | 8810                     | mov byte ptr ds:[rax],dl                | rax:"pass er"
0000000000DE5A07  | 0FB65424 50              | movzx edx,byte ptr ss:[rsp+50]          |
0000000000DE5A0C  | 44:0FB64424 51           | movzx r8d,byte ptr ss:[rsp+51]          |
0000000000DE5A12  | 44:31C2                  | xor edx,r8d                             |
0000000000DE5A15  | 8850 01                  | mov byte ptr ds:[rax+1],dl              | rax+1:"ass er"
0000000000DE5A18  | 0FB65424 4F              | movzx edx,byte ptr ss:[rsp+4F]          |
0000000000DE5A1D  | 44:0FB64424 4E           | movzx r8d,byte ptr ss:[rsp+4E]          |
0000000000DE5A23  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A26  | 8850 02                  | mov byte ptr ds:[rax+2],dl              | rax+2:"ss er"
0000000000DE5A29  | 0FB65424 4D              | movzx edx,byte ptr ss:[rsp+4D]          |
0000000000DE5A2E  | 44:0FB64424 4C           | movzx r8d,byte ptr ss:[rsp+4C]          |
0000000000DE5A34  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A37  | 8850 03                  | mov byte ptr ds:[rax+3],dl              | rax+3:"s er"
0000000000DE5A3A  | 0FB65424 4A              | movzx edx,byte ptr ss:[rsp+4A]          |
0000000000DE5A3F  | 44:0FB64424 4B           | movzx r8d,byte ptr ss:[rsp+4B]          |
0000000000DE5A45  | 44:01C2                  | add edx,r8d                             |
0000000000DE5A48  | 8850 04                  | mov byte ptr ds:[rax+4],dl              | rax+4:" er"
0000000000DE5A4B  | 0FB65424 49              | movzx edx,byte ptr ss:[rsp+49]          |
0000000000DE5A50  | 44:0FB64424 48           | movzx r8d,byte ptr ss:[rsp+48]          |
0000000000DE5A56  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A59  | 8850 05                  | mov byte ptr ds:[rax+5],dl              | rax+5:"er"
0000000000DE5A5C  | 0FB65424 46              | movzx edx,byte ptr ss:[rsp+46]          |
0000000000DE5A61  | 44:0FB64424 47           | movzx r8d,byte ptr ss:[rsp+47]          |
0000000000DE5A67  | 44:31C2                  | xor edx,r8d                             |
0000000000DE5A6A  | 8850 06                  | mov byte ptr ds:[rax+6],dl              |
0000000000DE5A6D  | 0FB65424 45              | movzx edx,byte ptr ss:[rsp+45]          |
0000000000DE5A72  | 44:0FB64424 44           | movzx r8d,byte ptr ss:[rsp+44]          |
0000000000DE5A78  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A7B  | 8850 07                  | mov byte ptr ds:[rax+7],dl              |
0000000000DE5A7E  | 0FB65424 43              | movzx edx,byte ptr ss:[rsp+43]          |
0000000000DE5A83  | 44:0FB64424 41           | movzx r8d,byte ptr ss:[rsp+41]          |
0000000000DE5A89  | 44:29C2                  | sub edx,r8d                             |
0000000000DE5A8C  | 8850 08                  | mov byte ptr ds:[rax+8],dl              |
0000000000DE5A8F  | 0FB65424 40              | movzx edx,byte ptr ss:[rsp+40]          |
0000000000DE5A94  | 44:0FB64424 42           | movzx r8d,byte ptr ss:[rsp+42]          |
0000000000DE5A9A  | 44:31C2                  | xor edx,r8d                             |
0000000000DE5A9D  | 8850 09                  | mov byte ptr ds:[rax+9],dl              |
0000000000DE5AA0  | 48:8D4B 0A               | lea rcx,qword ptr ds:[rbx+A]            |
0000000000DE5AA4  | 48:89C3                  | mov rbx,rax                             | rax:"pass er"
0000000000DE5AA7  | 31C0                     | xor eax,eax                             |
0000000000DE5AA9  | E8 D2D6E9FF              | call target.C83180                      |
0000000000DE5AAE  | 48:8B6C24 68             | mov rbp,qword ptr ss:[rsp+68]           | [rsp+68]:"袩\r"
0000000000DE5AB3  | 48:83C4 70               | add rsp,70                              |
0000000000DE5AB7  | C3                       | ret                                     |
0000000000DE5AB8  | E8 63C0EAFF              | call target.C91B20                      |
0000000000DE5ABD  | 0F1F00                   | nop dword ptr ds:[rax],eax              |
0000000000DE5AC0  | E9 FBFDFFFF              | jmp target.DE58C0                       |

没什么技术含量,以上纯属初次学习和分享。附件包含目标程序、和 patch 过后的程序。

debug 一小时,写文章好久了,有些图片截图的时间比较久了,后面重新换了,所以可能会有些输出对不上



app.zip

2.05 MB, 下载次数: 64, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 20威望 +1 吾爱币 +79 热心值 +20 收起 理由
xinluan + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
bobo2017365 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
timeni + 1 + 1 用心讨论,共获提升!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Huangyc + 1 + 1 谢谢@Thanks!
Wangming0214 + 1 + 1 我很赞同!
连晋 + 1 + 1 學習了 感謝分享 帖子寫的很詳細 nice
peiwithhao + 1 + 1 用心讨论,共获提升!
ddddhm + 1 + 1 我很赞同!
manyou + 1 + 1 谢谢@Thanks!
八月未央 + 1 + 1 我很赞同!
RUO + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
coder9527 + 1 + 1 热心回复!
MisfitsYaa + 1 + 1 用心讨论,共获提升!
苏紫方璇 + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Liona + 1 + 1 谢谢@Thanks!
Sound + 40 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
gaffey + 1 + 1 我很赞同!
woflant + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 蚯蚓翔龙 发表于 2022-9-4 23:48
|矢空 发表于 2022-9-4 21:16
IDA7.5 之后可以直接解析出go的函数符号,不需要插件了,可以方便一点

对于这个应该是strip过没法直接解析
jujumanman 发表于 2022-9-7 14:12
之前遇到过一个golang的程序,ida插件解析不出符号,现在看来可能也是strip掉了吧,学到了,感谢分享!
淡忘不了的记忆 发表于 2022-9-4 19:09
ciker_li 发表于 2022-9-4 19:12
感谢分享
hermanleung 发表于 2022-9-4 20:29
好强1111
|矢空 发表于 2022-9-4 21:16
IDA7.5 之后可以直接解析出go的函数符号,不需要插件了,可以方便一点
aspllh 发表于 2022-9-4 22:26
学习了..感谢大佬的教程!
lyn038111 发表于 2022-9-4 22:27
感谢分享,666
icjhao 发表于 2022-9-4 23:13
这个程序主要是做什么用的
kotlyne 发表于 2022-9-4 23:32
学习了学习了
友谊少年sss 发表于 2022-9-4 23:47
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 16:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表