[iOS逆向实战 之九]重组mach-o格式实现简单反ida

个人原创,转帖请注明来源:cnblogs.com/jailbreaker

之前3篇大致讲了下mach-o的相关知识,这篇主要讲解如何通过对mach-o文件简单的更改达到反ida静态分析的目的,此篇目的是抛砖引玉,掌握mach-o格式可以按自己的思路去更改,做到防反汇编器。

mach-o文件格式的节:

1.struct section { /* for 32-bit architectures */

2.    char        sectname[16];   /* name of this section */

3.    char        segname[16];    /* segment this section goes in */

4.    uint32_t    addr;       /* memory address of this section */

5.    uint32_t    size;       /* size in bytes of this section */

6.    uint32_t    offset;     /* file offset of this section */

7.    uint32_t    align;      /* section alignment (power of 2) */

8.    uint32_t    reloff;     /* file offset of relocation entries */

9.    uint32_t    nreloc;     /* number of relocation entries */

10.    uint32_t    flags;      /* flags (section type and attributes)*/

11.    uint32_t    reserved1;  /* reserved (for offset or index) */

12.    uint32_t    reserved2;  /* reserved (for count or sizeof) */

13.};

节属性的主要作用是告诉加载器,本节要加载到内存的虚拟地址(addr),大小(size),及节在文件物理地址的偏移(offset)。

实际上mach-o文件格式详细的指导了加载器如何加载文件到内存,但是ios并没有完全按照格式来加载,对可执行文件合法性的验证只是做到了segment一层,对于节section一层并没有验证,加载器只是简单的将段地址线性的映射到内存,粒度很大,没有细化到节,所以节属性在加载的时候没有用。

但是ida是完全依靠mach格式来分析文件,如此,bug就出现了。(实际上在win下,od也有类似的bug),那么下面手动做2个实验,达到ida不能加载,ios却能正常运行的效果。

实验1:更改节的物理地址偏移。

1,首先将文件拖到ida,我们看到TEXT段下面的2个节。

“__text"与"__stub_helper"

HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname

HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname

HEADER:0000408C DCD 0xAD00 ; addr

HEADER:0000408C DCD 0xD6938 ; size

HEADER:0000408C DCD 0x6D00 ; offset

HEADER:0000408C DCD 3 ; align

HEADER:0000408C DCD 0 ; reloff

HEADER:0000408C DCD 0 ; nreloc

HEADER:0000408C DCD 0x80000400 ; flags

HEADER:0000408C DCD 0 ; reserved1

HEADER:0000408C DCD 0 ; reserved2

HEADER:000040D0 DCB "__stub_helper",0,0,0; sectname

HEADER:000040D0 DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname

HEADER:000040D0 DCD 0xE1638 ; addr

HEADER:000040D0 DCD 0xE88 ; size

HEADER:000040D0 DCD 0xDD638 ; offset

HEADER:000040D0 DCD 2 ; align

HEADER:000040D0 DCD 0 ; reloff

HEADER:000040D0 DCD 0 ; nreloc

HEADER:000040D0 DCD 0x80000400 ; flags

HEADER:000040D0 DCD 0 ; reserved1

HEADER:000040D0 DCD 0 ; reserved2

“__text”节的的内存加载地址为 0xad00,文件偏移为0x6d00

"__stub_helper"节的的内存加载地址为 0xE1638,文件偏移为0xDD638

2,我们将“__text”的的文件偏移更改为"__stub_helper"的文件偏移,修改后保持文件,继续拖到ida下分析,如下图:

HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname

HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname

HEADER:0000408C DCD 0xAD00 ; addr

HEADER:0000408C DCD 0xD6938 ; size

HEADER:0000408C DCD 0xDD638 ; offset

HEADER:0000408C DCD 3 ; align

HEADER:0000408C DCD 0 ; reloff

HEADER:0000408C DCD 0 ; nreloc

HEADER:0000408C DCD 0x80000400 ; flags

HEADER:0000408C DCD 0 ; reserved1

HEADER:0000408C DCD 0 ; reserved2

HEADER:000040D0 DCB "__stub_helper",0,0,0; sectname

HEADER:000040D0 DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname

HEADER:000040D0 DCD 0xE1638 ; addr

HEADER:000040D0 DCD 0xE88 ; size

HEADER:000040D0 DCD 0xDD638 ; offset

HEADER:000040D0 DCD 2 ; align

HEADER:000040D0 DCD 0 ; reloff

HEADER:000040D0 DCD 0 ; nreloc

HEADER:000040D0 DCD 0x80000400 ; flags

HEADER:000040D0 DCD 0 ; reserved1

HEADER:000040D0 DCD 0 ; reserved2

两个节的物理偏移都为0xDD638。

双击“__text”节,进入代码的。

可以看到左下角,物理地址为0xdd638,实际上这是错误的,物理地址应该为0x6D00。我们可以得出结论,ida直接使用了节的物理地址,偷懒了,实际上应该使用段地址来计算。

实验2:给节的物理偏移更改为一个远超文件大小的数。

HEADER:0000408C ; Sections

HEADER:0000408C DCB "__text",0,0,0,0,0,0,0,0,0,0; sectname

HEADER:0000408C DCB "__TEXT",0,0,0,0,0,0,0,0,0,0; segname

HEADER:0000408C DCD 0xAD00 ; addr

HEADER:0000408C DCD 0xD6938 ; size

HEADER:0000408C DCD 0xFFFFFFFF ; offset

