re | [FlareOn2]Android

re | [FlareOn2]Android

因为arm的调试机被我丢学校了,,,所以这个题没法调试,小小的参考了一下国外师傅的文章:
http://nieluj.github.io/flareon2/

题目主要是native层的一个安卓逆向,ida打开,然后修一下参数:

int __fastcall Java_com_flareon_flare_ValidateActivity_validate(JNIEnv *env, jobject thiz, jstring str1)
{
  JNIEnv *v3; // r5
  int input; // r0
  int input_1; // r6
  jstring (*v6)(JNIEnv *, const char *); // r3
  JNIEnv *v7; // r0
  const char *v8; // r1
  unsigned int v9; // r4
  int v10; // r7
  size_t i; // [sp+0h] [bp-1BB8h]
  int v13; // [sp+4h] [bp-1BB4h]
  jstring v14; // [sp+8h] [bp-1BB0h]
  signed int v15; // [sp+Ch] [bp-1BACh]
  unsigned int v16; // [sp+10h] [bp-1BA8h]
  char dest[92]; // [sp+1Ch] [bp-1B9Ch]
  char s; // [sp+78h] [bp-1B40h]

  v3 = env;
  v14 = str1;
  j_memset(&s, 0, 0x1B28);
  j_memcpy(dest, &off_5004, 92);
  input = ((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*v3)->GetStringUTFChars)(v3, v14, 0);
  input_1 = input;
  if ( input && j_strlen(input) <= 46 )
  {
    v13 = 0;
    v15 = 1;
    for ( i = 0; i < j_strlen(input_1); i += 2 )
    {
      j_memset(&s, 0, 0x1B28);
      v9 = 0;
      if ( *(_BYTE *)(input_1 + i) )
      {
        v9 = *(unsigned __int8 *)(input_1 + i);
        if ( *(_BYTE *)(input_1 + i + 1) )
          v9 = (unsigned int)&unk_7E7E >= ((*(unsigned __int8 *)(input_1 + i) << 8) | (unsigned int)*(unsigned __int8 *)(input_1 + i + 1)) ? (*(unsigned __int8 *)(input_1 + i) << 8) | *(unsigned __int8 *)(input_1 + i + 1) : 0;
      }
      v10 = 0;
      do
      {
        v16 = *(unsigned __int16 *)((char *)&word_2214 + v10);
        while ( !(v9 % v16 & 0xFFFF) )
        {
          ++*(_WORD *)(&s + v10);
          v9 = v9 / v16 & 0xFFFF;
          if ( v9 <= 1 )
            goto LABEL_10;
        }
        v10 += 2;
      }
      while ( v10 != 0x1B28 );
LABEL_10:                                       // 应该是比较
      if ( !j_memcmp(*(_DWORD *)&dest[4 * v13], &s, 0xD94) )
        ++v13;
      else
        v15 = 0;
    }
    ((void (__fastcall *)(JNIEnv *, jstring, int))(*v3)->ReleaseStringUTFChars)(v3, v14, input_1);
    v6 = (*v3)->NewStringUTF;
    v7 = v3;
    if ( v13 == 23 && v15 )                     // 正确
                                                // 
      v8 = "That's it!";
    else
      v8 = (const char *)&unk_3D3C;
  }
  else
  {
    ((void (__fastcall *)(JNIEnv *, jstring, int))(*v3)->ReleaseStringUTFChars)(v3, v14, input_1);
    v6 = (*v3)->NewStringUTF;
    v7 = v3;
    v8 = (const char *)&unk_3D3C;
  }
  return ((int (__fastcall *)(JNIEnv *, const char *))v6)(v7, v8);
}

先清空了s,然后将全局区的一块内容拷贝到dest,这块内容是23个有效地址:

image

这些地址都指向了3476长度的word数组,其中大部分是0:

image

中间反正就是基层循环,然后v9能不能整除一个数组里的元素,这数组在rodata区,直接能看到:

image

image

如果能整除,s[index] ++;
最后反正就是比较s和dest里的东西:
image

国外那个师傅用的是ruby写的exp,我直接用python写了,其实中间的关键就是还原的乘方运算,在程序中是除几次,在这里其实就是乘方还原,总的来说这个题是比较有意思的一个题,比较新鲜又能学到一点东西,感觉flare-on确实是高质量比赛。

exp:

import struct
# author Mz1
t1_addr = 0x5004
with open('libvalidate.so', 'rb') as f:
	f.seek(t1_addr-0x1000)   # 这里要-0x1000其实我没有特别搞清楚,应该是跟elf的fov有关系的
	t1_data = f.read(23*4)
	t1 = struct.unpack("<"+"I"*23,t1_data)
	for i in t1:    # 先get所有对照表的地址
		print(hex(i))
	print()
	f.seek(0x2214)
	word_2214_data = f.read(6952)
	word_2214 = struct.unpack("<"+"H"*3476, word_2214_data)
	print(word_2214[:5])   # 才反应过来这不是质数吗?
	
	res = []
	
	for i in t1:
		offset = i - 0x1000
		f.seek(offset)
		data = f.read(6952)
		a = struct.unpack("<"+"H"*3476, data)
		v = 1
		for j in range(len(a)):
			if a[j] != 0:
				v *= word_2214[j] ** a[j]
		res.append((v >> 8))
		res.append((v & 0xff))
		
print(res)
for i in res:
	print(chr(i),end='')


posted @ 2023-01-08 23:06  Mz1  阅读(201)  评论(0编辑  收藏  举报