样本与之前的魔改MD5是同一个so,就换了个方法,直接IDA梭哈
第一个传参是明文,第二个传参是请求体的长度
代码逻辑很清晰了,将明文,明文长度和输出都传进了 ctrip_enc
直接进入 ctrip_enc
填充模式
这里可以看到他对明文长度进行了计算,将受影响的算法提取出来
复制代码 隐藏代码if ( (input_len & 0xF) != 0 ) input_len_10 = (input_len + 16) & 0xFFFFFFF0;else input_len_10 = input_len + 16;// ============================== //if ( (input_len & 0xF) != 0 ) v8 = 16 - (input_len & 0xF);else v8 = 16;//===============================//input_ = (char *)malloc(input_len_10);memcpy(input_, input, (unsignedint)input_len);memset(&input_[input_len], v8, (unsignedint)(v8 - 1) + 1LL);
复制代码 隐藏代码v10 = ctrip_enc_internal((__int64)input_, input_len_10, &v12, 16, output);
v12的值上面可以看到赋值是, v12 = xmmword_112D4; 直接点过去
看着啥也不像,长度正好为 16,暂且将这个当做一个 IV 吧
encrypt_one 生成真实key
进入方法 ctrip_enc_internal
复制代码 隐藏代码void __fastcall encrypt_one(_OWORD *randomkey, _OWORD *iv, unsigned __int8 **a3){// [COLLAPSED LOCAL DECLARATIONS. PRESS NUMPAD "+" TO EXPAND]aes_gen_tables(); v6 = (unsigned __int8 *)malloc(0x10uLL); *a3 = v6; v7 = v6; *(_OWORD *)v6 = *randomkey; v8 = (int8x8_t *)malloc(0x10uLL); *(_OWORD *)v8->n64_u64 = *iv; sbox = get_sbox(); v10 = v7[1]; v11 = v7[2]; v12 = v7[3]; v13 = *(_BYTE *)(sbox + *v7); v14 = v7[4]; v15 = v7[5]; v16 = v7[6]; *v7 = v13;LOBYTE(v10) = *(_BYTE *)(sbox + v10); v17 = v7[7]; v18 = v7[8]; v19 = v7[9]; v7[1] = v10;LOBYTE(v11) = *(_BYTE *)(sbox + v11); v20 = v7[10]; v21 = v7[11]; v22 = v7[12]; v7[2] = v11;LOBYTE(v12) = *(_BYTE *)(sbox + v12); v27.n64_u8[0] = v13; v23 = v7[13]; v27.n64_u8[1] = v10; v7[3] = v12;LOBYTE(v14) = *(_BYTE *)(sbox + v14); v24 = v7[14]; v27.n64_u8[2] = v11; v25 = v7[15]; v7[4] = v14;LOBYTE(v15) = *(_BYTE *)(sbox + v15); v27.n64_u8[3] = v12; v27.n64_u8[4] = v14; v26 = 2; v7[5] = v15;LOBYTE(v16) = *(_BYTE *)(sbox + v16); v27.n64_u8[5] = v15; v7[6] = v16;LOBYTE(v17) = *(_BYTE *)(sbox + v17); v27.n64_u8[6] = v16; v7[7] = v17;LOBYTE(v18) = *(_BYTE *)(sbox + v18); v27.n64_u8[7] = v17; v7[8] = v18;LOBYTE(v19) = *(_BYTE *)(sbox + v19); v29.n64_u8[0] = v18; v7[9] = v19;LOBYTE(v20) = *(_BYTE *)(sbox + v20); v29.n64_u8[1] = v19; v7[10] = v20;LOBYTE(v21) = *(_BYTE *)(sbox + v21); v29.n64_u8[2] = v20; v7[11] = v21; v28 = *(_BYTE *)(sbox + v22); v29.n64_u8[3] = v21; v7[12] = v28;LOBYTE(v10) = *(_BYTE *)(sbox + v23); v29.n64_u8[4] = v28; v7[13] = v10;LOBYTE(v11) = *(_BYTE *)(sbox + v24); v29.n64_u8[5] = v10; v7[14] = v11; v29.n64_u8[6] = v11; v29.n64_u8[7] = *(_BYTE *)(sbox + v25); v7[15] = v29.n64_u8[7];while ( 1 ) { v30 = veor_s8(v29, v8[1]).n64_u64[0]; *(int8x8_t *)v7 = veor_s8(v27, (int8x8_t)v8->n64_u64[0]); *((_QWORD *)v7 + 1) = v30;row_rotation(v7, 4LL, 1LL);if ( !v26 )break;column_rotation(v8, 4LL, 1LL); v31 = get_sbox(); v32 = v8->n64_u8[1]; v27.n64_u64[0] = *(unsigned __int64 *)v7; v29.n64_u64[0] = *(_QWORD *)(v7 + 8); --v26; v8->n64_u8[0] = *(_BYTE *)(v31 + v8->n64_u8[0]); v33 = *(_BYTE *)(v31 + v32); v34 = v8->n64_u8[2]; v8->n64_u8[1] = v33; v35 = *(_BYTE *)(v31 + v34); v36 = v8->n64_u8[3]; v8->n64_u8[2] = v35; v37 = *(_BYTE *)(v31 + v36); v38 = v8->n64_u8[4]; v8->n64_u8[3] = v37; v39 = *(_BYTE *)(v31 + v38); v40 = v8->n64_u8[5]; v8->n64_u8[4] = v39; v41 = *(_BYTE *)(v31 + v40); v42 = v8->n64_u8[6]; v8->n64_u8[5] = v41; v43 = *(_BYTE *)(v31 + v42); v44 = v8->n64_u8[7]; v8->n64_u8[6] = v43; v45 = *(_BYTE *)(v31 + v44); v46 = v8[1].n64_u8[0]; v8->n64_u8[7] = v45; v47 = *(_BYTE *)(v31 + v46); v48 = v8[1].n64_u8[1]; v8[1].n64_u8[0] = v47; v49 = *(_BYTE *)(v31 + v48); v50 = v8[1].n64_u8[2]; v8[1].n64_u8[1] = v49; v51 = *(_BYTE *)(v31 + v50); v52 = v8[1].n64_u8[3]; v8[1].n64_u8[2] = v51; v53 = *(_BYTE *)(v31 + v52); v54 = v8[1].n64_u8[4]; v8[1].n64_u8[3] = v53; v55 = *(_BYTE *)(v31 + v54); v56 = v8[1].n64_u8[5]; v8[1].n64_u8[4] = v55; v57 = *(_BYTE *)(v31 + v56); v58 = v8[1].n64_u8[6]; v8[1].n64_u8[5] = v57; v59 = *(_BYTE *)(v31 + v58); v60 = v8[1].n64_u8[7]; v8[1].n64_u8[6] = v59; v8[1].n64_u8[7] = *(_BYTE *)(v31 + v60); }free(v8);}
复制代码 隐藏代码v7= v6 = *randomkey; v8->n64_u64 = *iv; sbox = get_sbox();
这里然后将randomkey赋值给了v7,iv赋值给了v8, 以及获取了sbox
复制代码 隐藏代码char *get_fbox(){aes_gen_tables(); return &byte_1D090;}
点过去 byte_1D090 发现没有值,那么aes_gen_tables 实际上就是为了给这个sbox赋值
unidbg 看下返回结果
对比标准的sbox
复制代码 隐藏代码Sbox = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 。。。。。。)
复制代码 隐藏代码 v10 = v7[1]; LOBYTE(v10) = *(_BYTE *)(sbox + v10); v11 = v7[2]; LOBYTE(v11) = *(_BYTE *)(sbox + v11);
不就是取值然后把取的值当成索引嘛,直接使用 java 进行还原
复制代码 隐藏代码privatestaticvoidtake_sbox(byte[] data) {for (int i = 0; i < data.length; i++) {int byte_data = data[i] & 0xFF; data[i] = SBOX[byte_data]; } }
所以,这个方法前面的那么大一串,实际上6行就能解决,实际上就是做了s盒替换
行移位+列混淆
然后就进入了一个while循环
里面其实就调用了两个方法
复制代码 隐藏代码row_rotation(v7, 4LL, 1LL);column_rotation(v8, 4LL, 1LL);
可以发现值的变换情况
复制代码 隐藏代码执行前:D4 3F 8B 24 1A 5E 7E 9D2414 7E C6 49 7F DB 9E执行后:3F 8B 24 D4 7E 9D 1A 5E C6 2414 7E 49 7F DB 9E
注意观察不难发现,他是四个字节分组,然后第一组循环左移一位,第二组循环左移两位,第三组循环左移三位,第四组循环左移四位(等于没动)
就是标准AES的 行移位
复制代码 隐藏代码D4 3F 8B 24 --->3F 8B 24 D4 //左移一位1A 5E 7E 9D --->7E 9D 1A 5E //左移两位24147E C6 ---> C6 24147E //左移三位497F DB 9E --->497F DB 9E //左移四位(等于没动)
java 还原,懒得写逻辑,直接强行换位
ok,开始看那个列混淆
同样unidbg打断点,查看执行前后的值
复制代码 隐藏代码执行前:C0 B4 0751A4A262 B3 307E 3C 8146C5F275执行后:A47E F25130C507 B3 46 B4 6281C0A23C 75
再次尝试找到规律
复制代码 隐藏代码C0 B4 0751A47E F251A4A262 B3 30C507 B3307E 3C 8146 B4 628146C5F275C0A23C 75
而方法传入都很明了,只有一个v22未知,那就v22基本就是IV了
IDA点过去查看v22的值
复制代码 隐藏代码 xmmword_112C4 DCB 0x69, 0xD2, 0x55, 0xB8, 0x32, 0x9E, 0xAC, 0xD4, 0xC, 0x2A, 0x9C, 0x8B, 0x68, 0x75, 0x87, 5
通过验证,是标准AES没有魔改,Key和IV也是对的
encrypt_two 随机key插入密文
复制代码 隐藏代码encrypt_two(input, input_len_10, (__int64)&randomkey, iv_len, output);
复制代码 隐藏代码 v10 = input_len & 0xFFFFFFFE; v12 = 0; v13 = 0; v14 = input + 1; v15 = v10; do { v16 = *(v14 - 1); v17 = *v14; v14 += 2; v15 -= 2LL; v12 += v16; v13 += v17; } while ( v15 );
复制代码 隐藏代码 if ( v10 != input_len ) goto LABEL_9;LABEL_11: if ( ivlen < 1 ) goto LABEL_19;LABEL_12: if ( ivlen == 1 ) { v21 = 0LL; } else
然后开始执行对 randomKey 的操作
复制代码 隐藏代码 v21 = ivlen & 0xFFFFFFFE; v22 = 0; v23 = (unsigned __int8 *)(randomkey + 1); v24 = v21; do { v25 = *(v23 - 1); v26 = *v23; v23 += 2; v24 -= 2LL; v11 += v25; v22 += v26; } while ( v24 );
同理,和input的处理是一样的,每次循环都依次往后取两位值,分别累加在v11和v22上
复制代码 隐藏代码*output = malloc((int)(ivlen + input_len));result = memcpy(output, input, (int)input_len); if ( ivlen >= 1 ) { v32 = 0LL; LODWORD(i) = 0; do { v34 = v32 + (int)input_len; v35 = *output; v36 = *(_BYTE *)(randomkey + v32); for ( i = ((int)i + v11) % (int)(v32 + input_len) + 1LL; v34 > i; *v37 = v38 ) { v37 = (_BYTE *)(v35 + v34); v38 = *(_BYTE *)(v35 + v34-- - 1); } ++v32; *(_BYTE *)(v35 + i) = v36; } while ( v32 != ivlen ); }
复制代码 隐藏代码 for ( i = ((int)i + v11) % (int)(v32 + input_len) + 1LL; v34 > i; *v37 = v38 ) { v37 = (_BYTE *)(v35 + v34); v38 = *(_BYTE *)(v35 + v34-- - 1); }
· 今 日 推 荐 ·
本文内容来自吾爱破解,如有侵权请联系删除
原文始发于微信公众号(逆向有你):安卓逆向 -- 某程 encode 算法分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论