写点什么

【iOS 逆向与安全】使用 ollvm 混淆你的源码

作者:小陈
  • 2023-02-27
    四川
  • 本文字数:7976 字

    阅读完需:约 26 分钟

前言

当你在研究别人源码的时候,是不是期望着别人代码没有进行任何的防护和混淆。这时的你,是不是应该考虑一下自己代码的安全.本篇文章将告诉你,如何使用 ollvm 来混淆 iOS 端的代码【此文为入门贴,大佬请绕道】。



一、目标

编译 ollvm 工具,并在 Xcode 中来混淆你的 ipa 或动态库,增加别人破解你源码的难度。

二、工具

  • ollvm:下载地址:https://github.com/heroims/obfuscator

  • Xcode:iOS 开发工具

三、步骤

1、基础知识

LLVM

LLVM(Low Level Virtual Machine)是一个开源的编译器基础架构,它包含了一组模块化、可重用的编译器和工具,支持多种编程语言和目标架构,包括 x86、ARM 和 MIPS 等。LLVM 最初由美国伊利诺伊大学香槟分校(University of Illinois at Urbana–Champaign)的 Chris Lattner 教授开发,现在由 LLVM 社区进行维护和发展。


LLVM 的核心思想是将编译器分为前端和后端两个部分,前端负责将源代码转换为中间表示(IR),后端负责将中间表示转换为目标机器的汇编代码。这种设计使得 LLVM 可以支持多种编程语言,因为只需要为每种语言编写一个前端,就可以利用后端的通用性支持多种目标架构。


除了编译器之外,LLVM 还包括了一些工具,例如优化器、调试器、汇编器和反汇编器等,这些工具可以帮助开发者更好地分析和调试程序,提高代码的性能和可靠性。


LLVM 已经成为了广泛使用的编译器基础架构,许多编程语言和工具链都采用了 LLVM 作为后端,例如 C、C++、Objective-C、Swift、Rust、Go 等。LLVM 还被广泛应用于计算机体系结构研究、代码安全性分析、机器学习等领域。


Clang

Clang 是基于 LLVM 框架的 C、C++、Objective-C 和 Objective-C++编译器,它是一个开源项目,由 LLVM 社区进行开发和维护。Clang 的设计目标是提供高质量的诊断、快速的编译速度、低内存占用和良好的可移植性。


Clang 的编译器前端使用了现代的编译器架构,包括基于词法分析器和语法分析器的语法分析,生成抽象语法树(AST)并进行类型检查和语义分析等步骤。这些步骤的优化和并行化使得 Clang 能够快速地进行编译,同时提供了更好的错误和警告信息,有助于开发者更快地发现和修复代码中的问题。


除了作为独立的编译器之外,Clang 还可以作为其他工具的库使用,例如静态分析工具、编辑器插件和代码重构工具等。Clang 的模块化设计和良好的 API 使得它可以轻松地被集成到其他工具中,从而提供更好的编程体验。


由于 Clang 的优秀性能和良好的设计,它已经成为了许多项目的首选编译器,例如 LLVM 自身、macOS 和 iOS 的默认编译器等。同时,许多开发者和组织也在积极地开发和贡献 Clang 的代码,使得它在未来仍有广阔的发展空间。

OLLVM

OLLVM(Obfuscator-LLVM)是基于 LLVM 框架的混淆器,它可以对程序进行混淆以提高程序的安全性。OLLVM 的设计目标是提供一种灵活的、可定制的混淆方案,使得攻击者更难理解和分析程序的行为。


OLLVM 通过对程序进行多种混淆操作来实现混淆效果,例如代码替换、函数内联、控制流平坦化、加密等。这些混淆操作可以改变程序的控制流图和数据流图,使得程序更难以被理解和逆向分析。同时,OLLVM 还提供了一些额外的安全机制,例如加密程序的字符串、使用栈保护和位置无关代码等,以增加程序的安全性。


