逆向一个IOS CrackMe

本文详细介绍了如何逆向分析一个iOS的CrackMe应用,包括理解Fat Mach-O文件结构,选择反汇编工具,解析动态和静态链接地址,以及将汇编代码反编译为C语言伪码。通过对Objective C的特性分析,揭示了栈保护和可变参数函数的参数传递机制。
摘要由CSDN通过智能技术生成

<0x01> 前言

本文涉及的CrackMe是看雪IOS安全小组招募的开门题目。题目提供了一个IOS应用,要求给出该应用的注册机。作为开门题目,其控制逻辑比较简单,为了实现注册机,主要的工作量在于其注册校验算法的逆向。
招募帖地址为http://bbs.pediy.com/thread-212736.htm
CrackMe程序下载地址为(需要注册论坛账号才能下载)http://bbs.pediy.com/attach-download-108214.htm
本文通过逆向这个IOS应用探索了Fat Mach-O文件结构,介绍了手动将ARM AArch64汇编代码反编译为C语言伪码的过程,该应用的注册校验算法则不做分析,有兴趣的读者可自行完成。

<0x02> IOS应用初探

原题提供的是一个ZIP压缩包,下载压缩并解压后得到一个Crack_Me.ipa文件。IPA文件和Android APK打包机制类似,实际上也是一个ZIP压缩包,其中包含了应用的二进制可执行文件、应用描述文件、静态资源等。
解压ipa文件
从AppStore下载的IOS应用是被Apple签名并加密的,不能直接被反汇编,而这个CrackMe没有通过AppStore发布,也就没有被加密,这给我节省了些许时间。

<0x03> 对应用进行反汇编

<0x03 0x01> Fat Mach-O格式简介

IOS应用以及OS X应用的二进制可执行文件是Fat Mach-O或者Mach-O格式。Mach-O是和Linux ELF或者Windows PE类似的存储二进制可执行代码的文件格式。
Mach-O文件一般由Mach-O Header、包含应用可执行代码的__TEXT段(Segment)、包含应用数据的__DATA段、用于ASLR和动态链接的__LINKEDIT段以及加载这些段的Load Commands组成,__TEXT段以及__DATA段还包含多个不同用途的节(Section)。而Fat Mach-O则可将多个支持不同CPU架构的Mach-O文件内嵌在同一文件中。
Fat Mach-O文件结构

<0x03 0x02> 反汇编工具的选择

如果读者有OS X环境,MachOView/otool/class-dump是不错的选择。更好的选择是IDA Pro,IDA Pro 6.9支持将ARM AArch64汇编指令反编译到C语言伪码。
然而笔者作为一个买不起IDA Pro以及MAC又不想使用盗版软件的穷屌,选择了Linux + GNU Binutils。需要注意的是2.27版本之前的Binutils并不支持Mach-O-AArch64,我的Linux发行版上的Binutils版本是2.24,所以让我们下载最新版本并编译安装:

$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.28.tar.gz
$ tar xvfzp binutils-2.28.tar.gz
$ cd binutils-2.28/
$ ./configure --target=aarch64-apple-darwin
$ make
$ sudo make install
$ aarch64-apple-darwin-objdump -v
GNU objdump (GNU Binutils) 2.28
Copyright (C) 2017 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.

<0x03 0x03> 分析应用头部信息

$ aarch64-apple-darwin-objdump ./Crack_Me -P header
In archive ./Crack_Me:

armv5te:     file format mach-o-arm
Mach-O header:
 magic     : feedface
 cputype   : 0000000c (arm)
 cpusubtype: 00000009
 filetype  : 00000002 (execute)
 ncmds     : 00000016 (22)
 sizeofcmds: 00000a14 (2580)
 flags     : 00200085 (noundefs+dyldlink+twolevel+pie)
 reserved  : 00000000



aarch64:     file format mach-o-arm64
Mach-O header:
 magic     : feedfacf
 cputype   : 0100000c (arm64)
 cpusubtype: 00000000
 filetype  : 00000002 (execute)
 ncmds     : 00000016 (22)
 sizeofcmds: 00000be0 (3040)
 flags     : 00200085 (noundefs+dyldlink+twolevel+pie)
 reserved  : 00000000

通过文件的头部信息可以知道这是一个Fat Mach-O文件,包含适用于ARMv5te以及AArch64两个架构的可执行代码。Fat Mach-O文件中包含的多个目标架构的二进制可执行代码从应用功能上来说是等价的,在进行逆向分析时可以任选一个架构的代码进行分析。
考虑32位ARM指令集使用多年,相关资料已经相当完备了,而ARMv8 AArch64架构的中文资料还相当匮乏,本文中笔者则选择了AArch64架构的目标代码进行分析,是为抛砖引玉。
为了对AArch64部分进一步分析,需要查看文件的Fat Header以确定该部分在文件中的偏移。
Fat Header的结构定义如下:

#define FAT_MAGIC   0xcafebabe
#define FAT_CIGAM   0xbebafeca

struct fat_header {
    unsigned long   magic;      /* FAT_MAGIC */
    unsigned long   nfat_arch;  /* number of structs that follow */
};

struct fat_arch {
    cpu_type_t  cputype;    /* cpu specifier (int) */
    cpu_subtype_t   cpusubtype; /* machine specifier (int) */
    unsigned long   offset;     /* file offset to this object file */
    unsigned long   size;       /* size of this object file */
    unsigned long   align;      /* alignment as a power of 2 */
};

使用十六进制编辑器打开Crack_Me,Fat Header在文件头:
这里写图片描述
由于Fat Header的魔数与上面定义的FAT_MAGIC相同,表明Fat Header是大字节序,如果魔数为FAT_CIGAM,则Fat Header为小字节序。
结合以上结构定义我们知道ARMv5te部分在文件中的偏移为0x00000400,而AArch64部分在文件中的偏移为0x00020000。0x00020000处即为AArch64部分的Mach-O Header,64位Mach-O Header的结构定义如下(请注意,32位Mach-O Header的魔数和结构与64位Mach-O Header的不同):

#define MACH_O_MH_MAGIC_64 0xfeedfacf
#define MACH_O_MH_CIGAM_64 0xcffaedfe
struct mach_o_header_64
{
  unsigned char magic[4];   /* Magic number.  */
  unsigned char cputype[4]; /* CPU that this object is for.  */
  unsigned char cpusubtype[4];  /* CPU subtype.  */
  unsigned char filetype[4];    /* Type of file.  */
  unsigned char ncmds[4];   /* Number of load commands.  */
  unsigned char sizeofcmds[4];  /* Total size of load commands.  */
  unsigned char flags[4];   /* Flags for special featues.  */
  unsigned char reserved[4];    /* Reserved.  Duh.  */
};

这里写图片描述
根据Mach-O Header的魔数,AArch64部分的代码为小字节序,而在64位Mach-o Header之后有22(0x00000016)个Load Commands。
打印所有的Load Commands:

$ aarch64-apple-darwin-objdump ./Crack_Me -P load >> crack_me_load_cmds

AArch64部分的Load Commands如下:

aarch64:     file format mach-o-arm64
Load command #0  (size:  72, offset:   32): segment_64
     name:       __PAGEZERO  nsects: 0  flags: 0  initprot: ---  maxprot: ---
   vmaddr: 0000000000000000   vmsize: 0000000100000000
  fileoff: 0000000000000000 filesize: 0000000000000000 endoff: 0000000000000000

