【Android逆向】算法还原2
这题比较简单
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,没毛病