学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题
发表于 2020-9-18 13:36:10 | 查看: 7648| 回复: 6
0x00 前言
小伙伴给我发来一道android题,涉及花指令,记录一下去除花指令和算法还原的过程。
样本
强网杯 flower.apk
0x01 花指令
花指令是企图隐藏掉不想被逆向工程的代码块(或其它功能)的一种方法,在真实代码中插入一些垃圾代码的同时还保证原有程序的正确执行,而程序无法很好地反编译, 难以理解程序内容,达到混淆视听的效果。
主要目的加大静态分析难度
1、不可执行的花指令
运行是不执行的汇编指令,会对反汇编造成影响,影响静态分析(如ida无法f5)
2、可执行的花指令
可执行花指令一般都是无意义的汇编指令,会被反汇编正常识别
参考:
http://dyf.ink/reverse/windows/anti-debug/junk-code/
https://www.anquanke.com/post/id/208682
0x02 算法还原1、样本分析(1) java层

Android记去花指令还原算法

Android记去花指令还原算法
(2) native层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __fastcall Java_com_a_flower_MainActivity_check(int a1, int a2, int a3)
{
  int v3; // r5
  int v4; // r4
  char *v5; // r6
  int v6; // r8

  v3 = a1;
  v4 = a3;
  v5 = (*(*a1 + 676))(a1, a3, 0);
  v6 = sub_F34(v5);
  (*(*v3 + 680))(v3, v4, v5);
  return v6;
}

sub_F34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __fastcall sub_F34(char *s)
{
  char *v1; // r8
  size_t v2; // r0
  int v3; // r4

  v1 = s;
  v2 = strlen(s);
  if ( v2 <= 0x80 )
  {
    if ( (signed int)v2 >= 1 )
    {
      v3 = (unsigned __int8)*v1 << 8;
      sub_F8E((int)&dword_0 + 3);
    }
    sub_FD0((int)&dword_0 + 3);
  }
  return 1;
}

sub_F8E

Android记去花指令还原算法

Android记去花指令还原算法

sub_FD0

Android记去花指令还原算法

Android记去花指令还原算法

遇到JUMPOUT要进行path修复
JUMPOUT修复参考:https://bbs.pediy.com/thread-259062.htm
修复 sub_F8E
根据ida的提示sub_F8E应该跳转的位置是 0xFA4 = 0xF98 + 0xC
patch脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
def put_unconditional_branch(source, destination):
    offset = (destination - source - 4) >> 1
    if offset > 2097151 or offset < -2097152:
        raise RuntimeError("Invalid offset")
    if offset > 1023 or offset < -1024:
        instruction1 = 0xf000 | ((offset >> 11) & 0x7ff)
        instruction2 = 0xb800 | (offset & 0x7ff)
        PatchWord(source, instruction1)
        PatchWord(source + 2, instruction2)
    else:
        instruction = 0xe000 | (offset & 0x7ff)
        PatchWord(source, instruction)
put_unconditional_branch(0xF98, 0xFA4)

path之后要重建函数(神奇的P键)

Android记去花指令还原算法

Android记去花指令还原算法

修复前

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

修复后

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

Android记去花指令还原算法

使用如上方法对sub_FD0可以进行函数重建,让ida识别成功后可以使用F5.
2、去花指令
动态调试可以发现不可以执行的花指令

Android记去花指令还原算法

Android记去花指令还原算法

经过分析可以将可以执行的花指令识别出来
1
2
3
4
5
6
7
8
9
10
11
8F 46 7D 46 00 DF 8F BD BF 46 70 47 02 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

8F 46 FF 46 00 DF 8F BD BF 46 70 47 04 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

8F 46 7B 46 00 DF 8F BD BF 46 70 47 80 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

8F 46 79 46 00 DF 8F BD BF 46 70 47 04 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

8F 46 7e 46 00 DF 8F BD BF 46 70 47 08 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

