记录一些小恶(1)

又好久不写这种话就不说了…考虑弄个不会经常抽风被墙的vps…godaddy阉割到如今连ssh -D都无法正常工作。无奈呀。

说正经的,最近由于各种需要,hack了几个Mac OS X的程序,大致写些记录下来。基本不会指明具体程序名字(其实是由于某程序的keygen引发的道德感所致),纯为了个人记录(会有少量的软件描述, 愿意猜的人就去猜吧)。

app1

一个将iPhone/iPad可以镜像到Mac OS X的软件, 处理过两个版本.

版本1

曾经化名在一个论坛和一个网盘放出过Activation, 后被广泛传播, 以至于原程序的开发方在升级至版本2时不但屏蔽了Activation生成的码, 同时还弹窗来说, 大意是”我们是个小的开发团队, 我们的目标是帮助人们更有效的使用他们的设备. 如果想免费使用, 可以试试试用版. 或者可以买一份”. 而且同时官方提供了7天的试用版. 也因此, 我有了不小的最恶感.

大致说一下版本1当时的crack过程和Activation的实现思路.

以gdb -arch i386来加载后(仅仅因为i386的读着习惯, 而且demo版的ida pro6也无法处理x86_64的), 结合ida pro6给出的静态代码, 找到诸如Activation1, Activation2, Activation3这样的字符串描述. 而objc反汇编后, 可以很容易的发现这样的逻辑.

mov eax, ds:off_56901C ;NSUserDefaults
mov ecx, ds:off_569258 ;standardUserDefaults
mov [esp+4], ecx
mov [esp], eax
call _objc_msgSend
mov ecx, ds:off_5692AC ;objectForKey:
mov [esp+4], ecx
mov [esp], eax
mov dword ptr [esp+8], offset cfstr_keyString ; "keyString"
call _objc_msgSend

从中我们可以看出, call _objc_msgSend是实际进行系统调用的过程, 而之前向esp的操作是进行堆栈的准备, 而这几行翻译过来其实就是一句很直白的ObjC代码

[[NSUserDefaults standardUserDefaults] objectForKey:@"keyString"];

正是这样的直白, 让逆向变得容易了很多. 而后沿着之前发现的ActivationX查看后续的逻辑, 一时并无结果. 后对获取到的几个Activation字符串加内存访问断点, 才找到了真正校验的地方. 分析后得知其大致验证方式如下:

利用OSX的sdk内提供的CCCrypt进行Encrypt/Decrypt, 使用的算法是kCCAlgorithmRC4. 在客户端对activation进行decrypt后, 会对原文(Message)进行检测. 而CCCrypt要求的key, 是使用text1:text2:text3这样的格式来构成的.

text1: 注册时使用的email地址
text2: 一段salt, 表明此activation用于哪个地方的校验
text3: os x系统的UUID, 可从系统中使用如下函数取出

+ (NSString *)hardwareUUID {
    NSString *returnString = nil;
    io_service_t    platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));

    if (platformExpert) {
        CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
                                                                           CFSTR(kIOPlatformUUIDKey),
                                                                           kCFAllocatorDefault, 0);

        if (serialNumberAsCFString) {
            returnString = [(NSString *)serialNumberAsCFString copy];
        }

        IOObjectRelease(platformExpert);
    }

    return [returnString autorelease];
}

得到Message将会用于一些关键步骤的检测, 主要是在建立连接时, 用以在相关连接中进行关键字匹配. 比如POST.

分析出算法后, 自然就做出了Activation.

版本2

由于版本1我放出了Activation, 同时由于版本1对activationCode的检测过于薄弱, 只要了解了算法和Message, 很容易搞定. 在版本2中, 对方加大了防护力度. 首先使用了RSA2048进行key的加解密, 客户端内嵌入了Public Key, 而在无法拿到对应Private Key的情况下, 想不修改程序而直接用一个keygen/activation来解决战斗是不可能了, 那么首先要做的就是使用自己生成一对key做替换, 替换掉原程序中的Public Key, 这样我们就可以用我们自己的Private Key来做Encrypt, 使得程序可以正常Decrypt我们生成的activation. 当然至于Public Key和Private Key的生成细节是可以从程序中挖出来的, 比如rsa中的”e”.

而接下来的问题就是原始的activation的格式了, 其实耐心去跟, 也是可以搞定的, 不过后来人比较懈怠, 外加正好有朋友购买了一份正版的, 故直接要来他的Activation, Decrypt出原文, 也就知道了原始的格式. 程序也就此告破.

哦, 对了, 差点忘了说, 在版本2中, 对方还进行了反gdb的保护. 以至于程序是无法正常通过gdb进行加载的. 探究其方法, 是使用了ptrace. 那么就好办了, 直接处理掉ptrace就好了. 使用如下gdb脚本来解决

set breakpoint pending on
break ptrace
commands 1
    return
    continue
end

就这样, 版本2也算破了. 不过由于上文提到的良心问题, 版本2的Crack仅仅停留在研究和自用的范畴, 不会向外公开.

其他程序的后续慢慢发吧, 这篇暂时就到这里了.

One thought on “记录一些小恶(1)”

晓行进行回复 取消回复

邮箱地址不会被公开。 必填项已用*标注