由于 OLLVM 是基于 LLVM 框架开发的,它可以与现有的 LLVM 工具和编译器集成,例如 Clang 和 LLDB 等。这使得开发者可以轻松地在现有的开发环境中使用 OLLVM,并且可以使用现有的工具对混淆后的程序进行调试和分析。


尽管 OLLVM 的主要目的是提高程序的安全性,但它也可以用于其他领域,例如代码保护、代码压缩和代码优化等。由于其灵活性和可定制性,OLLVM 已经被广泛应用于许多领域,例如网络安全、游戏开发和金融等。



IR 之间的 pass,就是混淆器工作的地方。相关代码位于obfuscator/llvm/lib/Transforms/Obfuscation/

2、编译 ollvm

命令如下:


witchan@witchandeMacBook-Air ~ % git clone -b llvm-13.x https://github.com/heroims/obfuscator.gitwitchan@witchandeMacBook-Air ~ % $cd obfuscatorwitchan@witchandeMacBook-Air ~ % mkdir buildwitchan@witchandeMacBook-Air ~ % cd buildwitchan@witchandeMacBook-Air ~ % cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF ../llvmwitchan@witchandeMacBook-Air ~ % make -j8witchan@witchandeMacBook-Air ~ % sudo make install-xcode-toolchainwitchan@witchandeMacBook-Air ~ % mv /usr/local/Toolchains  /Library/Developer/
复制代码


注:make -j8这命令编译的快慢,取决于你的硬件设备


挨个执行以上命令后,ollvm 就编译并安装完成,效果如下:


3、混淆命令及效果对比

混淆命令简介


  • fla:该选项使用函数级别的混淆来隐藏程序的结构。这通过随机重命名函数、添加不必要的控制流和删除调用的函数来实现。这增加了反编译和分析代码的难度。

  • bcf:该选项使用基本块级别的混淆来隐藏代码的结构。这通过改变基本块之间的控制流、添加不必要的基本块和移除基本块之间的条件分支来实现。

  • -sub:该选项使用字符串混淆来隐藏代码中的常量字符串。这通过将字符串分成几个小块、将其存储在数组中并在运行时重新组合来实现。这使得分析代码和查找敏感信息更加困难。

  • split:该选项使用控制流混淆来增加程序的复杂性。这通过将函数分成几个基本块、添加随机的跳转指令和在运行时随机重组这些基本块来实现。这使得代码的流程更难以跟踪,从而增加了破解和反编译的难度。

  • sobf:该选项使用源代码混淆技术来隐藏代码的逻辑和结构。这通过使用类似加密的方式对代码进行变换,使其难以理解和分析。这可以通过运行时解密来执行,从而隐藏代码的真实功能。


示例代码如下:


- (void)testMethod {    NSString *name = @"wit";    int age = 18;        NSArray *list = @[@1,@3,@5,@18];    for (int i=0; i<list.count; i++) {        int value = [list[i] intValue];        if (value == age) {            age += 10;            name = @"chan";        }    }    NSLog(@"name = %@", name);    NSLog(@"age = %d", age);}
复制代码


未使用混淆:


