原文地址:http://reverse.put.as/2012/02/02/anti-disassembly-obfuscation-1-apple-doesnt-follow-their-own-mach-o-specifications/

当想到这个特性时,我非常高兴!因为我喜欢突破束缚,并且写了一个CrackMe来展示这个有趣的特性。

产生问题的原因是:苹果没有遵循自己的文档与标准(Mach-O方面的),但是逆向工具却要遵循。

当逆向修改过Section信息的Mach-O文件时,IDA可能会崩溃、输出错误的反汇编结果、混乱的字符串,

LLDB输出错误的反汇编结果(不是GDB),class-dump 会失败,逆向工程师看到是无意义的Mach-O文件头。

最后,这是一个有趣的混淆手段。^_^

 

当你使用IDA加载CrackMe时,程序会报这样的错误:负的Section大小或偏移。

当Sections的信息(偏移或者大小)超过文件大小时,otool也会输出错误的结果。

 

造成这个问题的具体方法是:修改Mach-O的Section信息。在32位下,Section的结构如下:

  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. };

 

让我们从最容易引起问题的offset字段说起。根据标准offset的定义如下:指示当前Section在文件中的偏移值。

我的理解是:这个字段用来指示代码或者数据在文件的位置。这么理解没错吧?

既然是一个偏移值,那么理论上Section是没有必要是按照顺序排列的或者按照指定的循序排列(主要是指:没有必要跟Section在Segment中顺序一致)。这就打开了错误之门。

 

如果我们将offset指向其他地址?比如:IDA需要根据offset指向的地址来读取相应的数据。

我们来做一个测试,修改cstring setion的偏移值,然后使用IDA加载修改后的文件。

喔,现在程序中的字符串被“混淆”了,因为IDA加载了错误的数据。

 

很有意思,是吗?如果你修改Section信息(将offset改成一个错误的值),然后运行对应的程序,程序的行为还完全正确!

同样,修改 text section的便宜后,程序的中指令应该都错了,但是程序还是可以正常运行。

 

为什么程序还可以正确运行?这是非常有趣的。我认为主要的原因是:内核只是将文件线性的加载到内存而忽略了offset。

《Mac OS X Internal》812页中对execve()系统调用的说明可以解释问题原因。

exec_mach_imgact()函数(bsd/kern/kern_exec.c)会调用load_machfile()函数,

后者主要用来加载可执行文件,处理具体的Mach-O加载命令等。代码片段如下:

@bsd/kern/kern_exec.c

  1. /*
  2. * Actually load the image file we previously decided to load.
  3. */
  4. lret = load_machfile(imgp, mach_header, thread, map, &load_result);

在load_machfile()内部会调用parse_machfile()函数来解析文件,

@bsd/kern/mach_loader.c

  1. lret = parse_machfile(vp, map, thread, header, file_offset, macho_size,
  2. 0, result);

在这里我们可以看到有趣的注释:

  1. /*
  2. * The file size of a mach-o file is limited to 32 bits; this is because
  3. * this is the limit on the kalloc() of enough bytes for a mach_header and
  4. * the contents of its sizeofcmds, which is currently constrained to 32
  5. * bits in the file format itself. We read into the kernel buffer the
  6. * commands section, and then parse it in order to parse the mach-o file
  7. * format load_command segment(s). We are only interested in a subset of
  8. * the total set of possible commands.
  9. */

 

在实现的下部,我们可以看到处理所有command的循环,其中section command是在segment(LC_SEGMENT/LC_SEGMENT_64)command下处理的。

因为我们需要看下load_segment()的实现。

在load_segment()内,我们发现对于可执行文件合法性的验证只是做到了segment一层,并没有验证section。

这也造成我们没法混淆segment :-))。

 

当parse_machfile()函数返回时,所有的解析工作已经完成,链接的库被加载,程序的入口函数被调用。

程序的布局与其在文件系统中一致(这就是我前面所说的线性),并且section信息根本没有被使用。

这是一种隐性的约定:可执行文件的格式是正确的。

 

这种行为(指内核加载可执行文件)正确吗?我认为是错误的。因为内核并没有遵循Mach-O标准,或者是我对标准理解有错误?

这又是一个信任不可信数据的例子,我们应该显式的校验输入数据。

 

我们应该继续了解真个加载过程,在CrackMe中还有另一个有趣的特性;-)。

 

我们还可以改变这些section结构的这些字段:flags,size, section和segment的名字,section 的顺序。

这样可以迷惑工具和逆向工程师。这里需要注意的是跟内核遵循同样的隐式约定,忽略如上的字段。

看起来有点怪异,是吧?

 

我希望你享受如上的分析过程,并且为你带来阅读xnu与dyld源代码的动力。

 

Have fun,

fG!

 

更新 1:

如下是本文观点的PoC。代码是32位的、non-fat mach-o文件、控制台程序。如果在Objective-C目标上应用这个特性,

会引起加载错误,因为并不是所有的 section 都可以被混淆。

manglemacho.c.gz

SHA256(manglemacho.c.gz)= d79a612b72130732d7e47b2925fba7fc0b63824622d05f08e7f33641d522a8b5

更新 2:

实际的情况是上section 的所有字段都可以是0,并不会带来什么不利的影响(除了mod_init_func)。

我这样试过,但是没有做笔记。如果不做更深入的混淆,IDA有时还可以聪明得进行反汇编,

