Hmily 发表于 2012-12-4 18:20

IPAD 破文一篇

标 题:【原创】IPAD 破文一篇
作 者: U士回
时 间: 2011-08-14,00:20:57
链 接: http://bbs.pediy.com/showthread.php?t=138743


前言:
一个偶然的机会,得到一台IPAD2,若只当个娱乐玩具,还是挺很不错的。在苹果封闭的体系保护中,不去苹果那儿注册,安装自己开发软件是相当的困难,尤其在没有MAC笔记本的情况下,安装IPAD的开发环境相当艰苦,我到现在还没安装成功过(要是你成功安装过,欢迎教我一下),呵呵。前不久,jailbreakme利用PDF漏洞实现了越狱,可以安装各种软件和开发工具了,哈哈,可以在没有XCode开发环境下,从另一个方面深入地了解一下其内部系统了。
言归正传,在APP中找了款免费的SSH软件,体验了一下,整体感觉还是不错的,只是使用时会有150次按键的限制,有点不爽,这便激发我来解决这一点。特别说明,本文仅以学习研究为目的。


准备:
一台越狱后的IPAD2,GCC编译工具,GDB调试工具,Open SSH服务,当然还有我们的目标软件zaTelnet。
一台电脑,装有Putty系列工具,IDA6.1工具。
保证电脑和IPAD的网络畅通。


分析:
以zaTelnet3.0.6为例

通过SSH连接在IPAD找到zaTelnet所在目录
/private/var/mobile/Applications/DFFD7B8E-D0F6-422C-86C3-5F27FDE8FA1A
将主程序zaTelnet拉下来看看



一地鸡毛,像加了壳似的。静态分析是没法做了,只能通过动态调试的来看看。

上GDB工具,使用ATTACH命令,进入ZaTelnet进程的领空。

再使用info sharedlibrary命令,查看加载的模块信息

发现进程占用的空间 为 0x1000 ~ 0x5b000
再使用dump zaTelnetPatch_dump 0x1000 0x5b000命令,将内存DUMP到zaTelnetPatch_dump文件中。
再上IDA来分析下zaTelnetPatch_dump文件。


貌似是解过密的原始代码了。
通过提示特征信息,快速定位。




相关的处理
__text:00032CB8               PUSH            {R4-R7,LR}
__text:00032CBA               ADD             R7, SP, #0xC
__text:00032CBC               PUSH.W          {R8,R10,R11}
__text:00032CC0               VPUSH         {D8-D15}
__text:00032CC4               SUB             SP, SP, #0x74
__text:00032CC6               LDR.W         R3, =(off_44154 - 0x32CD2)
__text:00032CCA               STR             R0,
__text:00032CCC               ADD             R0, SP, #0x40
__text:00032CCE               ADD             R3, PC
__text:00032CD0               STR             R2,
__text:00032CD2               LDR             R3,
__text:00032CD4               STR             R7,
__text:00032CD6               STR.W         SP,
__text:00032CDA               STR             R3,
__text:00032CDC               LDR.W         R3, =(unk_42C94 - 0x32CE4)
__text:00032CE0               ADD             R3, PC
__text:00032CE2               STR             R3,
__text:00032CE4               LDR.W         R3, =(loc_32F02 - 0x32CEC)
__text:00032CE8               ADD             R3, PC
__text:00032CEA               ORR.W         R3, R3, #1
__text:00032CEE               STR             R3,
__text:00032CF0               BLX             sub_43F80
__text:00032CF4               LDR.W         R0, =(unk_4DE58 - 0x32D04)
__text:00032CF8               LDR.W         R1, =(off_4DDF0 - 0x32D06)
__text:00032CFC               MOV.W         R2, #0xFFFFFFFF
__text:00032D00               ADD             R0, PC
__text:00032D02               ADD             R1, PC
__text:00032D04               LDR             R0,
__text:00032D06               LDR             R1,
__text:00032D08               STR             R2,
__text:00032D0A               BLX             sub_43FE4
__text:00032D0E               TST.W         R0, #0xFF
__text:00032D12               BEQ.W         loc_32E7E
__text:00032D16               LDR.W         R2, =(unk_4CB98 - 0x32D22)
__text:00032D1A               LDR             R3,
__text:00032D1C               LDR             R4,
__text:00032D1E               ADD             R2, PC
__text:00032D20               LDR             R1,
__text:00032D22               STR             R3,
__text:00032D24               LDR             R3,
__text:00032D26               SUBS            R3, #1       按一次计数器减1
__text:00032D28               STR             R3,
__text:00032D2A               LDR             R3,
__text:00032D2C               LDR             R3,
__text:00032D2E               CMP             R3, #0