__int64 __fastcall -[ViewController testMethod](__int64 a1, __int64 a2){  void *v2; // x0  __int64 v3; // ST70_8  void *v4; // x0  __int64 v5; // ST68_8  void *v6; // x0  __int64 v7; // ST60_8  void *v8; // x0  __int64 v9; // ST58_8  void *v10; // x0  void *v11; // x0  void *v12; // ST20_8  int v13; // ST2C_4  __int64 result; // x0  int i; // [xsp+7Ch] [xbp-54h]  void *v16; // [xsp+80h] [xbp-50h]  int v17; // [xsp+8Ch] [xbp-44h]  __int64 v18; // [xsp+90h] [xbp-40h]  __int64 v19; // [xsp+98h] [xbp-38h]  __int64 v20; // [xsp+A0h] [xbp-30h]  __int64 v21; // [xsp+A8h] [xbp-28h]  __int64 v22; // [xsp+B0h] [xbp-20h]  __int64 v23; // [xsp+B8h] [xbp-18h]  __int64 v24; // [xsp+C0h] [xbp-10h]  __int64 v25; // [xsp+C8h] [xbp-8h]
v25 = *(_QWORD *)__stack_chk_guard_ptr; v20 = a1; v19 = a2; v18 = objc_retain(&stru_100008078); v17 = 18; v2 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 1LL); v3 = objc_retainAutoreleasedReturnValue(v2); v21 = v3; v4 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 3LL); v5 = objc_retainAutoreleasedReturnValue(v4); v22 = v5; v6 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 5LL); v7 = objc_retainAutoreleasedReturnValue(v6); v23 = v7; v8 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 18LL); v9 = objc_retainAutoreleasedReturnValue(v8); v24 = v9; v10 = objc_msgSend(off_10000D2D8, (const char *)off_10000D298, &v21, 4LL); v16 = (void *)objc_retainAutoreleasedReturnValue(v10); objc_release(v9); objc_release(v7); objc_release(v5); objc_release(v3); for ( i = 0; i < (unsigned __int64)objc_msgSend(v16, (const char *)off_10000D2A0); ++i ) { v11 = objc_msgSend(v16, (const char *)off_10000D2A8, i); v12 = (void *)objc_retainAutoreleasedReturnValue(v11); v13 = (unsigned __int64)objc_msgSend(v12, (const char *)off_10000D2B0); objc_release(v12); if ( v13 == v17 ) { v17 += 10; objc_storeStrong(&v18); } } NSLog(&stru_1000080B8); NSLog(&stru_1000080D8); objc_storeStrong(&v16); result = objc_storeStrong(&v18); *(_QWORD *)__stack_chk_guard_ptr; return result;}
复制代码


开启 ollvm 混淆:







混淆参数:-mllvm -fla -mllvm -bcf -mllvm -sub -mllvm -split -mllvm -sobf


混淆后效果如下:


