| 0x00 前言 小伙伴给我发来一道android题,涉及花指令,记录一下去除花指令和算法还原的过程。样本 强网杯 flower.apk0x01 花指令 花指令是企图隐藏掉不想被逆向工程的代码块(或其它功能)的一种方法,在真实代码中插入一些垃圾代码的同时还保证原有程序的正确执行,而程序无法很好地反编译, 难以理解程序内容,达到混淆视听的效果。1、不可执行的花指令主要目的加大静态分析难度
 运行是不执行的汇编指令,会对反汇编造成影响,影响静态分析(如ida无法f5)2、可执行的花指令0x02 算法还原1、样本分析(1) java层 
(2) native层Android记去花指令还原算法   sub_F34| 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_F8E| 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;
 }
 
 
 | 
 
 根据ida的提示sub_F8E应该跳转的位置是 0xFA4 = 0xF98 + 0xCpatch脚本
 | 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记去花指令还原算法   
 修复后
2、去花指令Android记去花指令还原算法   Android记去花指令还原算法   Android记去花指令还原算法   
使用如上方法对sub_FD0可以进行函数重建,让ida识别成功后可以使用F5. 动态调试可以发现不可以执行的花指令
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记去花指令还原算法   
 去花指令之后(函数重建之后ida识别成功)
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;
 }
 
 
 | 
 去花指令之后伪代码 3、算法还原(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;
 }
 
 
 | 
 根据伪代码结合动态调试进行算法还原
(2) 加密算法Android记去花指令还原算法   
这里需要动态调试获取值
 Android记去花指令还原算法   
调试的时候断点参考 loc_11B0 loc_10AA 加密过程 | 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、输入字符串(3) 算法还原2、按首字符填充长度为首字符10进制长度 + 字符串长度 + 尾字符填充 = 128长度
 3、循环128位字符 先与data1和data2进行异或,再循环 28x16(1-7 6-0) 次 进行高/低四位保留(0xf0 0xf 与运算),最后异或0x88
 4、结果与data3进行比较
 加密 | 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]);
 }
 
 }
 }
 
 
 | 
 运行结果:
0x03 总结Android记去花指令还原算法   1、识别花指令2、对Jumpout进行修复
 3、动态调试
 4、算法还原
 |