0x00

Typora是一款强大的markdown编辑器,它可以让你轻松地写出美观的文档。但是其一直是不开源的,而且现在也已经开始收费了。所以本着学习探索的精神去逆向看看~

0x01

众所周知Typora是基于electron+reacta开发的,所以先看看js代码~



然后在顺着这个O继续康康~





关键就是这个e.hasActivated = "true" == e.hasActivated 但是这样的话有个小问题就是每次进去的话那个右下角都会有一个未激活悬浮框。而且只进行到这里也没啥意思,话不多说继续弄macos的可执行文件。

0x02

直接上ida,通过刚才的js思路走下去,这个可执行文件里肯定有生成url方法。搜索一下果不其然:



然后我们看到其调用了一个getLicensePanelUrlParams方法。进去康康!





ok!直接开始hook!!打开code编写dylib!

hook其返回值,setReturnValue后然后打印一下看看。

    id LicenseWindowController = NSClassFromString(@"LicenseWindowController");
[LicenseWindowController aspect_hookSelector:@selector(pageURL) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info){
NSInvocation *invocation = info.originalInvocation;
[invocation invoke];
__unsafe_unretained NSArray * tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSLog(@"hook==pageURL-result=%@",tempResultSet);
} error:nil ];
}

嗯,失败了。url参数没变。。估计是哪里还有验证。但是找了一下调用没看到。所以换个思路。

我们看到其获取url参数时是通过LicenseManager类的成员属性获取。所以直接修改这里,我觉得比hook返回值的url更优。那么开始查找~

查找ING~

0x03



找到了读取和写入LicenseInfo的方法那么下面就好说了~



第一眼就看到一个方法,recordFilePathNew



hook住它我们看看返回值~

v3 = objc_msgSend(&OBJC_CLASS___NSKeyedArchiver, "archivedDataWithRootObject:", self->_licenseDict, v2);
v4 = objc_retainAutoreleasedReturnValue(v3);
v5 = v4;
v6 = +[Crypto encryptAES:](&OBJC_CLASS___Crypto, "encryptAES:", v4);
v7 = (void *)objc_retainAutoreleasedReturnValue(v6);
objc_release(v5);
v8 = -[LicenseManager recordFilePathNew](self, "recordFilePathNew");
v9 = objc_retainAutoreleasedReturnValue(v8);
objc_msgSend(v7, "writeToFile:atomically:", v9, 1LL);
//writeLicenseInfo这里我们看到他是把licenseDict AES加密存到了刚才的地址中去。
//那么licenseDict里都有什么呢?
//通过 getLicensePanelUrlParams:
objc_msgSend((void *)self->_licenseDict, "objectForKeyedSubscript:", CFSTR("email"));
objc_msgSend((void *)self->_licenseDict, "objectForKeyedSubscript:", CFSTR("license"));
v27 = -[LicenseManager dayRemains](self, "dayRemains");
v28 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("%ld"), v27);
v29 = objc_retainAutoreleasedReturnValue(v28);
v30 = v29;
v31 = objc_msgSend(&OBJC_CLASS___NSURLQueryItem, "queryItemWithName:value:", CFSTR("dayRemains"), v29);
//我们看到了里面有email和license
//然后我们进入LicenseManager dayRemains
signed __int64 __cdecl -[LicenseManager dayRemains](LicenseManager *self, SEL a2)
{
return (signed __int64)-[LicenseManager dayRemainsFrom:](self, "dayRemainsFrom:", 15LL);
}
//通过LicenseManager dayRemainsFrom
objc_msgSend((void *)self->_licenseDict, "setObject:forKeyedSubscript:", v8, CFSTR("installDate"));
//也就是说LicenseManager类的成员字典里_licenseDict包含了邮箱和license以及installDate

installDate安装时间也就是判断我们15天试用的关键。

所以这里只要把这个AES加密后储存的文件定期删除就可以永续15天试用进行一个破解。

但是这样也不太优雅~

可是直接修改类成员hasActivated也不行。

0x04

我们先回顾一下线索。

  • electron是通过接收解析url参数“hasActivated”来判断是不是激活用户。
  • macos里可执行文件修改让其发送url时把hasActivated赋值为true
  • getLicensePanelUrlParams 和 pageUrl修改返回值无效。
  • LicenseManager类里包含两个成员。1_hasLicense,2_licenseDict
  • 直接hook赋值hasActivated也不行,怀疑需要licenseDict。
  • licenseDict包含邮箱和license以及installDate,可以通过修改installDate来破解试用
  • licenseDict会加密储存在本地。

思考:

直接修改发送前的url和hasLicense不行,我怀疑是哪里还有验证,也就是验证licenseDict,尤其是licenseDict里的license。可以选择做掉验证license的方法(最轻松),也可以逆向算法追出正确的license(应该可以毕竟有离线验证)

但是,程序不会哪个环节都会验证license。

划重点,加密存储。既然加密了,估计程序应该会很信任这段数据吧~

所以一般是在存储前验证下license!

思路有了!

我们看看hook下writeLicenseInfo~~

上代码~

    id LicenseManager = NSClassFromString(@"LicenseManager");
[LicenseManager aspect_hookSelector:@selector(writeLicenseInfo) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info){
NSInvocation *invocation = info.originalInvocation;
[invocation invoke];
id instance = info.instance;
[instance setValue:@"1" forKeyPath:@"hasLicense"];
NSDictionary *licenseDict = @{@"email":@"huajia@huaji.com", @"license":@"hackBy:huajia"};
[instance setValue:licenseDict forKeyPath:@"licenseDict"];
} error:nil ];