8F 46 FE 46 00 DF 8F BD BF 46 70 47 04 BC 8E BC 08 46 11 46 1A 46 3B 46 80 BC

将以上替换成
1
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

去花指令之前

Android记去花指令还原算法

Android记去花指令还原算法

去花指令之后(函数重建之后ida识别成功)

Android记去花指令还原算法

Android记去花指令还原算法

去花指令之前伪代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int __fastcall sub_F34(char *s)
{
  char *v1; // r8
  size_t v2; // r0
  int v3; // r4

  v1 = s;
  v2 = strlen(s);
  if ( v2 <= 0x80 )
  {
    if ( (signed int)v2 >= 1 )
    {
      v3 = (unsigned __int8)*v1 << 8;
      sub_F8E();
    }
    sub_FD0();
  }
  return 1;
}

去花指令之后伪代码
1
2
3
4
5
6
7
8
9
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// write access to const memory has been detected, the output may be wrong!
int __fastcall sub_F34(char *s)
{
  char *v1; // r8
  _DWORD *v2; // r10
  size_t v3; // r0
  int v4; // r9
  unsigned int v5; // r3
  int v6; // r0
  int v7; // r1
  char *v8; // r2
  int v9; // r4
  signed int v10; // r3
  int v11; // r6
  int v12; // r10
  unsigned int v13; // r6
  int v14; // r3
  void *v15; // r11
  char *i; // r0
  unsigned int v17; // r1
  int v18; // r10
  char *v19; // r2
  int v20; // t1
  int *v21; // r2
  int v22; // lr
  int v23; // r1
  unsigned __int8 *v24; // r8
  int v25; // r12
  int j; // r4
  int k; // r4
  int v28; // r9
  int v29; // r5
  int v30; // r1
  int v31; // r4
  char v32; // r5
  int v33; // r1
  int l; // r0
  int v35; // r0
  char v36; // r2
  int v37; // r4
  unsigned __int8 v38; // r3
  int result; // r0
  int v40; // [sp+0h] [bp-11Ch]
  int *v41; // [sp+4h] [bp-118h]
  int v42; // [sp+8h] [bp-114h]
  __int64 *v43; // [sp+Ch] [bp-110h]
  int *v44; // [sp+10h] [bp-10Ch]
  int v45; // [sp+14h] [bp-108h]
  int *v46; // [sp+18h] [bp-104h]
  int v47; // [sp+1Ch] [bp-100h]
  __int64 *v48; // [sp+20h] [bp-FCh]
  char *v49; // [sp+28h] [bp-F4h]
  int v50; // [sp+2Ch] [bp-F0h]
  int *v51; // [sp+30h] [bp-ECh]
  int v52; // [sp+34h] [bp-E8h]
  __int64 *v53; // [sp+38h] [bp-E4h]
  unsigned int v54; // [sp+3Ch] [bp-E0h]
  int v55; // [sp+40h] [bp-DCh]
  int v56; // [sp+44h] [bp-D8h]
  char *v57; // [sp+48h] [bp-D4h]
  unsigned int v58; // [sp+4Ch] [bp-D0h]
  __int64 *v59; // [sp+50h] [bp-CCh]
  int *v60; // [sp+54h] [bp-C8h]
  void *v61; // [sp+58h] [bp-C4h]
  int v62; // [sp+5Ch] [bp-C0h]
  char *v63; // [sp+60h] [bp-BCh]
  int v64; // [sp+64h] [bp-B8h]
  __int64 *v65; // [sp+68h] [bp-B4h]
  int v66; // [sp+74h] [bp-A8h]
  int v67; // [sp+98h] [bp-84h]
  __int64 savedregs; // [sp+11Ch] [bp+0h]

  v1 = s;
  v2 = &_stack_chk_guard;
  v3 = strlen(s);
  if ( v3 <= 0x80 )
  {
    v4 = v3;
    v5 = 0;
    v6 = 4129;
    v7 = v4;
    v8 = v1;
    while ( v7 >= 1 )
    {
      v9 = v5 ^ (*v8 << 8);
      v10 = 8;
      while ( v10 )
      {
        v11 = v6 ^ 2 * v9;
        if ( !(v9 & 0x8000) )
          v11 = 2 * v9;
        v61 = v6;
        v62 = v7;
        v63 = v8;
        v64 = v10;
        v65 = &savedregs;
        v8 = &loc_F8E;
        v60 = (&dword_0 + 3);
        v6 = 4 * (&dword_0 + 3);
        v7 = 4 * (&dword_0 + 3) + 3992;
        --v10;
        v9 = v11;
      }
      --v7;
      v5 = v9;
      ++v8;
    }
    v61 = &_stack_chk_guard;
    v55 = 128;
    v56 = v7;
    v57 = v8;
    v58 = v5;
    v59 = &savedregs;
    v54 = v5;
    v12 = v5 & 0xF;
    v13 = (v5 >> 8) & 0x3F;
    v15 = malloc(4 * (&dword_0 + 3));
    for ( i = 0; v13 != i; ++i )
      i[v15] = *v1;
    v17 = v13 + v4;
    v18 = v12 + 16;
    v19 = v1;
    while ( v13 < v17 )
    {
      v20 = *v19++;
      v14 = v20;
      *(v15 + v13++) = v20;
    }
    while ( v13 <= 0x7F )
      *(v15 + v13++) = v1[v4 - 1];
    v21 = &v56;
    v57 = 0x88776655;
    v22 = 0;
    v23 = 0x44332211;
    v24 = v15;
    v56 = 0x44332211;
    while ( v22 != 16 )
    {
      v25 = 8 * v22;
      for ( j = 0; j != 8; ++j )
      {
        v49 = i;
        v50 = v23;
        v51 = v21;
        v52 = v14;
        v53 = &savedregs;
        i = &dword_0 + 3;
        v21 = &loc_1076;
        v23 = v24[j] ^ *(&loc_1076 + j);
        *(&loc_1076 + j) = v23;
      }
      for ( k = 0; k != 8; ++k )
        *(v21 + k) ^= byte_2B98[k];
      v28 = 0;
      while ( v28 != v18 )
      {
        v14 = HIBYTE(v51);
        v29 = 0;
        v30 = HIBYTE(v51);
        while ( v29 + 6 >= 0 )
        {
          v44 = (v21 + v29);
          v45 = v30;
          v46 = v21;
          v47 = HIBYTE(v51);
          v48 = &savedregs;
          v21 = &loc_10E2;
          --v29;
          byte_9[1] = (v30 & 0xF0) + (byte_9[0] & 0xF);
          v30 = byte_9[0];
        }
        v31 = 0;
        v32 = v46 & 0xF0;
        LOBYTE(v46) = (HIBYTE(v51) & 0xF) + (v46 & 0xF0);
        while ( v31 != 7 )
        {
          v33 = v21 + v31;
          v40 = v21 + v31;
          v41 = v21;
          v42 = v14;
          v43 = &savedregs;
          v21 = &loc_1140;
          *(&loc_1140 + v31) = (*(&loc_1140 + v31) & 0xF) + (*(v33 + 1) & 0xF0);
          ++v31;
        }
        ++v28;
        HIBYTE(v42) = HIBYTE(v42) & 0xF | v32;
      }
      v23 = v42;
      v24 += 8;
      *(v15 + v25) = v41;
      i = v15 + v25;
      ++v22;
      *(v15 + v25 + 4) = v42;
    }
    _aeabi_memcpy8(&v43, &unk_2BA0, 128);
    v2 = v40;
    for ( l = 0; ; l = v35 + 1 )
    {
      if ( l == 128 )
      {
        free(v15);
        result = 0;
        goto LABEL_43;
      }
      v35 = 4 * (&dword_0 + 3);
      v36 = *(&v43 + 4 * (&dword_0 + 3));
      v37 = *(v15 + 4 * (&dword_0 + 3));
      v38 = v36 ^ (4 * (&dword_0 + 3) - 30);
      *(&v43 + 4 * (&dword_0 + 3)) = v38;
      if ( v37 != v38 )
        break;
      *(&v43 + v35) = v36;
    }
    free(v15);
  }
  result = 1;
LABEL_43:
  if ( *v2 == v66 )
    JUMPOUT(__CS__, v67);
  return result;
}

