Moom 分析记录之二(劫持篇 )- tree_fly
本帖最后由 tree_fly 于 2016-10-31 22:51 编辑Moom 分析记录之一(爆破篇 )-tree_fly
https://www.chinapyg.com/thread-87213-1-1.html
(出处: 飘云阁(PYG官方论坛) )
Moom 分析记录之二劫持篇
by tree_fly/P.Y.G
分析:
继续分析这款小巧实用的Moom,今天的任务是如何一步一步分析注册验证过程,并创建dylib,完成劫持关键函数的破解实现。
首先仍然在注册界面寻找有用的信息:
红色下划线标注这句话:双击注册文件或者拖拽它到上面的文字区域。
很容易联想到拖拽控件,尝试在Hopper中搜索drag:
很明显,我们看到了ViewController:PMCertificateView,和一些拖拽方法:draggingEntered:, preformDragOperation:等,继续看看具体代码,
代码稍作整理以利于理清调用逻辑:
逐层调用的关系:
为了调试,我们需要创建一个plist文件,可是plist的具体内容是什么呢,继续向下分析方法:
以上代码已精简,由上向下一层一层深入,最后来到了 _PMCertificateDictionaryWithKey 方法,其中_APSetKey方法设置了全局dsa公钥,用于解密,
调试的时候可以查看其内容,但是没什么意义:
接下来看_APCreateDictionaryForLicenseData方法,从字面义来看,处理提供的验证数据后返回Dictionary,该方法的具体细节如下:
回忆上一篇提到的_PMHasValidCertificate方法,字典返回值至少应包含Email、Name:
根据上述代码,可以推断Moom使用了Security Transforms API,实现非对称加密算法,
参考这里: Security Transforms Programming Guide-Signing and Verifying
为了搞明白具体的加密解密过程,我们创建一个验证文件:moomlicense.plist
hopper下定位函数_APCreateDictionaryForLicenseData,代码段首下断点,启动调试器,运行程序,打开验证注册窗口,拖拽上述文件,释放鼠标后,中断下来,单步走起来,
po $rax{ "E-Mail" = "[email protected]"; Name = "tree_fly"; Signature = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;}
已正确传送了注册文件内容,在SecDigestTransformCreate(*_kSecDigestSHA1, 0x0, 0x0) 对应的汇编代码处下个断点,输入lldb命令:
po $r14<69 74 72 65 65 66 6c 79 40 68 6f 74 6d 61 69 6c 2e 63 6f 6d 74 72 65 65 5f 66 6c 79>i tree fly@hotm ail. comtree _f ly
发现将E-Mail和Name拼接,作为加密对象,结果和 Signature 继续比较, 后者应该是Moom官方私钥加密后的数据。
至此,初步分析已告一段落。我们思考下有哪些方法可以破解Moom。
[*]替换公钥。 用自定义的私钥生成注册文件,替换APP公钥,过验证流程。
[*]直接返回包含Name和Email的Dictionary。 无视加解密验证过程。
实践:方法1:关于第1种方法,Github搜索一下找到 iccir 的repositories,参看:https://github.com/iccir/SignAndVerify
其中提供了sha1Hashes和sha256Hashes两种方式,我们修改一下代码,测试一下:
构造虚假plist文件,然后劫持_APSetKey修正公钥。上述方法,稍显复杂,为了更优雅,采用第2种方法。
方法2:写一段代码,生成dylib,想办法在app启动的时候hook感兴趣的函数接口。
关于劫持的函数接口,可以选择:
_PMCheckBundleSignature
或者
_APCreateDictionaryForLicenseData
后者更接近算法底层。 关于mach_override, 参考:https://github.com/rentzsch/mach_override
dylib的代码:
//
//main.m
//Moom
//
//Created by tree_fly on 2016/10/18.
//Copyright © 2016年 tree_fly. All rights reserved.
//
#import <Foundation/Foundation.h>
#include "mach_override.h"
#include "mach-o/dyld.h"
intptr_t image_vmaddr_slide;
#pragma mark - PMCheckBundleSignature
void _PMCheckBundleSignature(){
//NSLog(@" ***** %s *****", __FUNCTION__);
typedef int (*def_PMCBS)(id);
def_PMCBS orig_PMCBS = def_PMCBS(image_vmaddr_slide + 0x10003fa44);
kern_return_t err;
MACH_OVERRIDE(int, orig_PMCBS, (id arg0), err) {
return 1;
} END_MACH_OVERRIDE(orig_PMCBS);
}
#pragma mark - Persistent Certificate Dictionary
void _PMValidPersistentCertificateDictionary(){
//NSLog(@" ***** %s *****", __FUNCTION__);
typedef id (*def_PMVPCD)(id, id);
def_PMVPCD orig_PMVPCD = def_PMVPCD(image_vmaddr_slide + 0x100026483);
kern_return_t err;
MACH_OVERRIDE(id, orig_PMVPCD, (id arg0, id arg1), err){
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
@"www.chinapyg.com", @"Name", nil];
return dic;
} END_MACH_OVERRIDE(orig_PMVPCD);
}
void _APCreateDictionaryForLicenseData(){
NSLog(@" ***** %s *****", __FUNCTION__);
typedef int (* def_APCDFD)(id);
def_APCDFD orig_APCDFD = def_APCDFD(image_vmaddr_slide + 0x100025456);
kern_return_t err;
MACH_OVERRIDE(id, orig_APCDFD, (id arg0), err){
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
@"www.chinapyg.com", @"Name", nil];
return dic;
} END_MACH_OVERRIDE(orig_APCDFD);
}
#pragma mark - install
void install(void) __attribute__ ((constructor));
void install()
{
//NSLog(@" *****Start *****");
image_vmaddr_slide = _dyld_get_image_vmaddr_slide(0x0);
//printf(" image_vmaddr_slide = 0x%lx\n", image_vmaddr_slide);
_PMCheckBundleSignature();
//_APCreateDictionaryForLicenseData();
}
bash脚本:
#!/bin/bash
App_PATH="`dirname "${0}"`"
App_BIN="`dirname "${0}"`"/Moom_
export DYLD_FORCE_FLAT_NAMESPACE=1
export DYLD_INSERT_LIBRARIES="${App_PATH}/libMoomHook.dylib"
"$App_BIN"
采用下划线方法注入即可。
1.打开/Moom.app/Contents/MacOS/目录,将 Moom 改名为 Moom_
2.将bash脚本文件及dylib文件复制到上述目录,启动主程序即可!
就写到这来,文章纰漏欢迎指点,谢谢阅读。
tree_fly
2016-10-31
前排学习 飞树大神威武! PYG有你更精彩! PYG有你更精彩!
不错啊!谢谢 非常非常精彩 讲的很好,还是不是很懂。 学习了学习了学习了 见帖就回,是一种套路