从android锁屏病毒来探索smali语法
字数 2152 2025-08-22 22:47:30

Android锁屏病毒分析与Smali语法教学

引言

本文通过分析一个简单的Android锁屏病毒样本,深入讲解Smali语法和Android恶意软件分析技术。该病毒通过设备管理器实现锁屏功能,利用开机广播和服务实现开机锁屏,解锁方式是通过电话拨入并与解密后的资源文件字符串匹配。

样本基本信息

  • 应用名称: 红包强盗(后台版)
  • MD5: F3ADAADC7A8CB0D16A1AD05AADC8B1F2
  • 包名: com.cjk

样本行为分析

1. 主要行为特征

  1. 申请设备管理员权限
  2. 弹出锁屏界面
  3. 通过开机广播实现持久化
  4. 通过电话拨入特定号码解锁

2. 可疑文件

  • res/raw目录下四个可疑文本文件(加密字符串)
  • res/drawable目录下的QQ二维码

Smali语法详细解析

1. 方法定义

Smali方法定义格式:

.method [修饰符] 方法名(参数类型)返回值类型
    .registers N  // 使用的寄存器数量
    .annotation  // 注解
    .end annotation
    // 方法体
.end method

示例:

.method public onBind(Intent)IBinder
    .registers 6
    .annotation runtime Override
    .end annotation
    move-object v0, p0
    move-object v1, p1
    const/4 v3, 0
    check-cast v3, IBinder
    move-object v0, v3
    return-object v0
.end method

2. 寄存器使用

  • pX表示参数寄存器(p0通常是this)
  • vX表示局部变量寄存器
  • .registers N声明使用的寄存器总数

3. 常见指令解析

数据移动指令

  • move-object vA, vB: 将vB中的对象引用移动到vA
  • move/from16 vAA, vBBBB: 从vBBBB移动到vAA(16位)
  • const/4 vA, #+B: 将4位常量B存入vA
  • const-string vA, string: 将字符串常量存入vA

方法调用指令

  • invoke-virtual: 调用虚方法
  • invoke-static: 调用静态方法
  • invoke-direct: 调用直接方法(构造方法等)
  • invoke-super: 调用父类方法

示例:

invoke-static MD5Util->getMD5String(String)String, v3

控制流指令

  • if-eq vA, vB, target: 如果vA == vB则跳转
  • if-ne vA, vB, target: 如果vA != vB则跳转
  • goto target: 无条件跳转

数组操作

  • new-array vA, vB, type: 创建新数组
  • array-length vA, vB: 获取数组长度
  • aget vA, vB, vC: 获取数组元素
  • aput vA, vB, vC: 存储数组元素

4. 类与对象操作

  • new-instance vA, type: 创建新实例
  • check-cast vA, type: 类型检查转换
  • iput-object vA, vB, field: 设置实例字段
  • iget-object vA, vB, field: 获取实例字段

病毒组件分析

1. 服务组件(s)

构造方法分析

构造方法中初始化了几个敏感数据:

const-string v3, "by:彼岸花 qq:127****738"
iput-object v3, v2, s->bahk:String

然后对字符串进行MD5处理:

iget-object v3, v3, s->bahk:String
invoke-static MD5Util->getMD5String(String)String, v3
move-result-object v3
iput-object v3, v2, s->Lycorisradiata:String

MD5处理函数分析

getMD5String方法实现了复杂的加密过程:

  1. 对输入字符串进行MD5摘要计算
  2. 创建长度为摘要字节数组两倍的char数组
  3. 对每个字节进行两次加密处理

加密逻辑伪代码:

char[] charArray1 = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
byte[] md5ByteArray = MessageDigest.getInstance("MD5").digest(string.getBytes());
char[] charArray2 = new char[2 * md5ByteArray.length];

for(int i=0; i<md5ByteArray.length; i++) {
    byte b = md5ByteArray[i];
    // 第一次加密
    charArray2[j++] = charArray1[(b >> 4) & 0xF];
    // 第二次加密
    charArray2[j++] = charArray1[b & 0xF];
}
return new String(charArray2);

onCreate方法分析

  1. 注册监听短信和电话状态的广播
  2. 初始化DES加密对象
  3. 设置手机震动模式(每0.1秒震动1.5秒)

关键代码:

// 注册广播接收器
new-instance v8, s$IncomingCallReceiver
invoke-direct s$IncomingCallReceiver-><init>(s)V
iput-object v8, v7, s->mReceiver:s$IncomingCallReceiver

