App信息
包名:com.tencent.tencent2016a

Java层分析
MainActivity

c

NativeCheckRegister

so分析
定位NativeCheckRegister函数位置

NativeCheckRegister
类型修复及函数重命名之后的NativeCheckRegister函数如下

check
类型修复及函数重命名后的check函数
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
| bool __fastcall check(const char *name, char *code) { signed int namelength; _BOOL4 result; int i; _DWORD *nametempaddr; int nametempresult; int j; int codetemp; _DWORD nameresultarray[5]; _DWORD coderesultarray[5]; _BYTE namemix[20]; _BYTE codeResult[1052];
namelength = j_strlen(name); if ( (namelength - 6) > 0xE ) return 0; j_memset(namemix, 0, sizeof(namemix)); for ( i = 0; i != 16; ++i ) { nametempaddr = &namemix[i]; nametempresult = name[i % namelength] * (i + 20160126) * namelength; *nametempaddr += nametempresult; } j_memset(codeResult, 0, 0x400u); if ( codeEnc1(code) > 1024 || codeEnc2(codeResult, code) != 20 ) return 0; j_memset(nameresultarray, 0, sizeof(nameresultarray)); j_memset(coderesultarray, 0, sizeof(coderesultarray)); for ( j = 0; j != 5; ++j ) { codetemp = *&codeResult[j * 4]; nameresultarray[j] = *&namemix[j * 4] / 10; coderesultarray[j] = codetemp; } result = 0; if ( coderesultarray[4] + nameresultarray[0] == coderesultarray[2] && coderesultarray[4] + nameresultarray[0] + nameresultarray[1] == 2 * coderesultarray[4] && nameresultarray[2] + coderesultarray[3] == coderesultarray[0] && nameresultarray[2] + coderesultarray[3] + nameresultarray[3] == 2 * coderesultarray[3] ) { return nameresultarray[4] + coderesultarray[1] == 3 * nameresultarray[2]; } return result; }
|
根据以上信息,当满足以下条件,程序验证成功
1 2 3 4 5
| coderesultarray[4] + nameresultarray[0] == coderesultarray[2] coderesultarray[4] + nameresultarray[0] + nameresultarray[1] == 2 * coderesultarray[4] nameresultarray[2] + coderesultarray[3] == coderesultarray[0] nameresultarray[2] + coderesultarray[3] + nameresultarray[3] == 2 * coderesultarray[3] nameresultarray[4] + coderesultarray[1] == 3 * nameresultarray[2]
|
变换,整理得到如下内容:
1 2 3 4 5
| coderesultarray[4] + nameresultarray[0] == coderesultarray[2] nameresultarray[0] + nameresultarray[1] == coderesultarray[4] nameresultarray[2] + coderesultarray[3] == coderesultarray[0] nameresultarray[2] + nameresultarray[3] == coderesultarray[3] nameresultarray[4] + coderesultarray[1] == 3 * nameresultarray[2]
|
由此可知:
- coderesultarray[0]可由nameresultarray[2]+nameresultarray[2]+nameresultarray[3]得到
- coderesultarray[1]可由3 * nameresultarray[2]-nameresultarray[4]]得到
- coderesultarray[2]可由nameresultarray[0] + nameresultarray[1]+nameresultarray[0]]得到
- coderesultarray[3]可由nameresultarray[2] + nameresultarray[3]]得到
- coderesultarray[4]可由nameresultarray[0] + nameresultarray[1]]得到
分析
由以上信息,我们可以知道,由name->namemix->nameresultarray->coderesultarray
还知道code->codeResult->coderesultarray
猜测可通过coderesultarray还原code
接下来分析code的两个处理函数codeEnc1和codeEnc2
codeEnc1

a456789

观察数据窗口
发现末尾有一串Base64表,盲猜会出现Base64编码

