吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8893|回复: 14
收起左侧

[第十三题] 【分析】【吾爱破解2014CrackMe大赛】【第十三组】

  [复制链接]
〇〇木一 发表于 2014-11-7 15:24
android逆向什么的几乎没接触过啊,都是些基本的操作(看着大大们的文章完成的),分析也是简单的分析,感兴趣的可以看看。写的有什么问题就请见谅了。

一. 简单分析
先用apktools解开看,发现java层获取name和password后直接调用的libverify.so中的verify();
然后用IDA打开libverify.so
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
unsigned __int64 __fastcall verify(unsigned int a1, int a2, int a3, unsigned int a4)
{
  unsigned int v4; // r5@1
  int v5; // r6@1
  int v6; // r7@1
  unsigned __int64 v8; // [sp+0h] [bp-20h]@1
 
  v8 = __PAIR__(a4, a1);
  v4 = a1;
  v5 = a2;
  v6 = a3;
  if ( !sub_12A0() )
    ((void (__fastcall *)(unsigned int, int, int, _DWORD))*off_4F64)(v4, v5, v6, HIDWORD(v8));
  return v8;
}

看见他先调用了sub_12A0,通过之才去真正验证的地方
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
signed int __fastcall sub_12A0()
{
  void *v0; // r6@1
  signed int v1; // r4@1
  __pid_t v2; // r0@1
  FILE *v3; // r5@1
  char *v4; // r0@3
  signed int result; // r0@9
  int v6; // [sp+4h] [bp-7Ch]@4
  char s; // [sp+8h] [bp-78h]@1
  int v8; // [sp+6Ch] [bp-14h]@1
 
  v0 = off_4F60;
  v1 = 1;
  v8 = *(_DWORD *)off_4F60;
  memset(&s, 0, 0x64u);
  v2 = getpid();
  sprintf(&s, "/proc/%d/status", v2);
  v3 = fopen(&s, "r");
  if ( v3 )
  {
    while ( fgets(&s, 99, v3) )
    {
      v4 = strstr(&s, "TracerPid:");
      if ( v4 )
      {
        sscanf(v4 + 10, "%d", &v6);
        v1 = v6;
        if ( !v6 )
          goto LABEL_8;
        break;
      }
    }
    v1 = 1;
LABEL_8:
    fclose(v3);
  }
  result = v1;
  if ( v8 != *(_DWORD *)v0 )
    _stack_chk_fail(v1);
  return result;
}


我对linux了解的也不多,但是看见TracerPid就知道是在检测调试器了(跟踪的进程嘛)。
然后去看看真正验证的地方,发现什么都没有。想想也知道,肯定是加密了。需要调试安卓,想想就头疼。
查了几篇看雪、吾爱上的文章,还是决定要试试,虽然没有可以用的手机,但虚拟机也完全没问题。


二.ida调试
需要下载android sdk(就用个虚拟机),还有就是看雪前辈给的ida6.5
用到的adb命令在sdk/platform-tools上有,调试用的android_server在ida的dbgsrv文件夹下。
先打开虚拟机,安装apk,可以用adb install CrackMe.apk 来安装。
之后打开cmd具体操作如下:
QQ截图20141107140522.jpg

开启监听后,不要关闭cmd。打开CrackMe程序,打开ida,Debugger->Attcah->Remote ARMLinux/Android debugger

QQ截图20141107141328.jpg

选择运行着的CrackMe52进程
QQ截图20141107141556.jpg
ok,到这里就可以调试了。


三.动态跟踪

打开Modules选择libverify.so,找到verify,并下好断点。

QQ截图20141107130347.jpg

运行到此处不让它跳(前面讲得检测调试器)

QQ截图20141107130927.jpg

之后就进入真正验证的地方了

QQ截图20141107143309.jpg

四.算法分析(截图或者代码是分几次搞的,地址不一样)

