换到OSX快两个月了,装了个Hopper,回忆起N年前破解某游戏的美好时光,不禁手痒难耐,忍不住拿了某常用Android模拟器试刀。在Windows下已经有人用各种手法干掉了它,OSX上估计还算首次吧。
该模拟器未注册时付费功能按钮是锁定的,且左下角有一个难看的水印。该app是用QT开发的,方便跨平台,也方便借鉴前人的思路。
解锁按钮
首先依然是找字符串,按钮锁定无非是enable之类的函数,丢进去看看:
发现有个函数很可疑:
sub_1000ce0b0: 00000001000ce0b0 push rbp ; XREF=sub_1000ce0a0+5 00000001000ce0b1 mov rbp, rsp 00000001000ce0b4 push r14 00000001000ce0b6 push rbx 00000001000ce0b7 sub rsp, 0x30 00000001000ce0bb mov r14, rdx 00000001000ce0be mov rbx, rdi 00000001000ce0c1 mov edx, ecx ; argument #3 for method sub_1000d0900 00000001000ce0c3 call sub_1000d0900 00000001000ce0c8 lea rax, qword [ds:0x10080b9c0] 00000001000ce0cf lea rcx, qword [ds:rax+0x10] 00000001000ce0d3 mov qword [ds:rbx], rcx 00000001000ce0d6 add rax, 0x1d8 00000001000ce0dc mov qword [ds:rbx+0x10], rax 00000001000ce0e0 mov qword [ds:rbx+0x50], r14 00000001000ce0e4 mov esi, 0x1 00000001000ce0e9 mov rdi, rbx 00000001000ce0ec call imp___stubs___ZN15QAbstractButton12setCheckableEb ; QAbstractButton::setCheckable(bool) 00000001000ce0f1 xor esi, esi 00000001000ce0f3 mov rdi, rbx 00000001000ce0f6 call imp___stubs___ZN15QAbstractButton10setCheckedEb ; QAbstractButton::setChecked(bool) 00000001000ce0fb lea rdx, qword [ds:0x10077c5ce] ; "2activationChanged(bool)" 00000001000ce102 lea r8, qword [ds:0x10077c5e7] ; "1widgetActivationChanged(bool)" 00000001000ce109 lea rdi, qword [ss:rbp+var_18] 00000001000ce10d xor r9d, r9d 00000001000ce110 mov rsi, r14 00000001000ce113 mov rcx, rbx 00000001000ce116 call imp___stubs___ZN7QObject7connectEPKS_PKcS1_S3_N2Qt14ConnectionTypeE ; QObject::connect(QObject const*, char const*, QObject const*, char const*, Qt::ConnectionType) 00000001000ce11b lea rdi, qword [ss:rbp+var_18] 00000001000ce11f call imp___stubs___ZN11QMetaObject10ConnectionD1Ev ; QMetaObject::Connection::~Connection() 00000001000ce124 xor esi, esi ; argument #2 for method sub_1000ce240 00000001000ce126 mov rdi, rbx ; argument #1 for method sub_1000ce240 00000001000ce129 call sub_1000ce240 00000001000ce12e lea rdx, qword [ds:0x10077c454] ; "2toggled(bool)" 00000001000ce135 lea r8, qword [ds:0x10077c606] ; "1buttonToggled(bool)" 00000001000ce13c lea rdi, qword [ss:rbp+var_20] 00000001000ce140 xor r9d, r9d 00000001000ce143 mov rsi, rbx 00000001000ce146 mov rcx, rbx 00000001000ce149 call imp___stubs___ZN7QObject7connectEPKS_PKcS1_S3_N2Qt14ConnectionTypeE ; QObject::connect(QObject const*, char const*, QObject const*, char const*, Qt::ConnectionType) 00000001000ce14e lea rdi, qword [ss:rbp+var_20] 00000001000ce152 call imp___stubs___ZN11QMetaObject10ConnectionD1Ev ; QMetaObject::Connection::~Connection() 00000001000ce157 mov rcx, qword [ds:rbx+0x50] 00000001000ce15b lea rdx, qword [ds:0x10077c61b] ; "2buttonEnabled(bool)" 00000001000ce162 lea r8, qword [ds:0x10077c630] ; "1setEnabled(bool)"
这家伙在调用setEnable,八成不是好事。看看谁在调它:
跳转到这个函数:
================ B E G I N N I N G O F P R O C E D U R E ================ sub_1000ce0a0: 00000001000ce0a0 push rbp ; XREF=sub_1000d4e80+494, sub_1000d4e80+785, sub_1000d4e80+1103, sub_1000d4e80+1427, sub_1000d4e80+1751, sub_1000d4e80+2075, sub_1000d4e80+2399, sub_1000d4e80+2723 00000001000ce0a1 mov rbp, rsp 00000001000ce0a4 pop rbp 00000001000ce0a5 jmp sub_1000ce0b0 ; endp 00000001000ce0aa nop word [ds:rax+rax]
发现好多地方都在调它:
看看它们都传了些什么参数,拿第一个举个例子:
00000001000d5030 lea rdi, qword [ds:0x10077ca8f] ; "battery" 00000001000d5037 mov esi, 0x7 00000001000d503c call imp___stubs___ZN7QString16fromAscii_helperEPKci ; QString::fromAscii_helper(char const*, int) 00000001000d5041 mov qword [ss:rbp+0xffffffffffffff98], rax 00000001000d5045 mov edi, 0xb8 00000001000d504a call imp___stubs___Znwm ; operator new(unsigned long) 00000001000d504f mov rbx, rax 00000001000d5052 xor edx, edx 00000001000d5054 mov rdi, rbx 00000001000d5057 mov rsi, r15 00000001000d505a call sub_1000e93d0 00000001000d505f lea rsi, qword [ss:rbp+0xffffffffffffff98] 00000001000d5063 mov ecx, 0x3 00000001000d5068 mov rdi, r12 00000001000d506b mov rdx, rbx 00000001000d506e call sub_1000ce0a0
似乎是针对电池按钮的,这个参数很可疑:
00000001000d5063 mov ecx, 0x3
改为0试试:
00000001000d5063 mov ecx, 0x0
保存为executable,发现按钮果然解锁了。于是对剩下所有的调用,都将参数改为0,就能解锁这些功能了。
不过pixelperfect按钮还是灰的,查找这个String,又发现一个调用:
00000001000d2253 lea rsi, qword [ss:rbp+0xffffffffffffff60] ; argument #2 for method sub_1000cf9d0 00000001000d225a mov edx, 0x2 00000001000d225f mov rdi, rbx ; argument #1 for method sub_1000cf9d0 00000001000d2262 call sub_1000cf9d0
改为
00000001000d225a mov edx, 0x0
就行了,至此全部功能都被强制激活了。
去水印
不过美中不足的是,左下角还残留着一行水印:
free for personal use
直接搜索这个字符串找不到任何线索,变换思维,搜索watermark,找到一个字符串id:
倒是没看到对应的字符值,可能跟QT的国际化有关吧。
不过我找不到原文完全没关系,让它也找不到就行了。直接将这个id的第一个字符修改为0:
这样水印对应的id就变成了空白字符串,谁也找不到原文,所以就不会显示水印了。
至此完美拿下所有功能。
心得
-
逆向玩得是耐心,前面踩点很枯燥,一旦找到突破口后面就很无趣了。
-
在软件开发中用明文字符串简直是作死。
http://origami.design
https://github.com/ilovebamboo/AngulrHtml/issues/1
您好,我在网上找了好多关于macos的逆向 都没有找到能查到这个文字到方法。麻烦您能不能看看这个红框文字哪里到。我hopper hex修改都没有效果
关注。博主目前在哪里
美国