Typora LicenseManager过期分析

Typora 0.11.18是最后一个免费测试的版本,但是使用一阵子后会提示已经过期,出现这个问题主要原因是软件打开后会读取系统时间进行判断是否过期。

Typora LicenseManager过期分析

所以绕过的方法分为三种:

►►►

手动修改时间

手动将时间修改至2年之前,然后打开typora,不退出窗口就可以正常使用,打开其他md文件也不会弹出窗口了,然后再将时间调整回正常时间。

►►►

自动修改时间

通过mac的脚本编辑器,来自动修改时间,自动打开typora,并自动恢复时间。
tell application "Terminal"
  # 关闭自动设置日期
 set currentTab to do script "sudo systemsetup -setusingnetworktime off"
 # 设置过去时间
 do script "sudo date 0415110022" in currentTab
 do script "sleep 2" in currentTab
 # 打开typora
 do script "open /Applications/Typora.app -g" in currentTab
 do script "sleep 2" in currentTab
 # 开启自动设置日期
 do script "sudo systemsetup -setusingnetworktime on" in currentTab
 do script "sleep 2" in currentTab
 # 退出terminal
 do script "killall Terminal" in currentTab
end tell
然后将它导出为app,这样可以不用每次都手动修改时间,只要先运行一次这个app就可以了。

Typora LicenseManager过期分析

但是它仍然有个问题,有时候想直接打开个md文档,还是会弹窗,必须得先运行这个app才行。

►►►

修改APP

最直接的办法就是修改app。

Typora LicenseManager过期分析


主要目标是MacOS里的Typora二进制文件和Resources里的zh-Hans.lproj翻译文件。
ida64打开,代码量非常大。从报错的窗口入手吧。在Resources里Panel.strings中:
“This beta version of Typora is expired, please download and install a newer version.” = “当前测试版版本过低,请下载较新版本”;
在ida的strings窗口中,找到相应的字符串:
Typora LicenseManager过期分析
一路往上追:
; Attributes: bp-based frame