验证部分:
[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
int __fastcall sub_492EECD4(int a1, int a2, int a3, int a4)
{
  int v4; // r5@1
  int v5; // r6@1
  int result; // r0@1
  int v7; // r4@3
  int Name; // r0@3
  int v9; // r3@3
  char *v10; // r3@8
  int v11; // r6@11
  int Password; // r7@11
  signed int v13; // r4@11
  int v14; // r1@12
  char v15; // cf@13
  int v16; // r6@14
  int v17; // r4@15
  int (__fastcall *v18)(_DWORD, _DWORD, _DWORD, _DWORD); // r7@16
  int v19; // r7@16
  int v20; // r0@17
  int jName; // [sp+8h] [bp-80h]@1
  int jPassword; // [sp+Ch] [bp-7Ch]@1
  int v23; // [sp+10h] [bp-78h]@1
  unsigned int v24; // [sp+18h] [bp-70h]@1
  char v25; // [sp+1Ch] [bp-6Ch]@1
  char NamePad[12]; // [sp+20h] [bp-68h]@4
  char charTable[64]; // [sp+2Ch] [bp-5Ch]@1
  int v28; // [sp+6Ch] [bp-1Ch]@1
 
  v23 = a2;
  jPassword = a4;
  v4 = a1;
  jName = a3;
  v28 = _stack_chk_guard;
  memcpy_0(charTable, "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm", 63);
  v5 = 0;
  v24 = 0x213F2E2Cu;
  v25 = 0;
  result = (*(int (__fastcall **)(int, int))(*(_DWORD *)v4 + 672))(v4, jPassword);// GetStringLength
  if ( result == 12 )
  {
    result = (*(int (__fastcall **)(int, int))(*(_DWORD *)v4 + 672))(v4, jName) - 8;// GetStringLength
    if ( (unsigned int)result <= 0xC )
    {
      v7 = (*(int (__fastcall **)(int, int))(*(_DWORD *)v4 + 672))(v4, jName);// GetStringLength
      Name = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v4 + 676))(v4, jName, 0);// GetStringUTFChars
      v9 = 0;
      if ( v7 <= 12 )
      {
        while ( v9 < v7 )
        {
          NamePad[v9] = *(_BYTE *)(Name + v9);
          ++v9;
        }
        v10 = (char *)&v24 - v7;
        while ( v7 != 12 )                      // ,.?! pad
        {
          NamePad[v7] = v10[v7];
          ++v7;
        }
      }
      else
      {
        do
        {
          NamePad[v5] = *(_BYTE *)(Name + v5);
          ++v5;
        }
        while ( v5 != 12 );
      }
      v11 = 0;
      Password = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v4 + 676))(v4, jPassword, 0);// GetStringUTFChars
      v13 = 11;//从最后开始循环
      while ( 1 )
      {
        v11 += (unsigned __int8)NamePad[v13];//累加
v14=62;
        result = ((int (__fastcall *)(int, signed int))sub_492EEF2C)(v11, v14);
        if ( (unsigned __int8)charTable[v14] != *(_BYTE *)(Password + v13) )
          break;
        v15 = (unsigned int)v13-- >= 1;
        if ( !v15 )
        {
          result = (*(int (__fastcall **)(int, _DWORD))(*(_DWORD *)v4 + 24))(v4, "android/widget/Toast");
          v16 = result;
          if ( result )
          {
            result = (*(int (__fastcall **)(int, int, _DWORD, _DWORD))(*(_DWORD *)v4 + 452))(
                       v4,
                       result,
                       "makeText",
                       "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");
            v17 = result;
            if ( result )
            {
              v18 = *(int (__fastcall **)(_DWORD, _DWORD, _DWORD, _DWORD))(*(_DWORD *)v4 + 456);
              (*(void (__fastcall **)(int, _DWORD))(*(_DWORD *)v4 + 668))(v4, "Congratulation! You crack it!");
              result = v18(v4, v16, v17, v23);
              v19 = result;
              if ( result )
              {
                v20 = (*(int (__fastcall **)(int, int, _DWORD, _UNKNOWN *))(*(_DWORD *)v4 + 132))(
                        v4,
                        v16,
                        "show",
                        &unk_492F053C);
                result = (*(int (__fastcall **)(int, int, int))(*(_DWORD *)v4 + 244))(v4, v19, v20);
              }
            }
          }
          break;
        }
      }
    }
  }
  if ( v28 != _stack_chk_guard )
    result = ((int (__fastcall *)(int))unk_492EEC68)(result);
  return result;
}


其中需要知道sub_492EEF2C是干什么的,就跟进去看了下,里面还会调用sub_492EEE58

