代码改变世界

iOS安全攻防(十九)重组mach-o格式实现简单反ida

2015-01-09 10:11  16字节  阅读(3050)  评论(1编辑  收藏  举报

个人原创,转帖请注明来源: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,如图:

 

 NewImage

 

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

 

 NewImage

 

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

 

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

 NewImage

 

 

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