void __cdecl -[LicenseManager showTrailEnd](LicenseManager *self, SEL)
__LicenseManager_showTrailEnd_ proc near
push    rbp
mov     rbp, rsp
push    r15
push    r14
push    r13
push    r12
push    rbx
push    rax
mov     rdi, cs:classRef_NSAlert ; id
mov     rsi, cs:selRef_new ; SEL
mov     r12, cs:_objc_msgSend_ptr
call    r12 ; _objc_msgSend
mov     r14, rax
mov     rsi, cs:selRef_setMessageText_ ; SEL
lea     rdx, cfstr_Error_1 ; "Error"
mov     rdi, rax        ; id
call    r12 ; _objc_msgSend
mov     rdi, cs:classRef_I18nUtils ; id
mov     rsi, cs:selRef_getLocalizedPanelItem_ ; SEL
lea     rdx, cfstr_ThisBetaVersio ; "This beta version of Typora is expired, please download and install a newer version."
call    r12 ; _objc_msgSend ; +[I18nUtils getLocalizedPanelItem:]
mov     rdi, rax        ; id
call    _objc_retainAutoreleasedReturnValue
mov     rbx, rax
mov     rsi, cs:selRef_setInformativeText_ ; SEL
mov     rdi, r14        ; id
mov     rdx, rax
call    r12 ; _objc_msgSend
mov     r13, cs:_objc_release_ptr
mov     rdi, rbx        ; id
call    r13 ; _objc_release
mov     rdi, cs:classRef_NSRunningApplication ; id
mov     rsi, cs:selRef_currentApplication ; SEL
call    r12 ; _objc_msgSend
mov     rdi, rax        ; id
call    _objc_retainAutoreleasedReturnValue
mov     rbx, rax
mov     rsi, cs:selRef_activateWithOptions_ ; SEL
mov     edx, 2
mov     rdi, rax        ; id
call    r12 ; _objc_msgSend
mov     rdi, rbx        ; id
call    r13 ; _objc_release
mov     rsi, cs:selRef_runModal ; SEL
mov     rdi, r14        ; id
call    r12 ; _objc_msgSend
mov     rdi, cs:classRef_NSWorkspace ; id
mov     rsi, cs:selRef_sharedWorkspace ; SEL
call    r12 ; _objc_msgSend
mov     rdi, rax        ; id
call    _objc_retainAutoreleasedReturnValue
mov     r15, rax
mov     rdi, cs:classRef_NSURL ; id
mov     rsi, cs:selRef_URLWithString_ ; SEL
lea     rdx, cfstr_HttpsTyporaIoD ; "https://typora.io/#download"
call    r12 ; _objc_msgSend
mov     rdi, rax        ; id
call    _objc_retainAutoreleasedReturnValue
mov     rbx, rax
mov     rsi, cs:selRef_openURL_ ; SEL
mov     rdi, r15        ; id
mov     rdx, rax
call    r12 ; _objc_msgSend
mov     rdi, rbx        ; id
call    r13 ; _objc_release
mov     rdi, r15        ; id
call    r13 ; _objc_release
mov     rdi, cs:classRef_NSApplication ; id
mov     rsi, cs:selRef_sharedApplication ; SEL
call    r12 ; _objc_msgSend
mov     rdi, rax        ; id
call    _objc_retainAutoreleasedReturnValue
mov     rbx, rax
mov     rsi, cs:selRef_terminate_ ; SEL
mov     rdi, rax        ; id
xor     edx, edx
call    r12 ; _objc_msgSend
mov     rdi, rbx        ; id
call    r13 ; _objc_release
mov     rdi, r14
mov     rax, r13
add     rsp, 8
pop     rbx
pop     r12
pop     r13
pop     r14
pop     r15
pop     rbp
jmp     rax
__LicenseManager_showTrailEnd_ endp
F5看一下伪C代码。
void __cdecl -[LicenseManager showTrailEnd](LicenseManager *self, SEL a2)
{
  NSAlert *v2; // r14
  id v3; // rax
  id v4; // rbx
  id v5; // rax
  id v6; // rbx
  id v7; // rax
  id v8; // r15
  NSURL *v9; // rax
  NSURL *v10; // rbx
  id v11; // rax
  id v12; // rbx

  v2 = objc_msgSend(&OBJC_CLASS___NSAlert, "new");
  objc_msgSend(v2, "setMessageText:", CFSTR("Error"));
  v3 = +[I18nUtils getLocalizedPanelItem:](
         &OBJC_CLASS___I18nUtils,
         "getLocalizedPanelItem:",
         CFSTR("This beta version of Typora is expired, please download and install a newer version."));
  v4 = objc_retainAutoreleasedReturnValue(v3);
  objc_msgSend(v2, "setInformativeText:", v4);
  objc_release(v4);
  v5 = objc_msgSend(&OBJC_CLASS___NSRunningApplication, "currentApplication");
  v6 = objc_retainAutoreleasedReturnValue(v5);
  objc_msgSend(v6, "activateWithOptions:"2LL);
  objc_release(v6);
  objc_msgSend(v2, "runModal");
  v7 = objc_msgSend(&OBJC_CLASS___NSWorkspace, "sharedWorkspace");
  v8 = objc_retainAutoreleasedReturnValue(v7);
  v9 = objc_msgSend(&OBJC_CLASS___NSURL, "URLWithString:", CFSTR("https://typora.io/#download"));
  v10 = objc_retainAutoreleasedReturnValue(v9);
  objc_msgSend(v8, "openURL:", v10);
  objc_release(v10);
  objc_release(v8);
  v11 = objc_msgSend(&OBJC_CLASS___NSApplication, "sharedApplication");
  v12 = objc_retainAutoreleasedReturnValue(v11);
  objc_msgSend(v12, "terminate:"0LL);
  objc_release(v12);
  objc_release(v2);
}

主要是以下这几个对象和函数:

  NSAlert

