SCTF-RE200破解笔记

来源:互联网 发布:李小璐遭网络诈骗 编辑:程序博客网 时间:2024/06/08 15:18

菜鸟一个,主要是学习Android破解,记录提高自己。


1. 准备环境

  • IDA Pro 6.1以上版本
  • Android 虚拟机或一部root的手机
  • 安卓改之理(apktool与jeb也行)
  • JD-Gui

2. 分析过程

首先利用ApkIDE将apk文件解压,获得以下结构,如何调用JD-Gui查看代码

从代码中可以看到,程序做了反调试的操作。输入的字符串为flag时,弹出来一个Toast提示,所以关键代码在libeasy中。

用IDA 打开libeasy,查找导出函数Java_com_syc_kitkat_func(为什么是这样子?请查找相关资料,JNI编程),但是找了半天没有发现此函数,顿时没了方向。

后来记起来,so文件申明注册函数,可以在JNI_Onload中注册。dex文件加载so文件时,首先会在导出函数中查找JNI_Onload函数,JNI_Onload的默认情况下,不需要我们去声明与定义,但是我们可以重写JNI_Onload,来注册func函数。

查看JNI_Onload函数,由于对arm不是很熟,直接用IDA+f5 arm插件


可以看出,真正处理字符串的函数为cxa_begin_match函数。

查看cxa_begin_match函数

这里先说明下,主办方给了提示:反调试,代码在.init段

我们查看.init段,发现定义了个函数,_cxa_chk_fail函数。

该函数创建了一个线程执行某些任务。

void __fastcall sub_1A74(){  __pid_t v0; // r4@2  int v1; // r6@2  FILE *v2; // r2@2  signed int v3; // r5@4  int v4; // r0@6  unsigned int v5; // r4@8  const char *v6; // r0@12  signed int v7; // r3@14  const char *v8; // r0@15  struct timeval tv; // [sp+Ch] [bp-ECh]@2  struct timeval v10; // [sp+14h] [bp-E4h]@10  char command; // [sp+1Ch] [bp-DCh]@2  char s; // [sp+5Ch] [bp-9Ch]@2  int v13; // [sp+DCh] [bp-1Ch]@1  v13 = _stack_chk_guard;  while ( 1 )  {    gettimeofday(&tv, 0);    v0 = getpid();    v1 = sub_1880();//判断pid中,status的状态    memset(&s, 0, 0x80u);    memset(&command, 0, 0x40u);    sprintf(&command, "cat /proc/%d/wchan", v0);    v2 = popen(&command, "r");    if ( v2 )      fgets(&s, 128, v2);    v3 = 17;    if ( strncasecmp(&s, "sys_epoll_wait", 0xEu) )      v3 = (unsigned int)strncasecmp(&s, "ptrace_stop", 0xBu) <= 0;    v4 = sub_1910(v0);//判断TracePid的值,一般为0    if ( v3 == 1 || v1 == 2 )      v5 = 0;    else      v5 = (v4 | (unsigned int)(v4 - 1)) >> 31;    gettimeofday(&v10, 0);    if ( v5 )    {      if ( !tempabc[0] )//如果为空,赋值为syc      {        v6 = (const char *)gun_Unwind1("u{e");//syc        strcpy(tempabc, v6);      }      if ( !m_y )      {        v7 = 6;LABEL_20:        m_y = v7;//m_y=9        goto LABEL_21;      }    }    else    {      v8 = (const char *)gun_Unwind1("zevh");tempabc等于"xctf"      if ( strcmp(tempabc, v8) )        strcpy(tempabc, "xctf");      if ( m_y == 6 || !m_y )      {        v7 = 9;        goto LABEL_20;      }    }LABEL_21:    sleep(0xFu);  }}

也就是,共享so初始化了几个内容,最终初始化tempabc=“xctf”或“syc”(根据环境),m_y=9或6。

之后,当点击wa按钮后,cxa_begin_match函数执行,做了很多的判断,判断进程的运行状态等。最终的字符串处理也在这。
if ( (signed int)v6 <= 32 && (j = v6 <= 0, str1 = str, v6 > 0) )  {    while ( j < (signed int)v6 )                // 字符串与自己所在位置进行异或    {      ++j;      *(_BYTE *)str1 ^= j;      str1 = (char *)str1 + 1;    }    sleep(1u);    getpid();    v9 = getppid();    if ( !aeabi_unwind_pr0(v4, v9, &s1) )      exit(0);    v10 = (const char *)jiemi(v4, "hec");       // gdb    if ( !strcmp(&s1, v10) || (v11 = (const char *)jiemi(v4, "tusbdf"), !strcmp(&s1, v11)) )// strace      gun_Unwind_Resume(v4, str);               // exit(0)    imp_Unwind_k(v4, (const char *)str, m_y);   // 将字符串位置交换,向左交换m_y 放到tempstr中    v12 = gun_armfini_33(v4, tempStr, tempabc, (int)&s);// 简单的字符串交换,并且判断字符串条件,正确返回1    if ( v12 )    {      v12 = 0;      if ( v16 > 15 )      {        strcpy(dest, &v21);        strncpy((char *)&seed, &src, 3u);       // src存的是输入的字符串变换后的24个字符        gun_armfini_21(v4, tempabc, dest);      // 计算出dest字符串        v13 = 0;        for ( i = 0; i < strlen(dest); ++i )    // 字符串转化为16进制形式表示,放到v23中        {          sprintf(&v18, "%x", (unsigned __int8)dest[i]);          v14 = strlen(&v18);          strncpy(&v23[v13], &v18, v14);          v13 += strlen(&v18);        }        v12 = gun_arm_ldiv0(v4, v23) & 0xFF;    // 比对字符串是否为a8e5588f7e3f758      }    }  }

其中imp_Unwind_k的处理如下,其中v5为字符串长度
while ( v8 < v5 )                             // 以v12为单位进行字符串移位,往左移  {    v9 = (v8 + v12) % v5;    v10 = v4[v8++];    s[v9] = v10;  }  result = strncpy(tempStr, s, v5);

gun_armfini_33对字符串做单表替换,然后比较比较前11位字符,通过四个方程及其它位数进行计算得出前11位字符为GoodCrack3R,然后后5位字符,与(tempabc计算生成的值)dest进行异或,然后再与a8e5588f7e3f758进行比较。

最终的逆向的程序为:
import binasciidata="GoodCracK3R;{0jN|B6"tmp=""key="syc"print len(data)for i in range(0,len(data)):    if ord(data[i])>=65 and ord(data[i])<=90 :        tmp = tmp + chr(65+ (ord(data[i])-65 - (ord(key[i%len(key)])-97))%26)        print tmp    elif ord(data[i])>=97 and ord(data[i])<=122 :        tmp = tmp + chr(97+ (ord(data[i])-97 - (ord(key[i%len(key)])-97))%26)        print tmp    else:        tmp = tmp + data[i]        print tmpprint tmpdata = tmptmp=range(len(data))for i in range(0,len(data)):    tmp[(i-6)%len(data)]=data[i]data = ''.join(tmp)print datatmp=""for i in range(0,len(data)):    tmp=tmp+chr(ord(data[i])^(i+1))print tmp



0 0
原创粉丝点击