先了解一个关键字
NATIVE 静态链接
首先用jeb打开:
找到MainActivity(Tab反汇编):
package com.sec.ctf2;
import android.app.Activity;
import android.os.Bundle;
import android.view.View$OnClickListener;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final int FLAG_LEN = 15;
private static final String TAG = "main";
public MainActivity() {
super();
}
protected void onCreate(Bundle arg4) {
super.onCreate(arg4);
this.setContentView(0x7F030000);
this.findViewById(0x7F070001).setOnClickListener(new View$OnClickListener(this.findViewById(0x7F070000)) {
public void onClick(View arg6) {
try {
String v1 = this.val$etFlag.getText().toString();
if(v1 == null) {
Toast.makeText(MainActivity.this, "Invalid flag!", 0).show();
return;
}
if(v1.length() != 15) {
Toast.makeText(MainActivity.this, "Invalid flag!", 0).show();
return;
}
if(HelloJni.getFlag(v1.getBytes("utf-8"))) {
Toast.makeText(MainActivity.this, "You win!", 0).show();
return;
}
Toast.makeText(MainActivity.this, "Sorry, try again!", 0).show();
}
catch(Exception v0) {
v0.printStackTrace();
}
}
});
}
}
流程比较简单,flag长度是15,HelloJni.getFlag(v1.getBytes(“utf-8”)非0就可以输出You win
双击进入getFlag定义
package com.sec.ctf2;
public class HelloJni {
static {
System.loadLibrary("hello");
}
public HelloJni() {
super();
}
public static native boolean getFlag(byte[] arg0) {
}
}
却发现没有代码,这是怎么回事,还没学java,问了其他师傅,native关键字连接静态链接库hello,上面也能看到loadLibrary(“hello”),所以check密码的代码在os文件(静态链接库)中
怎么看静态链接库呢?
在上面窗口中我们看到了这个os文件,
可以直接把apk后缀改成zip,然后解压,把里面的os文件使用IDA打开:
打开以后,在函数窗口搜索(ctrl + f):hello
找到这个函数然后反汇编
但是发现提示aFlagIsNotHere;
在查看这个字符串的时候,下面有可疑字符
交叉引用:
int __fastcall sub_1104(int a1, int a2, int a3)
{
int v3; // r5
int v4; // r4
char *v5; // r6
size_t v6; // r0
signed int v7; // r4
unsigned __int8 *v8; // r0
unsigned __int8 *v9; // r5
size_t v10; // r0
signed int v11; // r2
_BYTE *v12; // r3
int v13; // t1
const char *v14; // r2
int result; // r0
int v16; // r3
int v17; // t1
int v18; // t1
v3 = a1;
v4 = a3;
v5 = (char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 736))(a1, a3, 0);
v6 = (*(int (__fastcall **)(int, int))(*(_DWORD *)v3 + 684))(v3, v4);
v7 = v6;
v8 = (unsigned __int8 *)malloc(v6);
v9 = v8;
if ( v7 <= 0 )
{
v8[v7] = 0;
LABEL_11:
LOBYTE(result) = 1;
return (unsigned __int8)result;
}
v10 = strlen(byte_4028) + 47;
v11 = v7;
v12 = v9;
do
{
v13 = *v5++;
--v11;
*v12++ = byte_4028[v10 - v13] ^ 0x5F;
}
while ( v11 );
v9[v7] = 0;
if ( v7 < 1 )
goto LABEL_11;
v14 = "vrt~rzey{vvyt{v";
LOBYTE(result) = 1;
do
{
v17 = *v9++;
v16 = v17;
v18 = *(unsigned __int8 *)v14++;
if ( v18 != v16 )
LOBYTE(result) = 0;
--v7;
}
while ( v7 );
return (unsigned __int8)result;
}
这里就是c语言了,有人会好奇,为什么安卓里面有c语言,这就看上面的native了。
流程比较简单,但是好像有两个地方不好理解:
v5 = (char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 736))(a1, a3, 0);
v6 = (*(int (__fastcall **)(int, int))(*(_DWORD *)v3 + 684))(v3, v4);
上面是输入的字符串,下面的是字符串的长度,也就是15
从程序看我也不知道为什么,这是后面的算法看出来的。
写逆向的脚本:
python3
x = 'vrt~rzey{vvyt{v'
y = [0x21, 0x3A, 0x23, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2B, 0x2D]#)-+!-%:&$))&+$)
flag = ""
for i in range(15):
for j in range(10):
if y[j] == 0x5F ^ ord(x[i]):
flag += chr(57-j)
print(flag)