吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9832|回复: 32
收起左侧

[MacOS逆向] 逆向OmniGraffle并编写注册机[Python](附带注册机源码)

  [复制链接]
longestusername 发表于 2021-5-22 17:44
本帖最后由 longestusername 于 2021-5-22 17:56 编辑

OmniGraffle是优秀的作图软件,尤其对于mac平台的逆向工程师来讲,是替代dia的好工具。dia虽然也讲有mac osx版本,但运行起来就是一个白板,怎么看起来都不对劲。相比Linux平台的Dia,OmniGraffle使用起来体验更优秀,

例如在逆向时,进行函数调用分析、程序内存布局分析等,如下图。个人觉得实在是没有比Graffle更好的工具来做这件事情了。
image.png




缺点就是有点贵:
image.png
每年125美元。

那么打开OmniGraffle以后,进行尝试注册:
image.png

获取有效信息:Invalid License, 验证License的按钮为save按钮。

1. 我们按照通常的过程尝试: 从Graffle的可执行文件中搜索Invalid License. 发现找不到哈。
不过我们搜到了isLicensed等判断是否已经注册的函数。
image.png

按照惯例,我们进入isLicensed函数,修改返回值,让它一直返回True。然后运行Graffle发现,这个软件运行起来但不现实窗口,且kill -9杀不死。各种杀不死。即便关机也会卡死关机进程。怀疑作者是防破解做了一些奇怪的事情导致的。具体为啥没有分析。
在强制关机几次以后,忍着心碎我决定不再爆破,还是看看注册逻辑吧。

2. 还是从Invalid License入手:
在`/Applications/OmniGraffle.app/Contents`目录中,用一下命令搜索:
find . -type f -print0|xargs -0 grep "Invalid License"
image.png

好的吧。可以看到实质上注册逻辑是在一个Framework文件里:./Frameworks/OmniZuul.framework/Versions/A/OmniZuul
如果仔细逆向一下这个文件,会发现一个神奇的东西,所有Omni公司的注册逻辑都在这里面。使用的同一套注册算法,只是算法常量不同。而各个版本的算法常量在这个文件里是一个表格的形式存在:
具体如下图:
image.png
其中数据结构大致为:
     
[C] 纯文本查看 复制代码
00000000 OmniCONSTTable  struc ; (sizeof=0x20, mappedto_284)
00000000 AppName         dq ?
00000008 AppUid          dd ?
0000000C AppConst        db 20 dup(?)
00000020 OmniCONSTTable  ends


这种形式。

我们继续在Strings window 里面搜索Invalid License:

image.png

然后定位到对应的函数:

大致看一眼,就是非法licese报错的地方
image.png

往上查找xref,一直找到:

[OZZuul _deleteLicense:] 函数。看来有那么一堆对License操作的函数哟。

在函数窗口我们搜一下License:
image.png
果然,有一个saveLicense函数。我们还记得一开始尝试输入License时,确认License的按钮名称为save。对应的处理函数就是它啦。
注册逻辑判定就在这个函数里面。

分析这个函数比较复杂,整个算法分散在很多函数调用里面。不过一点一点动态调试也比较容易弄清楚逻辑。
详细的算法逻辑,大家可以看复原出的python源码哟。
[Python] 纯文本查看 复制代码
#!/usr/bin/python
# coding=utf-8

#   Author    :   Simon Huang
#   Time      :   5/20/21 6:49 PM

import os, sys
import random
import time
import hashlib

log256_26 = [2, 4, 6, 7]

APP_VERSION_LIST = {"OmniFocus v3": 0xe,
                    "OmniFocus Pro v3": 0xf,
                    "OmniGraffle v7": 9,
                    "OmniGraffle Pro v7": 8,
                    "OmniOutliner Essentials v5": 0xc,
                    "OmniOutliner Pro v5": 0xd,
                    "OmniPlan v3": 6,
                    "OmniPlan Pro v3": 7
                    }

