作者论坛账号:QiuChenly
破解微软365之Excel:基于LLDB动态调试与Frida注入和静态补丁
序章:先睹为快
激活后的本地功能全部正常。
这里可以自由修改许可证类型,既然从AppStore下载了365版本的那就修改为365授权。
365赠送的云服务不生效,因为那是云端控制的,本地只能破解软件本体未解锁的功能。
有朋友可能不理解,明明网上到处有VL2019大客户授权激活文件为何还要手动破解,对此类问题我的评价是:By reason of i can do it, but u can't.
第一章 寻找蛛丝马迹
打开Excel我们可以看到是这个样子:
许可证未激活,菜单上有一个激活365的菜单,并且修改表格后提示需要订阅才可以保存和编辑。
如此吃相实在是大胆,在我泱泱天朝还有你洋鬼子软件的容身之地?
任何Microsoft Office终将绳之以法,喝嗳!Warwolf of China觉醒了,我们的鬼剑士已经二次觉醒甚至三次觉醒了!
老样子打开app文件搜索关键词“未激活”,看看有没有收获:
/Applications/Microsoft Excel.app/Contents/Resources/setupui_bundle.bundle/Contents/Resources/zh_CN.lproj/LocalizableGemini.strings
经历一番寻找竟然藏身于此,此子隐匿手段恐怖如斯,楼主当即便倒吸一口冷气!Excel见楼主霎时间便已查出他的下落,脸上闪过一丝慌张,嘴上却硬道:"即便是你找出我的下落,尔不过区区筑基期修为,老夫今日哪怕是法力尽失,却也是堂堂金丹期修为,尔若识趣速速滚开,否则待我法务团队跨国上门执法,必教你there is no place to die!"那Excel却是不知,楼主虽是筑基期修为,却有各种法宝屡次逃出生天一路灭神杀佛好不威风,听闻Excel仍敢言语威胁,当即便是冷笑一声:"前辈好大的威风,只是不知能否受得住我这IDA搜魂术?"
话毕也不等Excel反应过来,当即祭出IDA,授予Root权限绕过系统限制强行对Excel进行神识扫描:
楼主也不理会Excel的叫骂,操纵着IDA这法宝,打开String搜索"NoLicense",却愕然发现没有搜索到!
当即便祭出法宝终端,画出符咒:
此时Excel仍然存活于内存,所以利用法宝lldb直接进入Excel的元神。
光进入元神却也是无用,无法找到要害也无法抽丝剥茧破他的防御。
正苦思冥想间,忽然想起:
当即便回到Sublime搜索:
这下却是误打误撞寻到了漏洞,楼主大喜,取下"AboutPanel_LicenseType"时却发现来自依赖库:
跳转过去

