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