// 设置震动模式
const/4 v8, 4
new-array v8, v8, [J
const/4 v10, 0
const/16 v11, 100
int-to-long v11, v11
aput-wide v11, v9, v10  // longArray[0] = 100
const/4 v10, 1
const/16 v11, 1500
int-to-long v11, v11
aput-wide v11, v9, v10  // longArray[1] = 1500
// 以此类推设置震动模式

onStartCommand方法

主要调用私有方法c(),该方法:

  1. 创建悬浮窗口布局
  2. 设置窗口参数
  3. 解密资源文件内容并显示在TextView中

窗口参数设置:

const/16 v16, 201
iput v0, v15, WindowManager$LayoutParams->type:I  // type = 201
const/16 v16, 1
iput v0, v15, WindowManager$LayoutParams->format:I  // format = 1
const/16 v16, 0x050
iput v0, v15, WindowManager$LayoutParams->flags:I  // flags = 0x050
const/16 v16, 49
iput v0, v15, WindowManager$LayoutParams->gravity:I  // gravity = 49

2. 广播接收器(bbb)

处理开机完成广播,启动服务:

invoke-virtual Intent->getAction()String
const-string v8, "android.intent.action.BOOT_COMPLETED"
invoke-virtual String->equals(Object)Z  // 检查是否为开机广播

new-instance v7, Intent
const-string v10, "com.cjk.s"
invoke-static Class->forName(String)Class  // 获取服务类
invoke-direct Intent-><init>(Context, Class)V  // 创建Intent

const/high16 v8, 0x10000000
invoke-virtual Intent->addFlags(I)Intent  // 添加标志
invoke-virtual Context->startService(Intent)ComponentName  // 启动服务

3. 设备管理员组件(MyAdmin)

onEnabled方法

  1. 解密资源文件获取密码
  2. 启动服务
  3. 重置锁屏密码

关键代码:

const v12, 0x7F060002
invoke-virtual Resources->openRawResource(I)InputStream  // 打开资源文件
invoke-static BAH->getString(InputStream)String  // 读取内容
const-string v12, "\n"
const-string v13, ""
invoke-virtual String->replaceAll(String, String)String  // 去除换行
invoke-static DU->getsss(String)String  // 解密得到密码

invoke-virtual MyAdmin->getManager(Context)DevicePolicyManager  // 获取设备策略管理器
const/4 v13, 0
invoke-virtual DevicePolicyManager->resetPassword(String, I)Z  // 重置密码

onPasswordChanged和onDisableRequested方法

这两个方法都会执行锁屏和重置密码操作,防止用户修改密码或取消设备管理员权限。

解密算法分析

1. 资源文件解密

病毒使用DU类的getsss方法解密资源文件:

invoke-static DU->getsss(String)String

2. 电话解锁机制

当有电话拨入时,广播接收器会:

  1. 获取来电号码
  2. 与解密后的资源文件字符串比较
  3. 如果匹配则:
    • 结束前台呼叫
    • 移除锁屏布局
    • 设置铃声静音
    • 停止服务

防御与检测建议

  1. 设备管理员权限:谨慎授予设备管理员权限,特别是来源不明的应用
  2. 开机启动:监控应用的BOOT_COMPLETED广播接收器
  3. 窗口类型:注意type=201的悬浮窗口
  4. 密码重置:警惕应用调用DevicePolicyManager.resetPassword
  5. 广播优先级:注意priority="2147483647"的高优先级广播

Smali分析技巧总结

  1. 从AndroidManifest.xml入手:优先分析注册的组件
  2. 关注服务组件:恶意行为常放在服务中
  3. 跟踪方法调用链:特别是onCreate、onStartCommand等生命周期方法
  4. 注意加密字符串:资源文件中的可疑字符串可能是关键
  5. 分析广播接收器:特别是高优先级和系统广播接收器
  6. 设备管理员相关:注意DeviceAdminReceiver的子类

参考资源

  1. Google官方Smali语法
  2. Dalvik opcodes

通过本案例的详细分析,我们不仅了解了Android锁屏病毒的工作原理,也掌握了Smali代码的分析方法和关键语法点,为后续的Android逆向分析和安全研究打下了坚实基础。

Android锁屏病毒分析与Smali语法教学 引言 本文通过分析一个简单的Android锁屏病毒样本,深入讲解Smali语法和Android恶意软件分析技术。该病毒通过设备管理器实现锁屏功能,利用开机广播和服务实现开机锁屏,解锁方式是通过电话拨入并与解密后的资源文件字符串匹配。 样本基本信息 应用名称 : 红包强盗(后台版) MD5 : F3ADAADC7A8CB0D16A1AD05AADC8B1F2 包名 : com.cjk 样本行为分析 1. 主要行为特征 申请设备管理员权限 弹出锁屏界面 通过开机广播实现持久化 通过电话拨入特定号码解锁 2. 可疑文件 res/raw 目录下四个可疑文本文件(加密字符串) res/drawable 目录下的QQ二维码 Smali语法详细解析 1. 方法定义 Smali方法定义格式: 示例: 2. 寄存器使用 pX 表示参数寄存器(p0通常是this) vX 表示局部变量寄存器 .registers N 声明使用的寄存器总数 3. 常见指令解析 数据移动指令 move-object vA, vB : 将vB中的对象引用移动到vA move/from16 vAA, vBBBB : 从vBBBB移动到vAA(16位) const/4 vA, #+B : 将4位常量B存入vA const-string vA, string : 将字符串常量存入vA 方法调用指令 invoke-virtual : 调用虚方法 invoke-static : 调用静态方法 invoke-direct : 调用直接方法(构造方法等) invoke-super : 调用父类方法 示例: 控制流指令 if-eq vA, vB, target : 如果vA == vB则跳转 if-ne vA, vB, target : 如果vA != vB则跳转 goto target : 无条件跳转 数组操作 new-array vA, vB, type : 创建新数组 array-length vA, vB : 获取数组长度 aget vA, vB, vC : 获取数组元素 aput vA, vB, vC : 存储数组元素 4. 类与对象操作 new-instance vA, type : 创建新实例 check-cast vA, type : 类型检查转换 iput-object vA, vB, field : 设置实例字段 iget-object vA, vB, field : 获取实例字段 病毒组件分析 1. 服务组件(s) 构造方法分析 构造方法中初始化了几个敏感数据: 然后对字符串进行MD5处理: MD5处理函数分析 getMD5String 方法实现了复杂的加密过程: 对输入字符串进行MD5摘要计算 创建长度为摘要字节数组两倍的char数组 对每个字节进行两次加密处理 加密逻辑伪代码: onCreate方法分析 注册监听短信和电话状态的广播 初始化DES加密对象 设置手机震动模式(每0.1秒震动1.5秒) 关键代码: onStartCommand方法 主要调用私有方法 c() ,该方法: 创建悬浮窗口布局 设置窗口参数 解密资源文件内容并显示在TextView中 窗口参数设置: 2. 广播接收器(bbb) 处理开机完成广播,启动服务: 3. 设备管理员组件(MyAdmin) onEnabled方法 解密资源文件获取密码 启动服务 重置锁屏密码 关键代码: onPasswordChanged和onDisableRequested方法 这两个方法都会执行锁屏和重置密码操作,防止用户修改密码或取消设备管理员权限。 解密算法分析 1. 资源文件解密 病毒使用DU类的getsss方法解密资源文件: 2. 电话解锁机制 当有电话拨入时,广播接收器会: 获取来电号码 与解密后的资源文件字符串比较 如果匹配则: 结束前台呼叫 移除锁屏布局 设置铃声静音 停止服务 防御与检测建议 设备管理员权限 :谨慎授予设备管理员权限,特别是来源不明的应用 开机启动 :监控应用的BOOT_ COMPLETED广播接收器 窗口类型 :注意type=201的悬浮窗口 密码重置 :警惕应用调用DevicePolicyManager.resetPassword 广播优先级 :注意priority="2147483647"的高优先级广播 Smali分析技巧总结 从AndroidManifest.xml入手 :优先分析注册的组件 关注服务组件 :恶意行为常放在服务中 跟踪方法调用链 :特别是onCreate、onStartCommand等生命周期方法 注意加密字符串 :资源文件中的可疑字符串可能是关键 分析广播接收器 :特别是高优先级和系统广播接收器 设备管理员相关 :注意DeviceAdminReceiver的子类 参考资源 Google官方Smali语法 Dalvik opcodes 通过本案例的详细分析,我们不仅了解了Android锁屏病毒的工作原理,也掌握了Smali代码的分析方法和关键语法点,为后续的Android逆向分析和安全研究打下了坚实基础。