PolarCTF_REVERSE_Android

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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值