注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

碳基体

http://weibo.com/tanjiti

 
 
 
 
 

日志

 
 

objective-c runtime安全措施之三:反汇编(inline编译方式)  

2012-04-01 11:20:02|  分类: iOS app security |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

《O'Reilly.Hacking.and.Securing.iOS.Applications>>读书笔记

反汇编:通过优化编译器选项、去除符号表来复杂化编译后生成的汇编代码(使用反汇编工具结合动态调试工具弄清并篡改程序逻辑)

方法1:采用inline函数

原理:设置inline属性、static属性,可以使得编译后生成的目标代码在反汇编成汇编代码时,不容易阅读,弄清其中的逻辑,因为inline会导致汇编代码中是直接将inline函数的函数体拷贝到main中,而不是清晰的call调用;static属性,则会让编译生成的二进制代码中,没有清晰的符号表,同样使得攻击者很难通过逆向弄清楚程序逻辑。

例子1. non-inline函数和其反汇编代码

#include <stdlib.h>

int is_session_valid(int session_id) {//session_id为偶数返回1,为奇数返回0

if (session_id % 2 == 0) {

return 1;

} else {

return 0;

}

}

 

int main( ) {

int session = 3;

if (! is_session_valid(session))

return EXIT_FAILURE;

/*

* Do something else

*/

if (! is_session_valid(session))

return EXIT_FAILURE;

/*

* Do something else

*/

if (! is_session_valid(session))

return EXIT_FAILURE;

return EXIT_SUCCESS;

}

编译$ gcc -o securitycheck securitycheck.c

使用otool工具反汇编该程序,为了方便阅读start函数已经被移除了。

$ otool -tV securitycheck

_is_session_valid:

0000000100000e70 pushq %rbp

0000000100000e71 movq %rsp,%rbp

0000000100000e74 movl %edi,0xfc(%rbp)

0000000100000e77 movl 0xfc(%rbp),%eax

0000000100000e7a andl $0x01,%eax

0000000100000e7d cmpl $0x00,%eax

0000000100000e80 jne 0x100000e8b

0000000100000e82 movl $0x00000001,0xf4(%rbp)

0000000100000e89 jmp 0x100000e92

0000000100000e8b movl $0x00000000,0xf4(%rbp)

0000000100000e92 movl 0xf4(%rbp),%eax

0000000100000e95 movl %eax,0xf8(%rbp)

0000000100000e98 movl 0xf8(%rbp),%eax

0000000100000e9b popq %rbp

0000000100000e9c ret

0000000100000e9d nopl (%rax)

_main:

0000000100000ea0 pushq %rbp

0000000100000ea1 movq %rsp,%rbp

0000000100000ea4 subq $0x10,%rsp

0000000100000ea8 movl $0x00000003,0xf4(%rbp)

0000000100000eaf movl 0xf4(%rbp),%eax

0000000100000eb2 movl %eax,%edi

0000000100000eb4 callq _is_session_valid

0000000100000eb9 movl %eax,%ecx

0000000100000ebb cmpl $0x00,%ecx

0000000100000ebe jne 0x100000ec9

0000000100000ec0 movl $0x00000001,0xf8(%rbp)

0000000100000ec7 jmp 0x100000f04

0000000100000ec9 movl 0xf4(%rbp),%eax

0000000100000ecc movl %eax,%edi

0000000100000ece callq _is_session_valid

0000000100000ed3 movl %eax,%ecx

0000000100000ed5 cmpl $0x00,%ecx

0000000100000ed8 jne 0x100000ee3

0000000100000eda movl $0x00000001,0xf8(%rbp)

0000000100000ee1 jmp 0x100000f04

0000000100000ee3 movl 0xf4(%rbp),%eax

0000000100000ee6 movl %eax,%edi

0000000100000ee8 callq _is_session_valid

0000000100000eed movl %eax,%ecx

0000000100000eef cmpl $0x00,%ecx

0000000100000ef2 jne 0x100000efd

0000000100000ef4 movl $0x00000001,0xf8(%rbp)

0000000100000efb jmp 0x100000f04

0000000100000efd movl $0x00000000,0xf8(%rbp)

0000000100000f04 movl 0xf8(%rbp),%eax

0000000100000f07 movl %eax,0xfc(%rbp)

0000000100000f0a movl 0xfc(%rbp),%eax

0000000100000f0d addq $0x10,%rsp

0000000100000f11 popq %rbp

0000000100000f12 ret

 

如你所知,is_sesssion_valid函数和main函数的定义是非常清晰的。攻击者是非常容易通过动态调试设置断点的方法修改is_session_valid函数的返回值来绕过检查。

