【Mac】Hopper Disassembler系列之Sublime Text3 爆破
本帖最后由 云在天 于 2018-9-7 01:28 编辑# Hopper Disassembler系列之Sublime Text 3 爆破
>吾爱破解论坛首发
>作者:云在天(Harry)
>未经许可,请勿转载
## 写在前面
看到PYG有大佬在出关于Hopper 的系列视频教程,之前我也有这种想法,苦于没有找到很合适的软件去出。前几天看到有人去改Sublime Text,电脑上的这个也已经提示很久要更新,所以天时地利人和出一期这软件的爆破,并不是大佬,轻喷。
另,这个系列会不定时更新,因为刚开学,比较忙,这篇还是趁着上午没课写的。
## 0X1
知己知彼,百战不殆。想要破解就要找到关键点就分析,这个软件是基于注册码注册的,那我们就随意输入后看他提示什么
如上图,提示license不可用,有了这个字符串,我们就可以从Hopper里搜索关键字【license】
## 0X2
具体步骤:
1. 打开Hopper
2. 打开软件的目录,找到MacOS下的Sublime Text
3. 直接拖到Hopper的右侧窗口
4. 等待反编译完成
5. 完成后在左侧Search输入框中输入license,点击Strings这个标签,找到刚才提示的字符串
6. 双击这个字符串,观察右侧窗口,如下图
````
000000010063498c db "Hello! Thanks for trying out Sublime Text.\n\nThis is an unregistered evaluation version, and although the trial is untimed, a license must be purchased for continued use.\n\nWould you like to purchase a license now?", 0 ; DATA XREF=__ZL13show_reminderPv+10
0000000100634a61 db "Purchase", 0 ; DATA XREF=__ZL13show_reminderPv+17
0000000100634a6a db "Enter your license key below. You can purchase one from https://www.sublimetext.com/buy", 0 ; DATA XREF=__Z19show_license_windowP24text_control_environmentP21secondary_window_listP14window_factoryP12license_infoRKNSt3__18functionIFvvEEE+254
0000000100634ac2 db "Use License", 0 ; DATA XREF=__Z19show_license_windowP24text_control_environmentP21secondary_window_listP14window_factoryP12license_infoRKNSt3__18functionIFvvEEE+476
0000000100634ace db "That license key has been invalidated, due to being shared.\n\nPlease email sales@sublimetext.com to get your license key reissued.", 0 ; DATA XREF=__ZL11show_sharedPv+4
0000000100634b50 db "That license key is no longer valid.", 0 ; DATA XREF=__ZL12show_revokedPv+4
0000000100634b75 db "That license key doesn't appear to be valid.\n\nPlease check that you have entered all lines from the license key, including the BEGIN LICENSE and END LICENSE lines.", 0 ; DATA XREF=__ZL16show_invalid_keyPv+4
0000000100634c19 db "Thanks for purchasing!", 0 ; DATA XREF=__ZL11show_thanksPv+4
0000000100634c30 db "Hello! Thanks for trying out Sublime Text 3!\n\nSublime Text 3 is a paid upgrade from Sublime Text 2, and your license key is for Sublime Text 2.\n\nWould you like to upgrade your license now?", 0 ; DATA XREF=__ZL21show_upgrade_requiredPv+10
0000000100634ced db "Upgrade", 0 ; DATA XREF=__ZL21show_upgrade_requiredPv+17
0000000100634cf5 db "Unable to write license file: ", 0 ; DATA XREF=__ZL20show_unable_to_writePv+21
0000000100634d14 db "license_check", 0 ; DATA XREF=__Z28live_validate_license_threadPv+37
````
7. 在这个字符串上点右键,点击Reference to翻译过来就是谁引用的他,会显示一些函数,这里只有一个,双击进入,如下图
8. 然后我们看这个函数的伪代码,发现只是一个提示框
```
int __ZL16show_invalid_keyPv(void * arg0) {
rax = px_show_error("That license key doesn't appear to be valid.\n\nPlease check that you have entered all lines from the license key, including the BEGIN LICENSE and END LICENSE lines.", rsi);
return rax;
}
```
然后我们继续右键找谁引用的这个函数,发现_ZN14license_window13on_ok_clickedEv()这是个按钮事件,我们双击进入这个事件
```
int __ZN14license_window13on_ok_clickedEv() {
r14 = rdi;
var_30 = *___stack_chk_guard;
TextBuffer::str();
rax = var_90 & 0xff;
rcx = 0x1 & rax;
rsi = var_8C;
if (rcx != 0x0) {
rsi = var_80;
}
rax = rax >> 0x1;
if (rcx != 0x0) {
rax = var_88;
}
convert_utf32_to_utf8(var_78);
if ((var_90 & 0x1) != 0x0) {
operator delete(var_80);
}
r13 = *(r14 + 0x250);
*r13 = 0x0;
rbx = r13 + 0x8;
if ((*(int8_t *)(r13 + 0x8) & 0x1) == 0x0) {
*(int16_t *)rbx = 0x0;
}
else {
*(int8_t *)*(r13 + 0x18) = 0x0;
*(r13 + 0x10) = 0x0;
}
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::reserve(rbx, 0x0);
r15 = var_C0;
*(rbx + 0x10) = *(r15 + 0x10);
rax = *r15;
*(rbx + 0x8) = *(r15 + 0x8);
*rbx = rax;
*(r15 + 0x10) = 0x0;
*(r15 + 0x8) = 0x0;
*r15 = 0x0;
rbx = r13 + 0x20;
if ((*(int8_t *)(r13 + 0x20) & 0x1) == 0x0) {
*(int16_t *)rbx = 0x0;
}
else {
*(int8_t *)*(r13 + 0x30) = 0x0;
*(r13 + 0x28) = 0x0;
}
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::reserve(rbx, 0x0);
*(rbx + 0x10) = *(var_A8 + 0x10);
rax = *var_A8;
*(rbx + 0x8) = *(var_A8 + 0x8);
*rbx = rax;
*(var_A8 + 0x10) = 0x0;
*(var_A8 + 0x8) = 0x0;
*var_A8 = 0x0;
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(var_A8);
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(r15);
rcx = (var_78 & 0xff) >> 0x1;
if ((0x1 & var_78 & 0xff) != 0x0) {
rcx = var_70;
}
if (rcx != 0x0) {
rax = *(r14 + 0x250);
rax = apple_fruit(var_78, rax + 0x8, rax + 0x4, var_CC, rax + 0x1);
rdi = *(r14 + 0x250);
*(int8_t *)rdi = COND_BYTE_SET(E);
if (rax == 0x1) {
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::operator=(rdi + 0x20, var_78);
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string(var_F0, var_78);
rax = operator new(0x28);
*rax = 0x1007169f8;
*(rax + 0x18) = 0x0;
*(rax + 0x10) = var_E8;
*(rax + 0x8) = var_F0;
var_F0 = intrinsic_movaps(var_F0, 0x0);
*(int32_t *)(rax + 0x20) = var_CC;
var_40 = rax;
work_queue::push_delayed(_g_work_queue, var_60);
rdi = var_40;
if (rdi != var_60) {
if (rdi != 0x0) {
rax = *rdi;
(*(rax + 0x28))();
}
}
else {
(*(var_60 + 0x20))(var_60);
}
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(var_F0);
encode_decode_license(var_78);
get_license_path();
rax = 0x1;
rdi = var_107;
if ((var_108 & rax) != 0x0) {
rdi = var_F8;
}
rdx = var_78 & 0xff;
rax = rax & rdx;
rsi = var_77;
if (rax != 0x0) {
rsi = var_68;
}
rdx = rdx >> 0x1;
if (rax != 0x0) {
rdx = var_70;
}
rbx = write_file(rdi, rsi, rdx, 0x1);
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(var_108);
if (rbx == 0x0) {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_unable_to_write(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
rax = create_thread(notify_license_entered_thread(void*), sign_extend_64(var_CC));
pthread_detach(rax);
if (*(int8_t *)(*(r14 + 0x250) + 0x1) != 0x0) {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_upgrade_required(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
else {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_thanks(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
}
else {
if (rax != 0x4) {
if (rax != 0x3) {
if (rax == 0x2) {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_invalid_key(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
}
else {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_revoked(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
}
else {
rax = operator new(0x18);
*rax = 0x100731948;
*(rax + 0x8) = show_shared(void*);
*(rax + 0x10) = 0x0;
work_queue::push_delayed(_g_work_queue, rax);
}
}
}
else {
get_license_path();
rdi = var_11F;
if ((var_120 & 0x1) != 0x0) {
rdi = var_110;
}
unlink(rdi);
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(var_120);
}
if (*(r14 + 0x2a0) != 0x0) {
std::__1::function<void (r14 + 0x280);
}
r12 = *___stack_chk_guard;
rdi = *(r14 + 0x28);
rax = *rdi;
rax = *(rax + 0x18);
(rax)(rdi);
rax = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string(var_78);
if (r12 != var_30) {
rax = __stack_chk_fail();
}
return rax;
}
```
代码在上面,我们大体看一看,前面都是些数据处理,我们找到刚才提示错误的那个函数,往上回溯,看
```
if (rax == 0x1)
{
//注册成功
}
else
{
//错误代码
}
```
那这个rax怎么被赋值的呢,在往上面找
```
if (rcx != 0x0) {//这个地方不需要再往上看了,因为输入错误注册码后直接跳到了错误代码那个区域,所以这个判断一定是true
rax = *(r14 + 0x250);
rax = apple_fruit(var_78, rax + 0x8, rax + 0x4, var_CC, rax + 0x1);//这个是rax最终的值,是一个函数返回的,那我们只要把这个rax赋值成1或者直接把这个函数的返回值设置成1就好了
rdi = *(r14 + 0x250);
*(int8_t *)rdi = COND_BYTE_SET(E);
```
那我们继续双击这个apple_fruit进入
```
//这里是个文本加密解密hash值的处理,无奈太长了,这里也不算码直接爆破,所以直接让这个函数返回1
//这样改
mov rax,0x1
ret
//只需要在函数开始处这样改就好了
```
这样就改完了,怎么保存,点击File---Produce New executable 他会提示你去除签名,然后保存就好了
## 写在最后
这里只是简单的介绍了Hopper的用法,主要还是找关键字,关键Call,然后修改。还是靠逻辑。
> 当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。
当参数为7个以上时, 前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。
参数个数大于 7 个的时候
H(a, b, c, d, e, f, g, h);
a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%r8, f->%r9
h->8(%esp)
g->(%esp)
call H
附上一些寄存器的值,供大家和x86对比
![](http://abcdxyzk.github.io/images/assembly/2013-06-04-1.png)
![](http://abcdxyzk.github.io/images/assembly/2013-06-04-2.png) 来学习了 emmmm 都不睡觉的吗? 学习了 。。 好东西。。 厉害呢。{:1_893:} 66666666 这个有点意思~~~先回帖插个眼再仔细看看~~ 咋一看这贴非常的耀眼 原来是版主
感谢分享:handshake 好厉害,感谢分享。