Load command #1  (size: 792, offset:  104): segment_64
     name:           __TEXT  nsects: 9  flags: 0  initprot: r-x  maxprot: r-x
   vmaddr: 0000000100000000   vmsize: 000000000000c000
  fileoff: 0000000000000000 filesize: 000000000000c000 endoff: 000000000000c000
 Section: __text           __TEXT           (bfdname: .text)
  addr: 000000010000775c size: 0000000000002b84 offset: 000000000000775c
  align: 2  nreloc: 0  reloff: 0000000000000000
  flags: 80000400 (type: regular attr: pure_instructions+some_instructions)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __stubs          __TEXT           (bfdname: __TEXT.__stubs)
  addr: 000000010000a2e0 size: 0000000000000270 offset: 000000000000a2e0
  align: 1  nreloc: 0  reloff: 0000000000000000
  flags: 80000408 (type: symbol_stubs attr: pure_instructions+some_instructions)
  first indirect sym: 0 (52 entries)  stub size: 12  reserved3: 0x0
 Section: __stub_helper    __TEXT           (bfdname: __TEXT.__stub_helper)
  addr: 000000010000a550 size: 0000000000000288 offset: 000000000000a550
  align: 2  nreloc: 0  reloff: 0000000000000000
  flags: 80000400 (type: regular attr: pure_instructions+some_instructions)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_methname  __TEXT           (bfdname: __TEXT.__objc_methname)
  addr: 000000010000a7d8 size: 0000000000000be2 offset: 000000000000a7d8
  align: 0  nreloc: 0  reloff: 0000000000000000
  flags: 00000002 (type: cstring_literals attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __cstring        __TEXT           (bfdname: .cstring)
  addr: 000000010000b3ba size: 00000000000002d5 offset: 000000000000b3ba
  align: 0  nreloc: 0  reloff: 0000000000000000
  flags: 00000002 (type: cstring_literals attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_classname __TEXT           (bfdname: __TEXT.__objc_classname)
  addr: 000000010000b68f size: 0000000000000067 offset: 000000000000b68f
  align: 0  nreloc: 0  reloff: 0000000000000000
  flags: 00000002 (type: cstring_literals attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_methtype  __TEXT           (bfdname: __TEXT.__objc_methtype)
  addr: 000000010000b6f6 size: 000000000000081a offset: 000000000000b6f6
  align: 0  nreloc: 0  reloff: 0000000000000000
  flags: 00000002 (type: cstring_literals attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __const          __TEXT           (bfdname: .const)
  addr: 000000010000bf10 size: 0000000000000018 offset: 000000000000bf10
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __unwind_info    __TEXT           (bfdname: __TEXT.__unwind_info)
  addr: 000000010000bf28 size: 00000000000000d4 offset: 000000000000bf28
  align: 2  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0

Load command #2  (size: 1352, offset:  896): segment_64
     name:           __DATA  nsects: 16  flags: 0  initprot: rw-  maxprot: rw-
   vmaddr: 000000010000c000   vmsize: 0000000000004000
  fileoff: 000000000000c000 filesize: 0000000000004000 endoff: 0000000000010000
 Section: __got            __DATA           (bfdname: __DATA.__got)
  addr: 000000010000c000 size: 0000000000000080 offset: 000000000000c000
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000006 (type: non_lazy_symbol_pointers attr: -)
  first indirect sym: 52 (16 entries)  reserved2: 0x0  reserved3: 0x0
 Section: __la_symbol_ptr  __DATA           (bfdname: __DATA.__la_symbol_ptr)
  addr: 000000010000c080 size: 00000000000001a0 offset: 000000000000c080
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000007 (type: lazy_symbol_pointers attr: -)
  first indirect sym: 68 (52 entries)  reserved2: 0x0  reserved3: 0x0
 Section: __cfstring       __DATA           (bfdname: .cfstring)
  addr: 000000010000c220 size: 0000000000000060 offset: 000000000000c220
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_classlist __DATA           (bfdname: __DATA.__objc_classlist)
  addr: 000000010000c280 size: 0000000000000010 offset: 000000000000c280
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 10000000 (type: regular attr: no_dead_strip)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_nlclslist __DATA           (bfdname: __DATA.__objc_nlclslist)
  addr: 000000010000c290 size: 0000000000000008 offset: 000000000000c290
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 10000000 (type: regular attr: no_dead_strip)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_protolist __DATA           (bfdname: __DATA.__objc_protolist)
  addr: 000000010000c298 size: 0000000000000018 offset: 000000000000c298
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_imageinfo __DATA           (bfdname: __DATA.__objc_imageinfo)
  addr: 000000010000c2b0 size: 0000000000000008 offset: 000000000000c2b0
  align: 2  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_const     __DATA           (bfdname: __DATA.__objc_const)
  addr: 000000010000c2b8 size: 0000000000000db8 offset: 000000000000c2b8
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_selrefs   __DATA           (bfdname: __DATA.__objc_selrefs)
  addr: 000000010000d070 size: 00000000000000d8 offset: 000000000000d070
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 10000005 (type: literal_pointers attr: no_dead_strip)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_protorefs __DATA           (bfdname: __DATA.__objc_protorefs)
  addr: 000000010000d148 size: 0000000000000008 offset: 000000000000d148
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_classrefs __DATA           (bfdname: __DATA.__objc_classrefs)
  addr: 000000010000d150 size: 0000000000000010 offset: 000000000000d150
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 10000000 (type: regular attr: no_dead_strip)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_superrefs __DATA           (bfdname: __DATA.__objc_superrefs)
  addr: 000000010000d160 size: 0000000000000008 offset: 000000000000d160
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 10000000 (type: regular attr: no_dead_strip)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_ivar      __DATA           (bfdname: __DATA.__objc_ivar)
  addr: 000000010000d168 size: 000000000000000c offset: 000000000000d168
  align: 2  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __objc_data      __DATA           (bfdname: __DATA.__objc_data)
  addr: 000000010000d178 size: 00000000000000f0 offset: 000000000000d178
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular attr: -)
  reserved1: 0x0  reserved2: 0x0  reserved3: 0x0
 Section: __data           __DATA           (bfdname: .data)
  addr: 000000010000d268 size: 0000000000000148 offset: 000000000000d268
  align: 3  nreloc: 0  reloff: 0000000000000000
  flags: 00000000 (type: regular at
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 [安全攻防进阶篇] 中,有关于逆向分析的教程可以帮助你了解如何使用OllyDbg逆向CrackMe程序。 OllyDbg是一种常用的逆向工具,可以用于分析和修改程序的执行流程和内存。使用内存断点和普通断点,可以在程序执行过程中捕获关键的代码位置,帮助我们找到CrackMe程序的OEP(Original Entry Point),即程序的入口点。 在 [安全攻防进阶篇] 中还有关于逆向分析两个CrackMe程序的详细教程,包括逆向分析和源码还原的步骤。这些教程将帮助你理解逆向分析的基本概念和技巧,提升你的安全能力。 如果你想深入学习如何使用OllyDbg逆向CrackMe程序,可以参考这些教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [[安全攻防进阶篇] 六.逆向分析之OllyDbg逆向CrackMe01-02及加壳判断](https://blog.csdn.net/Eastmount/article/details/107777190)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [逆向crackme之ESp定律脱壳](https://blog.csdn.net/qq_58970968/article/details/125357834)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值