so加固-加密特定section中的内容

本文参考自:Android逆向之旅—基于对so中的section加密技术实现so加固,增加了自己的实践过程,以及一些额外的验证和解释。

本文代码参见:https://github.com/difcareer/SoEncrypt

Android逆向之旅—基于对so中的section加密技术实现so加固 这篇文章写得真心好,建议先阅读一下原著,这里只是自己的实践过程(纸上得来终觉浅,绝知此事要躬行),和一些更细节的解释罢了。

一. 拆分section

这个demo的目的是为了将native函数getString()给保护起来(实际应用场景就是自己业务中的核心代码)。为了保护getString(),用到了gcc的Attributes特性

__attribute__((section ("xxx")))

上述的文档中提到,给变量或者方法增加这个修饰后,编译器将把对应的代码或者数据放到你指定的section中。 我们的demo中做了示例:

__attribute__((section (".encrypt"))) jstring getString(JNIEnv* env) {
    static const char* txt __attribute__((section (".encrypt2"))) = "Str from native";
    return (*env)->NewStringUTF(env, txt);
};

我们同时给getString()函数和txt变量添加了这个属性,分别指定了不同名称。我们看一下编译后的so:

Paste_Image.png

Paste_Image.png

Paste_Image.png

可以看到新增了我们自定义的section: encrypt、encrypt2,encrypt中存放getString()的代码,因此被映射为可执行,encrypt2中存放txt的数据,因此被映射为可写。

ok,到这里我们已经找到拆分核心代码到单独section的方法了。后续我们只要对这些section做加密即可保护核心代码。

二. 寻找解密时机

假设我们已经加密了这些section,运行的时候总是需要解密还原的,什么时机解密最好呢,当然是越早越好,最早可以在load so之后,执行JNI_Onload之前,这里也是需要gcc的另外一个Attributes特性

__attribute__((constructor (n)))

文档中指出,constructor (priority)可以在后面指定一个优先级,数字越小,优先级越高,越先被执行。

关于这点我们在demo中也做了验证:

void init_1() __attribute__((constructor (3)));
void init_getString() __attribute__((constructor (2)));
void init_2() __attribute__((constructor (1)));

我们申明了3个函数,优先级从低到高,按照规则,执行顺序应该是:init_2、init_getString、init_1,我们看一下so:

Paste_Image.png

已经按照优先级调整好了顺序。

我们看下日志:

Paste_Image.png

的确也是这个顺序。 ok,这样我们就可以在这个特性的修饰下,尽早能做解密逻辑了。

三. 加密逻辑

先说一下加密,作者的加密算法很简单:字节取反。在misc/encrpt.c中,我们可以发现其核心逻辑是寻找叫做 encrypt 的 section,然后字节取反写回,同时计算将一些值计算了写入ehdr.e_entry(这个对于正常的so是0值)和ehdr.e_shoff(这个是section表的偏移量,修改这个值将导致找不到section,后面会看到加密效果),这些值在解密的时候需要。 demo的misc下有编译后的脚本encrpt,需要在linux环境下执行,libencrypt.so是没有加密前的so,libencrypt2.so是加密后的so。你可以自行使用beyond compare比较差异。

四. 解密逻辑

回到最重要的解密逻辑了,我们在__attribute__((constructor (n)))修饰的方法init_getString()中实现了解密逻辑,其原理是,通过读取/proc/pid/maps中的内容,找到so被映射到内存中的地址,然后通过ehdr.e_entry和ehdr.e_shoff中的内容还原出decrypt section 的地址,字节取反恢复,内存写回。这样就做到了动态解密了。

五. 加密效果

使用ida打开misc/libencrypt2.so

Paste_Image.png

提示这个是因为修改了ehdr.e_shoff,破坏了第一个section 类型为SHT_NULL的规则。

Paste_Image.png

下一步直接解析section 报错。

Paste_Image.png

正常的section都看不到了,看到的都是program sections(上一个图的提示)。

而apk可以正常运行(加密后的apk为misc/signed.apk):

Paste_Image.png

参考链接: http://www.wjdiankong.cn/android%e9%80%86%e5%90%91%e4%b9%8b%e6%97%85-%e5%9f%ba%e4%ba%8e%e5%af%b9so%e4%b8%ad%e7%9a%84section%e5%8a%a0%e5%af%86%e6%8a%80%e6%9c%af%e5%ae%9e%e7%8e%b0so%e5%8a%a0%e5%9b%ba/ https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Variable-Attributes.html https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Seebug漏洞平台

CVE-2015-2545 Word 利用样本分析

0 引子 在上一篇文章中,我们分析了 Office 文档型漏洞 CVE-2015-1641 的利用,本文将继续对此类漏洞中的另一常见案例 CVE-2015...

34570
来自专栏智能大石头

STM32/GD32上内存堆栈溢出探测研究

无数次遭受堆栈溢出折磨,随着系统变得复杂,故障点越来越难以查找! 主要溢出情况如下: 1,一般RAM最后两块空间是堆Heap和栈Stack,堆从下往上用,栈从上...

26970
来自专栏分布式系统和大数据处理

C#网络编程(同步传输字符串) - Part.2

在与服务端的连接建立以后,我们就可以通过此连接来发送和接收数据。端口与端口之间以流(Stream)的形式传输数据,因为几乎任何对象都可以保存到流中,所以实际上可...

13030
来自专栏乐沙弥的世界

Linux/Unix shell sql 之间传递变量

       灵活结合Linux/Unix Shell 与SQL 之间的变量传输,极大程度的提高了DBA的工作效率,本文针对Linux/Unix shell s...

10130
来自专栏逆向技术

16位汇编语言第二讲系统调用原理,以及各个寄存器详解

   16位汇编语言第二讲系统调用原理,以及各个寄存器详解 昨天已将简单的写了一下汇编代码,并且执行了第一个显示到屏幕的helloworld 问题?   hel...

24400
来自专栏kangvcar

MongoDB 入门极简教程

11710
来自专栏AzMark

Python 学习之面向对象「下」

13530
来自专栏岑玉海

hbase源码系列(十三)缓存机制MemStore与Block Cache

这一章讲hbase的缓存机制,这里面涉及的内容也是比较多,呵呵,我理解中的缓存是保存在内存中的特定的便于检索的数据结构就是缓存。 之前在讲put的时候,put是...

52170
来自专栏游戏开发那些事

【Linux程序设计】之环境系统函数综合实验

这个系列的博客贴的都是我大二的时候学习Linux系统高级编程时的一些实验程序,都挺简单的。贴出来纯粹是聊胜于无。

15830
来自专栏Scott_Mr 个人专栏

RxSwift 系列(一) -- Observables

38070

扫码关注云+社区

领取腾讯云代金券