攻防世界mobile做题记录

碰到一道安卓题,好像要so动调,所以学一下安卓逆向

easyjni

使用jeb打开查看文件Manifest,查看name属性,可知入口为com.a.easyjni.MainActivity

package com.a.easyjni;

import android.os.Bundle;
import android.support.v7.app.c;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends c {
static {
System.loadLibrary("native");
}

static boolean a(MainActivity arg1, String arg2) {
return arg1.a(arg2);
}

private boolean a(String arg3) {
try {
return this.ncheck(new a().a(arg3.getBytes()));
}
catch(Exception v0) {
return false;
}
}

private native boolean ncheck(String arg1) {
}

@Override // android.support.v7.app.c
protected void onCreate(Bundle arg3) {
super.onCreate(arg3);
this.setContentView(0x7F04001B); // layout:activity_main
this.findViewById(0x7F0B0076).setOnClickListener(new View.OnClickListener() { // id:button
@Override // android.view.View$OnClickListener
public void onClick(View arg4) {
if(MainActivity.a(MainActivity.this, ((EditText)((MainActivity)this).findViewById(0x7F0B0075)).getText().toString())) { // id:edit
Toast.makeText(this, "You are right!", 1).show();
return;
}

Toast.makeText(this, "You are wrong! Bye~", 1).show();
}
});
}
}

主函数调用MainActivity.a方法,跟进发现调用另一个a方法

return this.ncheck(new a().a(arg3.getBytes()));  

首先实例化a对象,然后调用ncheck,这个ncheck是so文件的函数

首先分析a对象

package com.a.easyjni;

public class a {
private static final char[] a;
static {
a.a = new char[]{'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};
}

public String a(byte[] arg10) {
StringBuilder v4 = new StringBuilder();
int v0;
for(v0 = 0; v0 <= arg10.length - 1; v0 += 3) {
byte[] v5 = new byte[4];
int v3 = 0;
byte v2 = 0;
while(v3 <= 2) {
if(v0 + v3 <= arg10.length - 1) {
v5[v3] = (byte)(v2 | (arg10[v0 + v3] & 0xFF) >>> v3 * 2 + 2);
v2 = (byte)(((arg10[v0 + v3] & 0xFF) << (2 - v3) * 2 + 2 & 0xFF) >>> 2);
}
else {
v5[v3] = v2;
v2 = 0x40;
}

++v3;
}

v5[3] = v2;
int v2_1;
for(v2_1 = 0; v2_1 <= 3; ++v2_1) {
if(v5[v2_1] <= 0x3F) {
v4.append(a.a[v5[v2_1]]);
}
else {
v4.append('=');
}
}
}

return v4.toString();
}
}

进过观察发现加密函数为base64变表

然后分析so文件

if ( strlen(v5) == 32 )
{
for ( i = 0; i != 16; ++i )
{
v7 = &v12[i];
v12[i] = v5[i + 16];
v8 = v5[i];
v7[16] = v8;
}
(*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)a1 + 680))(a1, a3, v5);
v9 = 0;
do
{
v10 = v9 < 30;
v13 = v12[v9];
v12[v9] = v12[v9 + 1];
v12[v9 + 1] = v13;
v9 += 2;
}
while ( v10 );
result = memcmp(v12, "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7", 0x20u) == 0;
}

就交换然后比较,直接逆向写脚本

脚本

a="MbT3sQgX039i3g==AQOoMQFPskB1Bsc7"
s=[]
str=""
import base64
import string
for i in range(32):
s.append(a[i])
for i in range(0,32,2):
s[i],s[i+1]=s[i+1],s[i]
for i in range(16):
s[i],s[i+16]=s[i+16],s[i]
for i in range(32):
str+=s[i]

str1 = "i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN"
str2 = string.ascii_uppercase+string.ascii_lowercase+string.digits+"+/"
print(base64.b64decode(str.translate(str.maketrans(str1, str2))))
# flag{just_ANot#er_@p3}