$ gdb -q ./securitycheck

Reading symbols for shared libraries .. done

(gdb) break is_session_valid

Breakpoint 1 at 0x100000e77

(gdb) commands

Type commands for when breakpoint 1 is hit, one per line.

End with a line saying just "end".

>return 1

>continue

>end

(gdb) r

Starting program: /Users/jonz/securitycheck

Reading symbols for shared libraries +........................ done

Breakpoint 1, 0x0000000100000e77 in is_session_valid ()

Breakpoint 1, 0x0000000100000e77 in is_session_valid ()

Breakpoint 1, 0x0000000100000e77 in is_session_valid ()

Program exited normally.

(gdb)

程序在第一次调用is_session_valid时不会退出,因为调试器将is_session_valid函数值改成了1.

 

例子2inline函数和其反汇编代码

#include <stdlib.h>

inline int is_session_valid(int session_id) {

if (session_id % 2 == 0) {

return 1;

} else {

return 0;

}

}

int main( ) {

int session = 3;

if (! is_session_valid(session))

return EXIT_FAILURE;

/*

* Do something else

*/

if (! is_session_valid(session))

return EXIT_FAILURE;

/*

* Do something else

*/

if (! is_session_valid(session))

return EXIT_FAILURE;

return EXIT_SUCCESS;

}

编译, -finline-functions告诉编译器尽可能的采用inline编译方式;-Winline告诉编译器在不能使用inline编译方式编译时报错

$ gcc -o securitycheck securitycheck.c -finline-functions -Winline

使用otool工具反汇编该程序

$ otool -tV securitycheck

_is_session_valid:

0000000100000e20 pushq %rbp

0000000100000e21 movq %rsp,%rbp

0000000100000e24 movl %edi,0xfc(%rbp)

0000000100000e27 movl 0xfc(%rbp),%eax

0000000100000e2a andl $0x01,%eax

0000000100000e2d cmpl $0x00,%eax

0000000100000e30 jne 0x100000e3b

0000000100000e32 movl $0x00000001,0xf4(%rbp)

0000000100000e39 jmp 0x100000e42

0000000100000e3b movl $0x00000000,0xf4(%rbp)

0000000100000e42 movl 0xf4(%rbp),%eax

0000000100000e45 movl %eax,0xf8(%rbp)

0000000100000e48 movl 0xf8(%rbp),%eax

0000000100000e4b popq %rbp

0000000100000e4c ret

0000000100000e4d nopl (%rax)

_main:

0000000100000e50 pushq %rbp

0000000100000e51 movq %rsp,%rbp

0000000100000e54 movl $0x00000003,0xd0(%rbp)

0000000100000e5b movl 0xd0(%rbp),%eax

0000000100000e5e movl %eax,0xe4(%rbp)

0000000100000e61 movl 0xe4(%rbp),%eax

0000000100000e64 andl $0x01,%eax

0000000100000e67 cmpl $0x00,%eax

0000000100000e6a jne 0x100000e75

0000000100000e6c movl $0x00000001,0xdc(%rbp)

0000000100000e73 jmp 0x100000e7c

0000000100000e75 movl $0x00000000,0xdc(%rbp)

0000000100000e7c movl 0xdc(%rbp),%eax

0000000100000e7f movl %eax,0xe0(%rbp)

0000000100000e82 movl 0xe0(%rbp),%eax

0000000100000e85 cmpl $0x00,%eax

0000000100000e88 jne 0x100000e93

0000000100000e8a movl $0x00000001,0xd4(%rbp)

0000000100000e91 jmp 0x100000f0a

0000000100000e93 movl 0xd0(%rbp),%eax

0000000100000e96 movl %eax,0xfc(%rbp)

0000000100000e99 movl 0xfc(%rbp),%eax

0000000100000e9c andl $0x01,%eax

0000000100000e9f cmpl $0x00,%eax

0000000100000ea2 jne 0x100000ead

0000000100000ea4 movl $0x00000001,0xf4(%rbp)

0000000100000eab jmp 0x100000eb4

0000000100000ead movl $0x00000000,0xf4(%rbp)

0000000100000eb4 movl 0xf4(%rbp),%eax

0000000100000eb7 movl %eax,0xf8(%rbp)

0000000100000eba movl 0xf8(%rbp),%eax

0000000100000ebd cmpl $0x00,%eax

0000000100000ec0 jne 0x100000ecb

0000000100000ec2 movl $0x00000001,0xd4(%rbp)

0000000100000e91 jmp 0x100000f0a

