vlambda博客
学习文章列表

通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED

0. 预备

相关操作仅供学习,请勿用于非法操作,否则后果自负!

a. 硬件:MacBook或者安装macOS的虚拟机;


b. 最少软件:insert_dylib (直接跳转第5步下载编译好的静态库,然后通过第6步的注入进行操作);


c. 全文涉及软件:ida、insert_dylib、Sublime Text、otool、class-dump、svn


d. 版本号Sublime Text 3.2.1 Build 3207


1. 介绍


没有购买license的Sublime Text编辑器,在右上角会显示一个字符串“UNREGISTERED”,刚好最近在macOS复习一些逆向知识,准备练练手隐藏字符串“UNREGISTERED”。


2. 导出头文件

先用class-dump导出头文件:

class-dump -H "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text" -o ~/tmp/SublimeText_header

拖文件夹入Sublime Text,不多的几个文件:


3. 静态分析

没有找到isRegister/isBuy类似的简单方法,说明有比较复杂的防破解算法,应该要花好些功夫才能搞定。因为相应的字符显示在标题栏,先静态分析看看有没有处理标题栏相关的操作。


通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED


通过关键字符串“UNREGISTERED”找到处理的逻辑,前置算法确认v19的值,然后新建NSTextField控件v22,一并传入set_title_accessory_style方法,然后通过ns_title_bar_view获取到标题栏控件,再通过-(void)addSubview方法把新建v22做为子控件添加到标题栏上。


如此分析到这里就比较简单了,只需要编写一个tweak,通过类似ns_title_bar_view的算法找到标题栏控件,然后把其中字符值为“UNREGISTERED”的子控件移除即可。


分析ns_title_bar_view可知,标题栏是一个NSTitlebarView控件,它是NSTitlebarContainerView的子控件。

通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED


4. 编写tweak

xcode新建masOS平台的framework,为了hook Objective-C方法,我们还需要引入一个框架JRSwizzle,我们项目结构如下:


通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED


- (id)ns_title_bar_view:(NSWindow *)win { id res = nil; NSView *contenView = [win contentView]; NSArray *views = [[contenView superview] subviews];
Class titleBarClass = NSClassFromString(@"NSTitlebarContainerView"); for (id item in views) { if ([item isKindOfClass:titleBarClass]) { res = item; break;
} }
if (res) { NSArray *views = [res subviews]; for (id item in views) { if ([item isKindOfClass:NSClassFromString(@"NSTitlebarView")]) { res = item; break; } } }
return res;}

找到标题栏的算法如上,由于Sublime Text可以创建多窗口,所以我们不仅仅要实现启动的时候移除相关控件,新建了窗口我们也要对应移除一次,所以需要找一个经常被调用的OC方法,经过试验发现-[PXWindow update]被频繁调用,所以我们在此处进行移除相关控件的操作。

// - PXWindow- (void)m_st_update { // NSLog(@"SublimeText m_st_update"); [self m_st_update]; [self m_hidden_registerMarkView];}
- (void)m_hidden_registerMarkView { NSDictionary *mark = [[NSUserDefaults standardUserDefaults] objectForKey:@"removedMark"]; if (mark) { if ([[mark allKeys] containsObject:[self m_set_key]]) { return; } } NSArray *titleBars = [self ns_title_bar_views]; if (!titleBars) { return; } for (id item in titleBars) { [self m_hidden_registerMarkView:item]; }}

通过调用自定义的方法 -(void)m_hidden_registerMarkView 来移除对应的控件,由于是多窗口程序,我们自定义方法[self ns_title_bar_views]获取到的标题栏不止一个,然后再一一处理。


5. 构建tweak


没有相关工具链的同学可以准备好insert_dylib之后,下载我编译的hookSublimeText静态库文件(https://github.com/coleflowers/tweaks/releases/download/test/hookSublimeText)参考第6步进行注入操作。


想要自己探索一番的同学,通过以下命令下载我开源在github的源码,或者扫描下方的二维码浏览。

svn co https://github.com/coleflowers/tweaks/trunk/hookSublimeText

通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED


下载完的项目,使用xcode编译,然后复制出编译完的hookSublimeText.framework,使用insert_dylib导入Sublime Text的符号表,再次执行就会发现,Sublime Text窗口不再显示"UNREGISTERED"


6.注入


sudo /path/to/insert_dylib --all-yes "/path/to/hookSublimeText.framework/hookSublimeText" "/Applications/Sublime Text.app/Contents/MacOS/SublimeBk" "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text"

其中第一个SublimeBk为备份的Sublime Text原始可执行文件。

检查是否注入:

otool -L /path/to/Sublime\ Text

通过逆向的方法隐藏Sublime Text标题栏的UNREGISTERED

注入成功,重启检查无误。

之前:

之后: