您现在的位置是:首页 > 编程 > 

翻译——种脱壳安卓恶意软件的方式

2025-07-28 05:40:43
翻译——种脱壳安卓恶意软件的方式 之前Anubis这个安卓恶意软件家族比较流行,而且通过官方的应用商店进行传播。Android生态系统中的打包程序下面说的打包程序就是我们常说的加固,但是呢,恶意软件也用,用于隐藏他们恶意的payloads。这包含反射,混淆,控制流平坦化和垃圾代码,当然Anubis 也是使用了这些来阻碍我们分析。在运行时加载类Android应用程序必须在AndroidManife

翻译——种脱壳安卓恶意软件的方式

之前Anubis这个安卓恶意软件家族比较流行,而且通过官方的应用商店进行传播。

Android生态系统中的打包程序

下面说的打包程序就是我们常说的加固,但是呢,恶意软件也用,用于隐藏他们恶意的payloads。这包含反射,混淆,控制流平坦化和垃圾代码,当然Anubis 也是使用了这些来阻碍我们分析。

在运行时加载类

Android应用程序必须在AndroidManifest文件中定义其使用的服务,接收器和活动类才能使用它们。在Anubis示例中,很明显,清单文件中未定义的许多类仅存在于源代码中。

这意味着应在运行时将具有未定义类的文件加载到应用程序中。Android中有两种主要的运行时加载方式:

从文件: 1、API26之后,dalvik.system.DexFile.loadDex 2、dalvik.system.DexClassLoader 、dalvik.system.PathClassLoader

从内存: 1、dalvik.system.InMemoryDexClassLoader(在恶意软件中不常见)

从文件加载需要在文件系统中存在一个dex / jar文件。Anubis解压缩加密的数据文件,然后删除解密的版本。后来,恶意软件继续将解密的dex加载到应用程序中。使用DexClassLoader加载后,恶意软件会删除解密的dex文件。跟踪dexClassLoader应该使加载例程清晰可见。由于dexClassLoader是dalvik.system的类,因此在代码中应包含“ dalvik.system.dexClassLoader”包,但不到它。

反射

处理恶意软件时,另一个有用的方法是反射。反射是Java中的一个重要概念,它使您可以在不了解方法/类的情况下调用它们。有几种反映的类/方法。

  • java.lang.Class.forame
  • java.lang.ClassLoader.loadClass
  • java.lang.reflect.Method
  • java.lang.Class.getMethods

forame的用法示例

代码语言:javascript代码运行次数:0运行复制
cObj = Class.forame("dalvik.system.dexClassLoader");

cObj变量保存dexClassLoader的类对象。这使程序可以调用任何给定类的方法。问题是到对反射方法进行函数调用的位置。

使用Frida抓取packers

frida是几乎每个操作系统都支持的动态检测工具包。Frida使得可以注入一段代码来操纵目标程序并跟踪程序调用。在这种情况下,它将用于跟踪进行了哪些反射调用,从而分析线程。进行前面提到的函数调用时,将另外调用cole.log。但是在此之前,让我们快速回顾一下如何在Android模拟器上设置Frida。

从以下位置下载适合您的仿真器的frida-server:( 例如Genymotion使用x86架构。) 。

代码语言:javascript代码运行次数:0运行复制
adb push frida-server /data/local/tmp
adb shell
cd /data/local/tmp
chmod +x frida-server
./frida-server &

Frida工具在主机中安装

代码语言:javascript代码运行次数:0运行复制
pip install frida-tools

设置完成后,我们可以编写一个脚本来挂钩目标方法。先定义一些类方法等

代码语言:javascript代码运行次数:0运行复制
var classDef = Java.use('java.lang.Class');
var classLoaderDef = Java.use('java.lang.ClassLoader');
var loadClass = classLoaderDef.('java.lang.String', 'boolean');
var forame = classDef.('java.lang.String', 'boolean', 'java.lang.ClassLoader');
var reflect = Java.use('java.lang.reflect.Method')
var member = Java.use('java.lang.reflect.Member')
var dalvik = Java.use("dalvik.system.DexFile")
var dalvik2 = Java.use("dalvik.system.DexClassLoader")
var dalvik = Java.use("dalvik.system.PathClassLoader")
//var dalvik4 = Java.use("dalvik.system.InMemoryDexClassLoader")
var f = Java.use("java.io.File")
var url = Java.use("java.URL")
var obj = Java.use("java.lang.Object")
var fo = Java.use("java.io.FileOutputStream")

我们将使用此代码段更改方法的实现

代码语言:javascript代码运行次数:0运行复制
implementation = function(){
    cole.log("[+] targetmethod catched !")
    stackTrace()
    return ()
}

cole.log(“[+] {x} function catched !”) 将使我们能够查看该函数是否被调用。如果函数采用任何参数(例如字符串),则在分析过程中记录这些参数可能会有所帮助。然后,我们可以获得有关所处线程的更多信息。Frida可以调用任何Android函数,包括getStackTrace()。但这需要引用当前线程对象。让我们从获取线程类的实例开始:

代码语言:javascript代码运行次数:0运行复制
var ThreadDef = Java.use('java.lang.Thread');
var ThreadObj = ThreadDef.$new();

