隐藏smali方法后

java源码:

int b = fun2();

baksmali解释为:

invoke-virtual                  {v1}, <int MainActivity.fun2() imp. @ _def_MainActivity_fun2@I>

查看字节码:

6E 10 4E 32 01 00

6E 为  OP_INVOKE_VIRTUAL

要看 OP_INVOKE_VIRTUAL 指令的字节码格式,解释器是如何做指令和参数解释的

官方文档:【Dalvik bytecode】【Dalvik Executable instruction formats】

invoke-virtual  后面有至少3个参数

A: 参数字数(4 位)
B: 方法引用索引(16 位)
C..G: 参数寄存器(每个寄存器各占 4 位)

再看invoke-vitrual 这类指令的id 是 35c

看35c这类指令的格式

看看ID 的含义

大多数格式 ID 包含三个字符:前两个是十进制数,最后一个是字母。第一个十进制数表示格式中 16 位代码单元的数量。第二个十进制数表示格式包含的最大寄存器数量(使用最大值是因为某些格式可容纳的寄存器数量为可变值),特殊标识“r”表示已对寄存器的数量范围进行编码。最后一个字母以半助记符的形式表示该格式编码的任何其他数据类型。例如,“21t”格式的长度为 2,包含一个寄存器引用,另外还有一个分支目标。

