前言

尝试逆向macOS下的Typora,顺便记录一下。

成功案例

搜索相关文章看到成功破解 Win、Linux(Electron)的文章以及工具:

文章中分析(win|linux)addLicense 流程如下,macOS 上使用原生 webkit 开发,估计思路差不多:

Untitled

自己动手

直接打开 Hopper 分析搜索 License 找到了 LicenseManager 类:

Untitled

看到一个关键字为 activate 的方法,签名如下:

/* @class LicenseManager */
-(void)activate:(void *)arg2 with:(void *)arg3 force:(char)arg4 callback:(void *)arg5 {

/*
    - arg2  -> email
    - arg3 -> license
    - arg4 -> force
    - arg5 -> callback
*/

分析 LicenseManager.activate 其方法流程:

Untitled

但是我不知道传入的 callback 是什么,为了搞清楚整个流程,想使用 firda 来打印下activate传入的参数:

$ frida-trace -i "activate*" Typora
Attaching...
[1]    4229 killed     frida-trace -i "activate*" Typora

进程直接被杀掉了 emmm 算逑!继续静态分析吧。

(win|linux) addLicense 流程中的最后一步出现的 decrypt关键字,根据这个关键字搜索到了核心的加解密 Crypto 类:

Untitled

以及verifySig 方法:

/* @class LicenseManager */
-(char)verifySig:(void *)arg2 {

我猜测 callback 就是判断 response,将内容解密再去验证 license 成功后调用 writeLicenseInfo。

那破解的思路就很清晰了:

  1. 修改 [LicenseManager quickValidateLicense][Crypto verify] [LicenseManager verifySig]不去校验返回 true。
  2. 移除 sendPost 中网络请求的部分后写入证书。

汇编太难啦(菜是原罪),修改之后不是奔溃就是hang住(程序hang着的原因可能是前端传入了事件等待 callback 运行完成),就在我快要放弃的时候看到52pojie上一篇破解 1.0 版本的文章(感谢国光师傅群里的热心师傅):修改[LicenseManager hasLicense] 返回为true 。

其实这个方法我之前也试过了,显示已经被激活:

Untitled

修改系统时间使其到期,Typora软件还能用,点开Typora->我的许可证后只能退出:

Untitled

文章中的思路是hook showLicense 让其弹出其他窗口或者什么不做。

那我就用这种方法吧,又不是不能用~🤪。

编写插件

编写一个dylib hook [LicenseManager showLicense],hasLicense 我已经使用 Hopper 修改过了。

打开 XCode 创建 macOS-Libray:

Untitled

新建 main.m文件:

#import <Foundation/Foundation.h>
#include <Cocoa/Cocoa.h>
#import <objc/runtime.h>
#import "hookHelper.h"

@interface NSObject (LicenseManager)
+ (void) hookLicenseManager;
@end

@implementation NSObject (LicenseManager)
- (void)hook_showLicense:(char)arg2
{
    NSString *message = @"zznQ";
    NSAlert *alert = [NSAlert new];
    [alert addButtonWithTitle:@"OK"];
    [alert setMessageText:message];
    [alert setAlertStyle:NSAlertStyleCritical];
    [alert runModal];
}

+ (void) hookLicenseManager
{
    NSLog(@"in hookLicenseManager");
    hookMethod(objc_getClass("LicenseManager"),
               @selector(showLicense:),
               [self class],
               @selector(hook_showLicense:));
}
@end

static void __attribute__((constructor)) initialize(void) {
    NSLog(@"hook typora!!!");
    [NSObject hookLicenseManager];
}

hookHelper.hhookMethod 实现如下:

void hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector){
    Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
    if (originalMethod && swizzledMethod){
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

在M1机器上记得将 build active architecture only 参数改为 No:

Untitled

巴斯使用 Hopper 修改 Typora 后导出 Binary 为 x86_64 ,这里 dylib 也要瘦身为 x86_64(如果不是fat binary 就跳过):lipo libtyporahook.dylib -thin x86_64 -output libtyporahook_x86_64.dylib

将 libtyporahook_x86_64.dylib 和 Typora/Contents/MacOS/ 目录下和 Typora 可执行文件放在一起,运行:insert_dylib --all-yes @executable_path/libtyporahook_x86_64.dylib Typora 就好了。

运行效果

Untitled

Untitled


Powered by Kali-Team