APP_UID_LIST = [
    1000205, 1000216, 1000215, 1000200, 1000211, 1000210,
    1000219, 1000220, 1000221, 1000222, 1000212, 1000209,
    1000224, 1000223, 1000228, 1000226, 1000214, 1000208,
    1000207, 1000197
]

APP_CONST_LIST = [
    0x8F, 0x0E0, 0x1F, 0x81, 0x36, 0x28, 0x9B, 0x0D1, 0x45, 0x0A3, 0x1E, 0x0C7, 0x0B2, 0x56, 0x0BE, 0x0E7, 0x42, 0x96,
    0x7E, 0x0E9, 0x0DD, 0x18, 0x56, 0x0E8, 0x80, 0x0CF, 0x8E, 0x0E5, 0x0BF, 0x0FF, 0x0B1, 0x0BB, 0x39, 0x63, 0x0C0,
    0x57, 0x0C6, 0x0EA, 0x0D1, 0x0B5, 0x0C0, 0x0A2, 0x0F2, 0x0E4, 0x0CD, 0x0E9, 0x0FF, 0x39, 0x59, 0x0F, 0x79, 0x0DB,
    0x0D7, 0x29, 0x0A7, 0x68, 0x0D4, 0x68, 0x48, 0x16, 0x0, 0x15, 0x3A, 0x0A9, 0x17, 0x0D, 0x5, 0x6E, 0x75, 0x2F, 0x54,
    0x0AD, 0x0B6, 0x72, 0x0E5, 0x0E4, 0x0EB, 0x9C, 0x0C7, 0x75, 0x0BA, 0x72, 0x0F2, 0x6, 0x99, 0x8B, 0x4D, 0x4B, 0x46,
    0x17, 0x0CD, 0x0A, 0x0E1, 0x0E0, 0x82, 0x88, 0x0FB, 0x27, 0x0D8, 0x0B7, 0x87, 0x0D6, 0x87, 0x4B, 0x91, 0x9, 0x0A6,
    0x54, 0x32, 0x0E6, 0x0A0, 0x48, 0x0F2, 0x0E4, 0x7E, 0x0E, 0x82, 0x9E, 0x17, 0x0A7, 0x35, 0x0CF, 0x0EC, 0x5C, 0x0C1,
    0x0A7, 0x0F1, 0x0C9, 0x23, 0x0F4, 0x21, 0x96, 0x0C3, 0x0A7, 0x60, 0x0E0, 0x27, 0x0EF, 0x0A4, 0x17, 0x0B4, 0x33,
    0x52, 0x3C, 0x1F, 0x0DA, 0x11, 0x0C7, 0x12, 0x32, 0x0A2, 0x1A, 0x0B0, 0x6F, 0x0F9, 0x3F, 0x89, 0x8, 0x0C, 0x6C, 0x1,
    0x0F1, 0x0C2, 0x8D, 0x0C6, 0x60, 0x46, 0x55, 0x0D9, 0x2C, 0x10, 0x0B3, 0x7C, 0x14, 0x0E5, 0x38, 0x52, 0x39, 0x0B,
    0x2A, 0x3E, 0x0E2, 0x65, 0x30, 0x8, 0x0B2, 0x0A3, 0x0D6, 0x96, 0x40, 0x72, 0x0D6, 0x14, 0x5B, 0x5F, 0x0D2, 0x91,
    0x0B6, 0x51, 0x42, 0x4C, 0x0BF, 0x8A, 0x0BE, 0x0A1, 0x7D, 0x2F, 0x6, 0x36, 0x0B9, 0x0FD, 0x26, 0x81, 0x0C3, 0x0E8,
    0x90, 0x55, 0x7E, 0x8D, 0x7, 0x0B0, 0x2A, 0x8B, 0x0B5, 0x37, 0x0BE, 0x0C1, 0x85, 0x0EC, 0x8, 0x2C, 0x0FE, 0x0B9,
    0x2F, 0x0B0, 0x0FC, 0x42, 0x6F, 0x61, 0x0BC, 0x6F, 0x81, 0x0D1, 0x92, 0x13, 0x68, 0x0A3, 0x0DE, 0x75, 0x0D4, 0x0F6,
    0x0CC, 0x46, 0x69, 0x52, 0x4D, 0x53, 0x7B, 0x91, 0x0B7, 0x39, 0x17, 0x7E, 0x0A3, 0x6, 0x7, 0x8F, 0x47, 0x8E, 0x88,
    0x61, 0x0C0, 0x0F6, 0x0C9, 0x64, 0x7E, 0x4B, 0x0D0, 0x89, 0x0B3, 0x79, 0x89, 0x2E, 0x3C, 0x17, 0x3E, 0x0BB, 0x0C4,
    0x0E9, 0x0DB, 0x68, 0x91, 0x15, 0x1F, 0x0F2, 0x0B4, 0x47, 0x2B, 0x7, 0x63, 0x9B, 0x0A2, 0x71, 0x0E9, 0x0E6, 0x3A,
    0x1B, 0x5C, 0x0F6, 0x5, 0x0F8, 0x3F, 0x8B, 0x6E, 0x8E, 0x0D6, 0x8C, 0x0B2, 0x90, 0x0F7, 0x0A5, 0x0D, 0x2, 0x0B8,
    0x0AC, 0x0E3, 0x0F2, 0x0C6, 0x82, 0x0C5, 0x1E, 0x8E, 0x4C, 0x64, 0x0EE, 0x9A, 0x8, 0x5D, 0x77, 0x0D5, 0x28, 0x7E,
    0x72, 0x0B4, 0x58, 0x0BA, 0x0DD, 0x0F5, 0x0B2, 0x48, 0x6C, 0x8, 0x0ED, 0x0D0, 0x3C, 0x0, 0x7F, 0x0FD, 0x0D5, 0x1C,
    0x73, 0x91, 0x0CB, 0x4E, 0x24, 0x0B3, 0x0F6, 0x0FB, 0x0E5, 0x90, 0x4A, 0x0A8, 0x86, 0x22, 0x79, 0x0F6, 0x1E, 0x0E2,
    0x0A1, 0x18, 0x0E4, 0x0A3, 0x17, 0x0AB, 0x0B7, 0x99, 0x0C4, 0x8F, 0x67, 0x0F2, 0x0FD, 0x7B, 0x0BF, 0x4E, 0x4B, 0x71,
    0x0D7, 0x0C0, 0x29, 0x4C
]