所以35c = 有3个16位代码单元(3个“单词" 空格分割),最大支持5个寄存器数,c表示其他数据类型为常量池索引

按位布局

A|G|op BBBB F|E|D|C

每个以 空格 分割的区域被称作“单词”

每个单词占16位

”|“ 竖线用来平均分割该单词内的位宽

op”一词用于表示格式内八位操作码的位置

解析一下:

这里有3个单词,每个单词16位(2个字节),因为是小端序,所以需要重新按适合人类阅读的方式排列一下

6E 10      4E 32       01 00      就成了

10 6E      32 4E       00 01

第一个单词区域:

A|G|op = A(4位)G(4位)op(8位)

1|0 |6E = A=1  ,G=0, op=6E

op=6E = Invoke-vitural

A=1

G=0

第二个单词区域:

BBBB = 32 4E

第三个单词区域:

F|E|D|C = 00 01

F=0

E=0

D=0

C=1

根据A = 1

其操作码是

最后整理一下

op {vC},kind@BBBB 等于

op=6E=invoke-vitral

C = 1 , 那么{vC} = {v1}

BBBB=324E ,那么kind@BBBB = kind@324E

整个指令为

invoke-vitural {v1},kind@324E

现在看起来和backsmali解释的非常相似了

根据 B: 方法引用索引(16 位)

那么我们去看看324E = 12878 (十进制)的方法是什么

所以在执行阶段可以看出即使把class_defs[]中的方法 隐藏后

在解析指令的时候,是根据方法索引在method_ids[] 里去找的方法,然后根据方法名称和签名打印出smali的指令的人类可读命令字符串就完事了

但执行的时候会抛出异常

所以估计是找到method 对象后,根据给出的 class_idx  找到class,然后根据

1.函数名 和 函数签名

2.相同method_ids 的索引号(也就是324E)

去找该class 下 的 viturl方法列表(因为这里是invoke-vitural指令)中匹配的方法

但是发现找不到(因为原来fun2 方法指向的方法索引被改为为 fun1),就抛出异常(具体要看虚拟机如何执行invoke-viturl指令的)

反编译:

apktool 会提示 #dupliate method ignord  ,并反编译出 fun1 的代码

jeb 不提示异常,并解析出fun1的代码2次

android studio 不提示异常,但是看得到fun2 的导出(斜体字体,类似依赖的外部方法),但是无法查看bytecode

dex2jar 会提示 duplicated method

ida 不提示异常,看不到 fun2 有export,也没有找到 fun2的代码

对于隐藏方法,但不隐藏bytecode的做法

1.# Method 0 (0x0)

2.# Size of bytecode (in 16-bit units): 0x2 但是下面没有bytecode

手动c一下(转为code解析),正好2个16位的

于是浮出水面,但是IDA除了看mehtod(0x0) 没办法发现存在异常的线索,所以还是先校验一次比较靠谱

校验:

1.检查method id 为0的

2.根据mehtods_defs[] 总大小 除以 单个元素大小,得到实际总元素数量,对比  virtual_methods_size 的数值,看是否一致

但是进一步,可以把 virtual_methods_size 的大小减一,并且将隐藏方法的Dex_Method 删掉,重新计算文件索引和offset、checksum等,在运行时,打开dex文件二进制流到内存,用dex对象解析他,并插入隐藏的方法,然后重新计算偏移,池索引号,文件offset,checksum等,然后用dexclassloader 加载后,运行。

不如在编译时给编译器增加某个编译选项,可以不把一些方法编译进主dex(这个在编译环节应该比重新计算修改后dex,计算一大堆offset要好吧)

这种方法其实是将dex内本来存在有字节码的方法索引和方法字节码本身去掉,只留下DexMehtodID,因为指令的 中的 kind@BBBB 需要给出一个和索引号对应的DexMethodId元素,而这个元素内包含该方法所属的1.类 2.方法签名 3.方法名

由于反编译时,该方法所定义的类中的DexMethod 和 字节码被删除(或隐藏),所以反编译器认为这个所指向的方法是一个外部引用 (如 当你调用 android.util.Log 中的i方法时,Log类的字节码不需要你打包进apk,因为在运行时会自动加载)

(图中,该dex中只有1个自定义class,但需要用到androiod.util.Log.i 方法,但是该类并未在dex中定义,只有一个DexmethodID存在)

可以更进一步修改,既然删掉了方法的定义,那不如也把调用该方法的相关字节码也修改掉,让他指向一个别的方法,这样 DexMethodID 也可以删掉或者修改成具有混淆意义的方法了。因为加载这个dex前,总要修复,所以这个dex其实只是个可以任意修改,具有dex外表用于迷惑反编译器,而实际上却像是个分卷压缩文件中的一部分文件(带有一半的正确信息),还有另一半需要在 这个dex本身的一些可以第一次正常运行的方法里(无论java层还是native层,就算native,首次加载也是在java层代码被首次运行后才会加载) 将完整的dex还原,或者在运行时,根据需要运行到的方法动态还原(类似 ELF .plt   lazyLoad),在1级还原中将方法内的字节码指向一个 自定义的动态连接器,携带可以标识方法签名的参数,在需要执行时动态释放出字节码然后执行(2级还原),这样如果在运行时没有执行到的方法,始终不会有完整,正确的字节码被释放到内存里的dex中,即使用core dump,也无法获得完整的,正确的dex文件

总结:

本质是将修改后的dex当作加密文件,让反编译者在反编译时却不知道(因为并不是完全的密文导致不可读,有很大的可读性,产生了混淆),实际在使用这个方法之前,需要先按加密方式的反方法修复被改动的地方,重新将dex加载,然后执行(可以通过反射方式)

dex方法隐藏后的反编译和运行时 效果的更多相关文章

  1. JD-GUI反编译后代码逻辑分析

    一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可 ...

  2. 1. dex和Jar反编译对比

    Java源码 public class Hello { public int foo(int a,int b) { return (a + b) * (a - b); } public static ...

  3. Android安全攻防战,反编译与混淆技术完全解析(上)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/49738023 之前一直有犹豫过要不要写这篇文章,毕竟去反编译人家的程序并不是什么值 ...

  4. Android开发周报:反编译对抗研究、动手制作智能镜子

    新闻 <Android Wear落地中国 谷歌增强安卓生态控制力> :9月8日,由摩托罗拉推出的智能手表Moto 360二代作为国内发售的第一款搭载官方Android Wear的设备,正式 ...

  5. Xamarin android如何反编译apk文件

    Xamarin android 如何反编译 apk文件 这里推荐一款XamarinAndroid开发的小游戏,撸棍英雄,游戏很简单,的确的是有点大.等一下我们来翻翻译这个Xamarin Android ...

  6. C# Note30: 软件加密机制以及如何防止反编译

    参考文章: C#软件license管理(简单软件注册机制) 软件加密技术和注册机制 .NET中的许可证机制--License 背景 .net是一种建立在虚拟机上执行的语言,它直接生成 MSIL 的中间 ...

  7. Android反编译技术总结

    一.Apk反编译工具及其使用方法 1.原理 学习反编译之前,建议先学习一下Apk打包的过程,明白打包完成后的Apk里面都有什么文件,各种文件都是怎么生成的. 这里有两篇AndroidWeekly中推荐 ...

  8. Android程序的反编译对抗研究

    转自: http://www.freebuf.com/tools/76884.html 一.前言 对抗反编译是指让apk文件或者dex文件无法正常通过反编译工具,而且有可能导致工具异常或者崩溃,如ap ...

  9. Androd安全——反编译技术完全解析

    )第二步成功后我们会发现在当前目录下多了一个<APKName>文件夹,这个文件夹中存放的就是反编译的结果了.我们可以打开AndroidManifest.xml.res/layout即可查看 ...

随机推荐

  1. 爬虫学习(二)--爬取360应用市场app信息

    欢迎加入python学习交流群 667279387 爬虫学习 爬虫学习(一)-爬取电影天堂下载链接 爬虫学习(二)–爬取360应用市场app信息 代码环境:windows10, python 3.5 ...

  2. Spring底层源码分析

    Spring 运行原理 Spring 启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的Bean 配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean ...

  3. Java中的等待唤醒机制—至少50%的工程师还没掌握!

    这是一篇走心的填坑笔记,自学Java的几年总是在不断学习新的技术,一路走来发现自己踩坑无数,而填上的坑却屈指可数.突然发现,有时候真的不是几年工作经验的问题,有些东西即使工作十年,没有用心去学习过也不 ...

  4. HDU1944 S-NIM(多个NIM博弈)

    Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim is played as ...

  5. LNMP-Nginx配置不记录静态文件、过期时间

    用户访问web网站,通常日志文件会记录很多web站点上的一些静态文件信息,如果长期不处理,日志文件会越来越大,占用的系统资源也越大,此时就需要我们配置不记录静态文件和过期时间,减少日志文件记录过多不必 ...

  6. 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor

    [Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...

  7. Mysql添加path变量

    前提: 系统环境:Linux,服务器:阿里云轻量应用服务器 背景: 阿里云轻量应用服务器自带 mysql5.7,但是没有配置环境变量,因此直接输入 mysql -u root -p 将提示 comma ...

  8. [从今天开始修炼数据结构]图的最短路径 —— 迪杰斯特拉算法和弗洛伊德算法的详解与Java实现

    在网图和非网图中,最短路径的含义不同.非网图中边上没有权值,所谓的最短路径,其实就是两顶点之间经过的边数最少的路径:而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,我们称路径上第 ...

  9. 《Java数据结构》树形结构

    树形结构是一层次的嵌套结构. 一个树形结构的外层和内层有相似的结构, 所以这种结构多可以递归的表示.经典数据结构中的各种树形图是一种典型的树形结构:一颗树可以简单的表示为根, 左子树, 右子树. 左子 ...

  10. Java问题记录——循环里的二次判断与状态更新

    Java问题记录——循环里的二次判断与状态更新 摘要:本文主要记录了在循环操作时可能出现的问题. 问题重现 在使用循环结构时,如果使用了定时任务,或者代码会多次调用循环结构,可能会导致有些对象会被循环 ...