ThreadObj保存Thread类的实例,currentThread()可用于获取线程。调用getStackTrace(),我们可以遍历stackElements来打印调用堆栈。

代码语言:javascript代码运行次数:0运行复制
function stackTrace() {
        cole.log("------------START STACK---------------")
        var stack = ().getStackTrace();
        for (var i = 0; i < stack.length; i++) {
            cole.log(i + " => " + stack[i].toString());
        }
        cole.log("------------ED STACK---------------");
    }

打印调用堆栈有助于识别反射和拆包机制的调用图。例如,dexClassLoader可能创建了反射。但是,当frida hook了dexClassLoader并打印调用堆栈时,我们可以在调用dexClassLoader之前看到这些函数。在应用程序的最开始就调用了解包例程。因此,应该尽快安装frida以赶上解包过程。幸运的是,frida中的-f选项使frida能够生成目标应用程序本身。frida接受带有-l参数的脚本。 frida -U -f appname -l dereflect.js 然后,frida等待用户输入继续。%resume将恢复该过程。完整脚本可在我的github存储库中到。 .js

带stackTrace()的输出

您可以看到在write方法之前调用的函数。跟踪这些间隔函数后,您可以在它们之前看到RlkfTEUX和lqfRafMrGew被调用。事实证明,它们是用于解密加密文件的非常重要的功能,稍后我们将再次介绍。

如何脱壳呢
  • 动态 hooking:拦截file.delete (Java level),或者拦截unlink syscall (system level) 从内存里dump:用gameguardian来转存内存或者使用自定义工具转储内存
  • 静态 手动干(作者应该是写脚本的意思吧)

动态的拦截是最简单的办法

通过挂钩:Java级别

当我第一次遇到Anubis并意识到它正在删除文件时,我的第一个解决方案是挂钩到file.delete函数。

代码语言:javascript代码运行次数:0运行复制
Java.perform(function() { 
   var f = Java.use("java.io.File") 
   f.delete.implementation = function(a){ 
       s = this.getAbsolutePath() 
       if(s.includes("jar")){ 
          cole.log("[+] Delete catched =>" +this.getAbsolutePath()) 
       } 
       return true 
   } 
})

这段代码始终将true返回给file.delete函数。截获后,我们就可以知道文件路径,获取到那个jar了

除此之外,我们还可以使用python调用frida使工作自动化,并浏览目标文件所在的文件夹。这些c&c服务器通常会生成数千个apk。由于它们每个都可以嵌入不同的IP地址,因此自动化工具可以使我们的生活更轻松。

具体参考这个:

通过挂钩:系统级别

但是,如果恶意软件使用本机代码删除文件怎么办?我们不能总是钩在Java级别。我们需要更深入。

Unlink 函数有一个参数, 一个文件名的指针. 我们可以通过findExportByame来帮助我们hook. 代码来源于.html

但我稍微修改,会打印已删除的文件。

代码语言:javascript代码运行次数:0运行复制
var unlinkPtr = Module.findExportByame(null, 'unlink');
Interceptor.replace(unlinkPtr, new ativeCallback( function (a){
    cole.log("[+] Unlink : " + Memory.readUtf8String(ptr(a)))
    }, 'int', ['pointer']));

运行结果:

我们截获了unlink调用,因为我们的脚本只是用cole.log替换了原始函数的代码,所以文件不会从文件系统中删除。

从内存dump

即使由于文件已加载到进程而从文件系统中删除文件,我们也可以从该进程的内存中获取已删除文件的痕迹。由于Android继承自Linux,因此我们可以使用/proc/pid文件夹为我们提供有关指定进程的内存区域的信息。让我们看一下cat /proc/pid/maps | grep dex过滤dex的目标。

我们发现了dex文件的踪迹。现在我们需要转储这些部分。

使用Gameguardian来转储内存:

这种方法是“作弊”,有一个称为GameGuardian的工具可用于游戏黑客。您可以使用GameGuardian做很多有趣的事情,但是我们现在仅使用转储机制。

让我们从安装和运行APK开始。然后启动GameGuardian,然后从左上方的按钮中选择应用程序名称。选择最右边的按钮及其下面的按钮。现在,您可以在菜单中看到转储内存选项。通过单击箭头按钮放置区域的十六进制代码或选择区域,然后按保存。

我们可以使用以下方法拉出转储的东西

代码语言:javascript代码运行次数:0运行复制
adb pull /storage/emulated/0/packer .

然后您将在packer文件夹中看到2个文件

代码语言:javascript代码运行次数:0运行复制
bin 

当使用file命令检查时,它会将我们的dex文件检测为数据文件,所以我们需要删除不属于dex文件的部分来修复。

使用自定义工具转储内存:

感谢@theempire_h,我们可以使用C程序转储目标应用程序的内存区域。

代码语言:javascript代码运行次数:0运行复制
adb push androidDump /data/local/tmp
adb shell
cd /data/local/tmp
chmod +x androidDump
./androidDump appname

它转储个数据块