def ascii26str(data_bytes: bytes):
    data_length = len(data_bytes)
    sepchar = ''

    if data_length == 0:
        return sepchar

    tmpi = 0
    tmpv = 0

    data_cursor = 0

    buffer = [0] * 48
    buffer_cursor = 0
    sbuff = [0] * 8

    restult_str = ''

    while data_length > 0:
        data_length -= 1
        tmpv = ((data_bytes[data_cursor] | (tmpv << 8) & 0xffffffff)) & 0xffffffffffffffff

        if tmpi == 3:
            sbuff = [0] * 8

            j = logv = 7  # log256_26[3]
            sbuff_i = 0

            while j > 0:
                rdx = (((0x4EC4EC4EC4EC4EC5 * tmpv) >> 64) >> 3) & 0xffffffffffffffff
                eax = (rdx * 5) & 0xffffffff
                eax = (eax * 5) & 0xffffffff
                eax = (eax + rdx) & 0xffffffff

                sbuff[7 - j] = (tmpv - eax) & 0xff
                tmpv = rdx
                j -= 1

            i = 0
            buffer_cursor = 0
            while i != -7:
                buffer[buffer_cursor] = (sbuff[7 + i - 1] + 65) & 0xff
                buffer_cursor += 1
                i -= 1

            # bufutf8 =  utf-8.encode(buf[:7]
            # restult_str += (buffer[:7]).encode('utf-8')
            i = 0
            while buffer[i] != 0:
                restult_str += chr(buffer[i])
                i += 1
            tmpv = 0
            tmpi = 0

        else:
            tmpi += 1
        data_cursor += 1

    if tmpi > 0:
        sbuff = [0] * 8
        sbuff_i = 0
        tmpi1v = tmp1v = log256_26[tmpi - 1]

        while tmp1v > 0:
            rdx = (((0x4EC4EC4EC4EC4EC5 * tmpv) >> 64) >> 3) & 0xffffffffffffffff
            eax = (rdx * 5) & 0xffffffff
            eax = (eax * 5) & 0xffffffff
            eax = (eax + rdx) & 0xffffffff

            sbuff[sbuff_i] = (tmpv - eax) & 0xff
            sbuff_i += 1
            tmpv = rdx
            tmp1v -= 1

        buffer_cursor = 0
        negtmp1v = -log256_26[tmpi - 1]
        p = 0
        while p != negtmp1v:
            buffer[buffer_cursor] = (sbuff[tmpi1v + p - 1] + 65) & 0xff
            buffer_cursor += 1
            p -= 1

        i = 0
        while buffer[i] != 0:
            restult_str += chr(buffer[i])
            i += 1

    return restult_str


