Jeb打开apk
关键代码在Native函数getResult
IDA 打开 so
发现代码比较简单,可以直接静态分析。
输出字符串也就是flag 长度是15,然后分成三段,第一段是可以整除3,第二段是除3取余=1,第三段是除3取余等于2;
cpp
bool __fastcall Java_com_example_test_ctf03_JNI_getResult(JNIEnv *a1, int a2, int a3)
{
int v3; // r4
const char *v4; // r8
char *v5; // r6
char *v6; // r4
char *v7; // r5
int i; // r0
int j; // r0
v3 = 0;
v4 = (*a1)->GetStringUTFChars(a1, a3, 0); //输入字符串
if ( strlen(v4) == 15 ) //判断输入字符串长度==15
{
v5 = malloc(1u);
v6 = malloc(1u);
v7 = malloc(1u);
Init(v5, v6, v7, v4, 15); //输入字符串分成三段
if ( !First(v5) ) //第一部分比较
return 0;
for ( i = 0; i != 4; ++i )
v6[i] ^= v5[i];
if ( !strcmp(v6, " 5-\x16a") ) //第二部分比较
{
for ( j = 0; j != 4; ++j )
v7[j] ^= v6[j];
return strcmp(v7, "AFBo}") == 0; //第三部分比较
}
else
{
return 0;
}
}
return v3;
}
Init 字符串分成三段
int __fastcall Init(int result, char *a2, char *a3, const char *a4, int a5)
{
int v5; // r5
int v6; // r10
int v7; // r6
if ( a5 < 1 )
{
v6 = 0;
}
else
{
v5 = 0;
v6 = 0;
do
{
v7 = v5 % 3;
if ( v5 % 3 == 2 ) //除3取余 == 2 是第3段
{
a3[v5 / 3u] = a4[v5];
}
else if ( v7 == 1 ) //除3取余 == 1 是第2段
{
a2[v5 / 3u] = a4[v5];
}
else if ( !v7 )
{
++v6;
*(result + v5 / 3u) = a4[v5]; //除3是第1段
}
++v5;
}
while ( a5 != v5 );
}
*(result + v6) = 0;
a2[v6] = 0;
a3[v6] = 0;
return result;
}
计算第一段
就是一个异或运算,注意这里只计算了4位,第5位不用算就是"l";
cpp
First处理第一段
bool __fastcall First(char *a1)
{
int i; // r1
for ( i = 0; i != 4; ++i )
a1[i] = (2 * a1[i]) ^ 0x80; //经过运算后判断是否== LN^dl ,先乘以2再异或0x80, 反推就是用 LN^dl先异或0x80再除以2
return strcmp(a1, "LN^dl") == 0;
}
可以算出第一段的值是 fgorl
java
char[] chars = new char[]{'L','N','^','d','l'};
char[] res = new char[5];
for (int i = 0; i < 4; i++) {
res[i] = (char) ((chars[i] ^ 0x80)/2);
}
res[4] = 'l';
System.out.println(res);
计算第二段
第二段也是一个异或,同样也只算4位,第5位不用异或计算。注意这里的v5 不是上面计算出来的第一段的值,是上面异或之后的也就是"LN^dl" ,
cpp
for ( i = 0; i != 4; ++i )
v6[i] ^= v5[i];
if ( !strcmp(v6, a5A) )
可以算出第二段的值 是 l{sra
java
char[] c2 = new char[]{0x20,0x35,0x2D,0x16,0x61}; //a5A
char[] r2 = new char[5];
for (int i = 0; i < 4; i++) {
r2[i] = (char) (chars[i]^c2[i]); //chars 是上面的 LN^dl
}
r2[4] = 0x61;
System.out.println(r2);
计算第三段
一样的套路,还是异或计算4位,第5位直接照搬是"}"
cpp
for ( j = 0; j != 4; ++j )
v7[j] ^= v6[j];
return strcmp(v7, "AFBo}") == 0;
可以计算出第三段 是 asoy}
java
char[] c3 = new char[]{0x41, 0x46, 0x42, 0x6F, 0x7D}; // "AFBo}"
char[] r3 = new char[5];
for (int i = 0; i < 4; i++) {
r3[i] = (char) (c2[i] ^ c3[i]);
}
r3[4] = 0x7D;
System.out.println(r3);
组合起来就是flag
三段数据组合起来就是flag了
第一段:fgorl -------------整除3,对应的下标就是0,3,6,9,12
第二段:l{sra -------------除3余1,对应下标就是1,4,7,10,13
第三段:asoy} -------------除3余2,对应下标就是2,5,8,11,14
组合结果就是:flag{sosorryla}
完整计算代码:
java
public static void main(String[] args) {
char[] chars = new char[]{'L','N','^','d','l'};
char[] res = new char[5];
for (int i = 0; i < 4; i++) {
res[i] = (char) ((chars[i] ^ 0x80)/2);
}
res[4] = 'l';
System.out.println(res);
//第二段
char[] c2 = new char[]{0x20,0x35,0x2D,0x16,0x61};
char[] r2 = new char[5];
for (int i = 0; i < 4; i++) {
r2[i] = (char) (chars[i]^c2[i]);
}
r2[4] = 0x61;
System.out.println(r2);
//第三段
char[] c3 = new char[]{0x41, 0x46, 0x42, 0x6F, 0x7D};
char[] r3 = new char[5];
for (int i = 0; i < 4; i++) {
r3[i] = (char) (c2[i] ^ c3[i]);
}
r3[4] = 0x7D;
System.out.println(r3);
//还原
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 5; i++) {
stringBuilder.append(res[i]);
stringBuilder.append(r2[i]);
stringBuilder.append(r3[i]);
}
System.out.println(stringBuilder);
}