0
前言
1
抓包及定位
抓包截图中shield为本次分析的目标算法。
使用frida-trace通过跟进NSURL方法来跟踪调用:
frida-trace -UF com.xxx.xxx -m *[NSURL URLWithString*]"
通过分析调用堆栈找到shield算法生成的最外层函数:
+[XXXHandle reqAuthorityWithHeaders:request:bodyData:]
frida-trace -UF com.xxx.xxx -m "*[XXXHandle reqAuthorityWithHeaders:request:bodyData:]"
根据入参来固定参数,在frida中写一个主动调用,防止每次结果都不一样。
function callReqAuthority(){
var headers = ObjC.classes.NSMutableDictionary.dictionary();
headers.setObject_forKey_('xxx','xxx');
headers.setObject_forKey_('xxx','xxx');
var NSString = ObjC.classes.NSString;
var urlString = NSString.stringWithString_('xxxxxx');
var url = ObjC.classes.NSURL.URLWithString_(urlString);
var request = ObjC.classes.NSMutableURLRequest.requestWithURL_(url);
var bodyStr = NSString.stringWithString_('xxxxx');
var body = bodyStr.dataUsingEncoding_(4);
var XXXHandle = ObjC.classes.XXXHandle;
XXXHandle.reqAuthorityWithHeaders_request_bodyData_(headers,request,body);
}
2
Base64
属于sub_10786C1E8的返回值,验证下没问题。
验证后是标准base64算法。
3
RC4
sub_107873110->sub_107873408->sub_1078707ec。
var sub_107873110 = idaBase.add(0x107873110);
Interceptor.attach(sub_107873110,{
onEnter:function(args){
this.res = this.context.x8;
console.log('onEnter sub_107873110',hexdump(args[0].readPointer().add(24).readPointer()),'n',hexdump(this.context.x8));
},
onLeave:function(retval){
console.log('onLeave sub_107873110',hexdump(this.res.readPointer()))
}});
代码运行结果和之前hook一致
可以看到前一部分是从sub_107872DD8的第一个参数中固定偏移取值,中间是我们开始固定主动调用的函数中的build+deviceId。
后16位目前未知。
先看一下IDA:
三次从v5也就是第一个参数的固定偏移处memcpy数据,盲猜是参数的后三部分打印下看看。
281aba6b0 46 c2 9d 66 95 35 2f 99 e2 50 36 51 e5 31 2d 96 F..f.5/..P6Q.1-.
4
hmac-魔改md5
看一下sub_107872DD8的最外层调用addr_10786DE5C
打印下入参:
是我们要找的值,那就继续找addr_10786DE5C的入参
trace的指令中看到x0=16f58007,往上搜一下16f58007出现的地方。
进入ida中看一看
再看看进入 sub_107871554
简单看下是一个魔改后的MD5,首先能看出来左移的常量不同,
ida中显示为右移需要32减去后和标准的比较。其他地方是否魔改
需要继续确认。
hook下sub_107871554该方法会多次调用,看下第一次打印:
看到hmac填充数据,确认为HmacMD5,MD5有魔改,过程不多叙述, 就是固定入参保持一致,然后根据trace结果或者运行结果进行调试。 大致如下:
还原后拿到结果:
5
魔改AES
最终确认到key来自服务器下发的一个字段,在经过AES算法后得出。
frida打印下相关函数的入参,0x10786BC8C中的base64数据,对应的Bytes在0x10787220C计算后获取到Key,如下:
看下ida:
__int64 __fastcall sub_10786FF44(__int64 a1, __int64 aes_key_Len, _DWORD *a3)
{
_DWORD *v3; // x19
int value_10; // w9
__int64 v5; // x8
int value_388; // w9
__int64 v7; // x10
int *v8; // x9
int *v9; // x11
int v10; // w12
int v11; // w12
int v12; // w12
int v13; // w12
bool v14; // cc
int *v15; // x8
int v16; // w9
unsigned __int64 v17; // x15
unsigned __int64 v18; // x16
unsigned __int64 v19; // x15
unsigned __int64 v20; // x15
v3 = a3;
sub_10786F91C((unsigned int *)a1, aes_key_Len, a3);
value_10 = v3[60]; // // 0xa = 10
if ( value_10 >= 1 )
{
v5 = 0LL;
value_388 = 4 * value_10;
v7 = value_388 - 4LL;
v8 = &v3[value_388 + 2];
v9 = v3 + 2;
do
{
v10 = *(v9 - 2);
*(v9 - 2) = *(v8 - 2);
*(v8 - 2) = v10;
v11 = *(v9 - 1);
*(v9 - 1) = *(v8 - 1);
*(v8 - 1) = v11;
v12 = *v9;
*v9 = *v8;
*v8 = v12;
v13 = v9[1];
v9[1] = v8[1];
v8[1] = v13;
v5 += 4LL;
v8 -= 4;
v9 += 4;
v14 = v5 < v7;
v7 -= 4LL;
}
while ( v14 );
if ( v3[60] >= 2 )
{
v15 = v3 + 7;
v16 = 1;
do
{
v17 = (unsigned int)*(v15 - 3);
v18 = (unsigned int)*(v15 - 2);
LODWORD(v18) = dword_10F659E74[byte_10F65964C[4 * ((v18 >> 16) & 0xFF)]] ^ dword_10F659A74[byte_10F65964C[(v18 >> 22) & 0x3FC]] ^ dword_10F65A274[byte_10F65964C[4 * ((unsigned __int16)v18 >> 8)]] ^ dword_10F65A674[byte_10F65964C[4 * (unsigned __int8)v18]];
*(v15 - 3) = dword_10F659E74[byte_10F65964C[4 * ((v17 >> 16) & 0xFF)]] ^ dword_10F659A74[byte_10F65964C[(v17 >> 22) & 0x3FC]] ^ dword_10F65A274[byte_10F65964C[4 * ((unsigned __int16)v17 >> 8)]] ^ dword_10F65A674[byte_10F65964C[4 * (unsigned __int8)v17]];
*(v15 - 2) = v18;
v19 = (unsigned int)*(v15 - 1);
*(v15 - 1) = dword_10F659E74[byte_10F65964C[4 * ((v19 >> 16) & 0xFF)]] ^ dword_10F659A74[byte_10F65964C[(v19 >> 22) & 0x3FC]] ^ dword_10F65A274[byte_10F65964C[4 * ((unsigned __int16)v19 >> 8)]] ^ dword_10F65A674[byte_10F65964C[4 * (unsigned __int8)v19]];
v20 = (unsigned int)*v15;
*v15 = dword_10F659E74[byte_10F65964C[4 * ((v20 >> 16) & 0xFF)]] ^ dword_10F659A74[byte_10F65964C[(v20 >> 22) & 0x3FC]] ^ dword_10F65A274[byte_10F65964C[4 * ((unsigned __int16)v20 >> 8)]] ^ dword_10F65A674[byte_10F65964C[4 * (unsigned __int8)v20]];
v15 += 4;
++v16;
}
while ( v16 < v3[60] );
}
}
return 1LL;
}
__int64 __fastcall sub_10786F91C(unsigned int *a1, int a2, unsigned int *a3)
{
__int64 v3; // x8
int v4; // w8
unsigned int v6; // w9
__int64 v7; // x8
unsigned int *v8; // x10
int v9; // w0
unsigned __int64 v10; // x16
int v11; // w17
int v12; // w17
unsigned __int64 v13; // x12
int v14; // w13
unsigned int v15; // w15
int v16; // w14
int v17; // w15
unsigned int v18; // w17
int v19; // w16
int v20; // w17
int v21; // w13
int v22; // w0
int v23; // w13
int v24; // w14
int v25; // w15
int v26; // w16
int v27; // w17
int v28; // w13
int v29; // w0
int v30; // w13
int v31; // w14
int v32; // w15
int v33; // w16
int v34; // w17
int v35; // w13
int v36; // w0
int v37; // w13
int v38; // w14
int v39; // w15
int v40; // w16
int v41; // w17
int v42; // w13
int v43; // w0
int v44; // w13
int v45; // w14
int v46; // w15
int v47; // w16
int v48; // w17
int v49; // w13
int v50; // w0
int v51; // w13
int v52; // w14
int v53; // w15
int v54; // w16
int v55; // w17
int v56; // w13
int v57; // w0
int v58; // w13
int v59; // w14
int v60; // w15
int v61; // w16
int v62; // w17
unsigned int v63; // w8
int v64; // w8
__int64 v65; // x8
unsigned int *i; // x10
unsigned __int64 v67; // x16
int v68; // w0
int v69; // w17
int v70; // w0
unsigned int v71; // w17
int v72; // w17
int v73; // w0
int v74; // w17
v3 = 0LL;
if ( a1 && a3 )
{
if ( a2 != 128 && a2 != 256 && a2 != 192 )
return 0LL;
if ( a2 == 128 )
{
v4 = 10;
}
else if ( a2 == 192 )
{
v4 = 12;
}
else
{
v4 = 14;
}
a3[60] = v4;
v6 = bswap32(*a1) ^ 0xF1892131;
*a3 = v6;
a3[1] = bswap32(a1[1]) ^ 0xFF001123;
a3[2] = bswap32(a1[2]) ^ 0xF1001356;
a3[3] = bswap32(a1[3]) ^ 0xF1234890;
if ( a2 == 128 )
{
v7 = 0LL;
v8 = a3 + 4;
do
{
v9 = *(v8 - 2);
v10 = *(v8 - 1);
v6 ^= (byte_10F658A4C[4 * BYTE2(v10) + 3] << 24) ^ (byte_10F658E4C[4 * BYTE1(v10) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v10 + 1] << 8) ^ byte_10F65964C[(v10 >> 22) & 0x3FC] ^ *(_DWORD *)((char *)&unk_10F659A4C + v7);
v11 = *(v8 - 3) ^ v6;
*v8 = v6;
v8[1] = v11;
v12 = v9 ^ v11;
v8[2] = v12;
v8[3] = v12 ^ v10;
v7 += 4LL;
v8 += 4;
}
while ( v7 != 40 );
}
else
{
a3[4] = bswap32(a1[4]);
a3[5] = bswap32(a1[5]);
if ( a2 == 192 )
{
v13 = a3[5];
v14 = v6 ^ (byte_10F658A4C[4 * BYTE2(v13) + 3] << 24) ^ (byte_10F658E4C[4 * BYTE1(v13) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8) ^ byte_10F65964C[(v13 >> 22) & 0x3FC] ^ 0x12310000;
v15 = a3[2];
v16 = a3[1] ^ v14;
a3[6] = v14;
a3[7] = v16;
v17 = v15 ^ v16;
v18 = a3[4];
v19 = a3[3] ^ v17;
a3[8] = v17;
a3[9] = v19;
v20 = v18 ^ v19;
LODWORD(v13) = v20 ^ v13;
v21 = v14 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v22 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[10] = v20;
a3[11] = v13;
v23 = v21 ^ v22 ^ 0x2000100;
v24 = v16 ^ v23;
a3[12] = v23;
a3[13] = v24;
v25 = v17 ^ v24;
v26 = v19 ^ v25;
a3[14] = v25;
a3[15] = v26;
v27 = v20 ^ v26;
LODWORD(v13) = v27 ^ v13;
v28 = v23 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v29 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[16] = v27;
a3[17] = v13;
v30 = v28 ^ v29 ^ 0x4020000;
v31 = v24 ^ v30;
a3[18] = v30;
a3[19] = v31;
v32 = v25 ^ v31;
v33 = v26 ^ v32;
a3[20] = v32;
a3[21] = v33;
v34 = v27 ^ v33;
LODWORD(v13) = v34 ^ v13;
v35 = v30 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v36 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[22] = v34;
a3[23] = v13;
v37 = v35 ^ v36 ^ 0x8020200;
v38 = v31 ^ v37;
a3[24] = v37;
a3[25] = v38;
v39 = v32 ^ v38;
v40 = v33 ^ v39;
a3[26] = v39;
a3[27] = v40;
v41 = v34 ^ v40;
LODWORD(v13) = v41 ^ v13;
v42 = v37 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v43 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[28] = v41;
a3[29] = v13;
v44 = v42 ^ v43 ^ 0x10102000;
v45 = v38 ^ v44;
a3[30] = v44;
a3[31] = v45;
v46 = v39 ^ v45;
v47 = v40 ^ v46;
a3[32] = v46;
a3[33] = v47;
v48 = v41 ^ v47;
LODWORD(v13) = v48 ^ v13;
v49 = v44 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v50 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[34] = v48;
a3[35] = v13;
v51 = v49 ^ v50 ^ 0x30020400;
v52 = v45 ^ v51;
a3[36] = v51;
a3[37] = v52;
v53 = v46 ^ v52;
v54 = v47 ^ v53;
a3[38] = v53;
a3[39] = v54;
v55 = v48 ^ v54;
LODWORD(v13) = v55 ^ v13;
v56 = v51 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8);
v57 = byte_10F65964C[4 * ((unsigned int)v13 >> 24)];
a3[40] = v55;
a3[41] = v13;
v58 = v56 ^ v57 ^ 0x40002000;
v59 = v52 ^ v58;
a3[42] = v58;
a3[43] = v59;
v60 = v53 ^ v59;
v61 = v54 ^ v60;
a3[44] = v60;
a3[45] = v61;
v62 = v55 ^ v61;
LODWORD(v13) = v62 ^ v13;
a3[46] = v62;
a3[47] = v13;
v63 = v58 ^ (byte_10F658A4C[4 * (((unsigned int)v13 >> 16) & 0xFF) + 3] << 24) ^ (byte_10F658E4C[4 * ((unsigned __int16)v13 >> 8) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v13 + 1] << 8) ^ byte_10F65964C[4 * ((unsigned int)v13 >> 24)] ^ 0x80002000;
a3[48] = v63;
a3[49] = v59 ^ v63;
v64 = v60 ^ v59 ^ v63;
a3[50] = v64;
a3[51] = v61 ^ v64;
}
else
{
a3[6] = bswap32(a1[6]);
a3[7] = bswap32(a1[7]);
v65 = 0LL;
for ( i = a3 + 8; ; i += 8 )
{
v67 = *(i - 1);
v6 ^= (byte_10F658A4C[4 * BYTE2(v67) + 3] << 24) ^ (byte_10F658E4C[4 * BYTE1(v67) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * (unsigned __int8)v67 + 1] << 8) ^ byte_10F65964C[(v67 >> 22) & 0x3FC] ^ *(_DWORD *)((char *)&unk_10F659A4C + v65);
v68 = *(i - 6);
v69 = *(i - 7) ^ v6;
*i = v6;
i[1] = v69;
v70 = v68 ^ v69;
v71 = *(i - 5) ^ v70;
i[2] = v70;
i[3] = v71;
if ( v65 == 24 )
break;
v72 = *(i - 4) ^ (byte_10F658A4C[4 * (v71 >> 24) + 3] << 24) ^ (byte_10F658E4C[4 * ((v71 >> 16) & 0xFF) + 2] << 16) ^ (RijnDael_AES_10F65924C[4 * ((unsigned __int16)v71 >> 8) + 1] << 8) ^ byte_10F65964C[4 * (unsigned __int8)v71];
v73 = *(i - 3) ^ v72;
i[4] = v72;
i[5] = v73;
v74 = *(i - 2) ^ v73;
i[6] = v74;
i[7] = v74 ^ v67;
v65 += 4LL;
}
}
}
v3 = 1LL;
}
return v3;
}
__n128 __fastcall sub_101CAD760(unsigned __int64 *a1, __n128 *a2, unsigned __int64 a3, __int64 a4, __n128 *a5, void (__fastcall *a6)(__n128 *, __n128 *, __int64))
{
void (__fastcall *v6)(__n128 *, __n128 *, __int64); // x21
__n128 *v7; // x19
__int64 v8; // x22
unsigned __int64 v9; // x24
__n128 *v10; // x20
unsigned __int64 *v11; // x23
unsigned __int64 v12; // x26
__n128 *v13; // x8
__n128 *v14; // x27
unsigned __int64 v15; // x25
__n128 *v16; // x0
unsigned __int64 v17; // x8
unsigned __int64 v18; // x9
unsigned __int64 v19; // x10
_BYTE *v20; // x11
char *v21; // x12
char *v22; // x9
char v23; // w13
char v24; // t1
char v25; // t1
unsigned __int64 v26; // x10
unsigned __int64 v27; // x10
int8x8_t *v28; // x11
unsigned __int64 *v29; // x12
unsigned __int64 *v30; // x13
unsigned __int64 v31; // t1
int8x8_t v32; // d0
int8x8_t v33; // t1
__int64 v34; // x9
unsigned __int64 v35; // x11
__int64 *v36; // x13
_QWORD *v37; // x14
unsigned __int64 v38; // x11
__int64 v39; // t1
__n128 *v40; // x10
__n128 *v41; // x12
unsigned __int64 v42; // x13
__n128 v43; // t1
__n128 result; // q0
if ( a3 )
{
v6 = a6;
v7 = a5;
v8 = a4;
v9 = a3;
v10 = a2;
v11 = a1;
if ( a3 < 0x10 )
{
v17 = (unsigned __int64)a5;
v15 = a3;
if ( a3 >= 8 )
goto LABEL_14;
}
else
{
v12 = 0LL;
v13 = a5;
v14 = a2;
v15 = a3;
do
{
v16 = &v10[v12 / 0x10];
v13->n128_u64[0] ^ v11[v12 / 8]; =
v13->n128_u64[1] ^ v11[v12 / 8 + 1]; =
/ 0x10], &v10[v12 / 0x10], v8);
v15 -= 16LL;
v13 = v14;
++v14;
v12 += 16LL;
}
while ( v15 > 0xF );
v10 = (__n128 *)((char *)v10 + v12);
v17 = (unsigned __int64)v10[-1].n128_u64;
if ( v9 == v12 )
{
--v10;
LABEL_36:
result = *v10;
*v10; =
return result;
}
v11 = (unsigned __int64 *)((char *)v11 + v12);
if ( v15 >= 8 )
{
LABEL_14:
v18 = 0LL;
if ( (v10 >= (__n128 *)((char *)v11 + v15) || v11 >= (unsigned __int64 *)((char *)v10->n128_u64 + v15))
((unsigned __int64)v10 >= v17 + v15 || v17 >= (unsigned __int64)v10->n128_u64 + v15) )
{
v18 = v15 & 0xFFFFFFFFFFFFFFF8LL;
v27 = v15 & 0xFFFFFFFFFFFFFFF8LL;
v28 = (int8x8_t *)v10;
v29 = (unsigned __int64 *)v17;
v30 = v11;
do
{
v31 = *v30;
++v30;
v31; =
*v29; =
++v29;
veor_s8(v33, v32).n64_u64[0]; =
++v28;
v27 -= 8LL;
}
while ( v27 );
if ( v15 == v18 )
{
LABEL_11:
if ( v15 > 8 )
{
v26 = v15;
goto LABEL_34;
}
if ( (unsigned __int64)v10->n128_u64 + v15 < v17 + 16 && v17 + v15 < (unsigned __int64)v10[1].n128_u64 )
{
v26 = v15;
goto LABEL_34;
}
v34 = 16 - v15;
if ( v15 )
{
v35 = 0LL;
}
else
{
v35 = v34 & 0xFFFFFFFFFFFFFFF0LL;
v40 = (__n128 *)v17;
v41 = v10;
v42 = v34 & 0xFFFFFFFFFFFFFFF0LL;
do
{
v43 = *v40;
++v40;
v43; =
++v41;
v42 -= 16LL;
}
while ( v42 );
if ( v34 == v35 )
goto LABEL_35;
if ( !(v34 & 8) )
{
v26 = v34 & 0xFFFFFFFFFFFFFFF0LL;
do
{
LABEL_34:
*)v10->n128_u64 + v26) = *(_BYTE *)(v17 + v26);
++v26;
}
while ( v26 != 16 );
LABEL_35:
v10, v8);
goto LABEL_36;
}
}
v26 = v15 + (v34 & 0xFFFFFFFFFFFFFFF8LL);
v36 = (__int64 *)(v17 + v35 + v15);
v37 = (unsigned __int64 *)((char *)v10->n128_u64 + v35 + v15);
v38 = v35 - (v34 & 0xFFFFFFFFFFFFFFF8LL);
do
{
v39 = *v36;
++v36;
v39; =
++v37;
v38 += 8LL;
}
while ( v38 );
if ( v34 == (v34 & 0xFFFFFFFFFFFFFFF8LL) )
goto LABEL_35;
goto LABEL_34;
}
}
LABEL_9:
v19 = v15 - v18;
v20 = (char *)v10 + v18;
v21 = (char *)(v17 + v18);
v22 = (char *)v11 + v18;
do
{
v24 = *v22++;
v23 = v24;
v25 = *v21++;
v25 ^ v23; =
--v19;
}
while ( v19 );
goto LABEL_11;
}
}
v18 = 0LL;
goto LABEL_9;
}
return result;
}
可以看到魔改AES是查表法实现的, 我是看的头疼 直接扣代码吧。
结合trace的汇编结果复现。过程中就是坐屁股跟trace日志 看汇编,大致如下:
6
总结
这个样本虽然涉及到了几处魔改算法,我本人没有太多的奇淫巧技, 但是多坐屁股应该都可以搞定的。
撒花~ 今天的分享就到这了,咱们下次再会~
原文始发于微信公众号(小白逆向之旅):【iOS逆向】某社区电商最新版shield纯算
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论