3、算法还原(1) 动态调试
根据伪代码结合动态调试进行算法还原

Android记去花指令还原算法

Android记去花指令还原算法

这里需要动态调试获取值

Android记去花指令还原算法

Android记去花指令还原算法

调试的时候断点参考 loc_11B0 loc_10AA
(2) 加密算法
加密过程
1
2
3
4
5
6
7
8
9
10
11
12
data1 = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]

data2 = [0x77, 0x23, 0x9D, 0xAC, 0x13, 0x27, 0xCF, 0xFE]

data3 = [0xA8, 0xAF, 0x56, 0x98, 0x88, 0xEF, 0x40, 0x06, 0xFD, 0xAE, 0xE9, 0x9E, 0xB9, 0xEA, 0xAD, 0x52,
        0xCC, 0xAB, 0x04, 0xCA, 0xEC, 0xEB, 0x12, 0x54, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
        0xA8, 0xAF, 0x56, 0x98, 0x88, 0xEF, 0x40, 0x06, 0xFD, 0xAE, 0xE9, 0x9E, 0xB9, 0xEA, 0xAD, 0x52,
        0xCB, 0xAA, 0x19, 0xE5, 0xEC, 0xEB, 0x12, 0x5E, 0xA0, 0xA6, 0xA8, 0xF3, 0x8B, 0xD6, 0xCD, 0x6F,
        0xCB, 0xC0, 0x4F, 0xC1, 0xE0, 0xDA, 0x74, 0x00, 0x91, 0xBE, 0xC6, 0x83, 0xD0, 0xA6, 0x8D, 0x2E,
        0xBE, 0xFC, 0x3F, 0xAD, 0x9B, 0xE0, 0x26, 0x52, 0xF5, 0xBA, 0x94, 0xD1, 0xB4, 0xA2, 0xDF, 0x7C,
        0xDA, 0xF8, 0x6D, 0xFF, 0xFF, 0xE4, 0x74, 0x00, 0x91, 0xBE, 0xC6, 0x83, 0xD0, 0xA6, 0x8D, 0x2E,
        0xBE, 0xFC, 0x3F, 0xAD, 0x9B, 0xE0, 0x26, 0x52, 0xF5, 0xBA, 0x94, 0xD1, 0xB4, 0xA2, 0xDF, 0x7C]

