BananaFishSoft破解实战(算法分析|替换公钥|签名校验|注册机等)- tree_fly/P.Y.G
BananaFishSoft 破解实战(算法分析、替换公钥、签名校验、注册码生产等)tree_fly/P.Y.Gwww.chinapyg.comThanks to @creantan @飘云
所需工具:
[*]Hopper Disassembler v4
[*]Go
[*]lldb等
0x01 介绍软件今天主角是来自BananafishSoftware网站(https://bananafishsoftware.com)下面的三款 MacOS App。
先从Dumper入手,Dumper让class-dump变得非常容易上手,高亮的语法,快速搜索功能等,下面是Dumper的简介:Dumper lets you extract, browse and inspect the classdeclarations from any Mach-O file containing Objective-C runtime information.In other words, it generates information for all Objective-C classes andprotocols present in a Mach-O executable in a nice and friendly header fileformat.
0x02 寻找切入点
启动Hopper(Hopper Disassembler v4.0.8 论坛下载请移步https://www.chinapyg.com/thread-87967-1-1.html),尝试关键词搜索:
继续定位到Frameworks文件夹中的 LLRegistrationKit.framework,试试用Dumper来查看头文件:
不错,自带语法高亮 ,不过还是习惯了强大的Hopper,
0x03 算法分析1:Hopper的Show Pseudo Code of Procedure功能可以查看伪代码(类似IDA的F5):void -(void * self, void * _cmd, void * arg2) {
r13 = self;
r14 = [ retain];
rbx = [ retain];
rdx = r14;
r15 = [ verifyLicense:rdx error:0x0];
var_38 = ;
;
if (r15 != 0x0) {
rbx = [ retain];
;
;
rbx = [ retain];
;
;
}
else {
;
}
;
;
return;
}
一层一层分析
char +(void * self, void * _cmd, void * arg2, void * * arg3) {
r15 = ;
rbx = [ retain];
r13 = [ retain];
;
rbx = [ retain];
r12 = [ retain];
;
rbx = ___vl();
;
;
;
rax = sign_extend_64(rbx);
return rax;
}
关键验证函数:
int ___vl() {
var_108 = rcx;
var_30 = *___stack_chk_guard;
r13 = _objc_retain;
var_F0 = ;
var_F8 = ;
var_100 = ;
intrinsic_movaps(var_C0, 0x0);
intrinsic_movaps(var_D0, 0x0);
var_E0 = intrinsic_movaps(var_E0, 0x0);
r15 = [ retain];
rbx = [ retain];
r14 = ;
;
rdi = r15;
;
rbx = 0x0;
if (SecItemImport(r14, 0x0, 0xa, 0x2, 0x0, var_E0, 0x0, 0x0) == 0x0) {
rbx = 0x0;
if (CFArrayGetCount(0x0) > 0x0) {
rbx = CFRetain(CFArrayGetValueAtIndex(0x0, 0x0));
CFRelease(0x0);
}
}
注意关键词 public.pem,提示公钥文件,尝试查看文件路径,启动Hopper Debugger Server,在call语句下一行设置Breakpoints,查看返回值$rax
Tips:注意到断点设置在LLRegistrationKit.Framework内,此时调试需要双开Hopper,在Hopper的Dumper窗体下启动Debugger,同时需要注意执行文件的启动路径(以默认安装路径Application为例),如图示
设置完毕后,启动调试,稍等片刻,Dumper自动启动,菜单内点击注册界面,即可激活断点:
打开文件看看内容:
0x04 算法分析2 -Verify温习一下知识:Security transforms application programming interface(API) https://developer.apple.com/library/content/documentation/Security/Conceptual/SecTransformPG/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010801-CH1-SW1
分析几个关键函数_LLRegistrationKitDecodeConfusingCharactersAndRemoveGrouping();_LLRegistrationKitUniqueIdentifierLength(); _LLRegistrationKitDigest();
提取关键信息:SecDecodeTransformCreate(*_kSecBase32Encoding, rsi); // 解密SecVerifyTransformCreate(r12, rsi, rdx); // 验证
设置断点:SecVerifyTransformCreate的SecTransformSetAttribute(rdi, rsi, rdx,rcx);尝试如下注册码,来分析下被加密的信息:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
打印 $rdi
po $rdx
<41414141 41414141 41414141 41414141 41414141 41414141 41414141 41414141 4141417c 636f6d2e 64646576 696c6c65 2e64756d 7065727c 313030>
po [$rdx length]
0x000000000000003b
po [$rdx bytes]
0x00000001005ad200
x -c0x3b 0x00000001005ad200
0x1005ad200: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA
0x1005ad210: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41AAAAAAAAAAAAAAAA
0x1005ad220: 41 41 41 7c 63 6f 6d 2e 64 64 65 76 69 6c 6c 65AAA|com.ddeville
0x1005ad230: 2e 64 75 6d 70 65 72 7c 31 30 30 .dumper|100
...
至此算法分析完毕。同样分析其他两款软件,唯一区别的在于BundleID不同,他们分别是:"com.ddeville.spillo","com.ddeville.discodancer"
0x05 注册机- Sign提供几组随机飘云阁私钥签名加密的注册码:(飘云阁私钥、公钥链接:https://www.chinapyg.com/thread-91890-1-1.html)-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB7kiHY0omkKpzU9sDnaNwLQ6l
lxGbz+4mr1SIVVJtEA5YEQi+SVD1ALS2hZkpOjHUtLfiirz5sA+fhN0ngln12NjP
c0z8u3FuZ2aH4ffMlrWr9ysW0uvnkBlNXVF/g21l0H/Lt1HSVZmTBDMELeVlWIHL
HPRxEbVkjFhGliq13QIDAQAB
-----END PUBLIC KEY-----
注意:粘贴注册码之前,请手动替换公钥!!!
Dumper : ##WWW.CHINAPYG.COM##GFSWMMBVGAYWELJFC6D3X4TQFI3TAJB2Y3XZ4J7CRO2HPHRIVNFULX3CTVDFSJFDEP5XBGATN63DD25CP7JAY5K2AGFGRQCJ6SS6N4WN6UHVY2VA4AK37ERYJ6R2DZWH4FKJAIQMOL63CBQXBLMGPZIALT7QKXWHGBNTUESFLQVBE75YWCYBRKJPNDIK5NTODOGCLKR62ON32U77HAZRSFEZMQVO
Spillo : ##WWW.CHINAPYG.COM##GQYGCYLBMQ2DSLJQFB2QDSXSEASWH4ZLDT25PZJKZIU7QLH4PP2NWGN5G53EV3R4BQL2RPMG6TPWBXGEWI3XREXFKPL7FOKIOR5JDDJVSIGXBOGP372XIHFBNWTGVHIDWKRQ3NRWQXTHLCXCT3ZFCRXI2WNYGDMOMIJVADFKLIBVSWUBZSIBWHFZGWBFFB74IQGTS73GNBHBN65LWQ6EWBD5TCIS
Dancer : ##WWW.CHINAPYG.COM##HFSTENZUMMZDMLLF2SD5HB6LTUOOGGPWPH3HEQSFMTK6SOAMICKFJLQC4ZE5QCYRWBZBB4IIHHGGRMNQ4ZMDE7ZZ3PQWYFBPSR6S7XJLTU6XFUTQYM6XM44WSYZNVPEYRZMRPTKDSLSMBAXEDQCVPT46F54KG6UGFBJ6BVAJXZ7BIMQZUPJHQIY2BYX66QCAQRIT5BOO2ZA2SOW5L6MVYEAGA3U6
Go注册机源码:// ******************
// * code by creantan/P.Y.G
// ******************
package main
import (
"os"
"fmt"
"strings"
"encoding/pem"
"encoding/base32"
"crypto"
"crypto/x509"
"crypto/rsa"
"crypto/rand"
"github.com/urfave/cli"
"github.com/satori/go.uuid"
)
const (
pRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDB7kiHY0omkKpzU9sDnaNwLQ6llxGbz+4mr1SIVVJtEA5YEQi+
SVD1ALS2hZkpOjHUtLfiirz5sA+fhN0ngln12NjPc0z8u3FuZ2aH4ffMlrWr9ysW
0uvnkBlNXVF/g21l0H/Lt1HSVZmTBDMELeVlWIHLHPRxEbVkjFhGliq13QIDAQAB
AoGBAKCKTtZtVpwYVFKGj58tp3gchKyGI9iVyDOUH2mBIGwSx50V9OP5s6Auxmr2
q/UaLNhGBpfufERDAJvwlFe5rBfKv4H9tWiR82KFHZPQK+Cd3mlre0c2jB5aimIu
fiAmNZmlyudBm0eN45c/t8jcbeK2UXvseN5d9fdqnPs8XKjBAkEA+sej2nyG5YAJ
dUa5fLE1H45j9FikpXqIWZi/aVe9vwSUoXbzYqv/DssaZt5HejKzqYkf3f86O65u
wVN5sjmqzQJBAMX3tH9jb1nCF69tCB6tUTrTWX+wHVsvCHs3VQJXp5iaU2DewmL4
k0Dddis6xcBThywfbAMA/1Thn+DOubxgV1ECQEcCUo4iJpxDdeokPY9mKhGmYv0k
QHKu0H72NnTgqFS3OlLB+MaexxjsP6yTEhAy3RaLQl+8zkNp7+iD93iUxZ0CQQDF
mJbax98u0iJeARAnvorjkm00nA7RIsLuaa46Jk+sa+1pNS8FJmOkTOhUAde8PiMf
kUV4QhiZGpNAClcthWPhAkAa1L9X9J9ng8MaIDXMpjNAlFlnEuJ25wXbgiDWrfJY
QAMiDzc8qm0iB/9i86rCGnwFf1sO53L9gjiq13VjjLQg
-----END RSA PRIVATE KEY-----`
)
var bundleid []string = []string{"com.ddeville.dumper", "com.ddeville.spillo", "com.ddeville.discodancer"}
func RandKey() string{
u1 := uuid.NewV4().String()+uuid.NewV4().String()
randStr := base32.StdEncoding.EncodeToString([]byte(u1))
randKey := randStr[:35]
return randKey
}
func Sign(data string) ([]byte, error) {
block, _ := pem.Decode([]byte(pRIVATE_KEY))
if block == nil {
fmt.Println("pem.Decode err")
}
private, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
fmt.Println("ParsePKCS8PrivateKey err", err)
}
h := crypto.Hash.New(crypto.SHA1)
h.Write([]byte(data))
hashed := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand.Reader, private,
crypto.SHA1, hashed)
if err != nil {
fmt.Println("Error from signing: %s\n", err)
return nil, err
}
return signature, nil
}
func KeygenWithBundleId(bundleId string) string {
randKey := RandKey()
data,_ := Sign(randKey+"|"+bundleId+"|100")
base32Str := base32.StdEncoding.EncodeToString(data)
base32Str = strings.Replace(base32Str,"=","",-1)
encoded_signature := ""
for i:= 0; i<len(randKey)-1;i+=5{
encoded_signature += randKey+"-"
}
for i:= 0; i<len(base32Str)-1;i+=5{
encoded_signature += base32Str+"-"
}
encoded_signature = encoded_signature[:len(encoded_signature)-1]
encoded_signature = strings.Replace(encoded_signature,"O","8",-1)
encoded_signature = strings.Replace(encoded_signature,"I","9",-1)
return encoded_signature
}
func main() {
app := cli.NewApp()
app.Name = "\x1b[1m\x1b[95mBananaFish KeyGen"
app.Usage = "\x1b[4m\x1b[95mBBS.CHINAPYG.COM\x1b[0m"
app.UsageText = "\x1b Example: keygen 1\n\t [+] 1. Dumper\n\t [+] 2. Spillo\n\t [+] 3. Disco Dancer\x1b[0m"
app.Version = "\x1b[94m1.0.0\x1b[0m"
app.Action = func(c *cli.Context) error {
choose := c.Args().Get(0)
key := ""
if choose == "1" {
key = KeygenWithBundleId(bundleid)
fmt.Println("\x1b Dumper \x1b[0m: \x1b[1m\x1b[0m\x1b[93m",key)
} else if choose == "2" {
key = KeygenWithBundleId(bundleid)
fmt.Println("\x1b Spillo : \x1b[1m\x1b[0m\x1b[93m",key)
} else if choose == "3" {
key = KeygenWithBundleId(bundleid)
fmt.Println("\x1b Disco Dancer : \x1b[1m\x1b[0m\x1b[93m",key)
} else {
cli.ShowAppHelp(c)
}
return nil
}
app.Run(os.Args)
}
谢谢大神的讲解和分享!收藏了 坐沙发学习,谢谢表哥精彩破文 新一波MAC文章6 除了膜拜 还是膜拜 硬伤 膜拜飞博士~~ @tree_fly博士 你把C版大名写错了。蛤蛤 飘云 发表于 2017-8-17 12:50
@tree_fly博士 你把C版大名写错了。蛤蛤
哈哈,C版~,笔误笔误~
飞博士牛X~~~ 对飞树大表哥的敬仰:犹如滔滔江水绵绵不绝,又如黄河泛滥一发不可收拾!