__int64 __fastcall -[ViewController testMethod](__int64 a1, __int64 a2){  void *v2; // x0  void *v3; // x0  __int64 v4; // ST58_8  void *v5; // x0  __int64 v6; // ST50_8  void *v7; // x0  __int64 v8; // ST48_8  void *v9; // x0  void *v10; // x0  signed int v11; // w8  BOOL v12; // w9  signed int v13; // w8  BOOL v14; // w9  signed int v15; // w8  BOOL v16; // w14  signed int v17; // w8  void *v18; // x0  void *v19; // ST20_8  int v20; // ST2C_4  BOOL v21; // w12  signed int v22; // w8  BOOL v23; // w9  signed int v24; // w8  BOOL v25; // w12  signed int v26; // w8  signed int v27; // w8  BOOL v28; // w9  signed int v29; // w8  BOOL v30; // w12  signed int v31; // w8  BOOL v32; // w14  signed int v33; // w8  BOOL v34; // w9  signed int v35; // w8  void *v37; // x0  void *v38; // ST08_8  int v39; // ST14_4  signed int v40; // [xsp+94h] [xbp-DCh]  int v41; // [xsp+98h] [xbp-D8h]  int v42; // [xsp+9Ch] [xbp-D4h]  void *v43; // [xsp+A0h] [xbp-D0h]  int v44; // [xsp+ACh] [xbp-C4h]  __int64 v45; // [xsp+B0h] [xbp-C0h]  __int64 v46; // [xsp+B8h] [xbp-B8h]  __int64 v47; // [xsp+C0h] [xbp-B0h]  __int64 v48; // [xsp+C8h] [xbp-A8h]  __int64 *v49; // [xsp+D0h] [xbp-A0h]  const char *v50; // [xsp+D8h] [xbp-98h]  void *v51; // [xsp+E0h] [xbp-90h]  __int64 v52; // [xsp+E8h] [xbp-88h]  unsigned __int64 v53; // [xsp+F0h] [xbp-80h]  const char *v54; // [xsp+F8h] [xbp-78h]  void *v55; // [xsp+100h] [xbp-70h]  void *v56; // [xsp+108h] [xbp-68h]  __int64 v57; // [xsp+110h] [xbp-60h]  bool v58; // [xsp+11Fh] [xbp-51h]  __int64 *v59; // [xsp+120h] [xbp-50h]  int v60; // [xsp+128h] [xbp-48h]  int v61; // [xsp+12Ch] [xbp-44h]  __int64 v62; // [xsp+130h] [xbp-40h]  __int64 v63; // [xsp+138h] [xbp-38h]  __int64 v64; // [xsp+140h] [xbp-30h]  __int64 v65; // [xsp+148h] [xbp-28h]  __int64 v66; // [xsp+150h] [xbp-20h]  __int64 v67; // [xsp+158h] [xbp-18h]
v67 = *(_QWORD *)__stack_chk_guard_ptr; v47 = a1; v46 = a2; v45 = objc_retain(&stru_10000C078); v44 = 18; v2 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 1LL); v48 = objc_retainAutoreleasedReturnValue(v2); v63 = v48; v49 = &v64; v50 = (const char *)off_100011290; v51 = off_1000112D0; v40 = -1933834049; while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( v40 == -1944675086 ) { v23 = x_24 * (x_24 - 1) % 2u == 0; if ( ((unsigned __int8)v23 & (y_25 < 10) | v23 ^ (y_25 < 10)) & 1 ) v24 = -484710506; else v24 = -757913245; v40 = v24; } if ( v40 != -1933834049 ) break; v3 = objc_msgSend(v51, v50, 3LL); v52 = objc_retainAutoreleasedReturnValue(v3); v40 = -1240448313; } if ( v40 != -1917278325 ) break; v40 = 1916623537; } if ( v40 != -1863636706 ) break; if ( v58 ) v27 = -1295475565; else v27 = -706815919; v40 = v27; } if ( v40 != -1847141909 ) break; v10 = objc_msgSend(v55, v54); if ( v53 >= (unsigned __int64)v10 ) v11 = 1801130365; else v11 = 1380523063; v40 = v11; } if ( v40 != -1846767803 ) break; v40 = -267481379; } if ( v40 != -1502917571 ) break; v54 = (const char *)off_1000112A0; v55 = v43; v40 = -1847141909; } if ( v40 == -1361227290 ) break; switch ( v40 ) { case -1295475565: v44 += 10; v40 = 1987329712; break; case -1240448313: v4 = v52; *v49 = v52; v5 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 5LL); v6 = objc_retainAutoreleasedReturnValue(v5); v65 = v6; v7 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 18LL); v8 = objc_retainAutoreleasedReturnValue(v7); v66 = v8; v9 = objc_msgSend(off_1000112D8, (const char *)off_100011298, &v63, 4LL); v43 = (void *)objc_retainAutoreleasedReturnValue(v9); objc_release(v8); objc_release(v6); objc_release(v4); objc_release(v48); v42 = 0; v40 = -381231803; break; case -1088106110: v40 = -1361227290; break; case -1009849083: v61 = v60 + 1; v40 = -792637388; break; case -792637388: v42 = v61; v40 = -381231803; break; case -757913245: v40 = -484710506; break; case -706815919: v40 = 975706093; break; case -484710506: v58 = v41 == v44; v25 = x_24 * (x_24 - 1) % 2u == 0; if ( (!v25 ^ (y_25 >= 10) | (v25 && y_25 < 10)) & 1 ) v26 = -1863636706; else v26 = -757913245; v40 = v26; break; case -381231803: v53 = v42; v40 = -1502917571; break; case -267481379: v56 = v43; v57 = v42; v14 = x_24 * (x_24 - 1) % 2u == 0; if ( ((unsigned __int8)v14 & (y_25 < 10) | v14 ^ (y_25 < 10)) & 1 ) v15 = -1917278325; else v15 = -1846767803; v40 = v15; break; case 265667512: v60 = v42; v30 = x_24 * (x_24 - 1) % 2u == 0; if ( (!v30 ^ (y_25 >= 10) | (v30 && y_25 < 10)) & 1 ) v31 = 1998138173; else v31 = 1042960370; v40 = v31; break; case 543048662: NSLog(&stru_10000C0B8); NSLog(&stru_10000C0D8); v34 = x_24 * (x_24 - 1) % 2u == 0; if ( ((unsigned __int8)v34 & (y_25 < 10) | v34 ^ (y_25 < 10)) & 1 ) v35 = -1088106110; else v35 = 1393219629; v40 = v35; break; case 818848043: v37 = objc_msgSend(v56, (const char *)off_1000112A8, v57); v38 = (void *)objc_retainAutoreleasedReturnValue(v37); v39 = (unsigned __int64)objc_msgSend(v38, (const char *)off_1000112B0); objc_release(v38); v41 = v39; v40 = 1041770448; break; case 975706093: v28 = x_24 * (x_24 - 1) % 2u == 0; if ( ((unsigned __int8)v28 & (y_25 < 10) | v28 ^ (y_25 < 10)) & 1 ) v29 = 265667512; else v29 = 1042960370; v40 = v29; break; case 1041770448: v18 = objc_msgSend(v56, (const char *)off_1000112A8, v57); v19 = (void *)objc_retainAutoreleasedReturnValue(v18); v20 = (unsigned __int64)objc_msgSend(v19, (const char *)off_1000112B0); objc_release(v19); v41 = v20; v21 = x_24 * (x_24 - 1) % 2u == 0; if ( (!v21 ^ (y_25 >= 10) | (v21 && y_25 < 10)) & 1 ) v22 = 2069967268; else v22 = 818848043; v40 = v22; break; case 1042960370: v40 = 265667512; break; case 1146841418: v32 = x_24 * (x_24 - 1) % 2u == 0; if ( (v32 ^ (y_25 < 10) | (v32 && y_25 < 10)) & 1 ) v33 = 543048662; else v33 = 1393219629; v40 = v33; break; case 1380523063: v12 = x_24 * (x_24 - 1) % 2u == 0; if ( ((unsigned __int8)v12 & (y_25 < 10) | v12 ^ (y_25 < 10)) & 1 ) v13 = -267481379; else v13 = -1846767803; v40 = v13; break; case 1393219629: NSLog(&stru_10000C0B8); NSLog(&stru_10000C0D8); v40 = 543048662; break; case 1801130365: v62 = v45; v40 = 1146841418; break; case 1916623537: v16 = x_24 * (x_24 - 1) % 2u == 0; if ( (v16 ^ (y_25 < 10) | (v16 && y_25 < 10)) & 1 ) v17 = 1041770448; else v17 = 818848043; v40 = v17; break; case 1987329712: v59 = &v45; v40 = 2123926658; break; case 1998138173: v40 = -1009849083; break; case 2069967268: v40 = -1944675086; break; case 2123926658: objc_storeStrong(v59); v40 = -706815919; break; } } objc_storeStrong(&v43); return objc_storeStrong(&v45);}
复制代码



总结

简单的入门文章,希望能帮助到你。


提示:阅读此文档的过程中遇到任何问题,请关住工众好【移动端Android和iOS开发技术分享】或+99 君羊【812546729



发布于: 刚刚阅读数: 4
用户头像

小陈

关注

和昨天不一样 2019-03-12 加入

公众号:移动端Android和iOS开发技术分享

评论

发布
暂无评论
【iOS逆向与安全】使用ollvm混淆你的源码_ios开发_小陈_InfoQ写作社区