1、输入字符串
2、按首字符填充长度为首字符10进制长度 + 字符串长度 + 尾字符填充 = 128长度
3、循环128位字符 先与data1和data2进行异或,再循环 28x16(1-7 6-0) 次 进行高/低四位保留(0xf0 0xf 与运算),最后异或0x88
4、结果与data3进行比较
(3) 算法还原
加密
1
2
3
4
5
6
7
8
9
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
int sub_F34(char *s){

    char *v1; // r8
    char *v2;
    size_t v3; // r0
    int v4; // r9
    unsigned int v5; // r3
    int v6; // r0
    int v7; // r1
    char *v8; // r2
    int v9; // r4
    signed int v10; // r3
    int v11; // r6
    int v12; // r10
    unsigned int v13; // r6
    int v14; // r3
    char *v15; // r11
    char *v16;
    int i; // r0
    unsigned int v17; // r1
    int v18; // r10
    char *v19; // r2
    int v20; // t1
    int *v21; // r2
    int v22; // lr
    int v23; // r1
    char *v24; // r8
    int v25; // r12
    int j; // r4
    int k; // r4
    int v28; // r9
    int v29; // r5
    int v30; // r1
    int v31; // r4
    int v32; // r4
    int v33; // r5
    int v34; // r0
    int v59;



    v1 = s;
    v3 = strlen(s);
    if ( v3 <= 128 )
    {
        v4 = v3;
        v5 = 0;
        v6 = 0x1021;
        v7 = v4;
        v8 = v1;

        while ( v7 >= 1 )
        {
            v9 = v5 ^ (*v8 << 8);
            v10 = 8;
            while ( v10 )
            {
                v11 = v6 ^ 2 * v9;
                if ( !(v9 & 0x8000) )
                    v11 = 2 * v9;

                --v10;
                v9 = v11;
            }
            --v7;
            v5 = v9;
            ++v8;
        }
        v59 = 128;

        v12 = v5 & 0xF;
        v13 = (v5 >> 8) & 0x3F;
        v15 = (char *)malloc(128);

        for ( i = 0; v13 != i; ++i )
            v15 = *v1;
        v17 = v13 + v4;
        v18 = v12 + 16;
        v19 = v1;

        printf("before %s %d \n",v15, strlen(v15));

        while ( v13 < v17 )
        {
            v20 = *v19++;
            v14 = v20;
            v15[v13++] = v20;
        }
        printf("input %s %d \n",v15, strlen(v15));
        while ( v13 <= 0x7F )
            v15[v13++] = v1[v4 - 1];
        printf("after %s %d \n",v15, strlen(v15));


        unsigned char byte_2B98[8] = {0x77, 0x23, 0x9D, 0xAC, 0x13, 0x27, 0xCF, 0xFE};
        unsigned char v21[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};


        while ( v22 != 16 )
        {
            v25 = 8 * v22;
            for ( j = 0; j != 8; ++j )
                v21[j] ^= v15[v25 + j];

            for ( k = 0; k != 8; ++k )
                *(v21 + k) ^= byte_2B98[k];


            v28 = 0;

            while ( v28 != v18 )
            {

                v14 = v21[7];
                v29 = 7;
                while ( v29 >= 1 )
                {
                    v21[v29] = (v21[v29]&0xf0) + (v21[v29-1]&0xf);
                    --v29;
                }



                v32 = 0;
                v33 = v21[0] & 0xF0;
                v21[0] = (v14 & 0xF) + v33;
                v34 = v21[0];

                while ( v32 != 7 )
                {
                    v21[v32] = (v21[v32]&0xf) + (v21[v32+1]&0xf0);
                    ++v32;
                }
                v21[7] = (v21[7]&0xf) + (v34&0xf0);

                ++v28;
            }

            v30 = 0;

            while(v30 != 8){
                printf("0x%x ", v21[v30] ^ 0x88);
                ++v30;
            }
            printf("\n");

            ++v22;

        }

    }

    return 0;
}

