吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 22314|回复: 388
上一主题 下一主题
收起左侧

[原创] Typora 授权解密与剖析

    [复制链接]
跳转到指定楼层
楼主
十一七 发表于 2021-11-30 23:46 回帖奖励
本帖最后由 十一七 于 2021-12-1 12:44 编辑

11月23日,Typora 正式发布 1.0 版本,进入了收费时代。

1.0 版本是一次性付费而非订阅的,只要支付人民币 89 元,可以在 3 台设备里使用。

Typora之于我

如你所见,这一篇文章就是使用Typora所写。自搭建个人博客起,Typora就成为了我主要的写作平台。

用惯了Markdown,WordPress的古腾堡编辑器没法满足我的需求,于是开始寻找替代品,最终的结果便是typora。

当然,多数人使用的原因不外乎以下

  • 轻盈、干净

  • 所见即所得

  • 图床

  • 主题、生态

  • (beta)免费

  • ……

如今,typora进入收费阶段,不乏使用者被迫迁移至其他写作工具上。

(不扯了官方话了)下面,我们来一探究竟。

敬告

请勿使用盗版,支持正版授权。

文中内容仅作学习和讨论,请不要从事任何非法行为。

由此产生的任何问题都将读者/用户(您)承担。

寻踪觅源

通过火绒剑监测行为日志

程序加载的一些模块

在Windows下,typora会记录日志至{UsersRoot}\AppData\Roaming\Typora\typora.log

能看到可疑的注册表操作记录

正版激活的注册项内容

尝试修改SLicense

重新运行软件后,从错误日志中发现调用栈暴露。

渐入佳境

这里关注到了app.asar

通过搜索引擎,尝试解包

npm install -g asar
asar extract {installRoot}/Typora/resources/app.asar workstation/outs

发现文件被加密

JavaScript不管是字节码还是明文脚本都会在运行时加载,结合模块列表寻找加载点

关注到解包得到的main.node

IDA寻找字符串特征

通过交叉引用定位

看到一些导入函数

由字符串联想到对加密文件进行的base64解码

导入表查找到 napi Node-API | Node.js API 文档 (nodejs.cn)

简单分析伪代码后,其实就是运行

Buffer.from(e,"base64")

刻舟求剑

尝试Findcrypt寻找算法,找到AES的Sbox和InvBox

通过交叉引用定位到可疑函数点 main.node+E440

IDA动态调试,模块加载断点

跑起来,直至加载main.node

分析模块后,定位base+offset下断,运行

看到

正好与我们的文件对应偏移16

继续调试能看到 分组加密的形式

同时能够找到前16字节

正是作为iv进行异或

柳暗花明

分析调用函数,最终能够确定其函数功能

通过偏移EF19,能够确定AES轮数为13轮,对应为AES 256

偏移B510处的函数,能够得到AESKey

落叶归根

解密得到明文脚本,授权主逻辑在Lisence.js中

授权逻辑如下图

本地验证->获取用户特征->网络验证授权->返回密文->RSA公钥解密->设备指纹对比

破解的思路,不多做阐述。

修改完成后,只需要按相同格式加密并打包为app.asar即可实现补丁Patch

typoraCracker

typoraCracker是一个Typora解包解密程序,也是一个打包加密程序。你可以轻松的打造独属于你的补丁,但请注意法律上的可行性。

测试

总有一种人,喜欢享受“正版”激活的感觉。而我就是……

我采用 Patch+KeyGen

补丁去除网络授权,KeyGen用于本地验证,测试成功

尾声

typora针对electron下的源码加固仍是一片空白。

简单思考后,传统代码混淆的方式对关键逻辑的保护依然有较大的提升空间,不失为一个恰当的加固方向。

期待typora会越做越好——来自一个正版使用者

免费评分

