个人原创,转帖请注明来源: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直接卡死。