但是转储后,file命令仍然没有为我们提供正确的类型we事实证明,我们应该对文件进行一些修改。为了到dex的魔术数字,我编写了此脚本。

.py

代码语言:javascript代码运行次数:0运行复制
import binascii
import sys
filename = sys.ar[1]
with open(filename, 'rb') as f:
    content = f.read()
h = binascii.hexlify(content).split(b'6465780a')
h.pop(0)
h = b'6465780a' + b''.join(h)
dex = open(sys.ar[1][:-4]+".dex","wb")
dex.write(binascii.a2b_hex(h))
()

修复后我们就可以打开了

我们到了失去了的class

静态方法:

这是一篇博客文章,从不同的角度解释了解包过程。

,/reverse-engineering/2018/08/0/Unpacking-Anubis-APK.html

我在stackTrace的帮助下到了rc4密钥。但是显然,寻^这个符号是从Anubis到RC4例程的一种非常有效的方法。

在JADX中轻松到rc4密钥,这里有个tips

  • 搜索 “% length”
  • 右键单击要使用的方法,然后点 find Usage
  • 下面的bArr2用作rc4密钥进行解密

有了密钥,我们可以从APK的images文件夹中解密加密的文件。脚本带有2个参数,即bArr2和加密的文件

.py

解密并解压缩后,我们得到了dex

提取配置文件后,还有一个步骤来获取c&c服务器的地址。恶意软件从电报地址的页面获取,并用ASCII字母更改汉字。然后,它处理base64字符串。解码base64后,它用于service解密使用rc4方案加密的数据。这是一个将中文字符解密为c&c地址的代码段。(就是将中文一一对应数字字母,还原出数字字母是base64加密的,解密一下就好)

.py

我设法用Androguard在没有在模拟器中运行APK,去解密了Anubis payloads。转储dex文件后,我的脚本将到打印c2和加密密钥的config类。Config Class位于a,b or c 或者较新版本的ooooooooooooo{0,2}o中

通过检查类源代码中“ this”关键字的计数,我设法解密了所有版本的anubis。这是我的脚本的输出,用于从Anubis示例中获取c2和密钥。

结论

有很多解压缩安卓恶意软件和跟踪pack机制的方法,我们会在未来看到恶意软件使用dalvik.system.InMemoryDexClassLoader,如果使用此选项,则删除挂钩将无法捕获已删除的文件,因为一切都将在内存中完成,但是转储内存将捕获这些方法。知道不同的方式总是有帮助的。

参考链接

/n-ways-to-unpack-mobile-malware/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2019-10-25,如有侵权请联系 cloudcommunity@tencent 删除翻译函数脚本内存反射

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1207287.html

相关标签:无
上传时间: 2025-07-24 13:12:18
留言与评论(共有 18 条评论)
本站网友 龙德广场
10分钟前 发表
脚本带有2个参数
本站网友 跑步减肥最佳时间
12分钟前 发表
它将用于跟踪进行了哪些反射调用
本站网友 佛山商铺出租
14分钟前 发表
从不同的角度解释了解包过程
本站网友 治颈椎病
24分钟前 发表
它用于service解密使用rc4方案加密的数据
本站网友 乳腺肿瘤
12分钟前 发表
获取到那个jar了除此之外
本站网友 一点点奶茶加盟
11分钟前 发表
dalvik.system.DexClassLoader
本站网友 成都音画时尚
22分钟前 发表
'java.lang.ClassLoader'); var reflect = Java.use('java.lang.reflect.Method') var member = Java.use('java.lang.reflect.Member') var dalvik = Java.use("dalvik.system.DexFile") var dalvik2 = Java.use("dalvik.system.DexClassLoader") var dalvik = Java.use("dalvik.system.PathClassLoader") //var dalvik4 = Java.use("dalvik.system.InMemoryDexClassLoader") var f = Java.use("java.io.File") var url = Java.use("java.URL") var obj = Java.use("java.lang.Object") var fo = Java.use("java.io.FileOutputStream")我们将使用此代码段更改方法的实现代码语言:javascript代码运行次数:0运行复制implementation = function(){ cole.log("[+] targetmethod catched !") stackTrace() return () }cole.log(“[+] {x} function catched !”) 将使我们能够查看该函数是否被调用
本站网友 大印象减肥茶
15分钟前 发表
.py代码语言:javascript代码运行次数:0运行复制import binascii import sys filename = sys.ar[1] with open(filename
本站网友 奥沙利铂
20分钟前 发表
dexClassLoader可能创建了反射
本站网友 安以轩照片风波
11分钟前 发表
恶意软件继续将解密的dex加载到应用程序中
本站网友 ebody
20分钟前 发表
调用getStackTrace()
本站网友 raid10
0秒前 发表
跟踪dexClassLoader应该使加载例程清晰可见
本站网友 苏宁与京东
6分钟前 发表
但是在此之前
本站网友 1寸等于多少cm
10分钟前 发表
它们是用于解密加密文件的非常重要的功能
本站网友 沈阳华府天地
26分钟前 发表
幸运的是
本站网友 文鼎霹雳体
19分钟前 发表
使用DexClassLoader加载后
本站网友 王凯旋
22分钟前 发表
frida等待用户输入继续