解密
1
2
3
4
5
6
7
8
9
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
void decrypt(){

    char *v1; // r8
    char *v2;
    size_t v3; // r0
    int v4; // r9
    unsigned int v5; // r3
    int v6; // r0
    int v7; // r1
    char *v8; // r2
    int v9; // r4
    signed int v10; // r3
    int v11; // r6
    int v12; // r10
    unsigned int v13; // r6
    int v14; // r3
    char *v15; // r11
    char *v16;
    int i; // r0
    unsigned int v17; // r1
    int v18; // r10
    char *v19; // r2
    int v20; // t1
    int v22; // lr
    int v23; // r1
    char *v24; // r8
    int v25; // r12
    int j; // r4
    int k; // r4
    int v28; // r9
    int v29; // r5

    int v32; // r4
    int v33; // r5
    int v34; // r0

    unsigned char byte_2B98[8] = {0x77, 0x23, 0x9D, 0xAC, 0x13, 0x27, 0xCF, 0xFE};
    unsigned char v21[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
    unsigned char unk_2BA0[128] = {
            0xA8, 0xAF, 0x56, 0x98, 0x88, 0xEF, 0x40, 0x06, 0xFD, 0xAE, 0xE9, 0x9E, 0xB9, 0xEA, 0xAD, 0x52,
            0xCC, 0xAB, 0x04, 0xCA, 0xEC, 0xEB, 0x12, 0x54, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
            0xA8, 0xAF, 0x56, 0x98, 0x88, 0xEF, 0x40, 0x06, 0xFD, 0xAE, 0xE9, 0x9E, 0xB9, 0xEA, 0xAD, 0x52,
            0xCB, 0xAA, 0x19, 0xE5, 0xEC, 0xEB, 0x12, 0x5E, 0xA0, 0xA6, 0xA8, 0xF3, 0x8B, 0xD6, 0xCD, 0x6F,
            0xCB, 0xC0, 0x4F, 0xC1, 0xE0, 0xDA, 0x74, 0x00, 0x91, 0xBE, 0xC6, 0x83, 0xD0, 0xA6, 0x8D, 0x2E,
            0xBE, 0xFC, 0x3F, 0xAD, 0x9B, 0xE0, 0x26, 0x52, 0xF5, 0xBA, 0x94, 0xD1, 0xB4, 0xA2, 0xDF, 0x7C,
            0xDA, 0xF8, 0x6D, 0xFF, 0xFF, 0xE4, 0x74, 0x00, 0x91, 0xBE, 0xC6, 0x83, 0xD0, 0xA6, 0x8D, 0x2E,
            0xBE, 0xFC, 0x3F, 0xAD, 0x9B, 0xE0, 0x26, 0x52, 0xF5, 0xBA, 0x94, 0xD1, 0xB4, 0xA2, 0xDF, 0x7C
    };



    unsigned char flag[128];

    for(int i=0;i<16;i++){

        unsigned char data[8];
        unsigned char data1[8];

        for(int j=0;j<8;j++){
            data[j] = unk_2BA0[i*8 + j] ^ 0x88;
            data1[j] = data[j];
        }

        v28 = 0;

        while ( v28 != 28 )
        {

            v34 = data[0];

            v32 = 0;
            while ( v32 != 7 )
            {
                data[v32] = (data[v32]&0xf) + (data[v32+1]&0xf0);
                ++v32;
            }
            data[7] = (data[7]&0xf) + (v34&0xf0);

            v14 = data[7];
            v29 = 7;
            while ( v29 >= 1 )
            {
                data[v29] = (data[v29]&0xf0) + (data[v29-1]&0xf);
                --v29;
            }

            v33 = data[0] & 0xF0;
            data[0] = (v14 & 0xF) + v33;


            ++v28;
        }

        for(j=0; j<8; j++) {
            data[j] ^= byte_2B98[j];
            data[j] ^= v21[j];
            v21[j] = data1[j];
            printf("%c", data[j]);
        }

    }
}

运行结果:

Android记去花指令还原算法

Android记去花指令还原算法
0x03 总结
1、识别花指令
2、对Jumpout进行修复
3、动态调试
4、算法还原
游客,如果您要查看本帖隐藏内容请回复
游客,如果您要查看本帖隐藏内容请回复
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

    发表于 2020-9-19 07:59:54
    Android记去花指令还原算法,不错!
    发表于 2020-9-20 16:37:01
    资源很给力,请收下我的膝盖! 这个技术点好像很难掌握 谢谢

      发表于 2020-9-27 02:01:15
      6666666666666666666

        发表于 2021-12-11 21:45:39
        太给力了,这么多好东西!

          发表于 2023-10-12 01:46:09
          学习了 被这个JUMPOUT折磨

            发表于 2023-10-16 11:19:26
            支持学逆向论坛,资源不错!

            小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

            GMT+8, 2024-4-24 00:39 , Processed in 0.197105 second(s), 73 queries .

            Powered by Discuz! X3.4

            Copyright © 2001-2021, Tencent Cloud.

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