IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Zyspps for android APP简单的注册码分析 -> 正文阅读

[移动开发]Zyspps for android APP简单的注册码分析

作者:>

Zyspps for android简单的注册码分析

app名称:zyspps

作者:lao3

分析的版本是v1.0, 不过应该是通杀所有版本

一、注册码校验定位

  1. 运行后,弹出注册窗口,随便输入用户名和注册码,点击注册后该APP直接强制结束.

    2
  2. 原本想通过资源定位,发现类和方法变量全部混淆成abc之类的,很难读懂. 然后从log也没看出什么关键信息,也可能我漏掉了.

    1

  3. 考虑到大多APP一般是通过killProcess()或者exit()结束APP,所以我们从这里入手试试. 直接上frida hook掉

    function hook_java(){
        Java.perform(function(){
            var process = Java.use("android.os.Process");
            process.killProcess.implementation=function(pid)
            {
                console.log('pid ==>',pid);   
            }
        })
    }
    
    function main(){
        hook_java();
    }
    
    setImmediate(main)
    

    再次点击注册后,APP并没有结束, 证明确实是调用Process.killProcess()方法强制结束APP

    通过打印堆栈信息

    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
    

    定位到, 调用com.agis.pldps.j.a.a.a类下的方法a进行校验注册码

    package com.agis.pldps.h;
    
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.os.Process;
    import com.agis.pldps.b.a.o;
    import com.agis.pldps.j.a.a.a;
    import com.agis.pldps.j.f;
    
    class b extends o {
        b() {
        }
    
        public void b(DialogInterface dialogInterface, Bundle bundle) {
            if (new a(f.f()).a().booleanValue()) {
                super.b(dialogInterface, bundle);
         } else {
                Process.killProcess(Process.myPid());
         }
        }
    }
    

    到这里就比较清晰了,

    b.a().a(“regsoftkeyusername”)获取输入的用户名/注册码

    public Boolean a() {
            this.c = a(this.f288a, b.a().a("regsoftkeyusername"));
            if (this.c != null) {
                this.b = a(this.c);
                TelephonyManager telephonyManager = (TelephonyManager) this.f288a.getSystemService("phone");
                String a2 = b.a().a("regsoftkeyvalname");
                if (a2 != null && a2.equals(b(String.valueOf(Settings.Secure.getString(this.f288a.getContentResolver(), "android_id").toUpperCase()) + telephonyManager.getDeviceId()))) {
                    return true;
             }
            }
      return false;
        }
    
    

    注册码校验的完整类代码

    package com.agis.pldps.j.a.a;
    
    import android.content.Context;
    import android.provider.Settings;
    import android.telephony.TelephonyManager;
    import android.util.Base64;
    import android.util.Log;
    import com.agis.pldps.f.b;
    import com.esri.core.internal.io.handler.c;
    import java.security.NoSuchAlgorithmException;
    import java.security.spec.InvalidKeySpecException;
    import javax.crypto.Cipher;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class a {
    
        /* renamed from: a  reason: collision with root package name */
        private Context f288a = null;
        private byte[] b = null;
        private String c = null;
    
        public a(Context context) {
            this.f288a = context;
        }
    
        private String a(Context context, String str) {
            try {
                return a(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec((String.valueOf(str) + context.getPackageName()).toCharArray(), (String.valueOf(str) + Settings.Secure.getString(context.getContentResolver(), "android_id").toUpperCase()).getBytes(), 256, 128)).getEncoded());
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e2) {
                e2.printStackTrace();
            }
            return null;
        }
    
        private String a(byte[] bArr) {
            return Base64.encodeToString(bArr, 3);
        }
    
        private byte[] a(String str) {
            return Base64.decode(str, 3);
        }
    
        private String b(String str) {
            if (str == null || str.length() == 0) {
                return str;
            }
            try {
                Cipher instance = Cipher.getInstance("AES");
                instance.init(1, new SecretKeySpec(this.b, "AES"));
                return a(instance.doFinal(str.getBytes(c.f704a))).toUpperCase();
            } catch (Exception e) {
                Log.w(a.class.getName(), "encrypt", e);
                return null;
            }
        }
    
        public Boolean a() {
            this.c = a(this.f288a, b.a().a("regsoftkeyusername"));
            if (this.c != null) {
                this.b = a(this.c);
                TelephonyManager telephonyManager = (TelephonyManager) this.f288a.getSystemService("phone");
                String a2 = b.a().a("regsoftkeyvalname");
                if (a2 != null && a2.equals(b(String.valueOf(Settings.Secure.getString(this.f288a.getContentResolver(), "android_id").toUpperCase()) + telephonyManager.getDeviceId()))) {
                    return true;
                }
            }
            return false;
        }
    
        public Boolean b() {
            this.c = a(this.f288a, b.a().a("regsoftkeyusername"));
            if (this.c != null) {
                this.b = a(this.c);
                TelephonyManager telephonyManager = (TelephonyManager) this.f288a.getSystemService("phone");
                String a2 = b.a().a("regsoftkeyvalname");
                if (a2 != null && a2.equals(b(String.valueOf(Settings.Secure.getString(this.f288a.getContentResolver(), "android_id").toUpperCase()) + telephonyManager.getDeviceId()))) {
                    return true;
             }
            }
            return false;
        }
    }
    

二、注册码分析

获取注册用户名,手机android_id,使用PKDF2生成AES密钥…然后对android_id(大写)+imei 进行AES加密,再次对加密结果进行BASE64编码(大写)得到最终的注册码 与 我们输入的注册码进行比对~

三、注册机实现

# -*- coding: utf-8 -*- 
# @Time : 2021/8/12 21:59 
# @Author : lao3
# @File : zyspps_keygen.py
# @Dec : zyspps_keygen

import base64
from hashlib import pbkdf2_hmac
from Crypto.Cipher import AES

...
...
...

# 手机IMEI和android_id
deviceId = '865166028011578'
androidId = 'AA51B2B3149156A4'.upper()
username = 'lao3'

keyGen = KeyGen()
reg_code = keyGen.GenRegCode(username, deviceId, androidId)
print(f'用户名:{username},注册码:{reg_code}')

说明

完整的KeyGen代码因为限制,就没完整上传…样本比较简单,而且分析流程已经很详细…可自己动手实现

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:35:19  更:2021-08-21 15:37:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:19:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码