【Android逆向】算法还原2

android,逆向,算法,还原 · 浏览次数 : 30

小编点评

**摘要:** 这篇文章探讨了如何通过 Java 代码实现对 APK 文件的 AES 加密验证。 **步骤:** 1. **获取 APK 文件的二进制数据** 2. **使用 JNI 运行 native 代码** 3. **验证输入的用户名和密码** 4. **使用 EVP 模块对用户名和密码进行加密** 5. **将加密后的用户名和密码转换为 base64 字符** 6. **如果用户名和密码正确,则验证通过** **关键代码:** ```java private native boolean check(byte[] bArr, byte[] bArr2); ``` **说明:** * `check()` 函数使用 JNI 的 `GetByteArrayElements()` 方法获取 username 和密码的二进制数据。 * `EVP_CIPHER_CTX_new()` 和 `EVP_EncodeInit()` 用于对用户名和密码进行 AES 加密。 * `EVP_CIPHER_CTX_set_padding()` 设置加密的 padding。 * `EVP_aes_128_ecb()` 使用 AES 128 位加密。 * `b64encode()` 用于将加密后的用户名和密码转换为 base64 字符。

正文

这题比较简单

1. app-release.apk 安装至手机

提示需要输入账号和密码

2. jadx 打开看看

public native boolean check(byte[] bArr, byte[] bArr2);

    static {
        System.loadLibrary("native-lib");
    }

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        this.edt_username = (EditText) findViewById(R.id.edt_username);
        this.edt_code = (EditText) findViewById(R.id.edt_code);
        Button button = (Button) findViewById(R.id.btn_check);
        this.btn_check = button;
        button.setOnClickListener(this);
    }

    @Override // android.view.View.OnClickListener
    public void onClick(View view) {
        if (view.getId() != R.id.btn_check) {
            return;
        }
        String obj = this.edt_username.getText().toString();
        String obj2 = this.edt_code.getText().toString();
        if (obj.length() == 0 || obj2.length() == 0) {
            Toast.makeText(this, "输入不完整!", 1).show();
        } else if (check(obj.getBytes(), obj2.getBytes())) {
            Toast.makeText(this, "验证通过!", 1).show();
            congratulation();
        } else {
            Toast.makeText(this, "验证失败!", 1).show();
        }
    }

    private void congratulation() {
        startActivity(new Intent(this, Congratulation.class));
        finish();
    }

check 在native层

2. so 使用IDA打开看看

bool __fastcall Java_com_r0ysue_crackme_MainActivity_check(JNIEnv *env, jobject object, int username, int password)
{
  int v7; // r11
  jbyte *v8; // r10
  jbyte *password_chars; // r5
  jsize v10; // r6
  int v11; // r5
  int v12; // r0
  int v13; // r0
  int v14; // r4
  char *t_passwd_chars; // [sp+8h] [bp-100h]
  int v17; // [sp+Ch] [bp-FCh] BYREF
  int v18; // [sp+10h] [bp-F8h] BYREF
  int v19; // [sp+14h] [bp-F4h] BYREF
  char v20[104]; // [sp+18h] [bp-F0h] BYREF
  char v21[104]; // [sp+80h] [bp-88h] BYREF

  v7 = 0;
  v8 = (*env)->GetByteArrayElements(env, username, 0);
  password_chars = (*env)->GetByteArrayElements(env, password, 0);
  v10 = (*env)->GetArrayLength(env, (jarray)username);
  if ( (unsigned int)(v10 - 6) <= 0xE )
  {
    t_passwd_chars = password_chars;
    v11 = EVP_CIPHER_CTX_new();
    v12 = EVP_CIPHER_CTX_set_padding(v11, 1);
    v13 = EVP_aes_128_ecb(v12);
    EVP_EncryptInit(v11, v13, "kanxuenbkanxuenb", 0);
    memset(v21, 0, 0x64u);
    v18 = 0;
    v19 = 0;
    EVP_EncryptUpdate(v11, v21, &v19, v8, v10);
    EVP_EncryptFinal(v11, &v21[v19], &v18);
    EVP_CIPHER_CTX_free(v11);
    v18 += v19;
    v14 = EVP_ENCODE_CTX_new();
    EVP_EncodeInit();
    memset(v20, 0, 0x64u);
    v17 = 0;
    EVP_EncodeUpdate(v14, v20, &v17, v21, v18);
    EVP_EncodeFinal(v14, &v20[v17], &v17);
    return strncmp(t_passwd_chars, v20, v17 - 1) == 0;
  }
  return v7;
}