在GDB中,使用 00032D26命令,内存修改代码
(gdb) set {unsigned char} 0x00032D26 = 0x00
(gdb) x/i 0x00032D26
0x32d26:      subs    r3, #0
(gdb)
继续运行程序
(gdb) c
Continuing.
见证奇迹的时刻到了。你就会发现,按任何一个按键之后,右上角的计数不再减少了。至此完成的破解。当然实际使用时,总不能架一个GDB吧,总需要自动Patch吧。


补丁:
    进程执行时会检查 /Library/MobileSubstrate/DynamicLibraries/ 目录中 扩展名plist的文件中的描述来决定是否动态同名的扩展名为dylib的文件。用这个方法就可以实现在zaTelnet执行自动加载我们的Patch动态库。
附上Patch内存的核心代码,大部分都是从网上抄来的,呵呵。

static void patch_mem(void *p, unsigned char data)
{
    int page = getpagesize();
    uintptr_t address = (uintptr_t)(p);
    uintptr_t base = address / page * page;
    mach_port_t self = mach_task_self();
    kern_return_t error;

    if ((page - (uintptr_t)(p) - base) < 12)
      page *= 2;
      
    if (error = vm_protect(self, base, page, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY))
    {
      // fprintf(stderr, "vm_protect():%d\n", error);
      return;
    }
    *(unsigned char*) p = data;
    // __clear_cache((char *)(p), (char *)(p + 1));

    if (error = vm_protect(self, base, page, FALSE, VM_PROT_READ | VM_PROT_EXECUTE))
    {
      // fprintf(stderr, "vm_protect():%d\n", error);
      return;
    }
}

static mach_msg_type_number_t read_mem(void *p, char *data, mach_msg_type_number_t size)
{
    int page = getpagesize();
    vm_address_t address = (vm_address_t)(p);
    mach_port_t self = mach_task_self();
    pointer_t buf;
    kern_return_t error;

    if (error = vm_read(self, address, size, &buf, &size))
    {   
      //fprintf(stderr, "vm_read():%d\n", error);
      return 0;
    }
    memcpy(data, (void*)buf, (int)size);
    return size;
}

int _X_HIDDEN patcher_(unsigned char* pFun, unsigned char* pIns)
{
    unsigned char *p;
    char buf;
    p = pFun;
    if (read_mem(p, buf, sizeof(buf)) == sizeof(buf))
    {
      if (0 == memcmp(buf, "\xF0\xB5\x03\xAF\x2D\xE9\x00\x0D\x2D\xED\x10\x8B", 12))
      {
            p = pIns;
            if (p == '\x01' && p == '\x3b')
            {
                // 修改内存属性
                // p = '\0';
                patch_mem(p, '\0'); // 停止减少按键计数
                return 1;
            }
      }
    }
    return 0;
}


最后:
    就不贴执行文件了,重点是分析过程,初次接触苹果系统,水平有限,不足之处,欢迎各位指教。

最后来一张效果图

阿狸先森 发表于 2012-12-4 18:37

好复杂哦看不懂.......

SunerC 发表于 2012-12-4 19:43

好文,都开始破ipad了..

ytyay 发表于 2012-12-4 20:00

老大亲自转载分享 , 定要学习下 。

小雨细无声 发表于 2012-12-4 20:58

汗!深奥!打好基础再来逛,会容易一些.

z5757124 发表于 2012-12-4 21:24

前排慢慢学习。

52shadow 发表于 2012-12-4 22:08

好文 H大 赛高

莺歌燕语 发表于 2012-12-4 22:10

- -大神啊.内存补丁和外挂有什么差别

车俊 发表于 2012-12-5 11:37

知识有限,看着头晕乎乎的,我滴神哦

wkxq 发表于 2012-12-5 12:32

知识有限,看不懂
页: [1] 2
查看完整版本: IPAD 破文一篇