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?*/??
- ????uint32_t????addr;???????/*?memory?address?of?this?section?*/??
- ????uint32_t????size;???????/*?size?in?bytes?of?this?section?*/??
- ????uint32_t????offset;?????/*?file?offset?of?this?section?*/??
- ????uint32_t????align;??????/*?section?alignment?(power?of?2)?*/??
- ????uint32_t????reloff;?????/*?file?offset?of?relocation?entries?*/??
- ????uint32_t????nreloc;?????/*?number?of?relocation?entries?*/??
- ????uint32_t????flags;??????/*?flags?(section?type?and?attributes)*/??
- ????uint32_t????reserved1;??/*?reserved?(for?offset?or?index)?*/??
- ????uint32_t????reserved2;??/*?reserved?(for?count?or?sizeof)?*/??
- }; ?
属性的主要作用是告诉加载,本节要加载到内存的虚拟地址(addr),大小(size),及节在文件物理地址的偏移(offset)。
实际上mach-o文件格式详细的指导了加载器如何加载文件到内存,但是ios并没有完全按照格式来加载,对可执行文件合法性的验证只是做到了segment一层,对于节section一层并没有验证,加载器只是简单的将段地址线性的映射到内存,粒度很大,没有细化到节,所以节属性在加载的时候没有用,但是ida是个好学生,完全依靠mach格式来分析文件,bug就出现了。(实际上在win下,od也有类似的bug),那么下面我们来手动更改文件,达到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,如图: