灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:3267回复:0

[系统教程]objective-c runtime安全措施之三:反汇编(inline编译方式)

楼主#
更多 发布于:2012-09-10 17:40

《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.

例子2:inline函数和其反汇编代码
#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次
例子3:static 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时比较适用。


作者  danqingd


喜欢0 评分0
游客

返回顶部