用Hopper搞定Mac迅雷的会员之去自校验


#1

本文主要讲解最新版的子校验破解方法,离线等破解方法请看此文http://bbs.iosre.com/t/hopper-mac/1428

进入正题:
搜索特征字符串 “ForceQuit”,然后查看交叉引用,一共有2出,我们看第一处
来到这里:
000000010000b5fc mov rsi, qword [ds:0x10016ec58] ; @selector(boolForKey:), argument “selector” for method imp___got__objc_msgSend, XREF=_main+239
000000010000b603 lea rdx, qword [ds:cfstring_ForceQuit] ; @“ForceQuit”
000000010000b60a mov rdi, r13
000000010000b60d call qword [ds:imp___got__objc_msgSend]
000000010000b613 test al, al
000000010000b615 jmp 0x10000b61b

通过阅读上面的代码,我们发现有个md5的计算,下面就是几个跳转语句:把那几个跳转语句nop掉就可以了。我为了省事,就直接跳转到下一句:

000000010000b5ca mov bl, al
000000010000b5cc mov r14b, byte [ss:rbp+var_29]
000000010000b5d0 mov rdi, qword [ds:objc_cls_ref_NSUserDefaults] ; objc_cls_ref_NSUserDefaults, argument “instance” for method _objc_msgSend
000000010000b5d7 mov r12, qword [ds:0x10016ec40] ; @selector(standardUserDefaults)
000000010000b5de mov rsi, r12 ; argument “selector” for method _objc_msgSend
000000010000b5e1 call r15 ; _objc_msgSend
000000010000b5e4 mov r13, rax
000000010000b5e7 test bl, bl
000000010000b5e9 jmp 0x10000b5ef
000000010000b5eb sbb al, 0x1
000000010000b5ed add byte [ds:rax], al

000000010000b5ef movzx eax, r14b ; XREF=_main+226
000000010000b5f3 cmp eax, 0x1
000000010000b5f6 jmp 0x10000b5fc
000000010000b5f8 sgdt qword [ds:rax]
000000010000b5fb db 0x00 ; ‘.’

000000010000b5fc mov rsi, qword [ds:0x10016ec58] ; @selector(boolForKey:), argument “selector” for method imp___got__objc_msgSend, XREF=_main+239
000000010000b603 lea rdx, qword [ds:cfstring_ForceQuit] ; @“ForceQuit”
000000010000b60a mov rdi, r13
000000010000b60d call qword [ds:imp___got__objc_msgSend]
000000010000b613 test al, al
000000010000b615 jmp 0x10000b61b
000000010000b617 db 0x3f ; ‘?’
000000010000b618 db 0x01 ; ‘.’
000000010000b619 db 0x00 ; ‘.’
000000010000b61a db 0x00 ; ‘.’

000000010000b61b mov rbx, qword [ds:objc_cls_ref_NSMutableDictionary] ; objc_cls_ref_NSMutableDictionary, XREF=_main+270
000000010000b622 mov r12, qword [ds:0x10016e748] ; @selector(objectForKey:)
000000010000b629 lea rdx, qword [ds:cfstring_ThunderInstallCountDict] ; @“ThunderInstallCountDict”
000000010000b630 mov rdi, r13 ; argument “instance” for method _objc_msgSend
000000010000b633 mov rsi, r12 ; argument “selector” for method _objc_msgSend
000000010000b636 call r15 ; _objc_msgSend
000000010000b639 mov rsi, qword [ds:0x10016ec60] ; @selector(dictionaryWithDictionary:), argument “selector” for method _objc_msgSend
000000010000b640 mov rdi, rbx ; argument “instance” for method _objc_msgSend
000000010000b643 mov rdx, rax
000000010000b646 call r15 ; _objc_msgSend


用Hopper搞定Mac迅雷的会员以及离线下载功能
#2

我靠,撞帖了?我今天也逆向了这货,还把补丁写了。。


#3

