目录

Mac最新版迅雷逆向破解

https://cdn.fangpengjun.com/images/2017-01-06/Hopper-Disassembler.png

1. 下载安装 Hopper

  • Hopper Disassembler是一款是32位和64位的二进制反汇编器,反编译和调试。你可以使用此工具拆开你想要的任何二进制。

2. 寻找迅雷的可执行文件

  • 安装完迅雷之后,找到以下文件:/Applications/Thunder.app/Contents/MacOS/Thunder

3. 执行破解方法

  • 在Hopper菜单栏中的File下找到Read Executable to Disassembler选项,载入Thunder可执行文件

  • 找到以下四个方法,然后选择Modify->Assemble Instruction后,输入mov eax,0×1,再输入ret ,分别执行四次

1
2
3
4
5
6
7
[LocalTask isValidLixianTask]

[UserController isVip]

[UserController isPlatinum]

[UserController isDiamond]
  • 选择File-> Produce New Executable导出可执行文件替换原来的文件即可

针对最新版的迅雷可能会出现打开闪退的现象,提供以下脚本即可解决

  • 安装最新版的迅雷会出现闪退现象,因为新版加入了自校验,此时重装完最新版的迅雷之后执行以下 python 即可
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
#!/usr/bin/env python3
# requires XCode

import subprocess, sys, os, hashlib, plistlib


package = '/Applications/Thunder.app/Contents'
executable = os.path.join(package, 'MacOS/Thunder')
plugins_dir = os.path.join(package, 'BrowserPlugins')


def backup():
    from shutil import copyfile
    backup = executable + '.bak'

    if os.path.isfile(backup):
        print('Backup found, maybe the file has already been patched.')
        sys.exit(-1)

    copyfile(executable, backup)


def patch_exec():
    ret_1 = b'\xb8\x01\x00\x00\x00\xc3'

    try:
        output = subprocess.check_output(['nm', executable])
    except:
        print('Failed to execute nm, please install XCode.')
        sys.exit(-1)

    patch_list = ['-[LocalTask isValidLixianTask]', '-[UserController isVip]',
                  '-[UserController isPlatinum]', '-[UserController isDiamond]']
    base = None
    output = output.decode('utf8')

    with open(executable, 'r+b') as f:
        for line in output.splitlines():
            if '__mh_execute_header' in line:
                base, *_ = line.split()
                base = int(base, 16)

        if not base:
            print('Failed to retrive base address')
            sys.exit(-1)

        for line in output.splitlines():
            if not len(patch_list):
                break

            for func in patch_list:
                if func in line:
                    addr, *_ = line.split()
                    addr = int(addr, 16)

                    offset = addr - base
                    f.seek(offset, 0)
                    f.write(ret_1)  # patch function

                    print(func)
                    patch_list.remove(func)

                    break

    print('Successfully patched %s' % executable)


# 搞定main里的自校验
def patch_self_check():
    m = hashlib.md5()
    with open(executable, 'rb+') as f:
        while True:
            buf = f.read(1)
            if not buf:
                break
            m.update(buf)
            f.seek(1023, 1)
    digest = m.digest()
    lookup = (15, 4, 6, 3, 1, 0, 7, 8, 2, 11, 10, 13, 12, 14, 9, 5)
    hexdigest = ''.join(['%0.2X' % digest[index] for index in lookup])
    dirname = os.path.join(plugins_dir, hexdigest)

    if not os.path.isdir(dirname):
        os.mkdir(dirname)


def clear_quit_flag():
    plist_path = os.path.join(os.environ.get(
        'HOME'), 'Library/Preferences/com.xunlei.Thunder.plist')

    with open(plist_path, 'rb+') as f:
        pref = plistlib.load(f)

        force_quit = pref.get('ForceQuit')
        if force_quit:
            pref.update({'ForceQuit': True})
            plistlib.dump(pref, f)
            print('Clear quit flag')


if __name__ == '__main__':
    backup()
    patch_exec()
    patch_self_check()
    clear_quit_flag()