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. Python常见面试题016. 请实现如下功能|谈谈你对闭包的理解

    016. 请实现如下功能|谈谈你对闭包的理解 摘自<流畅的python> 第七章 函数装饰器和闭包 实现一个函数(可以不是函数)avg,计算不断增加的系列值的平均值,效果如下 def av ...

  2. Springboot一些常用注解

    Springboot启动注解 @SpringbootApplication 这个注解是Springboot最核心的注解,用在Springboot的主类上,标识这是一个Springboot应用,用来开启 ...

  3. 使用“纯”Servlet做一个单表的CRUD操作

    使用"纯"Servlet做一个单表的CRUD操作 每博一文案 庄子说:"独往独来,是谓独有.独有之人,是谓至贵".热闹是别人的狂欢,而孤独是自己的自由. 相聚总 ...

  4. Clion+dap仿真器,移植stm32项目

    如何将Keil项目移植到Clion,先看几位大佬的文章: 稚晖君的回答:配置CLion用于STM32开发[优雅の嵌入式开发] 野火论坛:DAP仿真器的使用教程 wuxx:nanoDAP使用疑难杂症解析 ...

  5. pandas小技巧

    1. 删除列 import pandas as pd df.drop("Unnamed: 0", axis=1, inplace=True) 2. 转换列的格式 df[" ...

  6. 从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(二)

    传送门:从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(一) 一.设置Swagger页面为首页--开发环境 我们虽然可以在输入 /swagger 后顺利的访问 ...

  7. .Net Core工作流WorkFlowCore

    前言 WorkFlowCore是一个针对.NetCore的轻量级的工作流引擎,提供了FluentAPI.多任务.持久化以及并行处理的功能,适合于小型工作流.责任链的需求开发.支持工作流长期运行,提供了 ...

  8. Python-pytest-repeat的简单使用

    前言: 一.简介 pytest-repeat是pytest的插件,重复执行单个用例,或多个测试用例,并指定重复次数. 二.安装 1.执行如下命令 pip3 install pytest-repeat ...

  9. boot-admin整合Liquibase实现数据库版本管理

    Liquibase 和 Flyway 是两款成熟的.优秀的.开源/商业版的数据库版本管理工具,鉴于 Flyway 的社区版本对 Oracle 数据库支持存在限制,所以 boot-admin 选择整合 ...

  10. 2022-02-20:设计内存文件系统。 设计一个内存文件系统,模拟以下功能: ls: 以字符串的格式输入一个路径。如果它是一个文件的路径,那么函数返回一个列表,仅包含这个文件的名字。如果它是一个文件

    2022-02-20:设计内存文件系统. 设计一个内存文件系统,模拟以下功能: ls: 以字符串的格式输入一个路径.如果它是一个文件的路径,那么函数返回一个列表,仅包含这个文件的名字.如果它是一个文件 ...