0x00 前言

总所周知,只有酷我音乐这个憨憨是本地认证(福利?),之前一直用别人破解的版本,但是版本太老,有很多bug,遂自力更生。

接下来的某些操作,如果不了解,就去看我上一篇关于sublime text 的保姆级教程

不多bb,直接开始。

0x01 ida搜索中文

开始之前,首先得让ida能够搜索中文

0x02 分析过程

播放

付费,按x找引用

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2021-07-04 10:55:47
# @Author  : 江南小虫虫 (fwh13612265462@gmail.com)
# @Link    : https://fengwenhua.top


import frida
import sys

# https://frida.re/docs/functions/


def on_message(message, data):
  print("[{}] => {}".format(message, data))


def main(target_process):
  session = frida.attach(target_process)
  hook_str = """
        var menuPlayMusics = ObjC.classes.KWSonglistTableView['- menuPlayMusics:checkFee:'];
        Interceptor.attach(menuPlayMusics.implementation, {
          onEnter: function (args) {
            console.log('KWSonglistTableView menuPlayMusics:checkFee: hooked in..');
            args[3] = ptr(0);
          },
          onLeave: function(retval) {
            console.log('return value:' + retval);
        }
        });
    """
  script = session.create_script(hook_str)
  script.on("message", on_message)
  script.load()
  print("[!] Ctrl+D or Ctrl+Z to detach from instrumented program.\n\n")
  sys.stdin.read()
  session.detach()


if __name__ == "__main__":
  main("酷我音乐")

先打开酷我音乐,再运行脚本。

ps: frida在mac上,需要关闭sip。。。

拿周董的音乐测试一下,能播放,但是不能下载

下载提示如下:

下载

这里通过关键字找半天没找到,但是发现Bought字眼的,不多bb,frida走一波

frida-trace -m "-[KW* *Bought*]" 酷我音乐

发现了isBought,那还等啥,搜索所有的isBought,全部hook了,代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2021-07-04 10:55:47
# @Author  : 江南小虫虫 (fwh13612265462@gmail.com)
# @Link    : https://fengwenhua.top


import frida
import sys

# https://frida.re/docs/functions/


def on_message(message, data):
    print("[{}] => {}".format(message, data))


def main(target_process):
    session = frida.attach(target_process)
    hook_str = """
        var menuPlayMusics = ObjC.classes.KWSonglistTableView['- menuPlayMusics:checkFee:'];
        Interceptor.attach(menuPlayMusics.implementation, {
          onEnter: function (args) {
            console.log('KWSonglistTableView menuPlayMusics:checkFee: hooked in..');
            args[3] = ptr(0);
          },
          onLeave: function(retval) {
            console.log('return value:' + retval);
        }
        });

        var KWMusicFeeOneItemPriceisBought = ObjC.classes.KWMusicFeeOneItemPrice['- isBought'];
        Interceptor.attach(KWMusicFeeOneItemPriceisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeOneItemPrice isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeOneItemPrice isBought return value:' + retval);
            retval.replace(0x1);
        }
        });

        var KWMusicFeeOneAlbumItemisBought = ObjC.classes.KWMusicFeeOneAlbumItem['- isBought'];
        Interceptor.attach(KWMusicFeeOneAlbumItemisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeOneAlbumItem isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeOneAlbumItem isBought return value:' + retval);
            retval.replace(0x1);
        }
        });

        var KWMusicFeeBoughtHistoryInfoisBought = ObjC.classes.KWMusicFeeBoughtHistoryInfo['- isBought'];
        Interceptor.attach(KWMusicFeeBoughtHistoryInfoisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeBoughtHistoryInfo isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeBoughtHistoryInfo isBought return value:' + retval);
            retval.replace(0x1);
        }
        });
    """
    script = session.create_script(hook_str)
    script.on("message", on_message)
    script.load()
    print("[!] Ctrl+D or Ctrl+Z to detach from instrumented program.\n\n")
    sys.stdin.read()
    session.detach()


if __name__ == "__main__":
    main("酷我音乐")

这下终于可以下载和播放了

喜欢

本来以为到这就结束了,没想到,我把周董的一首歌加入喜欢列表,竟然不行。。。

那还等啥,想起我在搞播放的时候,这里还有个btnLikeClick:的函数,如下图:

猜测可能是这玩意,不过为了预防万一,全hook了,如下:

frida-trace -m "-[KW* btnLikeClick:]" 酷我音乐

不多bb,直接hook

var KWMusicFeeConfig_isMusicFeeOn = ObjC.classes.KWMusicFeeConfig['- isMusicFeeOn'];
Interceptor.attach(KWMusicFeeConfig_isMusicFeeOn.implementation, {
  onEnter: function (args) {
    console.log('KWMusicFeeConfig isMusicFeeOn: hooked in..');
  },
  onLeave: function(retval) {
    console.log('KWMusicFeeConfig isMusicFeeOn return value:' + retval);
    retval.replace(0x0);
}
});

0x03 最终的frida脚本

至此,播放、下载、喜欢,都ok了,最终的frida代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2021-07-04 10:55:47
# @Author  : 江南小虫虫 (fwh13612265462@gmail.com)
# @Link    : https://fengwenhua.top


import frida
import sys

# https://frida.re/docs/functions/


def on_message(message, data):
    print("[{}] => {}".format(message, data))


