前言

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

第一次尝试粗浅的逆向破解golang程序"https://static.52pojie.cn/static/image/filetype/zip.gif" border="0" class="vm" alt="" />app.zip2022-9-4 17:36 上传点击文件名下载附件

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

第一次尝试粗浅的逆向破解golang程序"43921813_初步分析">初步分析

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

第一次尝试粗浅的逆向破解golang程序

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

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

第一次尝试粗浅的逆向破解golang程序

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

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

也没找到 .gopclntab 区段

开局,搜索字符串

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

第一次尝试粗浅的逆向破解golang程序"43921813_还原符号">还原符号

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

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

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

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

第一次尝试粗浅的逆向破解golang程序

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

第一次尝试粗浅的逆向破解golang程序"https://img1.imgtp.com/2022/09/04/63scSIy7.png" alt="image" />"https://img1.imgtp.com/2022/09/04/EtiJgD5X.png" alt="image" />

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

第一次尝试粗浅的逆向破解golang程序"43921813_动态调试-api-断点回溯">动态调试 API 断点回溯

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

第一次尝试粗浅的逆向破解golang程序"https://img1.imgtp.com/2022/09/04/1zjtt0oQ.png" alt="image" />

第一次尝试粗浅的逆向破解golang程序

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

第一次尝试粗浅的逆向破解golang程序

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

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

第一次尝试粗浅的逆向破解golang程序

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

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

第一次尝试粗浅的逆向破解golang程序

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

跟踪数据读写

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

package mainimport (        "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 中初始化的。

第一次尝试粗浅的逆向破解golang程序

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

第一次尝试粗浅的逆向破解golang程序"https://img1.imgtp.com/2022/09/04/THwHUB19.png" alt="1662194314120" />

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

第一次尝试粗浅的逆向破解golang程序

接着运行

第一次尝试粗浅的逆向破解golang程序"https://img1.imgtp.com/2022/09/04/2CxWv5mt.png" alt="image" />"https://img1.imgtp.com/2022/09/04/5YKmwxav.png" alt="image" />

可以发现赋给了一个值

第一次尝试粗浅的逆向破解golang程序

第一次尝试粗浅的逆向破解golang程序"https://img1.imgtp.com/2022/09/04/t7tDCauB.png" alt="image" />"43921813_patch-代码">patch 代码

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

第一次尝试粗浅的逆向破解golang程序"x86asm">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 一小时,写文章好久了,有些图片截图的时间比较久了,后面重新换了,所以可能会有些输出对不上


标签:
第一次尝试粗浅的逆向破解golang程序