[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
int __fastcall sub_492EEE58(int result, unsigned int a2)
{
  char v2; // nf@0
  int v3; // r12@1
  int v4; // r3@4
  char v5; // r0@8
  unsigned int v6; // r1@8
  unsigned int v7; // r2@8
  char v8; // zf@17
 
  v3 = result ^ a2;
  if ( v2 )
    a2 = -a2;
  if ( a2 == 1 )
  {
    if ( (v3 ^ result) < 0 )
      result = -result;
  }
  else
  {
    v4 = result;
    if ( result < 0 )
      v4 = -result;
    if ( v4 <= a2 )
    {
      if ( v4 < a2 )
        result = 0;
      if ( v4 == a2 )
        result = (v3 >> 31) | 1;
    }
    else if ( a2 & (a2 - 1) )
    {
      v5 = __clz(a2) - __clz(v4);
      v6 = a2 << v5;
      v7 = 1 << v5;
      result = 0;
      while ( 1 )
      {
        if ( v4 >= v6 )
        {
          v4 -= v6;
          result |= v7;
        }
        if ( v4 >= v6 >> 1 )
        {
          v4 -= v6 >> 1;
          result |= v7 >> 1;
        }
        if ( v4 >= v6 >> 2 )
        {
          v4 -= v6 >> 2;
          result |= v7 >> 2;
        }
        if ( v4 >= v6 >> 3 )
        {
          v4 -= v6 >> 3;
          result |= v7 >> 3;
        }
        v8 = v4 == 0;
        if ( v4 )
        {
          v7 >>= 4;
          v8 = v7 == 0;
        }
        if ( v8 )
          break;
        v6 >>= 4;
      }
      if ( v3 < 0 )
        result = -result;
    }
    else
    {
      result = (unsigned int)v4 >> (31 - __clz(a2));
      if ( v3 < 0 )
        result = -result;
    }
  }
  return result;
}


好吧,这个怎么看都想是稍微有点复杂的算法。可是...
分析了下发现这个就是个a/b,tm就是个除法,在百度了下ARM汇编没有除,就是这么干的...
之后就知道了sub_492EEF2C也就是个除法,返回之后R1是商,R2是余数。
所以这个算法就是
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
int sum=0;
bool ret=true;
for(i = 11 to 0)
{
  sum+=name[i];
  if(charTable[sum%62]!=password[i])
  {
     ret=false;
     break;
  }
}



注册机也就好些了:
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<iostream>
using namespace std;
 
char *charTable="0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
char *pad=",.?!";
char name[13];
char password[13];
int main()
{
    memset(name,0,13);
    memset(password,0,13);
    cout<<"请输入用户名:"<<endl;
    cin>>name;
    int len=strlen(name);
    if(len>=8 && len<=12)
    {
        int i=0,sum=0;
        for(i=len;i<12;i++)
        {
            name[i]=pad[i-8];
        }
        name[12]=0;
        for(i=11;i>=0;i--)
        {
            sum+=name[i];
            password[i]=charTable[sum%62];
        }
        cout<<"注册码为:"<<endl<<password<<endl;
    }
    else
    {
        cout<<"长度必须为8~12"<<endl;
    }
 
    system("pause");
    return 0;
}


两组key:
12345678
dmWDVyfx0ONB
52pojie0
4RHwg6Hd0ONB

以上仅是简单的分析,对什么加壳脱壳的还一概不了解(题主大大在看雪有几篇精华文章,可惜还看不懂)。













发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

bess 发表于 2014-11-13 11:00
@〇〇木一   用IDA打开libverify.so文件,之后你写的代码是你自己分析写出来的,还是IDA反编译出来的,我知道IDA可以进行反编译,但是这种LOAD:000012A0                 PUSH    {R4-R6,LR}也可以进行反编译吗?我的F5都不可以进行这个的反编译,求指导
 楼主| 〇〇木一 发表于 2014-11-13 18:52
bess 发表于 2014-11-13 11:00
@〇〇木一   用IDA打开libverify.so文件,之后你写的代码是你自己分析写出来的,还是IDA反编译出来的,我知 ...

http://bbs.pediy.com/showthread.php?t=191169
小清子、 发表于 2016-3-13 22:56
1294279706 发表于 2016-3-14 12:38
感谢分享!!!!!!!
joshdexipi 发表于 2016-3-19 13:30
多看看,再学学
isoul 发表于 2016-3-30 22:45
验证的那一段不是太懂
wincorry 发表于 2016-4-28 12:20
楼主好强大,学习一下
wincorry 发表于 2016-4-28 20:18 来自手机
膜拜大神
o6o7o5 发表于 2016-5-2 19:02
活到老,学到老!!加油。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-12 08:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表