def main(target_process):
    session = frida.attach(target_process)
    hook_str = """
        var KWMusicFeeConfig_isMusicFeeOn = ObjC.classes.KWMusicFeeConfig['- isMusicFeeOn'];
        Interceptor.attach(KWMusicFeeConfig_isMusicFeeOn.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeConfig isMusicFeeOn: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeConfig isMusicFeeOn return value:' + retval);
            retval.replace(0x0);
        }
        });

        var menuPlayMusics = ObjC.classes.KWSonglistTableView['- menuPlayMusics:checkFee:'];
        Interceptor.attach(menuPlayMusics.implementation, {
          onEnter: function (args) {
            console.log('KWSonglistTableView menuPlayMusics:checkFee: hooked in..');
            args[3] = ptr(0);
          },
          onLeave: function(retval) {
            console.log('return value:' + retval);
        }
        });

        var KWMusicFeeOneItemPriceisBought = ObjC.classes.KWMusicFeeOneItemPrice['- isBought'];
        Interceptor.attach(KWMusicFeeOneItemPriceisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeOneItemPrice isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeOneItemPrice isBought return value:' + retval);
            retval.replace(0x1);
        }
        });

        var KWMusicFeeOneAlbumItemisBought = ObjC.classes.KWMusicFeeOneAlbumItem['- isBought'];
        Interceptor.attach(KWMusicFeeOneAlbumItemisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeOneAlbumItem isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeOneAlbumItem isBought return value:' + retval);
            retval.replace(0x1);
        }
        });

        var KWMusicFeeBoughtHistoryInfoisBought = ObjC.classes.KWMusicFeeBoughtHistoryInfo['- isBought'];
        Interceptor.attach(KWMusicFeeBoughtHistoryInfoisBought.implementation, {
          onEnter: function (args) {
            console.log('KWMusicFeeBoughtHistoryInfo isBought: hooked in..');
          },
          onLeave: function(retval) {
            console.log('KWMusicFeeBoughtHistoryInfo isBought return value:' + retval);
            retval.replace(0x1);
        }
        });
    """
    script = session.create_script(hook_str)
    script.on("message", on_message)
    script.load()
    print("[!] Ctrl+D or Ctrl+Z to detach from instrumented program.\n\n")
    sys.stdin.read()
    session.detach()


if __name__ == "__main__":
    main("酷我音乐")

0x04 patch

patch啥的,就不多说了,直接开搞

最后保存到文件,替换之。

闪退修复

直接替换,可能会闪退,首先用以下命令打开任何来源

sudo spctl --master-disable

然后自签名一下(需要安装Command Line Tools 工具(xcode-select --install))

sudo codesign --force --deep --sign - /Applications/KuwoMusic.app

0x05 MonkeyAppMac

这里除了patch,可以用大佬的 MonkeyDev 来hook一波,安装链接:https://github.com/AloneMonkey/MonkeyDev/wiki/%E5%AE%89%E8%A3%85

ps:xcode 12.5 安装遇到闪退,可以去 https://github.com/AloneMonkey/MonkeyDev/issues/282 找到解决方案

装完之后,直接新建一个MonkeyAppMac项目

然后选个地方放就行

接下来把酷我app丢进TargetApp里面

这里可以去 http://www.cydiasubstrate.com/api/c/MSHookMessageEx/ 查看MSHookMessageEx查看用法:

模仿之,然后修改kuwo_crack.m代码如下:

//  weibo: http://weibo.com/xiaoqing28
//  blog:  http://www.alonemonkey.com
//
//
//  kuwo_crack.m
//  kuwo_crack
//
//  Created by fengwenhua on 2021/7/13.
//

#import "kuwo_crack.h"
#import "substrate.h"

@class KWMusicFeeConfig;
@class KWMusicFeeOneItemPrice;
@class KWMusicFeeOneAlbumItem;
@class KWMusicFeeBoughtHistoryInfo;
@class KWSonglistTableView;

static char new_KWMusicFeeConfig_isMusicFeeOn(KWMusicFeeConfig* self,SEL _cmd){
    return false;
}

static char new_KWMusicFeeOneItemPrice_isBought(KWMusicFeeOneItemPrice* self,SEL _cmd){
    return true;
}

static char new_KWMusicFeeOneAlbumItem_isBought(KWMusicFeeOneAlbumItem* self,SEL _cmd){
    return true;
}

static char new_KWMusicFeeBoughtHistoryInfo_isBought(KWMusicFeeBoughtHistoryInfo* self,SEL _cmd){
    return true;
}

static void (*origin_KWSonglistTableView_checkFee)(KWSonglistTableView*,SEL,id,char);
static void new_KWSonglistTableView_checkFee(KWSonglistTableView* self,SEL _cmd,id a3, char a4){
    origin_KWSonglistTableView_checkFee(self,_cmd,a3,false);
}


static void __attribute__((constructor)) initialize(void) {
    MSHookMessageEx(objc_getClass("KWMusicFeeConfig"),  @selector(isMusicFeeOn), (IMP)&new_KWMusicFeeConfig_isMusicFeeOn, NULL);
    MSHookMessageEx(objc_getClass("KWMusicFeeOneItemPrice"),  @selector(isBought), (IMP)&new_KWMusicFeeOneItemPrice_isBought, NULL);
    MSHookMessageEx(objc_getClass("KWMusicFeeOneAlbumItem"),  @selector(isBought), (IMP)&new_KWMusicFeeOneAlbumItem_isBought, NULL);
    MSHookMessageEx(objc_getClass("KWMusicFeeBoughtHistoryInfo"),  @selector(isBought), (IMP)&new_KWMusicFeeBoughtHistoryInfo_isBought, NULL);
    MSHookMessageEx(objc_getClass("KWSonglistTableView"),  @selector(menuPlayMusics:checkFee:), (IMP)&new_KWSonglistTableView_checkFee, (IMP*)&origin_KWSonglistTableView_checkFee);
}

Command+B运行,搞定

0x06 后言

难得遇到这么良心的播放软件,成品就不提供了,低调使用!!!

自评 TCV: 2

最后修改:2021 年 07 月 22 日 09 : 57 AM
如果觉得我的文章对你有用,请随意赞赏