参与人数 194威望 +2 吾爱币 +295 热心值 +177 收起 理由
h0st + 1 + 1 谢谢@Thanks!
coderwaves + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
一介书生 + 1 + 1 我很赞同!
lezaitianya + 1 + 1 我很赞同!
hemaeee + 1 用心讨论,共获提升!
STARSHINEA + 1 + 1 我很赞同!
sfyyy + 1 + 1 用心讨论,共获提升!
kikipu + 1 + 1 大佬操作,凡人看不懂
jackies + 1 + 1 热心回复!
XD9945 + 1 我很赞同!
Cookiesfly + 1 + 1 用心讨论,共获提升!
大豹子 + 1 我很赞同!
pojie_dd + 1 + 1 用心讨论,共获提升!
ACBur + 1 + 1 用心讨论,共获提升!
CyberAzrael + 1 + 1 我很赞同!
lyfff + 1 + 1 我很赞同!
Windysime + 1 + 1 我很赞同!
zhushui + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
p2003722 + 1 + 1 +1,同为支持正版但想尝试破解的快感的人
li1762951027 + 1 谢谢@Thanks!
liuhongxin1989 + 1 + 1 大神真心佩服
qq957413212 + 1 + 1 成功上车!
52SNORLAX + 1 有意思
Bexh0lder + 1 + 1 谢谢@Thanks!
meetAgain + 1 + 1 谢谢@Thanks!
wuqingyou + 1 用心讨论,共获提升!
摇曳的利奇马 + 1 + 1 用心讨论,共获提升!
my790978513 + 1 + 1 谢谢@Thanks!
cdmafvrty + 1 + 1 用心讨论,共获提升!
landwind + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
doomblade + 1 + 1 谢谢@Thanks!
BOB27 + 1 谢谢@Thanks!
繁星飞跃 + 1 + 1 我很赞同!
JonesDean + 1 + 1 谢谢@Thanks!
Simnet + 1 + 1 谢谢@Thanks!
systemuser + 1 谢谢@Thanks!
thepoy + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ht4266394 + 1 + 1 谢谢@Thanks!
1539173762 + 1 + 1 热心回复!
努力加载中 + 1 + 1 热心回复!
qq533 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
LibertyCola + 1 + 1 热心回复!
frank10010 + 1 + 1 我很赞同!
liuhongxin1989 + 1 + 1 谢谢@Thanks!
fusheng55555 + 1 好牛哇
nevinhappy + 1 + 1 鼓励转贴优秀软件安全工具和文档!
麦米尔加弗德 + 1 + 1 用心讨论,共获提升!
pandahan + 1 + 1 谢谢@Thanks!
pinesnow + 1 我很赞同!
5omggx + 1 + 1 感谢大佬
h1jacker + 1 + 1 谢谢@Thanks!
mi0070 + 1 + 1 谢谢@Thanks!
xyz349925756 + 1 + 1 我很赞同!
ihjun + 2 + 1 谢谢@Thanks!
裂石破天 + 1 我很赞同!
chenxz21 + 1 + 1 我很赞同!
Richex + 1 谢谢@Thanks!
无痕567 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
Reat + 1 + 1 谢谢@Thanks!
蓝纹鲸 + 1 + 1 <font style="vertical-align: inherit;"><font style=
lingjuehun + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
tobiasaxzc + 1 + 1 我很赞同!
klx234 + 1 谢谢@Thanks!
sunlei658 + 1 + 1 我很赞同!
ailanxier + 1 我很赞同!
We. + 1 + 1 感谢分享~
大大怪 + 1 + 1 我很赞同!
wanleya + 1 + 1 谢谢@Thanks!
lahmsworld + 1 + 1 我很赞同!
SouperGeng + 1 + 1 我很赞同!
Kristin_ + 1 + 1 我很赞同!
sunshine_昊 + 1 谢谢@Thanks!
FFF全部成为F + 1 + 1 分析讨论交流,论坛有你更精彩!
KylinYang + 1 + 1 谢谢@Thanks!
hqe + 1 谢谢@Thanks!
冯柟 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Smiling_Mask + 1 + 1 热心回复!
舒默哦 + 2 + 1 谢谢@Thanks!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
flying104 + 1 + 1 谢谢@Thanks!
0xC05 + 1 用心讨论,共获提升!
莫千秋 + 1 谢谢@Thanks!
漫卷西风Carol + 1 热心回复!
52PJmumu + 1 + 1 膜拜大佬
alderaan + 1 + 1 用心讨论,共获提升!
15235109295 + 1 + 1 我很赞同!
dualwind + 1 谢谢@Thanks!
nekoneko2021 + 1 + 1 我很赞同!
重置001 + 1 + 1 我很赞同!
莫问刀 + 1 + 1 谢谢@Thanks!
philonic + 1 + 1 我很赞同!
ContacNt + 1 + 1 我很赞同!
icegull + 1 + 1 用心讨论,共获提升!
Wawapj3333 + 1 + 1 谢谢@Thanks!
木羊羽 + 3 + 1 我很赞同!
andrew_a + 2 + 1 谢谢@Thanks!
wapj258 + 1 + 1 用心讨论,共获提升!
chiyaoss + 1 + 1 我很赞同!
backin886 + 1 + 1 谢谢@Thanks!
SunsetShimmer + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 2#
 楼主| 十一七 发表于 2022-2-18 14:04 |楼主