def createSerial(username="Simon Huang", napp_id=8, dbgRandList=None):
    if username is None or len(username.strip()) == 0:
        username = "Simon Huang"

    joinedName = ''
    for achr in username:
        if achr.isalpha() or achr.isnumeric():
            joinedName += achr
    joinedNameLen = len(joinedName)

    # random.seed(time.time())

    randvalue = random.randint(0, 0xff)
    if dbgRandList:
        randvalue = dbgRandList[0]
    md2 = [0] * 32
    i = 0
    while i != 4:
        md2[i + 5] = randvalue
        randvalue = random.randint(0, 0xff)
        if dbgRandList:
            randvalue = dbgRandList[i + 1]
        i += 1

    md2[9] = randvalue

    randvalue = random.randint(0, 0xff)
    if dbgRandList:
        randvalue = dbgRandList[5]

    md2[10] = randvalue & 3
    md2[11] = 0xff
    md2[12] = 0xff

    len8data = md2[5:5 + 8]
    len8str = ascii26str(len8data)

    len8str_04 = len8str[0:0 + 4]
    len8str_44 = len8str[4:4 + 4]
    len8str_84 = len8str[8:8 + 4]
    len8str_122 = len8str[12:12 + 2]

    formatedLic = "%s-%s-%s-%s" % (len8str_04, len8str_44, len8str_84, len8str_122)
    idLicNameStr = "%u%s%s" % (APP_UID_LIST[napp_id], formatedLic, joinedName)
    idLicNameStrUtf8 = idLicNameStr.encode('utf8')
    idLicNameBytes = idLicNameStrUtf8

    md = list(hashlib.sha1(idLicNameBytes).digest())

    appConstOffset = 20 * napp_id
    j = 0
    while j != 20:
        md[j] ^= APP_CONST_LIST[appConstOffset + j]
        j += 1

    k = 0
    while k != 5:
        md[k] ^= md[k + 15] ^ md[k + 10] ^ md[k + 5]
        k += 1

    i = 0
    while i < 5:
        md2[i] = md[i]
        i += 1

    if joinedNameLen > 0:
        n = 0
        while n != 13:
            md2[n] = (~(md2[n] ^ ord(joinedName[(n % joinedNameLen)]))) & 0xff
            n += 1

    md2len13d = md2[:13]
    md2len13dStr = ascii26str(md2len13d)
    insert_pos = [24, 20, 16, 12, 8, 4]
    for apos in insert_pos:
        md2len13dStr = md2len13dStr[:apos] + "-" + md2len13dStr[apos:]

    serial = md2len13dStr[:-1]
    return (username, serial)