经过分析,codeEnc1函数的功能是对输入的code进行校验,返回一个与字符串长度和规则相关的值,然后与1024进行比较。
codeEnc2
处理过后的codeEnc2函数如下
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
| int __fastcall codeEnc2(char *codeResult, char *code) { char *Cocode; int Cocode_code; int v4; int v5; char *codeResultTemp; int v7; int v8;
Cocode = code; do ++Cocode; while ( a456789[*(Cocode - 1)] <= 63u ); Cocode_code = Cocode - code; v4 = Cocode_code - 1; v5 = 3 * ((Cocode_code + 2) / 4); while ( 1 ) { codeResultTemp = codeResult; if ( v4 <= 4 ) break; v4 -= 4; *codeResult = (a456789[code[1]] >> 4) | (4 * a456789[*code]); codeResult[1] = (a456789[code[2]] >> 2) | (16 * a456789[code[1]]); v7 = code[2]; v8 = code[3]; code += 4; codeResult[2] = (a456789[v7] << 6) | a456789[v8]; codeResult += 3; } if ( v4 > 1 ) { *codeResult = (a456789[code[1]] >> 4) | (4 * a456789[*code]); if ( v4 == 2 ) { codeResultTemp = codeResult + 1; } else { codeResult[1] = (a456789[code[2]] >> 2) | (16 * a456789[code[1]]); if ( v4 == 4 ) { codeResultTemp = codeResult + 3; codeResult[2] = (a456789[code[2]] << 6) | a456789[code[3]]; } else { codeResultTemp = codeResult + 2; } } } *codeResultTemp = 0; return v5 - (-v4 & 3); }
|
这是一个Base64解码算法
hook验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function hook_native(){ var soAddr = Module.findBaseAddress("libCheckRegister.so"); var codeEnc2 = soAddr.add(0x1499) console.log(codeEnc2) Memory.protect(codeEnc2, 0x1000, 'rwx'); Interceptor.attach(codeEnc2,{ onEnter:function(args){ console.log("arg0:",hexdump(args[0])); console.log("arg1:",hexdump(args[1])); this.codeResult = args[0]; }, onLeave:function(ret){ console.log("codeResult:",hexdump(this.codeResult)); console.log("ret:",ret) this.ret=1 } }) } hook_native()
|
输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| arg0: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ffdc62f4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffdc6304 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffdc6314 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ arg1: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF deb247a0 31 32 33 34 35 36 37 38 00 00 00 00 00 00 00 00 12345678........ deb247b0 00 00 00 00 28 00 00 00 00 00 00 00 00 00 00 00 ....(........... codeResult: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF ffdc62f4 d7 6d f8 e7 ae fc 00 00 00 00 00 00 00 00 00 00 .m.............. ffdc6304 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ffdc6314 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ret: 0x6
|
如下证明codeEnc2是标准的Base64解码算法

分析
这里弄明白了,code经过Base64解码得到codeResult,codeResult部分数据经过Base64解码得到coderesultarray。
重新捋一遍流程
首先,我们输入name,name经过混淆得到namemix,namemix的前20字节经过处理得到nameresultarray,然后由nameresultarray推导出coderesultarray,coderesultarray经过Base64编码得到code。
C++还原
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
| #include <iostream> #include <cstring> using namespace std;
string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";
string base64_encode(unsigned char* bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4];
while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; i = 0; } }
if (i) { for (j = i; j < 3; j++) char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
while ((i++ < 3)) ret += '='; }
return ret; }
int main() { char name[20] = {0}; printf("Please input name:"); cin >> name;
int namelength = strlen(name); cout << "namelength:" << namelength << endl;
char* temppointer = NULL; int namemix[5] = {0};
for (int i = 0; i < 16; i++) { temppointer = (char*)namemix + i;
int tempnumber = name[i % namelength] * (i + 20160126) * namelength;
*(int*)temppointer += tempnumber; }
for (int i = 0; i != 5; i++) { }
int nameresultarray[5] = {0}; for (int i = 0; i < 5; i++) { nameresultarray[i] = namemix[i] / 10; }
for (int i = 0; i < 5; i++) { }
int coderesultarray[5] = {0}; coderesultarray[0] = nameresultarray[2] + nameresultarray[2] + nameresultarray[3]; coderesultarray[1] = 3 * nameresultarray[2] - nameresultarray[4]; coderesultarray[2] = nameresultarray[0] + nameresultarray[1] + nameresultarray[0]; coderesultarray[3] = nameresultarray[2] + nameresultarray[3]; coderesultarray[4] = nameresultarray[0] + nameresultarray[1];
for (int i = 0; i < 5; i++) { }
string encodeStr = base64_encode((unsigned char*)coderesultarray, 20); cout << "Code is :" << encodeStr;
return 0; }
|
验证成功
