没有注入补丁。因为Paste只有一个主程序文件,不方便注入。
本来这个帖子是有剧情的,但是情感失利,妹子常规好感度完美开局48小时内打成残血副本:
油腻男的聊天风格直接触发妹子的无视微信消息大招,绷不住了,绝望下编写此帖,实在没心情创作了😭😭😭😭😭
现在是半夜00:44还在emo😭😭😭😭😭😭😭😭😭😭
0x01 寻找入口点与分析
放错图了。这里应该是未激活的状态,差不多意思意思吧这样子。
因为楼主买不起苹果电脑手机平板,所以只能幻想自己左苹果右华为胸口纹嘉然脑门贴nanami的雄姿。
老样子搜索字符串,这次用Sublime Text。
根据上图的内容,我们尝试搜索“立即开始免费试用”:
这里"licensing.paywall.title"我们到ida搜索一下:
按下x看一下xref引用看看函数细节:
这里函数又被两个地方调用,我们直接用lldb看一下函数调用堆栈.我们记下这个函数地址方便后面下断点.
加载后我们先输入c让他继续运行。
然后我们给内存地址:0x1002253E0下断点: br s -a 1002253E0
随后输入r重启app,可以看到直接被断下了:
那么我们往上查堆栈看是谁触发这个Call:
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
frame #0: 0x00000001002253e0 Paste`___lldb_unnamed_symbol16296
Paste`___lldb_unnamed_symbol16296:
-> 0x1002253e0 <+0>: push rbp
0x1002253e1 <+1>: mov rbp, rsp
0x1002253e4 <+4>: lea rax, [rip + 0x167715] ; "licensing.paywall.title"
0x1002253eb <+11>: movabs rsi, -0x8000000000000000
Target 0: (Paste) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
* frame #0: 0x00000001002253e0 Paste`___lldb_unnamed_symbol16296
frame #1: 0x00007ff817b19033 libdispatch.dylib`_dispatch_client_callout + 8
frame #2: 0x00007ff817b1a267 libdispatch.dylib`_dispatch_once_callout + 20
frame #3: 0x000000010022544a Paste`___lldb_unnamed_symbol16297 + 42
frame #4: 0x00000001001f8045 Paste`___lldb_unnamed_symbol14918 + 293
frame #5: 0x00000001001f8905 Paste`___lldb_unnamed_symbol14923 + 37
frame #138: 0x00000001002489e6 Paste`___lldb_unnamed_symbol17865 + 86
frame #139: 0x0000000100248800 Paste`___lldb_unnamed_symbol17861 + 16
frame #140: 0x0000000100247a8e Paste`___lldb_unnamed_symbol17812 + 302
frame #141: 0x000000010006127a Paste`___lldb_unnamed_symbol5177 + 778
frame #142: 0x0000000100066423 Paste`___lldb_unnamed_symbol5291 + 195
frame #143: 0x0000000100068970 Paste`___lldb_unnamed_symbol5356
frame #144: 0x0000000100067870 Paste`___lldb_unnamed_symbol5313
frame #145: 0x0000000100068930 Paste`___lldb_unnamed_symbol5354
那么我们重点关注栈3-5-138-145,因为下面都是系统库,所以我们直接看#3看看有没有发现:
void *sub_100225420()
{
if ( qword_100466E50 != -1 )
swift_once(&qword_100466E50, sub_1002253E0);
return &unk_10046CF50;
}
qword_100466E50必然不是-1,所以这里没有可检查的必要,我们继续回溯到#142: 0x0000000100066423:
__int64 __fastcall sub_100066360()
{
__int64 v0; // r13
__int64 *v1; // r14
__int64 v2; // r15
__int64 v3; // r12
__int64 v4; // rax
__int64 v5; // r14
__int64 v6; // rbx
void *v7; // r14
__int64 v8; // rdi
__int64 v9; // r13
__int64 v10; // rbx
__int64 v11; // r15
v2 = *v1;
v3 = *v1;
swift_task_dealloc(*(_QWORD *)(*v1 + 48));
if ( v0 )
swift_errorRelease(v0);
v4 = *(_QWORD *)(v2 + 24);
v5 = *(_QWORD *)(v4 + 80);
v6 = *(_QWORD *)(v4 + 88);
sub_10000B980(v4 + 56, v5);
if ( ((*(__int64 (__fastcall **)(__int64, __int64))(v6 + 8))(v5, v6) & 1) != 0 )
{
if ( *(_BYTE *)(v2 + 56) == 1 )
{
(*(void (**)(void))(v2 + 32))();
}
else if ( (sub_100068390() & 1) != 0 )
{
sub_100066460();
}
}
else
{
v7 = *(void **)(v2 + 40);
v8 = *(_QWORD *)(v2 + 24);
v9 = *(_QWORD *)(v2 + 32);
v10 = *(_QWORD *)(v8 + 280);
v11 = *(_QWORD *)sub_10000B980(v8 + 144, *(_QWORD *)(v8 + 168));
swift_retain(v10);
sub_100060F70(v11, v9, v7, v10);
swift_release(v10);
}
return (*(__int64 (**)(void))(v3 + 8))();
}
可以看到这里(v6 + 8)这个指针所在的地址函数如果等于0 就执行到了我们的#142堆栈。
else
{
v7 = *(void **)(v2 + 40);
v8 = *(_QWORD *)(v2 + 24);
v9 = *(_QWORD *)(v2 + 32);
v10 = *(_QWORD *)(v8 + 280);
v11 = *(_QWORD *)sub_10000B980(v8 + 144, *(_QWORD *)(v8 + 168));
swift_retain(v10);
sub_100060F70(v11, v9, v7, v10);
swift_release(v10);
}
所以我们的工作重点放在这里这个判断上,在lldb中给这个地址下断点:
__text:00000001000663A8 loc_1000663A8: ; CODE XREF: sub_100066360+3E↑j
__text:00000001000663A8 mov rax, [r15+18h]
__text:00000001000663AC lea rdi, [rax+38h]
__text:00000001000663B0 mov r14, [rax+50h]
__text:00000001000663B4 mov rbx, [rax+58h]
__text:00000001000663B8 mov rsi, r14
__text:00000001000663BB call sub_10000B980
__text:00000001000663C0 mov r13, rax
__text:00000001000663C3 mov rdi, r14
__text:00000001000663C6 mov rsi, rbx
__text:00000001000663C9 call qword ptr [rbx+8] <-----这里下断点
__text:00000001000663CC test al, 1
__text:00000001000663CE jz short loc_1000663E1
lldb中输入br s -a 0x1000663c9,然后输入r重启,可以看到自动断下:
Process 28613 resuming
Process 28613 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1
frame #0: 0x00000001000663c9 Paste`___lldb_unnamed_symbol5291 + 105
Paste`___lldb_unnamed_symbol5291:
-> 0x1000663c9 <+105>: call qword ptr [rbx + 0x8]
0x1000663cc <+108>: test al, 0x1
0x1000663ce <+110>: je 0x1000663e1 ; <+129>
0x1000663d0 <+112>: cmp byte ptr [r15 + 0x38], 0x1
Target 0: (Paste) stopped.
(lldb)
我们来StepInto 这个Call:
我们IDA看一下这个地址所在的函数是干嘛的:
__int64 __fastcall sub_1001FBF10(__int64 a1, __int64 a2)
{
__int64 v2; // rax
__int64 v3; // r13
void *v4; // rsp
void *v5; // rsp
__int64 v6; // rdi
__int64 v7; // rax
unsigned int v8; // ebx
_QWORD v10[6]; // [rsp-8h] [rbp-30h] BYREF
v10[0] = v2;
sub_10000B6A0(&unk_100454320);
v4 = alloca(sub_10000C800(&unk_100454320, a2));
v5 = alloca(sub_10000C800(&unk_100454320, a2));
v6 = *(_QWORD *)(*(_QWORD *)v3 + 16LL);
swift_retain(v6);
_s7Combine19CurrentValueSubjectC5valuexvg();
swift_release(v6);
sub_1001FC3D0(v10, v10, &unk_100454320);
v7 = sub_1001F95A0(0LL);
v8 = (*(__int64 (__fastcall **)(_QWORD *, __int64, __int64))(*(_QWORD *)(v7 - 8) + 48LL))(v10, 1LL, v7);
if ( v8 != 1 )
sub_1001FC400(v10, &unk_100454320);
LOBYTE(v8) = v8 != 1;
sub_1001FC400(v10, &unk_100454320);
return v8;
}
可以看出v8返回值为0或者1,因为他有一个v8!=1的判断在这里,那么我们如果Hook 0x1001FBF10这个函数的返回值是否就ok了呢?
编写Frida代码进行内存注入:
import { HookApp, log } from "./Utils.js";
HookApp("Paste", (hook, point, method, baseAddr, tools) => {
// setTimeout(() => {
// hook(point(0x1f9f10), (ths, r) => {
// // r.replace(ptr(2));
// });
// }, 3000);
hook(point(0x1fbf10), (ths, r) => {
r.replace(ptr(1));
});
});
狠狠的按下F5启动,我们看看是否注入成功:
这里没有去修改有效订阅的那个函数,因为修改了这个信息之后会因为无法读取订阅数据而导致App崩溃,而且Paste只检查了0x1fbf10这个函数,所以我们直接返回1即可完成。
0x02 总结
文中使用的Frida js全文如下:
var appBaseAddr = Module.findBaseAddress("Paste");
var func = appBaseAddr.add(0x1fbf10)
Interceptor.attach(func, {
onEnter(this1, args) {
},
onLeave(retval) {
retval.replace(0x1)
},
})
安装python和Frida后,frida -p pid -l main.js启动注入。pid是进程列表中的进程id。