ok,我们在在原方法调用前执行我们的hook,先是修改了LicenseManager的成员属性hasLicense,让程序误认为我们已经激活,顺便把邮箱和License也加入了,哈哈。然后writeLicenseInfo会把我们的构造加密写入本地文件中,然后其他方法会读取,现在我们运行下程序看看!



233~

mac Typora最新版逆向破解的更多相关文章

  1. Navicat15 For Mysql最新版完美破解图文教程(支持Win和Mac)

    Navicat15 For Mysql最新版完美破解 欢迎关注博主公众号[跟着Mic学架构],专注于分享Java领域技术干货,回复关键字 [面试资料] 可以获得海量面试资料. 申明,本教程 Navic ...

  2. Android逆向破解表单登录程序

    Android逆向破解表单登录程序 Android开发 ADT: android studio(as) 程序界面如下,登录成功时弹出通知登录成功,登录失败时弹出通知登录失败. 布局代码 <?xm ...

  3. 【MyEclipse 2015】 逆向破解实录系列【终】(纯研究)

    声明 My Eclipse 2015 程序版权为Genuitec, L.L.C所有. My Eclipse 2015 的注册码.激活码等授权为Genuitec, L.L.C及其付费用户所有. 本文只从 ...

  4. 【MyEclipse 2015】 逆向破解实录系列【2】(纯研究)

    声明 My Eclipse 2015 程序版权为Genuitec, L.L.C所有. My Eclipse 2015 的注册码.激活码等授权为Genuitec, L.L.C及其付费用户所有. 本文只从 ...

  5. 20165223《网络对抗技术》Exp1 PC平台逆向破解

    目录--PC平台逆向破解 1 逆向及BOF基础实践说明 1.1 实践内容 1.2 实践要求 1.3 基础知识 2 实验步骤 2.1 直接修改程序机器指令,改变程序执行流程 2.2 通过构造输入参数,造 ...

  6. 20155324《网络对抗》Exp1 PC平台逆向破解(5)M

    20155324<网络对抗>Exp1 PC平台逆向破解(5)M 实验目标 本次实践的对象是一个名为~pwn1~的~linux~可执行文件. 该程序正常执行流程是:~main~调用~foo~ ...

  7. 2018-2019-2 20165237《网络攻防技术》Exp1 PC平台逆向破解

    2018-2019-2 20165237<网络攻防技术>Exp1 PC平台逆向破解 一.实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调 ...

  8. 2018-2019-2 20165234 《网络对抗技术》 Exp1 PC平台逆向破解

    实验一 PC平台逆向破解 实验目的 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含另 ...

  9. 20165221 《网络对抗技术》EXP1 PC平台逆向破解

    20165221 <网络对抗技术>EXP1 PC平台逆向破解 一.实验内容 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函 ...

  10. 2018-2019-2 网络对抗技术 20165325 Exp1 PC平台逆向破解

    2018-2019-2 网络对抗技术 20165325 Exp1 PC平台逆向破解(BOF实验) 实验有三个模块: (一)直接修改程序机器指令,改变程序执行流程: (二)通过构造输入参数,造成BOF攻 ...

随机推荐

  1. 【Mybatis】(一)

    Mybatis简介 提供持久层框架包括SQL Maps和Data Access Objects(DAO). SQL Maps提供数据库数据和java数据的映射关系,换句话说即是封装JDBC的过程. D ...

  2. c/c++快乐算法第三天

    c/c++感受算法快乐(3) 开始时间2023-04-16 22:21:10 结束时间2023-04-17 00:09:34 前言:很好,这周就要结束了,大家都回学校了么,嘻嘻.回顾一下昨天的算法题, ...

  3. CentOS配置Django虚拟环境--坑点总结

    1.CentOS原装有python2.7,编译安装python3.X版本 2.sqlite-devel未安装 3.sqlite3版本过低报错 升级sqlite3版本 参考 https://blog.c ...

  4. 深度学习入门系列之doc

    这周老师让把深度学习的名词过一遍,小玛同学准备在过一遍Deep Learning名词的同时把基本的模型也过一遍. 感谢杰哥发我深度学习入门系列能让我有机会快速入门. 下面就来doc一些学到的东西 线性 ...

  5. java递归算法之老鼠找路

    (上图出自B站韩顺平教育) 从上图的(1,1)处,寻找到(6,5)处的路线,红色格子是障碍 public class MiGong { public static void main(String[] ...

  6. error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file o

    error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file o ...

  7. Java Lambda Stream

    ::方法使用 条件:lambada表达式的主体仅包含一个表达式,且lambada表达式只调用一个已经存在的方法:被引用的方法的参数列表与lambada表达式的输入输出一致 以下是Java 8中方法引用 ...

  8. 揭秘Karmada百倍集群规模多云基础设施体系

    摘要:本文结合Karmada社区对大规模场景的思考,揭示Karmada稳定支持100个大规模集群.管理超过50万个节点和200万个Pod背后的原理 本文分享自华为云社区<Karmada百倍集群规 ...

  9. Pyhton F字符串引起的invalid syntax

    事发现场 偶然运行到之前写的爬虫,发现运行不了,报错invalid syntax,于是来找bug 报错截图: 原因: 这样用法称之为 f-string f-string,亦称为格式化字符串常量(for ...

  10. 【Java】Java代码拷贝文件的速度

    Java代码拷贝文件的速度究竟有多快? 前言 最近学习Java到了流处理,其中有种流叫FileInputStream和FileOutputStream,简单来说,就是操作文件的,老师给我们示范了一个非 ...