原因是入口地址是合法的。我们可以通过修改 size 和 offset 来对IDA进行更深入的迷惑。

通过设置如下工具的第二个参数可以将 section 的所有字段都设置成0.

manglemacho_v0.3.c.gz
SHA256(manglemacho_v0.3.c.gz)= 4b33dc5f43bbb9114e6a8c18dba8894ca44b991cd69a5e5e54bfdcd03607fc9c

.

[译]反-反汇编 & 混淆 #1: 苹果没有遵循自己制定的Mach-O规范?的更多相关文章

  1. 【Android 应用开发】 Android APK 反编译 混淆 反编译后重编译

    反编译工具 : 总结了一下 linux, windows, mac 上的版本, 一起放到 CSDN 上下载; -- CSDN 下载地址 : http://download.csdn.net/detai ...

  2. 格式化用jad反编译混淆过的代码,能去大部分错误 (zhuanzai)

    http://blog.csdn.net/chruan/article/details/8484783

  3. (Unity)Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进展混淆,避免被反编译

    Unity自定义Debug日志文件,利用VS生成Dll文件并使用Dotfuscated进行混淆,避免被反编译. 1.打开VS,博主所用版本是Visual Studio 2013. 2.新建一个VC项目 ...

  4. C#使用Xamarin开发可移植移动应用进阶篇(9.混淆代码,防止反编译)

    前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. 今天讲讲如 ...

  5. (译)UEFI 启动:实际工作原理

    本文是我翻译自国外技术博客的一篇文章,其中讲述了 UEFI 的一些基本概念和细节. 本文的原始链接位于: https://www.happyassassin.net/2014/01/25/uefi-b ...

  6. [C#防止反编译].NET 产品版权保护方案 (.NET源码加密保护)

    [C#防止反编译].NET 产品版权保护方案 (.NET源码加密保护) 标签: .net加密产品c#dll工具 2011-03-24 21:06 27009人阅读 评论(13) 收藏 举报 分类: C ...

  7. REST API设计指导——译自Microsoft REST API Guidelines(四)

    前言 前面我们说了,如果API的设计更规范更合理,在很大程度上能够提高联调的效率,降低沟通成本.那么什么是好的API设计?这里我们不得不提到REST API. 关于REST API的书籍很多,但是完整 ...

  8. java 反编译 android 反编译

    1. jad http://varaneckas.com/jad/jad158e.linux.intel.zip  下载jad, 给jad运行权限 ,运行 chmod a+x ./jad ./jad ...

  9. Javascript变量名混淆细节

    前言 UglifyJS会对JS文件的变量名进行混淆处理.要理解Javascript变量混淆的细节.我们须要回答下面几个问题: 1.遇到一个变量myName,我们怎么知道这个myName变量要不要混淆 ...

随机推荐

  1. 采纳ajax提交POST样本数据

    问题叙述性说明 我们会form该input和checkbox提交给异步数据phpserver.处理后的回. 提交之后显示的位置: 难点分析 採用from表单的onsubmit属性阻止表单的提交 < ...

  2. vs2012代码段,快捷键,snippet 的使用

    这篇还是介绍怎么简单我们编写代码------本想放在上一篇   插件    一起,但是怕搜不到, 大神们就没法给我教更好的方式,所以就另写了一篇 [大家看完后,插件resharp如果能实现这效果,请教 ...

  3. Jquery Jqprint—随着Jquery Jqprint实现网页打印

    研究关于利用空闲时间今天Jquery Jqprint插入,用这个Jquery脚本就可以实现轻松打印指定的页面内容功能区: 样品A: <!DOCTYPE html PUBLIC "-// ...

  4. HTML5 画一张图

    笔者:本笃庆军 原文地址:http://blog.csdn.net/qingdujun/article/details/33344289 一.绘制图像 使用drawImage()方法绘制图像. 画图环 ...

  5. 试想一下,在代码学习Swift!

    文件       https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11       htt ...

  6. 计算4000000000内的最大f(n)=n值---字符串的问题python实现(五岁以下儿童)

    问题: 写一个函数,计算4 000 000 000 以内的最大的那个f(n)=n的值,函数f的功能是统计全部0到n之间全部含有数字1的数字和.比方:f(13)= 6,由于"1"在& ...

  7. BIZTALK项目中WEB引用WEBSERVICES服务时候报错

    近期工作中须要完毕通过BIZTALK完毕调用WEBLOGIC公布的WebServices服务,环境搭建好后,打开VS开发工具新建一个BIZTALK项目,加入WEB引用将对方公布的地址拷贝上去,能够正常 ...

  8. [使用]Git--命令行

    如何利用终端命令将文件上传到github远程服务器 (1) git status 命令查看下状态. (2) git pull 更新代码,确保代码是库上最新代码,防止覆盖其他人的提交. (3) git ...

  9. 使用Visual Studio创建映像向导(Image Sprite)——Web Essential

    原版的:Creating Image Sprite in Visual Studio - Web Essential 译者注:有关图片精灵的信息请參阅http://baike.baidu.com/vi ...

  10. Socket 学习(三).5 UDP 的弱点

    前面 讲到了,udp 传输文本的例子,发现 udp 确实 比tcp 高效一些,现在我用来传输文件,问题果然来了,结果发现 他不能一次 传输大于 64K的东西! 那么 我自然想到了 切包,多次发送,再合 ...