关于
Transmit 是一种功能强大的FTP/SFTP/WebDAV客户端软件,是一个Mac OS X平台上设计的文件传输软件。
它由Panic(一家以软件工具为主的公司)开发和维护,是一款非常受欢迎且易于使用的软件,而且被广泛认为是Mac OS X平台上最好的文件传输客户端之一。
今天我们来基于 dylib 注入来搞一下。
环境/软件
- MacOS arm/x8
- IDA/Hopper
- xcode
分析
进入程序后, 右上角有使用弹框; >>>> 还剩 x 天。立即购买!

全局搜索扫描目录, 发现是 PanicAppKit 程序下的引用的字符串
复制代码 隐藏代码
/Applications/Transmit.app/Contents/Frameworks/PanicAppKit.framework/Versions/A/PanicAppKit
// PCTitleBarTrialView
"Expired. Buy now! " = "已过期。立即购买! ";
"1 day left. Buy now! " = "还剩 1 天。立即购买! ";
"%lu days left. Buy now! " = "还剩 %lu 天。立即购买! ";
__cfstring:00000000000D6598 dq offset aLuDaysLeftBuyN ; "%lu days left. Buy now! "
__cstring:00000000000B2205 aLuDaysLeftBuyN db '%lu days left. Buy now! ',0
但是查看不到有具体的方法引用, 这个时候偶然看到有一个注释 “PCTitleBarTrialView”, 猜测这几个字断都是该类下的;
可以看到 PanicAppKit 中 export 导出了 “PCTitleBarTrialView” , 并且主程序中也 import 导入了该类
在主程序中搜索 “PCTitleBarTrialView”, 并且查看引用, 追踪到了这个函数 -[TRDocument updateCountdownView]
复制代码 隐藏代码
__text:00000001000DDED8 loc_1000DDED8:
__text:00000001000DDED8
__text:00000001000DDED8 mov r13, cs:selRef_trialTitleBarViewController
__text:00000001000DDEDF mov rdi, rbx
__text:00000001000DDEE2 mov rsi, r13
__text:00000001000DDEE5 call cs:_objc_msgSend_ptr
__text:00000001000DDEEB mov rdi, rax
__text:00000001000DDEEE call _objc_retainAutoreleasedReturnValue
__text:00000001000DDEF3 mov r12, rax
__text:00000001000DDEF6 mov rdi, rax
__text:00000001000DDEF9 call cs:_objc_release_ptr
__text:00000001000DDEFF test r12, r12
__text:00000001000DDF02 jnz loc_1000DE072
__text:00000001000DDF08 mov rdi, cs:classRef_PCTitleBarTrialViewController
查看假码, 这里可以清晰的看到通过 TRTrialStatus 函数获取试用的剩余天数,之后调用 PCTitleBarTrialView 来显示;
复制代码 隐藏代码
void __cdecl -[TRDocument updateCountdownView](TRDocument *self, SEL a2)
{
unsigned int v3; // r15d
int v4; // eax
id v5; // rax
id v6; // r12
id v7; // rax
id v8; // r12
id v9; // rax
id v10; // r12
id v11; // rax
id v12; // r13
id v13; // rax
id v14; // rax
id v15; // r13
id v16; // rax
id v17; // r13
id v18; // rax
id v19; // r15
void *v20; // rdi
id v21; // rax
id v22; // rbx
id v23; // rax
id v24; // r15
id v25; // rax
id v26; // r14
id v27; // [rsp+0h] [rbp-30h]
v3 = 0;
v4 = TRTrialStatus(self, a2);
if ( v4 == -5 || v4 == -1 || v4 != 9999 && (v3 = v4, v4 > 0) )
{
v5 = objc_msgSend(self, "trialTitleBarViewController");
v6 = objc_retainAutoreleasedReturnValue(v5);
objc_release(v6);
if ( !v6 )
{
v7 = objc_alloc(&OBJC_CLASS___PCTitleBarTrialViewController);
v8 = objc_msgSend(v7, "initWithTrialDaysLeft:", v3);
objc_msgSend(self, "setTrialTitleBarViewController:", v8);
objc_release(v8);
v9 = objc_msgSend(self, "trialTitleBarViewController");
v10 = objc_retainAutoreleasedReturnValue(v9);
objc_msgSend(v10, "setWarningThreshold:", 5LL);
objc_release(v10);
v11 = objc_msgSend(self, "trialTitleBarViewController");
v12 = objc_retainAutoreleasedReturnValue(v11);
v13 = objc_msgSend(v12, "view");
v27 = objc_retainAutoreleasedReturnValue(v13);
objc_release(v12);
v14 = objc_msgSend(NSApp, "delegate");
v15 = objc_retainAutoreleasedReturnValue(v14);
objc_msgSend(v27, "setTarget:", v15);
objc_release(v15);
objc_msgSend(v27, "setAction:", "showRegistrationWindow:");
v16 = objc_msgSend(self, "window");
v17 = objc_retainAutoreleasedReturnValue(v16);
v18 = objc_msgSend(self, "trialTitleBarViewController");
LODWORD(v10) = v3;
v19 = objc_retainAutoreleasedReturnValue(v18);
objc_msgSend(v17, "addTitlebarAccessoryViewController:", v19);
v20 = v19;
v3 = (unsigned int)v10;
objc_release(v20);
objc_release(v17);
objc_release(v27);
}
v21 = objc_msgSend(self, "trialTitleBarViewController");
v22 = objc_retainAutoreleasedReturnValue(v21);
objc_msgSend(v22, "setDaysLeft:", v3);
objc_release(v22);
}
else
{
v23 = objc_msgSend(self, "trialTitleBarViewController");
v24 = objc_retainAutoreleasedReturnValue(v23);
objc_release(v24);
if ( v24 )
{
v25 = objc_msgSend(self, "trialTitleBarViewController");
v26 = objc_retainAutoreleasedReturnValue(v25);
objc_msgSend(v26, "removeFromParentViewController");
objc_release(v26);
objc_msgSend(self, "setTrialTitleBarViewController:", 0LL);
}
}
}
__text:00000001000DDEB3 call _TRTrialStatus
__text:00000001000DDEB8 cmp eax, 0FFFFFFFBh
__text:00000001000DDEBB jz short loc_1000DDED8
这块有一个判断 如果 天数为 9999, 则不会执行, 我么通过修改 eax , 即 函数 TRTrialStatus 返回值来验证下