1.题目分析
发现是一个apk文件,用jadx-gui工具载入apk,单击jadx-gui导航栏中的放大镜按钮打开搜索界面。
在搜索界面里文本框中输入“正确”或“失败”等字符串(为什么搜索“正确”,“失败”字符串?多次试错,首先可以从flag等有用信息开始搜索),发现一处代码关键位置,如下图所示。
跟进查看源码:
2.解题步骤
阅读代码,发现关键函数在jni层的Judge函数中,程序将用户输入的字符串传入Judge函数中,Judge函数返回的字符串跟”success”进行比较,很明显当输入正确flag时judge函数会返回“success”,接下来分析so层,将apk文件修改后缀为.zip压缩包格式,打开进入lib目录,将里面的libnative-lib.so拖入IDA中,通过在IDA函数窗口中搜索Judge关键字,发现找不到函数,猜测函数是用动态注册方式,在函数窗口搜索jni_onload函数,如下图所示。
从上图分析可知,动态注册的Judge()函数就是sub_7D0函数,双击进入到该函数,函数代码如下所示。
__int64 __fastcall sub_7D0(__int64 *a1, __int64 a2, __int64 a3)
{
__int64 v4; // x0
__int64 v5; // x23
__int64 v6; // x8
__int128 *v7; // x1
__int128 v9[3]; // [xsp+0h] [xbp-140h] BYREF
__int16 v10; // [xsp+30h] [xbp-110h]
__int128 v11[3]; // [xsp+40h] [xbp-100h] BYREF
__int16 v12; // [xsp+70h] [xbp-D0h]
__int128 v13[3]; // [xsp+80h] [xbp-C0h] BYREF
__int16 v14; // [xsp+B0h] [xbp-90h]
__int128 v15[3]; // [xsp+C0h] [xbp-80h] BYREF
__int16 v16; // [xsp+F0h] [xbp-50h]
__int64 v17; // [xsp+F8h] [xbp-48h]
v17 = *(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v4 = (*(*a1 + 1352))(a1, a3, 0LL);
memset(v15, 0, sizeof(v15));
memset(v11, 0, sizeof(v11));
v13[0] = *"success";
memset(&v13[1], 0, 32);
v14 = 0;
qmemcpy(v11, "false", 5);
v9[0] = unk_9DE;
v9[1] = unk_9EE;
v16 = 0;
v12 = 0;
v9[2] = xmmword_9FE;
v10 = 0;
__strcpy_chk(v15, v4, 50LL);
if ( __strlen_chk(v9, 0x32u) )
{
v5 = 0LL;
while ( *(v9 + v5) == (byte_A10[*(v15 + v5)] - (5 * (v5 / 5) + 4 == v5)) )
{
if ( __strlen_chk(v9, 0x32u) <= ++v5 )
goto LABEL_5;
}
v6 = *a1;
v7 = v11;
}
else
{
LABEL_5:
v6 = *a1;
v7 = v13;
}
return (*(v6 + 1336))(a1, v7);
}
简化的伪代码整体如下:
简化的伪代码整体如下:
char* Judge(JNIEnv* al, int a2, char* a3)
{
const char *v3; // eax
size_t v4; // esi
const char *v5; // edi
int v6; // edx
int v7; // eax
char *v8; // ecx
char v10[9]; // [esp+1Ah] [ebp-B2h] BYREF
int v11; // [esp+23h] [ebp-A9h]
int v12; // [esp+27h] [ebp-A5h]
int v13; // [esp+2Bh] [ebp-A1h]
int v14; // [esp+2Fh] [ebp-9Dh]
int v15; // [esp+33h] [ebp-99h]
int v16; // [esp+37h] [ebp-95h]
int v17; // [esp+3Bh] [ebp-91h]
int v18; // [esp+3Fh] [ebp-8Dh]
char v19; // [esp+43h] [ebp-89h]
int v20; // [esp+44h] [ebp-88h]
int v21; // [esp+48h] [ebp-84h]
_QWORD v22[6]; // [esp+4Ch] [ebp-80h] BYREF
__int16 v23; // [esp+7Ch] [ebp-50h]
char dest[16]; // [esp+80h] [ebp-4Ch] BYREF
__int128 v25; // [esp+90h] [ebp-3Ch]
__int128 v26; // [esp+A0h] [ebp-2Ch]
__int16 v27; // [esp+B0h] [ebp-1Ch]
v3 = (*a1)->GetStringUTFChars(a1, a3, 0);
memset(&v22[1], 0, 40); ,
v22[0] = “success”;
strcpy(v10, "false");
strcpy(input, v3);
for(int i, i< strlen(a3p); i++)
{
if(byte_8F8[input[i]] - (5 * (i/ 5) + 4 == i) == a3p[i])
{
//满足条件继续
}
else
{
//不满足条件跳出循环
v6 = a1;
v7 = *al;
v8 = v10;
return v7->NewStringUTF(v6, v8);
这几行代码,接着直接return走出函数,
}
}
v6 = a1;
v7 = *a1;
v8 = v22;
return v7->NewStringUTF(v6, v8);
解密:
取出a3p数组,
char a3p[50] = {0x33,0x50,0xef,0x85,0x20,0xd6,0x9d,0x8f,0x92
,0xce,0x5a,0xf9,0x40,0x8f,0x91,0xcf,0x20,0x40,0xb6,0xfe};
循环遍历a3p数组,当下标i满足5 * (i/ 5) + 4 == i时,将对应下标的值加一,然后再根据a3p数组中的值去找byte_8F8对应值的下标,
解密代码如下:
unsigned char sbox[256] = {
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,
0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,
0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,
0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,
0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,
0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,
0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,
0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,
0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,
0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,
0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,
0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,
0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,
0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,
0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,
0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,
0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
};
int main()
{
unsigned char a3p[50] = { 0x33,0x50,0xef,0x85,0x20,0xd6,0x9d,0x8f,0x92,0xce,0x5a,0xf9,0x40,0x8f,0x91,0xcf,0x20,0x40,0xb6,0xfe };
char result[50] = { 0 };
for (int i = 0; i < strlen((char*)a3p); i++)
{
if (5 * (i / 5) + 4 == i)
{
a3p[i] = a3p[i] + 1;
}
for (int j = 0; j < 256; j++)
{
if (sbox[j] == a3p[i])
{
result[i] = j;
}
}
}
printf("%s\n", result);
}
运行即可得到flag。