本帖最后由 十一七 于 2022-4-28 19:26 编辑

typoraCracker 因DMCA关闭,不再提供任何支持。
头像被屏蔽
受到警告 推荐
Airey 发表于 2021-12-3 19:07
推荐
涛之雨 发表于 2021-12-2 06:54

看完确实是清楚了密钥怎么来的,
有空尝试一下,
不过还是想找个通用hook点,
类似于DLL劫持那样,
不修改文件的情况下实现crack
推荐
smilencetion 发表于 2021-12-2 15:45
本帖最后由 smilencetion 于 2021-12-2 15:48 编辑
cyantea 发表于 2021-12-2 15:37
@91#,我按步骤操作的,也替换了文件,也生成了key,提示序列号不正确。

有替换License.js这个文件吗?这个需要替换

这一步以后
python typora.py {installRoot}/Typora/resources/app.asar workstation/outfile/
需要你把typoraCracker\example\patch下的License.js替换刚才生成的在dec_app里面的License.js,然后再进行下面这步python typora.py -u workstation/outfile/dec_app workstation/outappasar

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
ugvfpdcuwfnh + 1 + 1 我很赞同!

查看全部评分

推荐
xll816 发表于 2021-12-3 17:58

膜拜大佬,感谢分享提供的方式和工具

本帖最后由 xll816 于 2021-12-6 08:38 编辑

E:\typora.png

typora.png (108.87 KB, 下载次数: 125)

上车流程

上车流程
推荐
weefun92 发表于 2021-12-1 20:56
本帖最后由 weefun92 于 2021-12-2 21:48 编辑

