飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 19629|回复: 31

[macOS] BananaFishSoft破解实战(算法分析|替换公钥|签名校验|注册机等)- tree_fly/P.Y.G

  [复制链接]
  • TA的每日心情
    开心
    2019-3-17 22:44
  • 签到天数: 132 天

    [LV.7]常住居民III

    发表于 2017-8-17 01:52:07 | 显示全部楼层 |阅读模式
    BananaFishSoft 破解实战(算法分析、替换公钥、签名校验、注册码生产等)

    tree_fly/P.Y.G
    Thanks to @creantan @飘云

    所需工具:

    • Hopper Disassembler v4
    • Go
    • lldb

    0x01 介绍软件
    今天主角是来自BananafishSoftware网站(https://bananafishsoftware.com)下面的三款 MacOS App。

    QQ20170816-211820.png

    先从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.

    QQ20170816-212521.png



    0x02 寻找切入点

    启动Hopper(Hopper Disassembler v4.0.8 论坛下载请移步https://www.chinapyg.com/thread-87967-1-1.html),尝试关键词搜索:

    QQ20170816-215045.png


    继续定位到Frameworks文件夹中的 LLRegistrationKit.framework,试试用[size=14.6667px]Dumper来查看头文件:

    QQ20170816-215558.png


    不错,自带语法高亮 ,不过还是习惯了强大的Hopper,

    QQ20170816-215846.png

    0x03 算法分析1:
    Hopper的Show Pseudo Code of Procedure功能可以查看伪代码(类似IDA的F5):
    [Objective-C] 纯文本查看 复制代码
    void -[LLRegistrationWindowController verify:](void * self, void * _cmd, void * arg2) {
        r13 = self;
        r14 = [[self license] retain];
        rbx = [[r13 registrationController] retain];
        rdx = r14;
        r15 = [[rbx class] verifyLicense:rdx error:0x0];
        var_38 = [0x0 retain];
        [rbx release];
        if (r15 != 0x0) {
                rbx = [[r13 registrationController] retain];
                [rbx saveLicense:r14, 0x0];
                [rbx release];
                rbx = [[r13 registrationController] retain];
                [rbx hideApplicationModalRegistrationWindow];
                [rbx release];
        }
        else {
                [r13 _shakeWindow];
        }
        [var_38 release];
        [r14 release];
        return;
    }
    


    一层一层分析

    [Objective-C] 纯文本查看 复制代码
    char +[LLRegistrationController verifyLicense:error:](void * self, void * _cmd, void * arg2, void * * arg3) {
        r15 = [arg2 retain];
        rbx = [[NSBundle mainBundle] retain];
        r13 = [[rbx bundleIdentifier] retain];
        [rbx release];
        rbx = [[NSBundle mainBundle] retain];
        r12 = [[rbx objectForInfoDictionaryKey:@"LLRegistrationVersionIdentifier"] retain];
        [rbx release];
        rbx = ___vl();
        [r15 release];
        [r12 release];
        [r13 release];
        rax = sign_extend_64(rbx);
        return rax;
    }
    

    关键验证函数:

    [Objective-C] 纯文本查看 复制代码
    int ___vl() {
        var_108 = rcx;
        var_30 = *___stack_chk_guard;
        r13 = _objc_retain;
        var_F0 = [rdi retain];
        var_F8 = [rsi retain];
        var_100 = [rdx retain];
        intrinsic_movaps(var_C0, 0x0);
        intrinsic_movaps(var_D0, 0x0);
        var_E0 = intrinsic_movaps(var_E0, 0x0);
        r15 = [[NSBundle bundleWithIdentifier:rdx] retain];
        rbx = [[r15 URLForResource:@"public" withExtension:@"pem"] retain];
        r14 = [NSData dataWithContentsOfURL:rbx];
        [rbx release];
        rdi = r15;
        [rdi release];
        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

    QQ20170816-221320.png

    Tips:注意到断点设置在LLRegistrationKit.Framework内,此时调试需要双开Hopper,在Hopper的Dumper窗体下启动Debugger,同时需要注意执行文件的启动路径(以默认安装路径Application为例),如图示
    QQ20170816-223436.png

    设置完毕后,启动调试,稍等片刻,Dumper自动启动,菜单内点击注册界面,即可激活断点:
    QQ20170816-230725.png

    打开文件看看内容:
    QQ20170816-230944.png

    0x04 算法分析2 -Verify
    温习一下知识:Security transforms application programming interface(API)

    分析几个关键函数
    _LLRegistrationKitDecodeConfusingCharactersAndRemoveGrouping();
    _LLRegistrationKitUniqueIdentifierLength();
    _LLRegistrationKitDigest();

    提取关键信息:
    SecDecodeTransformCreate(*_kSecBase32Encoding, rsi);   // 解密
    SecVerifyTransformCreate(r12, rsi, rdx);                           // 验证

    设置断点:SecVerifyTransformCreate的SecTransformSetAttribute(rdi, rsi, rdx,rcx);
    尝试如下注册码,来分析下被加密的信息:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

    打印 $rdi
    [Objective-C] 纯文本查看 复制代码
    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 41  AAAAAAAAAAAAAAAA
    0x1005ad210: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
    0x1005ad220: 41 41 41 7c 63 6f 6d 2e 64 64 65 76 69 6c 6c 65  AAA|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
    [Plain Text] 纯文本查看 复制代码
    -----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

    QQ20170817-015510.png

    Go注册机源码:
    [Golang] 纯文本查看 复制代码
    // ******************
    // * 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[i:i+5]+"-"
            }
    
            for i:= 0; i<len(base32Str)-1;i+=5  {
                    encoded_signature += base32Str[i:i+5]+"-"
            }
    
            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[32m[+] 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[0])
                            fmt.Println("\x1b[33m[+] Dumper \x1b[0m: \x1b[1m\x1b[0m\x1b[93m",key)
                    } else if choose == "2" {
                            key = KeygenWithBundleId(bundleid[1])
                            fmt.Println("\x1b[33m[+] Spillo : \x1b[1m\x1b[0m\x1b[93m",key)
                    } else if choose == "3" {
                            key = KeygenWithBundleId(bundleid[2])
                            fmt.Println("\x1b[33m[+] Disco Dancer : \x1b[1m\x1b[0m\x1b[93m",key)
                    } else {
                            cli.ShowAppHelp(c)
                    }
                    return nil
            }
    
            app.Run(os.Args)
    }
    


    BananaFishkeygen.zip (2.24 KB, 下载次数: 9, 售价: 5 枚飘云币) 飘云阁私钥签名加密的注册码.txt.zip (1.27 KB, 下载次数: 5)

    评分

    参与人数 9威望 +84 飘云币 +84 收起 理由
    speedboy + 8 + 8 飞一般的感觉
    飞天 + 4 + 4 PYG有你更精彩!
    0xcb + 4 + 4 go go go ...
    smallhorse + 8 + 8 飞树大表哥,膜拜了!
    EvilNing + 4 + 4 很给力!
    NoNameX2016 + 8 + 8 赞一个!
    wgz001 + 8 + 8 赞一个!
    gagmeng + 20 + 20 飞树大表哥全能啊,膜拜
    不破不立 + 20 + 20 PYG有你更精彩!

    查看全部评分

    本帖被以下淘专辑推荐:

    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    10 小时前
  • 签到天数: 1173 天

    [LV.10]以坛为家III

    发表于 2017-8-18 10:00:37 | 显示全部楼层
    谢谢大神的讲解和分享!收藏了
    PYG19周年生日快乐!
    回复 支持 0 反对 1

    使用道具 举报

  • TA的每日心情
    开心
    11 小时前
  • 签到天数: 2205 天

    [LV.Master]伴坛终老

    发表于 2017-8-17 07:21:08 | 显示全部楼层
    坐沙发学习,谢谢表哥精彩破文
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-2-26 11:14
  • 签到天数: 459 天

    [LV.9]以坛为家II

    发表于 2017-8-17 08:02:27 | 显示全部楼层
    新一波MAC文章  6
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-3-25 15:21
  • 签到天数: 487 天

    [LV.9]以坛为家II

    发表于 2017-8-17 09:52:38 | 显示全部楼层
    除了膜拜 还是膜拜 硬伤
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    4 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    发表于 2017-8-17 12:36:52 | 显示全部楼层
    膜拜飞博士~~
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    4 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    发表于 2017-8-17 12:50:29 | 显示全部楼层
    @tree_fly  博士 你把C版大名写错了。蛤蛤

    点评

    哈哈,C版~,笔误笔误~  详情 回复 发表于 2017-8-17 14:27
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-3-17 22:44
  • 签到天数: 132 天

    [LV.7]常住居民III

     楼主| 发表于 2017-8-17 14:27:02 | 显示全部楼层
    飘云 发表于 2017-8-17 12:50
    @tree_fly  博士 你把C版大名写错了。蛤蛤

    哈哈,C版~,笔误笔误~
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 19:54
  • 签到天数: 1378 天

    [LV.10]以坛为家III

    发表于 2017-8-17 20:09:42 | 显示全部楼层
    对飞树大表哥的敬仰:犹如滔滔江水绵绵不绝,又如黄河泛滥一发不可收拾!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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