直接搜 EVP_CIPHER_CTX_new 和 EVP_EncodeInit ,发现是Openssl 的标准实现,那么猜测是先进行AES加密 , 再进行base64 encode
直接打开 https://gchq.github.io/CyberChef/ 验证猜想,发现还真是的

3. 编写注册机

from Crypto.Cipher import AES
from base64 import b64encode
 
key = b"kanxuenbkanxuenb"
mode = AES.MODE_ECB
 
 
bs = 16
PADDING = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
 
 
# 在这里输入username
text = "helloworld"
generator = AES.new(key, mode)
crypt = generator.encrypt(PADDING(text).encode())
b64 = b64encode(crypt)
print("username --> " + "helloworld")
print("code --> " + b64.decode())

日志

# python lesson202111.py 
username --> helloworld
code --> TyjG/EYaUC8EXxz7/sXiCA==

手机上输入,验证ok,没毛病

与【Android逆向】算法还原2相似的内容:

【Android逆向】算法还原2

这题比较简单 1. app-release.apk 安装至手机 提示需要输入账号和密码 2. jadx 打开看看 public native boolean check(byte[] bArr, byte[] bArr2); static { System.loadLibrary("native-l

【Android逆向】破解看雪9月算法破解第三题

这题的目标是算法还原,并写出注册机 1. 9月份算法第一题.apk 安装到手机 2. 随意输入账号密码,提示错误 3. apk拖入到jadx中 public native boolean register(String str, String str2); static { System.loadL

【Android 逆向】【攻防世界】android2.0

这是一道纯算法还原题 1. apk安装到手机,提示输入flag,看来输入就是flag 2. jadx 打开apk查看 this.button.setOnClickListener(new View.OnClickListener() { // from class: com.example.test

【Android逆向】破解看雪9月算法破解第一题

1. 安装apk到手机 2. 随意输入账号和密码,点击register,报错crackme1:ERROR 3. 将apk拖入到jadx中进行观察 public native String register(String str); static { System.loadLibrary("nativ

【Android逆向】破解看雪9月算法破解第二题

1. apk安装到手机,一样的界面,随便输入一样的报错 2. apk拖入到jadx重看看 public native String sha1(String str); static { System.loadLibrary("native-lib"); } /* JADX INFO: Access

【Android逆向】frida 破解 jwxdxnx02.apk

apk 路径: https://pan.baidu.com/s/1cUInoi 密码:07p9 这题比较简单,主要是用于练习frida 1. 安装apk到手机 需要输入账号密码 2. 使用jdax 查看apk package hfdcxy.com.myapplication; import andr

[Android逆向]Exposed 破解 jwxdxnx02.apk

使用exposed 遇到了一些坑,这里记录一下 源码: package com.example.exposedlesson01; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.X

[Android 逆向]frida 破解 切水果大战原版.apk

1. 手机安装该apk,运行,点击右上角礼物 提示 支付失败,请稍后重试 2. apk拖入到jadx中,待加载完毕后,搜素失败,找到疑似目标类MymmPay的关键方法payResultFalse 4. adb logcat 或者androidstudio 查看该进程的日志,发现以下日志 com.mf

[Android 逆向]Xposed 破解 切水果大战原版.apk

代码 public class Main implements IXposedHookLoadPackage { boolean flag = false; @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam

【Android逆向】frida 破解 滚动的天空

1. apk 安装到手机中 2. 玩十次之后,会提示 充值 3. adb shell dumpsys window | grep mCurrentFocus 查看一些当前activity是哪一个 是 AppActivity 4. 阅读代码,感觉是unity3d做的游戏 5. apk拖入到jadx中,