再次查找引用发现来自此处:
第一件事便是找出内存函数偏移地址下断点!
当即lldb打开,寻找mso99内存模块基本地址:
附加上Excel后自动暂停,画出c恢复执行代码。
在恢复执行前却是顺便读取出excel模块的基址待用:
复制代码 隐藏代码 [ 22] 0x000000011012b000 /Applications/Microsoft Excel.app/Contents/Frameworks/mso20.framework/Versions/A/mso20
[ 23] 0x000000010f25d000 /Applications/Microsoft Excel.app/Contents/Frameworks/mso30.framework/Versions/A/mso30
[ 24] 0x0000000111bc5000 /Applications/Microsoft Excel.app/Contents/Frameworks/mso40ui.framework/Versions/A/mso40ui
[ 25] 0x000000011258d000 /Applications/Microsoft Excel.app/Contents/Frameworks/mso99.framework/Versions/A/mso99
0xC3E169,得出断点地址为
0x1131CB169
重启后内存模块基址会发生改变,需要重新获取。
那Excel冷笑道:"怕是你看完就要吓死了!"
楼主不理,点开
果然断下了:
楼主呵呵一笑,只见那指尖微动,却是令那lldb法宝查看此堆栈寻调用方:
_objc_msgSend(v8, "setLicenseType:", a2);
显然就是设置授权类型了,那么我们再往上找到a2传入参数的地方:复制代码 隐藏代码 frame #10: 0x00000001018b0b51 Microsoft Excel`___lldb_unnamed_symbol123578 + 89
这里的v2显然就是类型名称
复制代码 隐藏代码 void *sub_1010FA3A6()
{
return objc_msgSend(qword_1036063C0, "copyLicenseType");
}
搜索一下找到函数名称,objectc函数调用必须明文,所以很好搜索:
回到mso99搜这个函数:
v0 = (void *)sub_1777251();
楼主连忙进入此函数看细节:复制代码 隐藏代码 id sub_1777251()
{
void *v0; // rax
id v1; // rax
void ***v2; // rax
void *v3; // rbx
void *v4; // rax
id v5; // r14
if ( (unsigned __int8)sub_1762768() ) // Is2021
{
v0 = (void *)sub_17772D5();
v1 = objc_retainAutoreleasedReturnValue(v0);
}
else
{
if ( (unsigned __int8)sub_82C8C() ) // 默认走这里
v2 = off_22C17E0; // StatusStrings/SubscriptionLicense
else
v2 = off_22C1820; // StatusStrings/NoLicense
v1 = objc_retain(*v2);
}
v3 = v1;
v4 = (void *)sub_1771816(v1);
v5 = objc_retainAutoreleasedReturnValue(v4);
_objc_release(v3);
return objc_autoreleaseReturnValue(v5);
}
复制代码 隐藏代码 __int64 sub_82C8C()
{
return Mso::Licensing::Category::IsSubscription(0LL);
}
复制代码 隐藏代码 // attributes: thunk
__int64 __fastcall Mso::Licensing::Category::IsSubscription(__int64 a1)
{
return __imp___ZN3Mso9Licensing8Category14IsSubscriptionENSt3__18optionalINS1_15LicenseCategoryEEE(a1);
}
复制代码 隐藏代码 __stubs:00000000019D9BCE __ZN3Mso9Licensing8Category14IsSubscriptionENSt3__18optionalINS1_15LicenseCategoryEEE proc near
__stubs:00000000019D9BCE ; CODE XREF: sub_812E0+19↑j
__stubs:00000000019D9BCE ; sub_82C8C+7↑j ...
__stubs:00000000019D9BCE jmp cs:__ZN3Mso9Licensing8Category14IsSubscriptionENSt3__18optionalINS1_15LicenseCategoryEEE_ptr ; Mso::Licensing::Category::IsSubscription(std::__1::optional<Mso::Licensing::Category::LicenseCategory>)
__stubs:00000000019D9BCE __ZN3Mso9Licensing8Category14IsSubscriptionENSt3__18optionalINS1_15LicenseCategoryEEE endp
00000000019D9BCE + 基址0x000000010f0d7000 = 0x110AB0BCE
复制代码 隐藏代码 (lldb) br s -a 0x110AB0BCE
Breakpoint 3: where = mso99`symbol stub for: Mso::Licensing::Category::IsSubscription(std::__1::optional<Mso::Licensing::Category::LicenseCategory>), address = 0x0000000110ab0bce
(lldb)
复制代码 隐藏代码 [ 22] /Applications/Microsoft Excel.app/Contents/Frameworks/mso20.framework/Versions/A/mso20 0x0000000107e71000
[ 23] /Applications/Microsoft Excel.app/Contents/Frameworks/mso30.framework/Versions/A/mso30 0x0000000106fa3000
[ 24] /Applications/Microsoft Excel.app/Contents/Frameworks/mso40ui.framework/Versions/A/mso40ui 0x000000010990b000
[ 25] /Applications/Microsoft Excel.app/Contents/Frameworks/mso99.framework/Versions/A/mso99 0x000000010f0d7000
复制代码 隐藏代码 __int64 __usercall Mso::Licensing::Category::IsSubscription@<rax>(unsigned int a1@<edi>, __int64 a2@<rax>, unsigned int a3@<edx>)
{
__int64 v3; // rbx
unsigned int v4; // er14
__int64 v6; // [rsp+8h] [rbp-18h]
v3 = sub_81B76(a2, a3, sub_81C28);
v6 = v3;
v4 = sub_81BB8(v3, a1, &v6);
if ( v3 )
{
v6 = 0LL;
(*(*v3 + 16LL))(v3);
}
return v4;
}
js代码可以翻我的以前帖子,有完整的文件代码。这里只展示用法。
激活成功。
但是我高兴不起来,因为这只是修改了表面,实际上没有激活:
此时又闻那Excel冷笑道:"破了我的防御又如何?我这元神你敢动那便两败俱伤!看你有什么本事动我?"
楼主闻言恶声道:“兀那老怪!如今你为鱼肉我为刀俎,识相的就快快交出储物袋储物戒指,小👴好送你上轮回路!”
Excel只管冷笑不答,楼主怒从心起,既然如此,我们就搜索"需要订阅才可编辑和保存"
20B958 + 0x000000010f0d7000 = 0x10F2E2958
复制代码 隐藏代码 (lldb) br s -a 0x10F2E2958
Breakpoint 4: where = mso99`SetupUI_CreateLocalizedRFMMessageBarStrings + 830, address = 0x000000010f2e2958
(lldb)
随便输入几个字,激活他的那个未激活提示:
因为无法复现卡文8个多小时,实际上第一次分析完毕也不过才2个多小时就找到了破解点,有兴趣的同学自己参考上面的思路自己跟踪一下,测试环境是通过修改hook以下代码将其变成365订阅授权后lldb调试:
复制代码 隐藏代码 HookApp("mso30", (hook, getPointer, getClass, appBaseAddr, tools) => {
hook(getPointer(0x81b0f), (ths, ret) => {
ret.replace(ptr(1));
});
});
复制代码 隐藏代码 void __cdecl -[DocsUILicensing handleActivationStateChange:](DocsUILicensing *self, SEL a2, id a3)
{
void ***v3; // rax
id v4; // rbx
if ( _objc_msgSend(self, "isActivated", a3) )
{
v3 = off_20DFFC0;
}
else if ( _objc_msgSend(self, "canRenew") )
{
v3 = off_20DFFC8;
}
else
{
v3 = &off_20DFFD0;
}
v4 = objc_retain(*v3);
_objc_msgSend(&OBJC_CLASS___DocsUIBridgeNotifications, "sendNotification:object:", v4, self);
_objc_release(v4);
}
然后我们看到如果isActivated成立,那么v3 = off_20DFFC0,而off_20DFFC0是这个地址的引用:
0000000001A3AD3F aDocsuibridgesu db 'DocsUIBridgeSubscriptionActivatedNotification',0
SubscriptionActivatedNotification翻译过来就是订阅激活通知,下面那个canRenew就是续费,不用管,最下面一个else说的是NoActivated,也不用管。
所以我们重点就来到了"isActivated"函数:
复制代码 隐藏代码 char __cdecl -[DocsUILicensing isActivated](DocsUILicensing *self, SEL a2)
{
__int64 LicensingAPI; // rax
LicensingAPI = Mso::Licensing::GetLicensingAPI(self);
return (*(*LicensingAPI + 8LL))(LicensingAPI, 65421851LL);
}
那么我们在这个函数下断点:
在80047偏移处,我们在这个偏移处下断点:
80047 + mso99基址0x000000010f0d7000 = 0x10F157047
复制代码 隐藏代码 (lldb) register read rcx
rcx = 0x000000011131e918 mso99`typeinfo for Mso::FontPicker::FontTypes::BaseFont + 116040
(lldb)
我们跳过去看一下:
函数5076才是被藏起来的最终函数。
顾不得Excel那惊恐的眼神,根据之前的逻辑分析,我们编写如下Frida代码验证我们的猜想:
复制代码 隐藏代码 import { HookApp, log } from "./Utils.js";
HookApp("mso99", (hook, getPointer, getClass, appBaseAddr, tools) => {
hook(getPointer(0x5076), (ths, ret) => {
ret.replace(ptr(1));
});
hook(getPointer(0x20bf04), (ths, ret) => {
// ret.replace(ptr(2270));
});
});
HookApp("mso30", (hook, getPointer, getClass, appBaseAddr, tools) => {
hook(getPointer(0x81b0f), (ths, ret) => {
ret.replace(ptr(1));
});
});
第二章 编写Dylib静态注入App文件
复制代码 隐藏代码 /**
* Office 全家桶 MAS版本破解
* 16.71 365订阅
*/
void Office(void){
if(checkSelfInject("com.microsoft.Excel")){
if (checkAppVersion("16.71")){
int32_t mso30 = getImageVMAddrSlideIndex("mso30");
int32_t mso99 = getImageVMAddrSlideIndex("mso99");
hookPtr(mso99, 0x5076, checkSignal, NULL);//破解激活逻辑 让Office开放激活全部可用功能
hookPtr(mso30, 0x81b0f, checkSignal, NULL);//修改关于面板的授权版本为365授权
}
}
}
复制代码 隐藏代码 /**
* 给定一个字符串 检查是否存在于app的framework中并返回index
*/
uint32_t getImageVMAddrSlideIndex(char* ModuleName){
int32_t size = _dyld_image_count();
for (int i =0; i<size; i++) {
const char* Name = _dyld_get_image_name(i);
NSString *nName = [NSString stringWithCString:Name encoding:NSUTF8StringEncoding];
NSString *nModuleName = [NSString stringWithCString:ModuleName encoding:NSUTF8StringEncoding];
if([nName rangeOfString:nModuleName].location != NSNotFound){
NSLog(@"找到模块 %s 序号是 %i",ModuleName,i);
return i;
}
}
return 0;
}
复制代码 隐藏代码 int checkSignal(void) {
return 1;
}
终章
复制一份FluentUI文件,然后注入dylib进去体验365尊享版。
复制代码 隐藏代码 sudo insert_dylib /Users/qiuchenly/libInlineInjectPlugin.dylib /Applications/Microsoft Excel.app/Contents/Frameworks/FluentUI.framework/Versions/A/FluentUI的副本 /Applications/Microsoft Excel.app/Contents/Frameworks/FluentUI.framework/Versions/A/FluentUI
Office Word/PowerPoint/Excel都是这两个文件 偏移都一样 这个hook可以通杀16.71版本的三个App全家桶
-官方论坛
www.52pojie.cn
--推荐给朋友
公众微信号:吾爱破解论坛
或搜微信号:pojie_52
原文始发于微信公众号(吾爱破解论坛):【MacOS逆向】破解微软365之Excel:基于LLDB动态调试与Frida注入和静态补丁
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论