第一次Android逆向初体验
不得不说,我的思维水平一直在低位徘徊,技术水平仍然停留在以前。
就像有家公司,你去面试,他说他对一个人说的话的根本就不感兴趣,他想看看你写的东西,比如博客。我后来才感觉,他是对的,从一个人的字里行间就可以知道他是什么人,他的思维模式,他经历的历史。
大约在2016年,我经历了第一次android逆向的完整过程,非常感谢当时老板的支持,因为我们那时候没人懂这个玩意儿,老板的奇思妙想,同事的信任,以及自己的任性,给了我很多的勇气和毅力来完成这个项目。我那时候一直坚信,我可以重构整个internet,只要我想的话。这种执着给我提供了源源不断的动力,就像在前线、在战场,意志力为一个战士的舞台提供了无与伦比的想象空间。
该程序是一个同步程序,用于备份同步本机和服务器上的通讯录、短信、通话记录等信息。其网络数据全部加密,其解密后的核心算法如下:
#include "stdafx.h"unsigned char TeaKey[256] = {0};unsigned char unk_19578[] = {
0x44,0x46,0x47,0x00,0x00,0x00,0x00,0x3C,0x3E,0x3C,0x00,0x00,0x00,0x00,0x26,0x2A,
0x4D,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x06,0x00,0x03,0x00,
0x05,0x00,0x04,0x00,0x00 };unsigned char * unk_1957F = unk_19578 + 7;
unsigned char * unk_19586 = unk_19578 + 14;
unsigned char * unk_1958E = unk_19578 + 22;unsigned char unk_1A43C[] = {
0x78,0xA4,0x6A,0xD7,0x56,0xB7,0xC7,0xE8,0xDB,0x70,0x20,0x24,0xEE,0xCE,0xBD,0xC1,
0xAF,0x0F,0x7C,0xF5,0x2A,0xC6,0x87,0x47,0x13,0x46,0x30,0xA8,0x01,0x95,0x46,0xFD,
0xD8,0x98,0x80,0x69,0xAF,0xF7,0x44,0x8B,0xB1,0x5B,0xFF,0xFF,0xBE,0xD7,0x5C,0x89,
0x22,0x11,0x90,0x6B,0x93,0x71,0x98,0xFD,0x8E,0x43,0x79,0xA6,0x21,0x08,0xB4,0x49,
//1a47c
0x62,0x25,0x1e,0xf6,0x40,0xB3,0x40,0xC0,0x51,0x5A,0x5E,0x26,0xAA,0xC7,0xB6,0xE9,
0x5D,0x10,0x2F,0xD6,0x53,0x14,0x44,0x02,0x81,0xE6,0xA1,0xD8,0xC8,0xFB,0xD3,0xE7,
0xE6,0xCD,0xE1,0x21,0xD6,0x07,0x37,0xC3,0x87,0x0D,0xD5,0xF4,0xED,0x14,0x5A,0x45,
0x05,0xE9,0xE3,0xA9,0xF8,0xA3,0xEF,0xFC,0xD9,0x02,0x6F,0x67,0x8A,0x4C,0x2A,0x8D,
0x42,0x39,0xFA,0xFF,0x81,0xF6,0x71,0x87,0x22,0x61,0x9D,0x6D,0x0C,0x38,0xE5,0xFD,
0x44,0xEA,0xBE,0xA4,0xA9,0xCF,0xDE,0x4B,0x60,0x4B,0xBB,0xF6,0x70,0xBC,0xBF,0xBE,
0xC6,0x7E,0x9B,0x28,0xFA,0x27,0xA1,0xEA,0x85,0x30,0xEF,0xD4,0x05,0x1D,0x88,0x04,
0x39,0xD0,0xD4,0xD9,0xE5,0x99,0xDB,0xE6,0xF8,0x7C,0xA2,0x1F,0x65,0x56,0xAC,0xC4,
0x44,0x22,0x29,0xF4,0x97,0xFF,0x2A,0x43,0xA7,0x23,0x94,0xAB,0x39,0xA0,0x93,0xFC,
0xC3,0x59,0x5B,0x65,0x92,0xCC,0x0C,0x8F,0x7D,0xF4,0xEF,0xFF,0xD1,0x5D,0x84,0x85,
0x4F,0x7E,0xA8,0x6F,0xE0,0xE6,0x2C,0xFE,0x14,0x43,0x01,0xA3,0xA1,0x11,0x08,0x4E,
0x82,0x7E,0x53,0xF7,0x35,0xF2,0x3A,0xBD,0xBB,0xD2,0xD7,0x2A,0x91,0xD3,0x86,0xEB,
//1a53c
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x01,0x06,0x0B,0x00,0x05,0x0A,0x0F,0x04,0x09,0x0E,0x03,0x08,0x0D,0x02,0x07,0x0C,
0x05,0x08,0x0B,0x0E,0x01,0x04,0x07,0x0A,0x0D,0x00,0x03,0x06,0x09,0x0C,0x0F,0x02,
0x00,0x07,0x0E,0x05,0x0C,0x03,0x0A,0x01,0x08,0x0F,0x06,0x0D,0x04,0x0B,0x02,0x09,
//1a57c
0x07,0x0C,0x11,0x16,0x05,0x09,0x0E,0x14,0x04,0x0B,0x10,0x17,0x06,0x0A,0x0F,0x15,
0x98,0x2F,0x8A,0x42,0x91,0x44,0x37,0x71,0xCF,0xFB,0xC0,0xB5,0xA5,0xDB,0xB5,0xE9,
0x5B,0xC2,0x56,0x39,0xF1,0x11,0xF1,0x59,0xA4,0x82,0x3F,0x92,0xD5,0x5E,0x1C,0xAB,
0x98,0xAA,0x07,0xD8,0x01,0x5B,0x83,0x12,0xBE,0x85,0x31,0x24,0xC3,0x7D,0x0C,0x55,
0x74,0x5D,0xBE,0x72,0xFE,0xB1,0xDE,0x80,0xA7,0x06,0xDC,0x9B,0x74,0xF1,0x9B,0xC1,
0xC1,0x69,0x9B,0xE4,0x86,0x47,0xBE,0xEF,0xC6,0x9D,0xC1,0x0F,0xCC,0xA1,0x0C,0x24,
0x6F,0x2C,0xE9,0x2D,0xAA,0x84,0x74,0x4A,0xDC,0xA9,0xB0,0x5C,0xDA,0x88,0xF9,0x76,
0x52,0x51,0x3E,0x98,0x6D,0xC6,0x31,0xA8,0xC8,0x27,0x03,0xB0,0xC7,0x7F,0x59,0xBF,
0xF3,0x0B,0xE0,0xC6,0x47,0x91,0xA7,0xD5,0x51,0x63,0xCA,0x06,0x67,0x29,0x29,0x14,
0x85,0x0A,0xB7,0x27,0x38,0x21,0x1B,0x2E,0xFC,0x6D,0x2C,0x4D,0x13,0x0D,0x38,0x53,
0x54,0x73,0x0A,0x65,0xBB,0x0A,0x6A,0x76,0x2E,0xC9,0xC2,0x81,0x85,0x2C,0x72,0x92,
0xA1,0xE8,0xBF,0xA2,0x4B,0x66,0x1A,0xA8,0x70,0x8B,0x4B,0xC2,0xA3,0x51,0x6C,0xC7,0x19,0xE8,0x92,0xD1,0x24,0x06,0x99,0xD6,0x85,0x35,0x0E,0xF4,0x70,0xA0,0x6A,0x10,
0x16,0xC1,0xA4,0x19,0x08,0x6C,0x37,0x1E,0x4C,0x77,0x48,0x27,0xB5,0xBC,0xB0,0x34,
0xB3,0x0C,0x1C,0x39,0x4A,0xAA,0xD8,0x4E,0x4F,0xCA,0x9C,0x5B,0xF3,0x6F,0x2E,0x68,
0xEE,0x82,0x8F,0x74,0x6F,0x63,0xA5,0x78,0x14,0x78,0xC8,0x84,0x08,0x02,0xC7,0x8C,
0xFA,0xFF,0xBE,0x90,0xEB,0x6C,0x50,0xA4,0xF7,0xA3,0xF9,0xBE,0xF2,0x78,0x71,0xC6};unsigned char * unk_1A47C = unk_1A43C + 0x40;
unsigned char * unk_1A53C = unk_1A43C + 0x100;
unsigned char * unk_1A57C = unk_1A43C + 0x140;int __fastcall sub_144C8(int result, unsigned int a2) //52,packet size/4
{char v2 = 0; // nf@0int v3; // r12@1int v4; // r3@4char v5; // r0@8unsigned int v6; // r1@8unsigned int v7; // r2@8bool v8; // zf@17v3 = result ^ a2;if ( a2 <= 0 )a2 = -a2;if ( a2 == 1 ){if ( (v3 ^ result) < 0 )result = -result;return 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);__asm{pushadmov eax,a2bsr ecx,eaxmov edx,32sub edx,ecxsub edx,1mov ebx,edxmov eax,v4bsr ecx,eaxmov edx,32sub edx,ecxsub edx,1sub ebx,edxmov v5,blpopad}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{int Tmp = 0;__asm{pushadmov eax,a2bsr ecx,eaxmov edx,32sub edx,ecxsub edx,1mov Tmp,edxpopad}result = (unsigned int)v4 >> (31 - Tmp);//result = (unsigned int)v4 >> (31 - __clz(a2));if ( result < 0 )result = -result;}}return result;
}int __fastcall sub_144C0(int a1, int a2) // 52, packet size
{if ( !a2 )return 0;//JUMPOUT(&loc_152A0);return sub_144C8(a1, a2);
}int __fastcall sub_B764(unsigned int a1, unsigned int a2, int a3) //a1 = key a2 = 64, a3 = int [] return by c160
{int v3; // r4@1int v4; // r5@1int v5; // r3@1int v6; // r6@1int v7; // r3@1int v8; // r1@4unsigned int v9; // r2@4int v10; // r4@4int *v11; // r3@4int v12; // r2@5int v13; // r0@5int v14; // r1@5int v15; // r6@5int v16; // r3@5int v17; // r4@7int v18; // r4@8int v19; // r6@8int v20; // r3@8int v21; // r2@10char v22; // r6@10int v23; // r2@10int v24; // r2@10int v25; // r3@11int v26; // r5@11int v27; // r0@13int v28; // r5@13int v29; // r0@13int v30; // r3@14int v31; // r5@14int v32; // r1@16int v33; // r5@16int v34; // r1@16int result; // r0@18int v36; // r2@20int v37; // r1@20int v38; // r3@20int v39; // r4@20int v41; // [sp+4h] [bp+4h]@5int v42; // [sp+8h] [bp+8h]@3int v43; // [sp+Ch] [bp+Ch]@3int v44; // [sp+10h] [bp+10h]@1int v45; // [sp+14h] [bp+14h]@11int v46; // [sp+18h] [bp+18h]@3int v47; // [sp+1Ch] [bp+1Ch]@1int v48; // [sp+20h] [bp+20h]@1int v49; // [sp+24h] [bp+24h]@1int v50; // [sp+28h] [bp+28h]@1unsigned int v51; // [sp+2Ch] [bp+2Ch]@3int v52; // [sp+30h] [bp+30h]@7int v53; // [sp+34h] [bp+34h]@3int v54[17]; // [sp+38h] [bp+38h]@19 //v44 = a1 + 4 * (a2 >> 2);v3 = *(_DWORD *)(a3 + 4);v4 = *(_DWORD *)(a3 + 8);v50 = *(_DWORD *)a3;v5 = *(_DWORD *)(a3 + 16);v6 = *(_DWORD *)(a3 + 12);v49 = v3;v7 = a2 + v5;v48 = v4;v47 = v6;*(_DWORD *)(a3 + 16) = v7;if ( v7 < a2 )++*(_DWORD *)(a3 + 20);v51 = a1;v46 = (int)unk_1A53C; //v53 = (int)&v54[16]; //v43 = (int)unk_1A57C; //v42 = a3;int Tmp = (int)v54;while ( 1 ){result = v44;if ( v51 >= v44 )break;v9 = v51;v11 = v54;do{v8 = *(_DWORD *)v9;v9 += 4;v10 = v53;*v11 = v8;++v11; //将16字节数据和接下来的原始密钥拷贝到此处}while ( v11 != (int *)v10 );v12 = v47;v51 += 64;v13 = v48;v14 = v49;v15 = v50;v16 = 0;v41 = (int)unk_1A53C;while ( 1 ){v52 = (v12 ^ v13) & v14 ^ v12; //顺序正确v52 += *((_DWORD *)unk_1A43C + v16) + v15 + *(DWORD*)((DWORD*)Tmp + *(_BYTE *)(v16 + v41) ); //v17 = __ROR4__(v52, 32 - *(_BYTE *)(v41 + 64 + (v16++ & 3)));if ( v16 == 16 )break;v15 = v12;v12 = v13;v13 = v14;v14 += v17;}v18 = v17 + v14;v19 = v12;v20 = 0;while ( 1 ){v21 = ((v14 ^ v18) & v13 ^ v14)+ v19+ *((_DWORD *)unk_1A43C + v20 + 16)+ *(DWORD*)((DWORD*)Tmp + *(_BYTE *)(v46 + v20 + 16));v22 = *(_BYTE *)(v43 + (v20++ & 3) + 4);v23 = __ROR4__(v21, 32 - v22);v24 = v23 + v18;if ( v20 == 16 )break;v19 = v13;v13 = v14;v14 = v18;v18 = v24;}v45 = (int)unk_1A57C;v25 = 0;v26 = v13;while ( 1 ){v27 = (v18 ^ v24 ^ v14) + v26 + *((_DWORD *)unk_1A43C + v25 + 32);v52 = v27;v52 = v27 + *(DWORD*)((DWORD*)Tmp + *((_BYTE *)unk_1A53C + v25 + 32) );v27 = (v27 & 0xffffff00) + *(_BYTE *)(v45 + (v25++ & 3) + 8);v28 = __ROR4__(v52, 32 - v27);v29 = v28 + v24;if ( v25 == 16 )break;v26 = v14;v14 = v18;v18 = v24;v24 = v29;}v45 = (int)unk_1A57C;v30 = 0;v31 = v14;while ( 1 ){v32 = ((~v18 | v29) ^ v24) + v31 + *((_DWORD *)unk_1A43C + v30 + 48);v52 = v32;v52 = v32 + *(DWORD*)((DWORD*)Tmp + *((_BYTE *)unk_1A53C + v30 + 48) );v32 = (v32 & 0xffffff00) + *(_BYTE *)(v45 + (v30++ & 3) + 12);v33 = __ROR4__(v52, 32 - v32);v34 = v33 + v29;if ( v30 == 16 )break;v31 = v18;v18 = v24;v24 = v29;v29 = v34;}v50 += v18;v49 += v34;v48 += v29;v47 += v24;}//v36 = v42;v37 = v50;v38 = v49;v39 = v48;*(_DWORD *)(v42 + 12) = v47;*(_DWORD *)v36 = v37;*(_DWORD *)(v36 + 4) = v38;*(_DWORD *)(v36 + 8) = v39;return result;
}int __fastcall sub_C160(int result)
{*(_DWORD *)result = 1732584193;*(_DWORD *)(result + 4) = -271733879;*(_DWORD *)(result + 8) = -1732584194;*(_DWORD *)(result + 12) = 271733878;*(_DWORD *)(result + 20) = 0;*(_DWORD *)(result + 16) = 0;*(_DWORD *)(result + 24) = 0;//C190拷贝原始密钥到后面的字节中return result;
}//将原始密钥传入C160返回的数组中的第28开始的字节中
void *__fastcall sub_C190(void *result, int a2, unsigned int a3) //int[] return by c160 ,key,keylen
{int v3; // r6@1int v4; // r5@3int v5; // r5@6unsigned int v6; // r4@7int v7; // r5@7unsigned int v8; // [sp+4h] [bp+4h]@1const void *src; // [sp+8h] [bp+8h]@1int n; // [sp+Ch] [bp+Ch]@1int na; // [sp+Ch] [bp+Ch]@4v3 = (int)result;src = (const void *)a2;v8 = a3;n = a3;if ( a3 << 26 ){v4 = *((_DWORD *)result + 6);if ( v4 ){na = a3;if ( a3 > 128 - v4 )na = 128 - v4;result = memcpy((char *)result + v4 + 28, (const void *)a2, na);v5 = na + v4;*(_DWORD *)(v3 + 24) += na;if ( (unsigned int)v5 > 0x40 ){v6 = v3 + (v5 & 0xFFFFFFC0);sub_B764(v3 + 28, v5 & 0xFFFFFFC0, v3);v7 = v5 & 0x3F;result = memcpy((void *)(v3 + 28), (const void *)(v6 + 28), v7);*(_DWORD *)(v3 + 24) = v7;}src = (char *)src + na;n = v8 - na;}if ( n > 64 ){result = (void *)sub_B764((unsigned int)src, n & 0xFFFFFFC0, v3);src = (char *)src + (n & 0xFFFFFFC0);n &= 0x3Fu;}if ( n > 0 ){result = memcpy((void *)(v3 + 28), src, n);*(_DWORD *)(v3 + 24) = n;}}else{result = (void *)sub_B764(a2, a3, (int)result);}return result;
}//低位是C160 C190制造的密钥,高位指向一个整数 a2是一个整数
__int64 __fastcall sub_C250(__int64 a1, int a2) //完成密钥的生成和复制,参数为两个地址
{int _8; // ST08_4@1unsigned int v3; // r5@1int v4; // r4@1int v5; // r3@1int v6; // r6@1signed int v7; // r3@3int v8; // r5@5int v9; // r3@5__int64 _0; // [sp+0h] [bp+0h]@1_0 = a1;_8 = a2;v3 = *(_DWORD *)(a1 + 24); //原始密钥长度21//v4 = a1;v5 = v3 + *(_DWORD *)(a1 + 16); //21v6 = HIDWORD(a1); //数组*(_DWORD *)(a1 + 16) = v5; //0if ( v5 < v3 )++*(_DWORD *)(a1 + 20);v7 = 120;if ( v3 <= 0x37 )v7 = 56;HIDWORD(_0) = v7 - v3; //35memset((void *)(a1 + v3 + 28), 0, v7 - v3);*(_BYTE *)(v4 + v3 + 28) = -128;v8 = HIDWORD(_0) + v3;v9 = v4 + v8;*(_DWORD *)(v9 + 28) = 8 * *(_DWORD *)(v4 + 16);*(_DWORD *)(v9 + 32) = *(_QWORD *)(v4 + 16) >> 29;sub_B764(v4 + 28, v8 + 8, v4);*(_DWORD *)v6 = *(_DWORD *)v4; //返回真实的密钥 key, 64 ,16 bytes params*(_DWORD *)(v6 + 4) = *(_DWORD *)(v4 + 4);*(_DWORD *)(v6 + 8) = *(_DWORD *)(v4 + 8);*(_DWORD *)(v6 + 12) = *(_DWORD *)(v4 + 12);return _0;
}int __fastcall sub_C2C4(const void *a1, unsigned int a2, void *a3) //a1== key, a2 == keylen, a3 == int[]
{void *v3; // r6@1unsigned int v4; // r5@1int result; // r0@1unsigned __int64 v6; // r2@1__int64 v7; // r0@3void * v8 = a3; // r2@3 //V8初始化为A3const void *src; // [sp+4h] [bp+4h]@1int v10[0x100]; // [sp+8h] [bp+8h]@3 //v3 = a3;src = a1;v4 = a2;//v11 = _stack_chk_guard;result = (int)memset(a3, 0, 0x10);v6 = __PAIR__((unsigned int)src, (unsigned int)src) - __PAIR__((unsigned int)((char *)src - 1), 1); //此处编译有问题if ( (signed int)v4 > 16 && HIDWORD(v6) ){sub_C160((int)v10); //sub_C190(v10, (int)src, v4); //LODWORD(v7) = (unsigned int)v10;HIDWORD(v7) = (unsigned int)v3;result = sub_C250(v7, (int)v8); //低位是C160 C190制造的密钥,根据汇编V8指向a3}else if ( (signed int)v4 > 0 && HIDWORD(v6) ){result = (int)memcpy(v3, src, v4);}
// if ( v11 != _stack_chk_guard )
// _stack_chk_fail(result);return result;
}
// 14FC: using guessed type int __fastcall _stack_chk_fail(_DWORD);unsigned int __fastcall sub_C340(void *src, size_t n, int a3, int a4, void *dest, int a6)
{unsigned int v6; // r6@11int v7; // r4@8unsigned int v8; // r3@9unsigned int v9; // r12@9char *v10; // r2@10int v11; // r0@11int v12; // r4@11int v13; // r6@11int v14; // r1@12signed int v15; // r3@15int v16; // r4@16bool v17; // cf@16unsigned int v19; // [sp+0h] [bp+0h]@11int v20; // [sp+4h] [bp+4h]@9unsigned int v21; // [sp+8h] [bp+8h]@11char *v22; // [sp+Ch] [bp+Ch]@9unsigned int v23; // [sp+10h] [bp+10h]@10int v24; // [sp+14h] [bp+14h]@9int v25; // [sp+18h] [bp+18h]@1int v26; // [sp+1Ch] [bp+1Ch]@12int v27[0x100] = {0}; // [sp+20h] [bp+20h]@8 //此处应该是个数组//v19 = (int)(v27-8);//memmove((char*)v35,"\\xf1\\x5e\\x78\\xd2\\x30\\x33\\xc2\\xc4\\xba\\xc8\\xa0\\x25\\x67\\x7e\\x86\\x3a",16);v6 = n;v26 = a3;v25 = a4;if ( (signed int)n <= 0 || !src )return 0;if ( n << 30 ) //长度为4的倍数return -32227;if ( !dest )return v6;if ( a6 < (signed int)n )return -32227;if ( dest != src ) //这里肯定相等memcpy(dest, src, n);sub_C2C4((const void *)v26, v25, v27); //v27 is int[]v26 = v6 >> 2;v25 = (v6 >> 2) - 1;v7 = *(_DWORD *)dest;if ( v25 <= 0 ){v15 = 3;do{v16 = __ROR4__(v7 - (*((int*)v27 + v15) ^ 0x9E3779B9), 16);v7 = v16 ^ 0x79B99E37;v17 = (unsigned int)v15-- >= 1;}while ( v17 );*(_DWORD *)dest = v7;}else{v24 = sub_144C0(52, v26);v8 = -1640531527 * (v24 + 6);v9 = v6;v22 = (char *)dest + 4 * v25;v20 = 4 * (v26 + 0x3FFFFFFF);while ( v24 != -6 ){v23 = (v8 >> 2) & 3;v10 = (char *)dest + v20;v26 = v25;do{v21 = (*(v27 + (v26 & 3 ^ v23) ) ^ *((_DWORD *)v10 - 1)) + (v7 ^ v8);v19 = ((unsigned int)v7 >> 3) ^ 16 * *((_DWORD *)v10 - 1);v11 = (v19 + (4 * v7 ^ (*((_DWORD *)v10 - 1) >> 5))) ^ v21;v12 = *(_DWORD *)v10;--v26;v13 = v26;v7 = v12 - v11;*(_DWORD *)v10 = v7;v10 -= 4;}while ( v13 );v7 = *(_DWORD *)dest- (((16 * *(_DWORD *)v22 ^ ((unsigned int)v7 >> 3)) + ((*(_DWORD *)v22 >> 5) ^ 4 * v7)) ^ ((v7 ^ v8)+ (*(_DWORD *)v22 ^ *(v27 + v23))));v14 = v24 - 1;*(_DWORD *)dest = v7;v8 += 1640531527;v24 = v14;}v6 = v9;}return v6;
}unsigned int __fastcall sub_C49C(void *a1, int a2, int a3, int a4, void *a5, int a6)
{unsigned int result; // r0@1int v7; // r3@3result = sub_C340(a1, a2, a3, a4, a5, a6);if ( (signed int)result > 0 && a5 ){v7 = *(_DWORD *)((char *)a5 + result - 4);if ( v7 < 0 || (signed int)(result - 3) <= v7 ){result = -32227;}else{*((_BYTE *)a5 + v7) = 0;result = v7;}}return result;
}//src == dest == packet, a2== a6 == pack len, a3 = key, a4 = keylen
int __fastcall sub_C4D8(void *src, int a2, int a3, int a4, void *dest, int a6)
{int v6; // r5@3size_t i; // r2@8unsigned int v8; // r3@11char *v9; // r6@11unsigned int v10; // r5@11unsigned int v11; // r3@12void *v12; // r1@13unsigned int v13; // r3@13int v14; // r2@13unsigned int v15; // r12@13int v16; // r0@14int v17; // r3@14int v18; // r3@14unsigned int v19; // r0@14int v20; // r0@14unsigned int v21; // r2@15int v22; // r1@15int *v23; // r2@18int v24; // r6@19int v25; // r3@19unsigned int v28; // [sp+4h] [bp+4h]@14size_t v29; // [sp+8h] [bp+8h]@12unsigned int v30; // [sp+Ch] [bp+Ch]@14unsigned int v31; // [sp+10h] [bp+10h]@13int v32; // [sp+14h] [bp+14h]@1size_t v33; // [sp+18h] [bp+18h]@1size_t n; // [sp+1Ch] [bp+1Ch]@1int v35[0x10] = {0}; // [sp+20h] [bp+20h]@11//memmove((char*)v35,"\\xf1\\x5e\\x78\\xd2\\x30\\x33\\xc2\\xc4\\xba\\xc8\\xa0\\x25\\x67\\x7e\\x86\\x3a",16);n = a2;v33 = a3;v32 = a4;if ( a2 > 0 && src ){v6 = (a2 + 3) & 0xFFFFFFFC;if ( dest ){if ( a6 >= v6 ){if ( dest != src )memcpy(dest, src, n);for ( i = n; (signed int)i < v6; ++i )*((_BYTE *)dest + i) = 0;n = i;sub_C2C4((const void *)v33, v32, v35);v8 = *(_DWORD *)dest;v9 = (char *)dest + 4 * ((n >> 2) - 1);v33 = (n >> 2) - 1;v10 = *(_DWORD *)v9;if ( (signed int)v33 <= 0 ){v23 = v35;do{v24 = *v23;++v23;v25 = __ROR4__(v8, 16);v8 = (v24 ^ 0x9E3779B9) + (v25 ^ 0x9E3779B9);}while ( v23 != &v35[4] );*(_DWORD *)dest = v8;}else{v32 = sub_144C0(52, n >> 2);v11 = 0;v29 = v33 & 3;while ( v32 != -6 ){v12 = dest;v13 = v11 - 1640531527; //0xffffffff9E3779B9v31 = (v13 >> 2) & 3;v14 = 0;v15 = v13;do{//v27 = 0;v16 = *(DWORD*)(v35 + (v14 & 3 ^ v31) );v17 = *(_DWORD *)((_DWORD *)v12 + 1);++v14;v30 = v16 ^ v10;v18 = (v16 ^ v10) + (v17 ^ v15);v19 = *((_DWORD *)v12 + 1);v30 = v18;v28 = 16 * v10 ^ (v19 >> 3);v10 = ((v28 + ((v10 >> 5) ^ 4 * v19)) ^ v18) + *(_DWORD *)v12;v20 = v33;*(_DWORD *)v12 = v10;v12 = (char *)v12 + 4;}while ( v14 < v20 );v21 = *(_DWORD *)dest;v11 = v15;v30 = (*(_DWORD *)dest >> 3) ^ 16 * v10;v10 = ((v30 + (4 * v21 ^ (v10 >> 5))) ^ ((v10 ^ *(v35 + (v31 ^ v29) )) + (v21 ^ v15))) + *(_DWORD *)v9;v22 = v32;*(_DWORD *)v9 = v10;v32 = v22 - 1;}}v6 = n;}else{v6 = -32226;}
// Utf8ToGB2312((char*)dest,v6);}}else{v6 = 0;}return v6;
}int __fastcall sub_C62C(void *src, int a2, int a3, int a4, void *dest, int a6)
{int v6; // r6@1int v7; // r5@1int i; // r1@5int v10; // [sp+8h] [bp+0h]@1int v11; // [sp+Ch] [bp+4h]@1v10 = a4;v6 = a2;v11 = a3;v7 = ((a2 + 3) & 0xFFFFFFFC) + 4;if ( dest ){if ( a6 < v7 ){v7 = -1;}else{if ( dest != src )memcpy(dest, src, a2);for ( i = v6; i < v7; ++i )*((_BYTE *)dest + i) = 0;*((_DWORD *)dest + (i >> 2) - 1) = v6;v7 = sub_C4D8(dest, i, v11, v10, dest, i);}}return v7;
}int __fastcall sub_183C(char * str,int strlen,char * key, int keylen, char * decbuf, int decbuflen,int Flag)
{int Cnt = 0;if ( Flag )Cnt = sub_C62C(str, strlen, (int)key, keylen, decbuf, decbuflen);elseCnt = sub_C49C(str, strlen, (int)key, keylen, decbuf, decbuflen);if (Cnt <= 0){return 0;}return Cnt;
}// void __cdecl New_sub_16f4()
// {
// __asm
// {
// //push edi
// //push esi
// //push ebx
// push ebp
// mov ebp,esp
// sub esp,0x7c
//
// push 64
// push 0
// push offset TeaKey
// call memset
// add esp ,12
//
// push dword ptr 0x7c
// push dword ptr 0
// push esp
// call memset
// add esp,12
// add esp,0x20
//
// mov ebx, esp
// add ebx ,8
//
// push 4
// push offset unk_19578
// mov eax, ebx
// add eax,0x1f
// push eax
// call memcpy
// add esp,12
//
//
// mov eax,0x252423
// mov [ebx + 0x54 - 0x3c], eax
// mov eax, offset unk_19578
// mov [ebx + 0x54 - 0x50],eax
// mov ax,0x235e
// mov [ebx + 0x54 - 0x2e],ax
// mov ax,0x25
// mov [ebx + 0x54 - 0x2c],ax
//
// push 4
// mov eax,offset unk_19578
// add eax, 7
// push eax
// mov eax,ebx
// add eax,0x2d
// push eax
// call memcpy
// add esp,12
//
// mov eax,0x475224
// mov [ebx + 0x54 - 0x20],eax
//
// push 4
// mov eax,offset unk_19578
// add eax,0x0e
// push eax
// mov eax,ebx
// add eax,0x3b
// push eax
// call memcpy
// add esp,12
//
//
// mov ax,0x5248
// mov [ebx + 0x42],ax
// mov ax,0x28
// mov [ebx + 0x42 + 2],ax
//
// push 0x0e
// mov eax,offset unk_19578
// add eax, 0x16
// push eax
// mov eax,ebx
// add eax,8
// push eax
// call memcpy
// add esp,12
//
// sub esp,0x20
// //push 0x20
// //push 0
// //push esp
// //call memset
// //add esp,12
//
// mov esi,esp
// add esi,8
//
// lea esi,TeaKey
//
// push esi
//
// mov [ebx + 0x54 - 0x50],esi
// mov edi,ebx
// add edi,0x18
//
//
// //r0 =esp - 0x20 + 8 == esi
// mov edx,0
// SetKey:
// push esi
//
// mov ecx,8
// add ecx,edx
// movzx eax,word ptr [ebx + ecx]
// add edx,2
//
// mov ecx,eax
// shl eax,1
// add eax,ecx
// add esi,eax
//
// mov cl,[edi]
// mov [esi ],cl
// mov cl,[edi+1]
// mov [esi + 1],cl
// mov cl, [edi + 2]
// mov [esi + 2],cl
// add edi,7
//
// pop esi
// cmp edx, 0x0e
// jnz SetKey
//
// pop eax
// mov esp,ebp
// pop ebp
//
// //pop ebx
// //pop esi
// //pop edi
// //retn 0
// }
//
// return ;
// }int AscToHex(unsigned char * Asc,int AscLen, unsigned char * Hex)
{unsigned char Table[] = "0123456789abcdef";unsigned int Index = 0;unsigned int Cnt = 0;unsigned int Counter = 0;unsigned char Tmp = 0;for (Cnt = 0; Cnt < AscLen; ){for (Index = 0; Index < 16; Index ++){if ( Asc[Cnt] == Table[Index] ){Tmp = Index << 4;}}Cnt ++;for (Index = 0; Index < 16; Index ++){if ( Asc[Cnt] == Table[Index] ){Tmp = Tmp | Index;}}Cnt ++;Hex[Counter] = Tmp;Counter ++ ;}return Counter;
}
上面的接口很简单,入口是sub_183C,最后的Flag字段代表要不要做md5验证,如果要的话,执行sub_C49C,否则执行sub_C62C函数。其中的sub_C2C4调用sub_C160和sub_C160,几个函数的作用是计算md5值。sub_C340是主要加解密函数。有些细节我也是模棱两可,知识照抄ida的反汇编伪C代码。
这个项目是我经历过难度最大最复杂的工程。
逆向过程持续了差不多一个月的时间,从java层smali插桩输入日志、观察参数,推导数据执行流程,到so层ARM反汇编过程。刚开始做的最频繁的,还是smali插桩分析。因为android程序用的arm汇编,解密程序是x86机器,需要将有些Arm汇编翻译为x86指令。
而在so层面,除了少量arm指令代码,将ida的伪代码直接拷贝到vs工程里编译是ok的,但在运行时解密结果是错的,因为这个原因,自己卡在这里好多天,后来偶然的机会纠正了这个错误,以至于到后来,到底是伪c代码和arm转x86汇编部分,哪里错了我都不记得了。
因为整个通信基本上都是加密数据通信,java层封装的各种加解密接口非常之多,我只能挑选某些地方插桩,最后找到从java的native接口到进入so的入口:
该程序的so库文件罗列如下:
本程序第一个数据包的解密密钥:“DFG#%^#%RGHR(&*M<><”,解密算法sub_183C。第一个pos或者get数据包中去掉http包头后,数据部分用这个密钥解密后,可以得到客户端登录信息,比如IMEI,IMSI,手机号等。同时,该数据包中还有一个密钥,该密钥用于解密服务器返回的数据包,结构的名称是“GetUserIdentity”,前缀一般是"\\x0b\\x8c\\x98\\x0c\\xa8\\x0c",是一个tlv数据结构,具体含义不明。
服务器端返回的数据包中包含另一个16(或许是21)字节的密钥,他所在的格式名称是“GetUserIdentityResp”,解密算法也是sub_183C。该密钥是字符串格式化的,需要转化为二进制后用到上的密钥解密,解密之后的16个字节就是通信过程中通讯录的密钥datakey。
当客户端和服务器通讯录同步时,先用密钥"DFG#%^#%RGHR(&*M<><"调用sub_183C函数解密,然后利用上面的密钥datakey再次调用sub_183C函数,对第一次解密后的数据再次解密,即可得到明文数据。
解密后的数据如下:
该程序所有的文本数据都是先转化为utf8和base64,然后先加密后压缩传输的。
其中的base64编码:
44CQ6YKu5YKo6ZO26KGM44CR5oKo5bC+5Y+3OTc4OeeahOmTtuihjOWNoeato+WcqOeUs+ivt+W8gOmAmumCruWCqOmTtuihjOaUr+S7mOWuneW/q+aNt+aUr+S7mO+8jOmqjOivgeegge+8mjQ2NzA5NO+8jOW/q+aNt+aUr+S7mOWPr+iDveS8muW4puadpei+g+mrmOeahOi1hOmHkeaNn+WksemjjumZqe+8jOivt+iwqOaFjuaTjeS9nOOAglvlt6XkvZzkurrlkZjkuI3kvJrntKLlj5bvvIzor7fli7/ms4TpnLJd
解码后是:【邮储银行】您尾号9789的银行卡正在申请开通邮储银行支付宝快捷支付,验证码:467094,快捷支付可能会带来较高的资金损失风险,请谨慎操作。[工作人员不会索取,请勿泄露]
自此,整个程序逆向的框架基本完毕。其中有个java层smali插桩的问题,那会刚接触android,但并不知道有个叫做xposed的神器,因此都是手动编写java,反汇编为smali后,将之插入到apk反汇编后的smali中,再次对apk的smali打包并签名,安装运行。
该程序还有一个孪生兄弟程序,叫做xxx电话本。该程序还有一个大名鼎鼎的大哥程序,叫做xxx信。他们初始化密钥相同:@#%^SEF#$Sddhfvh,而且解密过程更简单,数据解压缩后直接调用sub_183C函数即可。
但是不到一年之后,程序进行了更新,改为了RSA非对称方式加解密,因此此算法早已彻底失效。