那个 MD5 校验函数事实上是 MD5 的置换变形,而且把参数写错了,每 1k 文件内容只会有一个字节参与哈希计算(不知道是不是有意为之)。最后这个“跳跃”计算的 MD5 还会做一个置换操作。

我还有个比较猥琐的想法,除了自己计算并 mkdir 之外,还可以把这个函数 patch 成返回一个 @"…",这样在 main 函数里检查目录是否存在的时候,就会去检查一定存在的父目录……


#4

我还以为你们谁是其中一个的马甲呢,原来是2个人,都在今天发,太巧了……


#5

看到这帖子的时候一脸「 ???」


#6

为什么我没有找到

ForceQuit
呢?


#7

你的版本应该不是最新的


#8

@wsdlwx @ChiChou 两位能不能把整个分析的来龙去脉再写得更清楚一点,比如,怎么发现的“ForceQuit”;逆向工程的思路比编写代码和工具使用要重要多了


#9

直接阅读 main 函数就可以看到,代码也不长,我就贴一下:

int _main(int arg0, int arg1) {
    var_38 = arg1;
    var_3C = LODWORD(arg0);
    r15 = *objc_msgSend;
    r13 = [MD5 md5ValueOfFile:[[NSBundle mainBundle] executablePath]];
    var_29 = 0x0;
    LOBYTE(rbx) = LOBYTE([[NSFileManager defaultManager] fileExistsAtPath:[[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/BrowserPlugins"] stringByAppendingPathComponent:r13] isDirectory:var_29]);
    LOBYTE(r14) = var_29;
    r12 = @selector(standardUserDefaults);
    r13 = [NSUserDefaults standardUserDefaults];
    if ((LOBYTE(rbx) != 0x0) && (LODWORD(LOBYTE(r14) & 0xff) == 0x1)) goto loc_10000b5fc;
    goto loc_10000b70b;

loc_10000b5fc:
    rax = [r13 boolForKey:@"ForceQuit"];
    if (LOBYTE(rax) != 0x0) goto loc_10000b75a;
    goto loc_10000b61b;

loc_10000b75a:
    rax = exit(0x0);
    return rax;

另外,校验肯定要读取文件什么的,用 lldb 对一些常见的读文件方式下断点,最后通过断下 fread 函数找 bt(栈回溯)发现 MD5 + (id)md5ValueOfFile:(id)

另外追踪 Mac 应用的系统调用可以用 dtruss,如:sudo dtruss /Applications/Thunder.app/Contents/MacOS/Thunder,注意日志中一个 lstat64 的操作会查询 目录"/Applications/Thunder.app/Contents/BrowserPlugins/***\0"


#10

此外,对于这种自校验后退出的情况,一般是调用 exit( 函数,可以静态的找 exit 调用的 xref,或者直接在 lldb 里 b _exit (注意有下划线)


#11

新版本修改后不能正常启动,跟进以往的逆向经验,多半是再启动的时候加入了子校验,一般子校验的方法就是计算文件的crc,md5,sha等方法,windows下一般都是下createfile这个断点。因为迅雷这个代码没有经过混淆,直接找到main函数,看一下流程图就发现有个md5计算,下面有个forcequit字符串,大胆猜测就是这里了,然后仔细阅读md5下面的几个跳转语句就找到关键点了。


#12

哈哈,太巧了,看了一下你的补丁代码,不错。


#13

ChiChou的python写的好6,每1k文件有一个字节参与运算,这很大几率patch不到参与校验的字节,:sweat_smile:


#14

搞了i奇艺,可以看到普通会员变vip了,也是闪退,找不到自校验。


#15

你确定唉奇异是本地VIP?


#16

请问Hopper如何查看交叉引用


#17

跟IDA一样,x


#18

谢谢狗神!


#19

-。- 我在hopper也找不到forcequit呢?另外迅雷更新3.0了,之前的py补丁不能用了呢


#20

迅雷更新3.0了 有方法吗