0000000100000e93 movl 0xd0(%rbp),%eax

0000000100000e96 movl %eax,0xfc(%rbp)

0000000100000e99 movl 0xfc(%rbp),%eax

0000000100000e9c andl $0x01,%eax

0000000100000e9f cmpl $0x00,%eax

0000000100000ea2 jne 0x100000ead

0000000100000ea4 movl $0x00000001,0xf4(%rbp)

0000000100000eab jmp 0x100000eb4

0000000100000ead movl $0x00000000,0xf4(%rbp)

0000000100000eb4 movl 0xf4(%rbp),%eax

0000000100000eb7 movl %eax,0xf8(%rbp)

0000000100000eba movl 0xf8(%rbp),%eax

0000000100000ebd cmpl $0x00,%eax

0000000100000ec0 jne 0x100000ecb

0000000100000ec2 movl $0x00000001,0xd4(%rbp)

0000000100000ec9 jmp 0x100000f0a

0000000100000ecb movl 0xd0(%rbp),%eax

0000000100000ece movl %eax,0xf0(%rbp)

0000000100000ed1 movl 0xf0(%rbp),%eax

0000000100000ed4 andl $0x01,%eax

0000000100000ed7 cmpl $0x00,%eax

0000000100000eda jne 0x100000ee5

0000000100000edc movl $0x00000001,0xe8(%rbp)

0000000100000ee3 jmp 0x100000eec

0000000100000ee5 movl $0x00000000,0xe8(%rbp)

0000000100000eec movl 0xe8(%rbp),%eax

0000000100000eef movl %eax,0xec(%rbp)

0000000100000ef2 movl 0xec(%rbp),%eax

0000000100000ef5 cmpl $0x00,%eax

0000000100000ef8 jne 0x100000f03

0000000100000efa movl $0x00000001,0xd4(%rbp)

0000000100000f01 jmp 0x100000f0a

0000000100000f03 movl $0x00000000,0xd4(%rbp)

0000000100000f0a movl 0xd4(%rbp),%eax

0000000100000f0d movl %eax,0xd8(%rbp)

0000000100000f10 movl 0xd8(%rbp),%eax

0000000100000f13 popq %rbp

0000000100000f14 ret

新的反汇编代码有非常多的不同, is_session_valid函数不会在main函数中被调用了,而是在main函数中将is_session_valid的汇编代码拷贝了3

例子3static inline函数和其反汇编代码

#include <stdlib.h>

static int is_session_valid(int session_id) __attribute__((always_inline));

int is_session_valid(int session_id) {

if (session_id % 2 == 0) {

return 1;

} else {

return 0;

}

}

...

反汇编

$ otool -tV securitycheck

securitycheck:

(__TEXT,__text) section

start:

0000000100000e40 pushq $0x00

0000000100000e42 movq %rsp,%rbp

0000000100000e45 andq $0xf0,%rsp

0000000100000e49 movq 0x08(%rbp),%rdi

0000000100000e4d leaq 0x10(%rbp),%rsi

0000000100000e51 movl %edi,%edx

0000000100000e53 addl $0x01,%edx

0000000100000e56 shll $0x03,%edx

0000000100000e59 addq %rsi,%rdx

0000000100000e5c movq %rdx,%rcx

0000000100000e5f jmp 0x100000e65

0000000100000e61 addq $0x08,%rcx

0000000100000e65 cmpq $0x00,(%rcx)

0000000100000e69 jne 0x100000e61

0000000100000e6b addq $0x08,%rcx

0000000100000e6f callq _main

0000000100000e74 movl %eax,%edi

0000000100000e76 callq 0x100000f46 ; symbol stub for: _exit

0000000100000e7b hlt

0000000100000e7c nop

0000000100000e7d nop

0000000100000e7e nop

0000000100000e7f nop

_main:

0000000100000e80 pushq %rbp

0000000100000e81 movq %rsp,%rbp

0000000100000e84 movl $0x00000003,0xd0(%rbp)

0000000100000e8b movl 0xd0(%rbp),%eax

0000000100000e8e movl %eax,0xe4(%rbp)

0000000100000e91 movl 0xe4(%rbp),%eax

0000000100000e94 andl $0x01,%eax

0000000100000e97 cmpl $0x00,%eax

...

因为声明了static 属性,反汇编代码中没有了符号表说明,因此使得攻击者难以通过反汇编代码弄清楚程序的逻辑。方法3中将讲述另一种从二进制代码中隐藏符号表的方法,特别是在不能将函数声明为static时比较适用。

  评论这张
 
阅读(1092)| 评论(0)
推荐

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017