NSAlert 类的方法允许指定警报级别、警报文本、按钮标题和自定义图标(如果需要)。该类还允许警报显示帮助按钮,并为应用提供特定于警报的帮助的方法。

NSRunningApplication

一个对象,可以操作应用的单个实例并为其提供信息。应用的某些属性是固定的,例如捆绑标识符。其他属性可能会随时间而变化,例如应用是否处于隐藏状态。可以通过键值观察来观察不同的属性,在这种情况下,方法的说明注释会记录此功能。

currentApplication

返回表示此应用程序的函数 NSRunningApplication

activateWithOptions

尝试使用指定的选项激活应用程序。

NSApplicationActivateAllWindows = 1 << 0

runModal

将NSAlert作为应用模式对话框运行,并返回标识单击的按钮的常量。

sharedWorkspace 共享工作区

共享工作区对象。

objc_release

如果 value 为 null,则此调用不起作用。否则,它将执行释放操作,就像对象已发送消息 release 一样。

NSURL

表示资源位置的对象,例如远程服务器上的项或本地文件的路径。

URLWithString

创建并返回使用提供的 URL 字符串初始化的 NSURL 对象。

objc_retainAutoreleasedReturnValue

objc_retainAutoreleasedReturnValue  概念是,如果要从自动释放的函数返回一个值,但接下来要做的是对该对象进行保留,那么执行自动释放和保留是绝对没有意义的——我们只是在浪费周期。因此,如果我们能以某种方式确定我们将要保留,那么我们可以节省几个 CPU 周期。在运行应用程序的过程中,这可能会节省大量时间和精力。

如果调用方的指令立即调用objc_retainAutoreleasedReturnValue,则被调用方将省略objc_autoreleaseReturnValue,并将结果保存在线程本地存储中。如果调用方看起来不合作,则被调用方会像往常一样调用 objc_autoreleaseReturnValue。

setInformativeText

设置面板中显示的(可选)信息文本。

objc_msgSend

将具有简单返回值的消息发送到类的实例。

demo:

// in implementation file
- (void)errorPopUp:(NSString *)reason detail:(NSString *)detail {
        NSAlert *alert = [[NSAlert alloc] init];
        [alert setMessageText:reason];
        [alert setInformativeText:detail];
        [alert setAlertStyle:NSCriticalAlertStyle]; // or NSWarningAlertStyle, or NSInformationalAlertStyle
        [alert addButtonWithTitle:@"OK"];

        [alert runModal];
}

根据上面的分析,基本上可以确定这个函数的功能是:

弹窗This beta version of Typora is expired, please download and install a newer version.,并生成确定按钮,点击按钮后,打开urlhttps://typora.io/#download,最后执行terminate关闭程序。

那么修复的方法就比较简单了,直接把objc_msgSend(v12, "terminate:", 0LL);给nop掉就可以让程序弹窗后不再关闭。也可以将showTrailEnd这个函数nop掉,也就不会弹窗了。

上面的方法比较粗暴,还是想要知道为什么会导致过期,可以继续往上分析。

void __cdecl -[LicenseManager validateBetaTrailEnd](LicenseManager *self, SEL a2)
{
  double v2; // xmm0_8
  Setting *v3; // rax
  Setting *v4; // rbx
  id v5; // rax
  id v6; // r12
  id v7; // rax
  id v8; // rbx
  id v9; // r13
  id v10; // r13
  id v11; // rax
  id v12; // r15
  id v13; // rbx

  +[Setting passedSinceBuild](&OBJC_CLASS___Setting, "passedSinceBuild");
  v3 = +[Setting sharedInstance](&OBJC_CLASS___Setting, "sharedInstance");
  v4 = objc_retainAutoreleasedReturnValue(v3);
  v5 = -[Setting get:](v4, "get:", CFSTR("verInitTime"));
  v6 = objc_retainAutoreleasedReturnValue(v5);
  objc_release(v4);
  if ( v6 )
  {
    v7 = objc_msgSend(&OBJC_CLASS___NSDate, "date");
    v8 = objc_retainAutoreleasedReturnValue(v7);
    v9 = objc_msgSend(v8, "compare:", v6);
    objc_release(v8);
    if ( v9 != (id)-1LL )
    {
      v10 = objc_alloc(&OBJC_CLASS___NSDateInterval);
      v11 = objc_msgSend(&OBJC_CLASS___NSDate, "date");
      v12 = objc_retainAutoreleasedReturnValue(v11);
      v13 = objc_msgSend(v10, "initWithStartDate:endDate:", v6, v12);
      objc_msgSend(v13, "duration");
      objc_release(v13);
      objc_release(v12);
      if ( (int)v2 >= 17280001 )
        -[LicenseManager showTrailEnd](self, "showTrailEnd");
    }
  }
  objc_release(v6);
}

这个函数主要的功能是获取verInitTime属性,和现有date计算时间差,然后和17280001进行对比17280001/(3600*24)=200天。那么猜测verInitTime应该就是初次使用时生成的属性,运行超过200天之后就会弹窗。

接下来需要找到verInitTime这个属性保存的位置,从这个位置往上追引用一直没找到。后来换个思路,既然首次运行的时候会生成该文件,那么从main函数开始往下找应该也能找到。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  os_log_s *v3; // rbx
  Setting *v4; // rax
  os_log_s *v5; // rbx
  id v6; // rax
  os_log_s *v7; // rbx
  id v8; // rax
  __int16 buf[8]; // [rsp+0h] [rbp-50h] BYREF
  __int16 v11[8]; // [rsp+10h] [rbp-40h] BYREF
  __int16 v12[24]; // [rsp+20h] [rbp-30h] BYREF

  v3 = os_log_create("abnerworks.typora.plist""userOp");
  if ( os_log_type_enabled(v3, OS_LOG_TYPE_INFO) )
  {
    buf[0] = 0;
    _os_log_impl((void *)&_mh_execute_header, v3, OS_LOG_TYPE_INFO, "----Typora Start----", (uint8_t *)buf, 2u);
  }
  objc_release(v3);
  v4 = +[Setting sharedInstance](&OBJC_CLASS___Setting, "sharedInstance");
  objc_unsafeClaimAutoreleasedReturnValue(v4);
  if ( !NSClassFromString(CFSTR("NSTouchBar")) )
  {
    v5 = os_log_create("abnerworks.typora.plist""userOp");
    if ( os_log_type_enabled(v5, OS_LOG_TYPE_INFO) )
    {
      v11[0] = 0;
      _os_log_impl((void *)&_mh_execute_header, v5, OS_LOG_TYPE_INFO, "use mock NSTouchBar", (uint8_t *)v11, 2u);
    }
    objc_release(v5);
    v6 = objc_msgSend(&OBJC_CLASS___MockNSTouchBar, "class");
    objc_msgSend(&OBJC_CLASS___NSKeyedUnarchiver, "setClass:forClassName:", v6, CFSTR("NSTouchBar"));
  }

全盘搜该文件,找到对应路径/Users/xxxx/Library/Preferences/abnerworks.Typora.plist

Typora LicenseManager过期分析

打开后果然有verInitTime这个属性,那么把这个时间调到100年后就可以了。


免责声明:
本文所提供的信息仅为了解技术原理和安全风险,仅供学习目的,旨在提供有关旧版本软件破解的信息和知识分享。请注意,破解软件可能涉及侵犯版权和法律法规,可能导致严重的法律后果。任何人在使用本文中提供的信息时应自行承担风险和法律责任。本公众号和作者不鼓励、支持或提供任何形式的软件破解行为。

原文始发于微信公众号(山石网科安全技术研究院):Typora LicenseManager过期分析

版权声明:admin 发表于 2024年4月22日 上午11:32。
转载请注明:Typora LicenseManager过期分析 | CTF导航

相关文章