黑客精神
打开界面输入注册码后弹出:

JEB分析MainActivity:onCreat 函数中出现了刚刚的已注册,通过MyApp.m来判断是否已经注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public void onCreate(Bundle arg6) { String v2; super.onCreate(arg6); this.setContentView(0x7F04001A); String v1 = "Xman"; Log.d("com.gdufs.xman m=", v1); this.getApplication(); int v0 = MyApp.m; if(v0 == 0) { v2 = "未注册"; } else if(v0 == 1) { v2 = "已注册"; } else { v2 = "已混乱"; }
this.setTitle(v1 + v2); this.btn1 = this.findViewById(0x7F0B0054); this.btn1.setOnClickListener(new View$OnClickListener() { public void onClick(View arg5) { MainActivity.this.getApplication(); if(MyApp.m == 0) { MainActivity.this.doRegister(); } else { MainActivity.this.getApplication().work(); Toast.makeText(MainActivity.this.getApplicationContext(), MainActivity.workString, 0).show(); } } }); }
|
MyApp类分析:onCreate函数中调用了initSN()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class MyApp extends Application { public static int m;
static { MyApp.m = 0; System.loadLibrary("myjni"); }
public MyApp() { super(); }
public native void initSN() { }
public void onCreate() { this.initSN(); Log.d("com.gdufs.xman m=", String.valueOf(MyApp.m)); super.onCreate(); }
public native void saveSN(String arg1) { }
public native void work() { } }
|
RegActivity类中调用了saveSN方法,并把输入的值传到了本地
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void onClick(View arg5) { String v0 = RegActivity.this.edit_sn.getText().toString().trim(); if(v0 == null || v0.length() == 0) { Toast.makeText(RegActivity.this, "您的输入为空", 0).show(); } else { RegActivity.this.getApplication().saveSN(v0); new AlertDialog$Builder(RegActivity.this).setTitle("回复").setMessage("您的注册码已保存").setPositiveButton("好吧", new DialogInterface$OnClickListener() { public void onClick(DialogInterface arg2, int arg3) { Process.killProcess(Process.myPid()); } }).show(); }
|
分析so层代码
找到JNI_OnLoad注册函数

跟到n1:initSN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| v2 = j_fopen("/sdcard/reg.dat", "r+"); v3 = v2; if ( !v2 ) { v4 = a1; return setValue(v4, 0); } j_fseek(v2, 0, 2); v5 = j_ftell(v3); v6 = (const char *)j_malloc(v5 + 1); if ( !v6 ) { j_fclose(v3); v4 = a1; return setValue(v4, 0); } j_fseek(v3, 0, 0); j_fread(v6, v5, 1, v3); v6[v5] = 0; if ( !j_strcmp(v6, "EoPAoY62@ElRD") ) { v8 = a1; v9 = 1; } else { v8 = a1; v9 = 0; } setValue(v8, v9); return j_fclose(v3); }
|
跟到n2:saveSN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| v5 = j_fopen("/sdcard/reg.dat", "w+"); if ( !v5 ) return j___android_log_print(3, "com.gdufs.xman", byte_2E5A); strcpy(v13, "W3_arE_whO_we_ARE"); v7 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0); v8 = v7; v12 = j_strlen(v7); v9 = 2016; while ( 1 ) { v10 = v8 - v7; if ( v8 - v7 >= v12 ) break; if ( v10 % 3 == 1 ) { v9 = (v9 + 5) % 16; v11 = v13[v9 + 1]; } else if ( v10 % 3 == 2 ) { v9 = (v9 + 7) % 15; v11 = v13[v9 + 2]; } else { v9 = (v9 + 3) % 13; v11 = v13[v9 + 3]; } *v8++ ^= v11; } j_fputs(v7, v5); return j_fclose(v5); }
|
写脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| n1='EoPAoY62@ElRD' data='W3_arE_whO_we_ARE' v9=2016 flag='' for i in range(len(n1)): if i % 3 == 1: v9 = (v9 +5) % 16 res = data[v9 + 1] elif i % 3 ==2: v9 = (v9 + 7) % 15 res = data[v9 + 2] else: v9 = (v9 + 3) % 13 res = data[v9 + 3] flag+=chr(ord(n1[i])^ord(res)) print(flag)
|
运行
最终flag{201608Am!2333}