云在天 发表于 2018-9-7 01:24

【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)

ymgaoski 发表于 2018-9-18 16:17

世夕 发表于 2018-9-7 01:45

来学习了 emmmm 都不睡觉的吗?

冰浪 发表于 2018-9-7 04:16

学习了 。。

冰浪 发表于 2018-9-7 04:20

好东西。。

shenbl201 发表于 2018-9-7 08:13

厉害呢。{:1_893:}

xieyao0111 发表于 2018-9-7 08:15

66666666

rebort0628 发表于 2018-9-7 08:36

这个有点意思~~~先回帖插个眼再仔细看看~~

小小学生 发表于 2018-9-7 08:48

咋一看这贴非常的耀眼 原来是版主

lovelw17 发表于 2018-9-7 09:05


感谢分享:handshake

yssun 发表于 2018-9-7 09:19

好厉害,感谢分享。
页: [1] 2 3 4
查看完整版本: 【Mac】Hopper Disassembler系列之Sublime Text3 爆破