longestusername 发表于 2021-5-22 17:44

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

本帖最后由 longestusername 于 2021-5-22 17:56 编辑

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

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





缺点就是有点贵:

每年125美元。

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


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

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


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

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


好的吧。可以看到实质上注册逻辑是在一个Framework文件里:./Frameworks/OmniZuul.framework/Versions/A/OmniZuul
如果仔细逆向一下这个文件,会发现一个神奇的东西,所有Omni公司的注册逻辑都在这里面。使用的同一套注册算法,只是算法常量不同。而各个版本的算法常量在这个文件里是一个表格的形式存在:
具体如下图:

其中数据结构大致为:
   
00000000 OmniCONSTTablestruc ; (sizeof=0x20, mappedto_284)
00000000 AppName         dq ?
00000008 AppUid          dd ?
0000000C AppConst      db 20 dup(?)
00000020 OmniCONSTTableends

这种形式。

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



然后定位到对应的函数:

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


往上查找xref,一直找到:

函数。看来有那么一堆对License操作的函数哟。

在函数窗口我们搜一下License:

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

分析这个函数比较复杂,整个算法分散在很多函数调用里面。不过一点一点动态调试也比较容易弄清楚逻辑。
详细的算法逻辑,大家可以看复原出的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 =

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 = * 48
    buffer_cursor = 0
    sbuff = * 8

    restult_str = ''

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

      if tmpi == 3:
            sbuff = * 8

            j = logv = 7# log256_26
            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 = (tmpv - eax) & 0xff
                tmpv = rdx
                j -= 1

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

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

      else:
            tmpi += 1
      data_cursor += 1

    if tmpi > 0:
      sbuff = * 8
      sbuff_i = 0
      tmpi1v = tmp1v = log256_26

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

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

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

      i = 0
      while buffer != 0:
            restult_str += chr(buffer)
            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
    md2 = * 32
    i = 0
    while i != 4:
      md2 = randvalue
      randvalue = random.randint(0, 0xff)
      if dbgRandList:
            randvalue = dbgRandList
      i += 1

    md2 = randvalue

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

    md2 = randvalue & 3
    md2 = 0xff
    md2 = 0xff

    len8data = md2
    len8str = ascii26str(len8data)

    len8str_04 = len8str
    len8str_44 = len8str
    len8str_84 = len8str
    len8str_122 = len8str

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

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

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

    k = 0
    while k != 5:
      md ^= md ^ md ^ md
      k += 1

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

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

    md2len13d = md2[:13]
    md2len13dStr = ascii26str(md2len13d)
    insert_pos =
    for apos in insert_pos:
      md2len13dStr = md2len13dStr[:apos] + "-" + md2len13dStr

    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
      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


longestusername 发表于 2021-5-24 10:00

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

点击软件左上角的菜单栏里的OmniGraffle,然后。

悲蝉唱空凉 发表于 2021-5-24 11:31

longestusername 发表于 2021-5-24 10:00
点击软件左上角的菜单栏里的OmniGraffle,然后。

app 新下的没有许可证选项了,只显示购买,下了个 7.8.15 的 OK 了~{:1_893:}

去你的吧 发表于 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

谢谢,学习下。
页: [1] 2 3 4
查看完整版本: 逆向OmniGraffle并编写注册机[Python](附带注册机源码)