HEADER:0000408C DCD 3 ; align

HEADER:0000408C DCD 0 ; reloff

HEADER:0000408C DCD 0 ; nreloc

HEADER:0000408C DCD 0x80000400 ; flags

HEADER:0000408C DCD 0 ; reserved1

HEADER:0000408C DCD 0 ; reserved2

更改后保存文件,拖到ida,如图:

点击后,还是可以分析的,但是点击"__text"进入代码段,对比原来得数据(上面有图)你可以发现代码明显不对,物理地址也变成了未知:

经测试,程序可以正常运行。

我们再将其改为一个比较大的正数,0x01000000,结果ida不能打开。

以上修改经测试程序可以正常运行。实际上节的属性都可以改,比如addr,混淆的效果比offset要好的多。将text部分节的数据填充随机数据,ida直接卡死。

时间: 2024-08-25 09:26:53

[iOS逆向实战 之九]重组mach-o格式实现简单反ida的相关文章

[iOS逆向实战 之一]arm寄存器简介

个人原创,转帖请注明来源:cnblogs.com/jailbreaker [iOS逆向实战]这个系列的帖子,会涉及到arm汇编,以及调试工具的使用,加上实战解析一步步逆向,深入浅出. 这是第一篇帖子,简要说下arm的各个寄存器的功能. R0-R3:用于函数参数及返回值的传递 R4-R6, R8, R10-R11:没有特殊规定,就是普通的通用寄存器 R7:栈帧指针(Frame Pointer).指向前一个保存的栈帧(stack frame)和链接寄存器(link register, lr)在栈上的

[iOS逆向实战 之三]函数之基本类型(int)参数传递

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 在这[iOS逆向实战 之一]中讲到函数调用的参数传递通过r0-r3来实现,这篇帖子我们来验证下.先看一个4个参数的函数代码: main方法简单调用compute方法,先看main的汇编代码: 明显可以看出,参数值1,2,3,4分别传递给r0-r3,然后通过b调用函数 compute,接着看下compute的汇编代码: 最后一行 是返回到 调用者的下一行,之前帖子已经学过了,前面面3条代注释如下: add r0, r1  

[iOS逆向实战 之六]看懂mach-o(1)

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 在win下搞逆向需要看懂pe,同样搞iOS安全攻防必须看懂mach-o格式,水果的官方mach-o文档在此:https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/index.html 本文中实际项目分析,来达到“看懂”的目的,使用的工具还是前一篇blog所用的hopper. 先将目标文件拖进h

[iOS逆向实战 之四]创建objc对象

个人原创,转帖请注明来源:cnblogs.com/jailbreaker objc是完全面向对象的语言,所以逆向的重点就是逆向类,这篇帖子通过ida的神奇的f5功能,来逆向某个对象的创建. 我们直接看ida中的main方法的逆向出来的arm代码: 基本上看不出所以然,我们使用ida的f5分析得出c语法的伪代码如下: 提一下,我在源码中,把自动内存管理ARC关掉了,为的是让代码更整洁. 在 8,9行都看到objc_msgSend,这个objc_msgSend其实是编译器生成的代码,在源码中没有的,

[iOS逆向实战 之十]动态调试利器---gdb基础篇

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 一.调试平台搭建 1.GNU Debugger.首先安装ios下的gdb调试器,添加源:cydia.radare.org .搜索 GNU Debugger,安装之.(有些源的GDB好像不能用,这个测试没问题) 2.openSSH.这个应该都会装,没装过的参考,http://www.cnblogs.com/jailbreaker/p/4142609.html 3.adv-cmds.添加源:apt.saurik.com(这个应

[iOS逆向实战 之七]看懂mach-o(2)

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 接上一篇看懂mach-o(1),本文继续讲紧随mach-o的header文件的load command加载命令,看下面2张图,分别是hopper中显示的第一个load command区域和segment_command的定义: 第一张图截取的是第一个load command,从第一张图所知道,cmd类型是segment_command,就是截图的第2张图,依次分析: 1.cmd 是load command的类型,本文中值=

[iOS逆向实战 之八]看懂mach-o(3)

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 之前两篇帖子分别讲了mach-o的header区和load command区中的segment,今天继续讲segment中的的setcion,一般在__TEXT和__DATA段中有section.这里注意下命名规范,大写代表segment,小写是section,例如 __TEXT.__text,指的是__TEXT段的__text节. 先看section结构定义: 再看hopper中的__TEXT.__text 描述: 根据

[iOS逆向实战 之二]mov 和 mvn

个人原创,转帖请注明来源:cnblogs.com/jailbreaker 先看2段代码: 第一段代码main里面没有任何语句,第2段代码是返回0值,这2段代码的反汇编是一样的,看下图: 一共 2行汇编代码,第2行 bx lr 代表返回到main调用之后的语句,而第一行 movs是 mov的扩展,最后字母s代表影响标志位,从汇编代码可知,如果返回int类型,没有明显的 return 语句,那默认就是返回0(返回寄存器r0).(0x代表16机制) 接着修改代码为return  -1看下反汇编 ret

iOS可执行文件的简单反ida

ida就不用我就废话了,这篇主要讲解如何通过对mach-o文件简单的更改达到反ida静态分析的目的. 先说一下mach-o文件格式的节. ? ? struct?section?{?/*?for?32-bit?architectures?*/?? ????char????????sectname[16];???/*?name?of?this?section?*/?? ????char????????segname[16];????/*?segment?this?section?goes?in?*/