偶然翻到去年玩命大哥举办的CM大赛第一题APK,拿来逆向练手。(好久没写博客,刷下存在感)
补下APK下载链接:http://bbs.pediy.com/showthread.php?t=193755
---------------------------------------------------------------------------------------
由于壳子是自定义的加载器,ELF文件格式DIY得比较厉害,IDA直接打开就崩溃了。反编译查看APK,算法放在了SO中,JAVA层仅是UI代码而已。
知道SO加载时,先加载壳子,故选择等APK运行起来之后再进行调试。
Attach到进程后,可以看到被加密的SO的导出表已经被解密修复回来,直接在native方法下断点。
算法用C++编写,流程:
1. 初始化全局变量struct global{
char msg[0x32];
char *username;
char *passwd;
}
2. 校验用户名密码长度,用户名长度范围:[6, 20],密码:[12,30],不满足抛出异常返回。
3. 初始化code表:
typedef struct _tableStruct TableStruct;
struct _tableStruct{
char hasInitted;
char code[256];
};
TableStruct table;
void init_table(TableStruct *pTable){
char* code = pTable->code;
int i;
int j;
pTable->hasInitted = 1;
for(i=0;i<256;i++)
code[i] = -128;
for(i=0;i<0x1a;i++)
code[0x41 + i] = i;
j = 0;
for(;i<0x34;i++){
code[0x61 + j] = (i & 0xff);
j++;
}
j = 0;
for(;i<0x3e;i++){
code[0x30 + j] = (i & 0xff);
j++;
}
code[0x2c-1] = i;
code[0x30-1] = 0x3f;
code[0x3e-1] = 0;
}
4. 校验密码格式:xxx-xxx-xxx-xxxx...,即校验3个'-‘位置
5. 将短线去除,将字符串前移,生成校验码:
for (i=0;i<strlen(passwd)-3;i+=4){
for(j=0;j<4;j++){
result[j] = code[passwd[i + j]];
if(result[j] < 0){
result[j] = 0;
}
}
//存放校验码,也即生成用户名
username[count + 0] = (result[1] >> 4) | (result[0] << 2) & 0xff;
username[count + 1] = ((result[2] >> 2) | (result[1] << 4)) & 0xff;
username[count + 2] = (result[3] | (result[2] << 6)) & 0xff;
count += 3;
}
6. 最后比较生成的校验码和用户名。
还有一点就是,校验完成后,通过异常抛出来返回TAG:"success",若patch 正常返回,则没有任何信息。