真大佬,看的酣畅淋漓,痛快(可惜我不会~

更新-----

按照教程重新打包并替换后,用生成的key激活时提是需要联网,是哪里除了问题吗?求教~


再更-----

根据 @smilencetion 同学提示:

https://www.52pojie.cn/forum.php ... 553967&pid=40881603,需要替换一下 License.js,然后再重新打包,替换即可。
已经成功上车{:1_918:}
推荐
19770214 发表于 2021-12-25 16:26
本帖最后由 19770214 于 2021-12-25 16:46 编辑

感谢大佬写的脚本,又可以白嫖了/汪汪
有些萌新看不懂的话可以用我写的这个bat脚本来破解软件
要求:
1.有安装Nodejs并且知道Nodejs安装位置以及文件名称
2.有下载大佬制作的脚本包
用法:
1.将start.bat的代码粘贴进一个文本文档(记着改里面需要更改的地方!!!),改文本文档后缀为.bat
2.将bat文件放进大佬的文件包中
3.将License.js的代码粘贴进一个文本文档,改文本文档后缀为.js
4.将License.js也放进大佬的文件包中
5.运行bat文件

start.bat:
[Shell] 纯文本查看 复制代码
@echo OFF
::DEBUG
set workdir=%CD%\work
set nodedir=<修改为你的Nodejs安装位置>
set nodeapp=<修改为Nodejs可执行程序的名称>
set outputdir=%workdir%\output
set targetdir=<修改为你的Typora的安装路径>
if not exist "%CD%\init.success" goto :init
goto :start
:init
echo 安装所需环境
pip3 install -r requirements.txt
echo nul>init.success
goto :start
:start
echo 创建工作文件夹
mkdir "%workdir%"
mkdir "%workdir%\output"
echo 开始破解
python3 typora.py "%targetdir%\app.asar" "%workdir%"
rm -rf "%workdir%\dec_app\License.js"
xcopy License.js "%workdir%\dec_app\"
python3 typora.py -u "%workdir%\dec_app" "%workdir%\output"
rm -rf "%targetdir%\app.asar"
xcopy /R /Y "%workdir%\output\app.asar" "%targetdir%\"
echo 生成激活码
echo.
echo.
echo.
echo 您的激活码:
"%nodedir%\%nodeapp%" keygen.js
echo.
echo.
echo.
echo 您只需要使用上面的激活码进入软件进行激活即可
echo 破解结束
pause
rm -rf "%workdir%"
goto :EOF


License.js:
[JavaScript] 纯文本查看 复制代码
require("Env.js");var Dict=require("Dict.js"),electron=require("electron"),shell=electron.shell,app=electron.app,ipc=electron.ipcMain,BrowserWindow=electron.BrowserWindow,isWin="win32"==process.platform,isMac="darwin"==process.platform,isLinux="linux"==process.platform,WindowController=require("WindowController.js"),Raven=require("raven"),errorShown=!1;const mustRequire=function(e){try{return require(e)}catch(e){if(errorShown)return;errorShown=!0;var n=e.message;setTimeout((()=>{errorShown=!1,dialog=require("electron").dialog,dialog.showMessageBox(null,{type:"error",buttons:["OK"],defaultId:0,cancelId:0,title:"A required module cannot be loaded by Typora",message:n.split("\n")[0]+"\n\nPlease check if that file exists or reinstall Typora to fix."}).then((({response:e})=>{process.exit(1)}))}),1500)}};var installDate,lastShown,hasLicense=null,email="",licenseCode="",fingerPrint="";const ActiveResponseCode={SUCCESS:0,OUT_OF_LIMIT:1,INVALIDATE:-1,WRONG_USER:-2},PUB_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7nVoGCHqIMJyqgALEUrc\n5JJhap0+HtJqzPE04pz4y+nrOmY7/12f3HvZyyoRsxKdXTZbO0wEHFIh0cRqsuaJ\nPyaOOPbA0BsalofIAY3mRhQQ3vSf+rn3g+w0S+udWmKV9DnmJlpWqizFajU4T/E4\n5ZgMNcXt3E1ips32rdbTR0Nnen9PVITvrbJ3l6CI2BFBImZQZ2P8N+LsqfJsqyVV\nwDkt3mHAVxV7FZbfYWG+8FDSuKQHaCmvgAtChx9hwl3J6RekkqDVa6GIV13D23LS\nqdk0Jb521wFJi/V6QAK6SLBiby5gYN6zQQ5RQpjXtR53MwzTdiAzGEuKdOtrY2Me\nDwIDAQAB\n-----END PUBLIC KEY-----\n\n",DAY_IN_MS=864e5,HOST="https://store.typora.io",decrypt=e=>JSON.parse(Buffer.from(e,"base64").toString("utf-8")),makeHash=function(){var e=Array.from(arguments);const n=require("crypto").createHash("sha256");return e.forEach((e=>{n.update(e)})),n.digest("base64")},readLicenseInfo=()=>{const e=getLicenseLocalStore().get("SLicense");if(!e)return null;const[n,t,i]=e.split("#"),a=decrypt(n);return a.fingerprint!=fingerPrint?null:(Object.assign(a,{failCounts:t,lastRetry:new Date(i)}),a)},writeInstallDate=async e=>{console.log(`writeInstallDate fromBTime=${e}`);var n=new Date;if(e)try{var t=await require("fs-extra").stat(app.getPath("userData")+"/profile.data");n=new Date(t.birthtime),t.birthtime}catch(e){}installDate=n;const i=n.toLocaleDateString("en-US");return getLicenseLocalStore().put("IDate",i),installDate};var licenseLocalStoreInstance=null;const getLicenseLocalStore=function(){if(null==licenseLocalStoreInstance)if(isWin)licenseLocalStoreInstance=WindowsLicenseLocalStore();else{var e=app.setting.prepDatabase(fingerPrint);licenseLocalStoreInstance={put:function(n,t){console.log(`ls put ${n}`),e.getState()[n]=t,e.write()},get:function(n){return e.getState()[n]}}}return licenseLocalStoreInstance};function WindowsLicenseLocalStore(){const e=mustRequire("native-reg");return{get:function(n){const t=e.openKey(e.HKCU,"Software\\Typora",e.Access.READ);if(null==t)return"";const i=e.getValue(t,null,n);return e.closeKey(t),i},put:function(n,t){const i=e.createKey(e.HKCU,"Software\\Typora",e.Access.WRITE);e.setValueSZ(i,n,t),e.closeKey(i)}}}const getFingerPrint=async()=>{if(!fingerPrint){if(isWin){const e=mustRequire("native-reg"),n=e.openKey(e.HKEY.LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Cryptography",e.Access.WOW64_64KEY|e.Access.READ);fingerPrint=e.getValue(n,null,"MachineGuid"),e.closeKey(n)}else fingerPrint=await require("node-machine-id").machineId({original:!0});fingerPrint||Raven.captureMessage("[License] Failed to get fingerPrint"),fingerPrint=makeHash(fingerPrint,"typora").substr(0,10).replace(/[/=+-]/g,"a"),isMac&&(fingerPrint+="darwin")}return fingerPrint};var licenseInitialed=!1;const watchLicense=async e=>{console.log("[watchLicense]"),firstValidateLicense(e),await validateTrail(),!global.betaVersion&&console.log(`[watchLicense] hasLicense: ${hasLicense}`),showLicensePanelIfNeeded(),addToAnalysis()},addToAnalysis=()=>{var e=Raven.getContext().tags;e.hasLicense=hasLicense,Raven.mergeContext(e)},getOS=()=>process.platform.replace(/\d+/,""),renewLicense=async(e,n)=>{(new Date).toLocaleDateString("en-US");const{deviceId:t,lastRetry:i}=e||{};if(!n&&new Date-i<432e5)return;const a={v:getOS()+"|"+app.getVersion(),license:licenseCode,l:t,u:app.setting.generateUUID(),type:global.devVersion?"dev":""};JSON.stringify(a)},getInstallDate=e=>{var n=new Date(getLicenseLocalStore().get("IDate"));if(isNaN(n.getTime()))return e?null:new Date;if(e)return n;var t=1637934234708;return isNaN(t)?t=new Date("2021-10-01"):(t=new Date(t),isNaN(t.getTime())&&(t=new Date("2021-10-01"))),n<t?t:n},getTrailRemains=(e,n)=>{n=n||15;var t=Math.floor((new Date-installDate)/864e5),i=Math.max(0,n-t);return e&&(i>n||isNaN(i))&&(i=n),i},validateTrail=async()=>{var e=(installDate=getInstallDate(!global.devVersion))?getTrailRemains(!1):100;(e>15||isNaN(e))&&(console.log("[validateTrail] Read from incorrupted InstallDate"),await writeInstallDate(!0),e=15),console.log(`[validateTrail] installDate is ${installDate.toLocaleDateString("en-US")}, trail remains: ${e} days`)};function fillLicense(e,n){licenseCode=n,(hasLicense=!(!(email=e)||!licenseCode))&&onFillLicense()}function unfillLicense(e){hasLicense||(e=""),email="",licenseCode="",hasLicense=!1,getLicenseLocalStore().put("SLicense",""),e&&showDialog(Dict.getPanelString("Typora is now deactivated"),Dict.getPanelString(e)),onUnfillLicense()}const firstValidateLicense=e=>{console.log("[License] firstValidateLicense"),licenseInitialed=!0;const n=readLicenseInfo(),{license:t,email:i}=n||{};t&&i?(fillLicense(i,t),renewLicense(n,e),console.log("[License] pass validateLicenseInfoStr")):unfillLicense()},showDialog=(e,n)=>electron.dialog.showMessageBox(null,{type:"error",buttons:["OK"],defaultId:0,cancelId:0,title:e,message:n}),endDevTest=function(){app.expired=!0,showDialog(Dict.getPanelString("Error"),Dict.getPanelString("This beta version of Typora is expired, please download and install a newer version.")).then((()=>{shell.openExternal("https://typora.io/#download"),setTimeout((()=>{process.exit(1)}),1e3)}))},validateDevTest=function(){if(!hasLicense&&!isLinux&&global.devVersion&&global.PRODUCTION_MODE){var e=getInstallDate(),n=new Date;console.log("buildTime is 1637934234708"),(isNaN(1637934234708)||n-1637934234708>20736e6)&&endDevTest(),e-=0,console.log("verInitTime is "+e),!isNaN(e)&&n-e>1728e7&&endDevTest()}},showLicensePanelIfNeeded=function(){shouldShowNoLicenseHint(!0)&&!app.setting.inFirstShow&&(isLinux&&Math.random()<.95||(!lastShown||new Date-lastShown>36e5*(isLinux?4:2)||getTrailRemains(!0,20)<=0)&&showLicensePanel())};var licensePanel=null;const showLicensePanel=async function(e){if(lastShown=new Date,null==licensePanel)return(licensePanel=WindowController.showPanelWindow({width:525,height:420,path:`page-dist/license.html?dayRemains=${getTrailRemains(!0)}&index=${e?1:0}\n\t\t\t\t&hasActivated=${hasLicense||!1}&email=${email}&license=${licenseCode}&lang=${app.setting.getUserLocale()}&needLicense=${shouldShowNoLicenseHint()}`,frame:!1,alwaysOnTop:!errorShown})).on("closed",(function(){licensePanel=null})),void setTimeout((()=>{licensePanel&&!licensePanel.isDestroyed()&&licensePanel.setAlwaysOnTop(!1)}),5e3);licensePanel.focus()};var welcomePanel=null;const showWelcomePanel=async function(){if(lastShown=new Date,null==welcomePanel)return(welcomePanel=WindowController.showPanelWindow({width:760,height:460,path:`page-dist/welcome.html?lang=${app.setting.getUserLocale()}`,frame:!1,alwaysOnTop:!errorShown})).on("closed",(function(){welcomePanel=null})),void setTimeout((()=>{welcomePanel&&!welcomePanel.isDestroyed()&&welcomePanel.setAlwaysOnTop(!1)}),4e3);welcomePanel.focus()},quickValidate=e=>{const n="L23456789ABCDEFGHJKMNPQRSTUVWXYZ";if(!/^([A-Z0-9]{6}-){3}[A-Z0-9]{6}$/.exec(e))return!1;var t=e.replace(/-/g,""),i=t.substr(22);return!t.replace(/[L23456789ABCDEFGHJKMNPQRSTUVWXYZ]/g,"")&&i==(e=>{for(var t="",i=0;i<2;i++){for(var a=0,s=0;s<16;s+=2)a+=n.indexOf(e[i+s]);t+=n[a%=n.length]}return t})(t)},getComputerName=async function(){var e=process.env.USER;switch(e||(e=require("os").userInfo().username),process.platform){case"win32":return process.env.COMPUTERNAME+" | "+e+" | Windows";case"darwin":return new Promise((n=>{require("child_process").exec("scutil --get ComputerName",{timeout:5e3},((t,i)=>{n(!t&&i?i.toString().trim()+" | "+e+" | darwin":require("os").hostname()+" | "+e+" | darwin")}))}));default:return require("os").hostname()+" | "+e+" | Linux"}},doActivation=async function(e,n,t){if(e=(e||"").replace(/^[\s\u200b ]/g,"").replace(/[\s\u200b ]$/g,""),n=(n||"").replace(/^[\s\u200b ]/g,"").replace(/[\s\u200b ]$/g,""),!function(e){return/^[^\s@'"/\\=?]+@[^\s@'"/\\]+\.[^\s@'"/\\]+$/.test(e)}(e))return[!1,"Please input a valid email address"];if(!quickValidate(n))return[!1,"Please input a valid license code"];const i={v:getOS()+"|"+app.getVersion(),license:n,email:e,l:await getComputerName(),f:await getFingerPrint(),u:app.setting.generateUUID(),type:global.devVersion?"dev":"",force:t};JSON.stringify(i);try{const e={data:{code:0,msg:Buffer.from(JSON.stringify({deviceId:i.u,fingerprint:i.f,email:i.email,license:i.license,version:i.v,date:(new Date).toLocaleDateString("en-US")}),"utf-8").toString("base64")}};if(JSON.stringify(e.data),console.log(`[License] response code is ${e.data.code}`),e.data.code==ActiveResponseCode.SUCCESS)return await writeActivationInfo(e.data.msg)?[!0,""]:[!1,"Please input a valid license code"];if(e.data.code==ActiveResponseCode.OUT_OF_LIMIT)return t?await writeActivationInfo(e.data.msg)?[!0,"Your license has exceeded the max devices numbers.\nThe oldest device was unregistered automatically."]:[!1,"Please input a valid license code"]:["confirm",'Your license has exceeded the max devices numbers.\nIf you click "Continue Activation", this device will be activated and the oldest device will be unregistered automatically.'];if(e.data.code==ActiveResponseCode.INVALIDATE)return[!1,"Please input a valid license code"];if(e.data.code==ActiveResponseCode.WRONG_USER)return[!1,"This license code has been used with a different email address."]}catch(e){return e.response&&e.response.code?(console.warn(`[License] error from server ${e.response.code}`),[!1,"Unknown Error. Please contact [email]hi@typora.io[/email]"]):(Raven.captureException(e,{level:"warning"}),console.error(e.stack),[!1,"Failed to access the license server. Please check your network or try again later."])}},writeActivationInfo=async function(e){const n=decrypt(e)||{},{deviceId:t,fingerprint:i,email:a,license:s,version:o,date:r}=n;return i==await getFingerPrint()&&a&&s?(fillLicense(a,s),getLicenseLocalStore().put("SLicense",`${e}#0#${(new Date).toLocaleDateString("en-US")}`),hasLicense=!0,!0):(console.log("[License] validate server return fail"),unfillLicense(),!1)},doDeactivation=async()=>{hasLicense&&email&&licenseCode||console.error("doDeactivation on unregistered device");const{deviceId:e}=readLicenseInfo()||{};unfillLicense()};ipc.handle("addLicense",(async(e,{email:n,license:t,force:i})=>{console.log("handle addLicense");try{return await doActivation(n,t,i)}catch(e){console.error(e.stack)}})),ipc.handle("license.show",((e,n)=>{showLicensePanel(n||!1)})),ipc.handle("license.show.debug",(()=>{licensePanel&&licensePanel.webContents.openDevTools()})),ipc.handle("removeLicense",(async e=>{console.log("handle removeLicense");try{return await doDeactivation()}catch(e){console.error(e.stack)}}));const start=async(e,n)=>{console.log(`start LM in devVersion=${global.devVersion||!1}`);try{await getFingerPrint(),!e&&n||isLinux||(global.devVersion||!n||n.indexOf("dev")>-1)&&(console.log("re-write InstallDate"),await writeInstallDate()),validateDevTest(),watchLicense(e)}catch(e){Raven.captureException(e)}},shouldShowNoLicenseHint=e=>!hasLicense&&(e||!isLinux)&&!global.devVersion,getHasLicense=()=>hasLicense,appendLicenseHintIfNeeded=e=>{licenseInitialed&&shouldShowNoLicenseHint()&&onUnfillLicense(e)};function genClassName(){var e=(new Date).getTime();return"txxxx-xxxx-xxxxy".replace(/[x]/g,(function(n){var t=(e+16*Math.random())%16|0;return e=Math.floor(e/16),t.toString(16)}))}const className=genClassName(),onFillLicense=()=>{BrowserWindow.getAllWindows().forEach((e=>{e.webContents.executeJavaScript(`try{document.querySelector(".${className}").remove();}catch(e){};File.option && (File.option.hasLicense = true);File.megaMenu && File.megaMenu.forceReload();0;`)}))},onUnfillLicense=async e=>{if(isLinux||global.devVersion)return;await Dict.init();const n=`.typora-sourceview-on .${className}{\n\t\tdisplay:none;\n\t}\n\t.${className} {\n\t\tposition: fixed;\n    bottom: 2px;\n    z-index: 9999;\n    left: 70px;\n    font-size: 12px;\n    line-height: 24px;\n    background: rgb(120 120 120 / 30%);\n    padding: 0 12px;\n    color: var(--text-color);\n    border-radius: 4px;\n    cursor: pointer;\n\t}\n\t.pin-outline .${className}{\n\t\tleft:calc(var(--sidebar-width) + 70px);\n\t}`,t=`if(window.File.option){\n\t\tFile.option.hasLicense = false; \n\t\tFile.megaMenu && File.megaMenu.forceReload();\n\t\tif(!document.querySelector(".${className}")) {\n\t\t\tconst pos = Math.round(Math.random() * document.body.children.length);\n\t\t\tconst dom = document.createElement("DIV");\n\t\t\tdom.innerText = "${Dict.getPanelString("UNREGISTERED")} ×";\n\t\t\tdom.classList.add("${className}");\n\t\t\tdom.style = "position: fixed !important;bottom: 2px !important; display: block !important; opacity: 1 !important; height: auto !important; width: auto !important; z-index: 9999 !important;"\n\t\t\tdom.setAttribute("role", "button");\n\t\t\tdom.addEventListener("click", () => {\n\t\t\t\tdom.remove();\n\t\t\t\treqnode("electron").ipcRenderer.invoke("license.show");\n\t\t\t});\n\t\t\tdocument.body.insertBefore(dom, document.body.children[pos]);\n\t\t}\n\t};1;`;function i(e){e.webContents.insertCSS(n),e.webContents.executeJavaScript(t)}e?i(e):BrowserWindow.getAllWindows().forEach(i)};exports.shouldShowNoLicenseHint=shouldShowNoLicenseHint,exports.start=start,exports.showLicensePanel=showLicensePanel,exports.showWelcomePanel=showWelcomePanel,exports.appendLicenseHintIfNeeded=appendLicenseHintIfNeeded,exports.getHasLicense=getHasLicense,exports.showLicensePanelIfNeeded=showLicensePanelIfNeeded;
推荐
正己 发表于 2021-12-1 12:44
Mason大佬tql!!!
推荐
smilencetion 发表于 2021-12-2 14:25
尘叶云渡 发表于 2021-12-2 14:08
会报以下错:typora.py: error: unrecognized arguments: workstation/outfile/
请问是哪里出了问题呢?

这个workstation/outfile/,只是举个例子而已,如果你当前路径下没有 workstation/outfile/这个文件夹,当然会报错,改成你自己的名字,或者建立同名的的workstation/outfile/文件夹
推荐
cyantea 发表于 2021-12-2 15:37
@91#,我按步骤操作的,也替换了文件,也生成了key,提示序列号不正确。
12#
harryczqp 发表于 2021-12-1 12:57
牛啊,思路清洗
13#
iceprism 发表于 2021-12-1 13:19
才正版第一周内就分析出来了,太强了
14#
fangxiaoqi 发表于 2021-12-1 14:07
太强了太强了
15#
可坏 发表于 2021-12-1 14:15

太强了太强了  已经start
16#
Finley69 发表于 2021-12-1 14:20
膜拜膜拜大佬
17#
detewhkn 发表于 2021-12-1 14:22
经典教程,强强
18#
abstao 发表于 2021-12-1 14:30
受教了,我也来试试
19#
Tulubi 发表于 2021-12-1 14:31
为甚如此优秀!!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-5-17 11:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表