if __name__ == '__main__':
    username = input("Please input your username:")
    for app in APP_VERSION_LIST:
        appUid = APP_VERSION_LIST[app]
        license = createSerial(username=username, napp_id=appUid)
        print(license, '\tfor\t', app)



注意其中一部分加密算法在./Frameworks/OmniFoundation.framework/Versions/A/OmniFoundation文件中。
需要对该文件进行逆向一下哦。

该文件运行效果如下;
Please input your username:52pojie
('52pojie', 'JPJH-WWIL-CLRN-PLBM-DMTO-CEBD-MTO')         for         OmniFocus v3
('52pojie', 'ESKK-XEBH-SQGS-PHGR-NKMV-YEBN-KMV')         for         OmniFocus Pro v3
('52pojie', 'JKOT-VBFL-OMTL-YHJT-DZUI-SEBD-ZUI')         for         OmniGraffle v7
('52pojie', 'FWIY-MAJD-NVKT-DMIL-YYIL-MEBY-YIL')         for         OmniGraffle Pro v7
('52pojie', 'HOUP-JOKL-CRZN-BPMM-AVWK-GEBA-VWK')         for         OmniOutliner Essentials v5
('52pojie', 'KVUS-WLAD-XZCU-FBHB-PZTY-WEBP-ZTY')         for         OmniOutliner Pro v5
('52pojie', 'JBKN-GJPB-XJDQ-RQDV-FQPU-WEBF-QPU')         for         OmniPlan v3
('52pojie', 'DCAR-ZCSC-ATQZ-NICH-QRBH-IEBQ-RBH')         for         OmniPlan Pro v3


免费评分

参与人数 15吾爱币 +16 热心值 +15 收起 理由
rainmote + 1 + 1 大佬太强了!
weiye588 + 1 + 1 热心回复!
frank1245 + 1 + 1 谢谢@Thanks!
呆毛王与咖喱棒 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
kibaamor + 1 + 1 谢谢@Thanks!
xixixiuxiu + 1 + 1 热心回复!
zw2312 + 1 + 1 太强了!!
剑来…… + 1 + 1 大佬太强啦~
sodeep + 1 + 1 谢谢@Thanks!
舒默哦 + 1 + 1 谢谢@Thanks!
Ljh666 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Andrea + 1 + 1 我还缺台 mac 用来测试
fanvalen + 1 + 1 我很赞同!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
24k纯金滑稽 + 1 + 1 用心讨论,共获提升!

查看全部评分

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

 楼主| longestusername 发表于 2021-5-24 10:00
悲蝉唱空凉 发表于 2021-5-24 02:18
话说,我没找到在哪里输入序列号。。。点击购买是直连 app store 付款

点击软件左上角的菜单栏里的OmniGraffle,然后。
image.png
悲蝉唱空凉 发表于 2021-5-24 11:31
longestusername 发表于 2021-5-24 10:00
点击软件左上角的菜单栏里的OmniGraffle,然后。

app 新下的没有许可证选项了,只显示购买,下了个 7.8.15 的 OK 了~
头像被屏蔽
去你的吧 发表于 2021-5-22 17:57
24k纯金滑稽 发表于 2021-5-22 19:08
别的不说,大佬nb,要是换成我爆破失败估计就直接放弃了
Bruce_HD 发表于 2021-5-22 22:06
很不错,支持支持一下。
xixicoco 发表于 2021-5-22 23:55
好东西,牛逼哈
E_eYYF 发表于 2021-5-23 01:15
可惜没有Windows版
风华若 发表于 2021-5-23 08:22

好东西,顶一个
cll1101 发表于 2021-5-23 09:25
单是看着,就很厉害,膜拜大牛
zwtstc 发表于 2021-5-23 09:46
学习了,好东西
xtkj 发表于 2021-5-23 09:48
谢谢,学习下。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-4-26 16:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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