简单说一下个人的想法
第一题 (http://bbs.pediy.com/showthread.php?t=193755)
基本就是纯粹考察ARM的逆向能力,IDA F5 + 部分ARM汇编,很容易就可以将算法部分分析出来。最后得出的结论就是,其实就是base64加了三条'-'
值得一提的是,通过第一题,对加密部分代码有了比较深入的了解之后,对后面两道题解答有很大帮助
第二题(http://bbs.pediy.com/showthread.php?t=193824)
so加了壳,静态分析会发现dynamic字段是空。 当时偷懒,没细看,直接通过gDvm->loadedClasses找到 "Lcom/crackme/MainActivity"类的ClassObject,然后枚举Method获取了crackme函数的地址。
然后静态分析,发现就是倒序之后base64加密
补充一下"静态分析会发现dynamic字段是空"的问题,其实就是利用了文件和内存中使用的偏移不同的方法,如下图,文件中会读0x3C000,而内存中会读0x3D000,实际上(此SO)内存中布局是完全按照文件中的布局映射的,只要读取0x3D000处,就可以得到正常的dynamic了
第三题(http://bbs.pediy.com/showthread.php?t=193877)
貌似是添加了AntiDebug,由于是周末,家里啥环境都没有,也就没有细搞。按照第二题的思路,写了一个程序,进程注入,把crackme的函数地址读出来了,然后就没有然后了~~
希望大神来给分析一下AntiDebug怎么实现的,又是怎么绕过的。 好吧,我承认我懒得分析了,目测单步测试so加载部分代码应该能有所收获。
结论就是前面 n-2个字符两两交换,然后算base64
第四题(http://bbs.pediy.com/showthread.php?t=193953)
真正考逆向水平的题目。方法就是单步~读ARM指令~对照IDA F5~单步~读ARM指令~对照IDA F5~~~~多尝试几遍就行了。还好so里面保留了部分des的符号,让那些不熟悉des加密的娃(例如me)可以猜到是用了des加密。
不知道是不是我找的源码的问题。测试的时候,发现自己程序的加密结果和crackme的不同,经过反复反复反复反复地测试,发现是S_BOX和另外一个初始化的数组值有差异,测试的方法就是逐过程对照结果,看看哪一步得到的结果不一样,然后对照参数。最后找到不同点。
然后就很简单了。必须吐槽一下,这道题测试好麻烦,手工输入32个字符还算好的。
哦~忘了一点,秘钥生成,是使用了用户名的前8个字节,然后依次异或了0x100个字符 =.= ,话说,异或不是有交换结合律么,结果就是直接异或0x93就行了。 以上就是个人的一些方法,欢迎来讨论或者提供更好的解题思路啊
================== YD的分割线===============
我x~~竟然总顶了,受宠若惊啊,所以决定还是把整个解题流程写一下,方便各位查阅
持续更新中~~~~~~
===================低调的分割线=================
前言
这次比赛,前三道题目的算法都是base64,最后一题是des。
由于dex部分十分简单,就是调用libcrackme.so中的crackme函数,所以这里就不赘述了。
Crackme1
目的是分析libcrackme.so,不过这个so如果用IDA打开的话,会卡一段时间,然后报错,同时生成6G+的数据文件。这种情况明显是文件格式有猫腻 ,处理这种问题,推荐010Editor的模板。
用010Editor打开libcrackme.so,然后执行ELF模板,会提示解析出错。然后就能找到出错的内容了
可以看到,是一个程序节内容错误,本着简(懒)单(惰)的原则,直接将此节内容清零,保存文件后,IDA就可以正常打开文件了。此问题在后续的so里面都会出现,就不再赘述了。
之后就是找到Java_com_crackme_MainActivity_crackme函数,F5分析代码。
然后发现。。。。。。原来是加密的。
处理加密,考虑到运行时必定已经解密,所以运行crackme1,然后再吧so文件dump出来,过程不多说了,这里提一下用IDA下面python插件dump内存的方法:
import idaapi
base = 0x74E71000
size = 266252
data = idaapi.dbg_read_memory(base,size)
if data != None:
f = open("e:\\crackme1.so","wb")
f.write(data)
f.close()
int __fastcall Java_com_crackme_MainActivity_crackme(int a1, int a2, int a3, int a4)
{
v4 = a4;
v5 = a1;
v6 = (*(int (**)(void))(*(_DWORD *)a1 + 676))();
v7 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v5 + 676))(v5, v4, 0);
sub_536C(&dword_15220[1], v6, v7);
sub_597C(&dword_15220[1]);
return (*(int (__fastcall **)(int, int *))(*(_DWORD *)v5 + 668))(v5, &dword_15220[1]);
}
int __fastcall sub_536C(int a1, const char *a2, const char *a3)
{
v3 = a3;
v4 = a1;
v5 = a2;
result = sub_5328();
if ( v3 )
{
if ( v5 )
{
v7 = strlen(v5);
v13 = v7;
v8 = v7;
v9 = strlen(v3);
v10 = v8 + 1;
v14 = v9;
n = v9 + 1;
*(_DWORD *)(v4 + 52) = operator new[](v10);
result = operator new[](n);
v11 = *(void **)(v4 + 52);
*(_DWORD *)(v4 + 56) = result;
if ( v11 )
{
if ( result )
{
memset(v11, 0, v10);
memset(*(void **)(v4 + 56), 0, n);
memcpy(*(void **)(v4 + 52), v5, v13);
result = (int)memcpy(*(void **)(v4 + 56), v3, v14);
}
}
}
}
return result;
}
signed int __fastcall sub_597C(int a1)
{
v1 = a1;
sub_53E4();
v2 = *(_DWORD *)(v1 + 56);
if ( *(_BYTE *)(v2 + 3) != 45 || *(_BYTE *)(v2 + 7) != 45 || *(_BYTE *)(v2 + 11) != 45 )
{
*(_BYTE *)_cxa_allocate_exception(1) = 1;
_cxa_throw();
}
sub_5430(v1);
v3 = *(const char **)(v1 + 56);
v4 = (unsigned __int8)byte_15120;
if ( !byte_15120 )
{
do
byte_15121[v4++] = -128;
while ( v4 != 256 );
v5 = 0;
do
{
byte_15121[v5 + 65] = v5;
++v5;
}
while ( v5 != 26 );
v6 = &byte_15182;
do
{
*v6 = v5;
v5 = (v5 + 1) & 0xFF;
++v6;
}
while ( v5 != 52 );
v7 = &byte_15151;
do
{
*v7 = v5;
v5 = (v5 + 1) & 0xFF;
++v7;
}
while ( v5 != 62 );
byte_1514C = 62;
byte_15150 = 63;
byte_1515E = 0;
byte_15120 = 1;
}
if ( v3 )
{
v8 = strlen(v3);
v9 = (const void *)operator new[](v8 + 1);
}
else
{
v9 = 0;
}
v10 = strlen(v3);
v11 = 0;
v12 = v9;
v13 = 0;
v14 = v3;
while ( v11 < (signed int)(v10 - 3) )
{
v15 = 0;
do
{
v16 = byte_15121[*(&v14[v11] + v15)];
*(&v21 + v15) = v16;
if ( v16 & 0x80 )
*(&v21 + v15) = 0;
++v15;
}
while ( v15 != 4 );
v13 += 3;
v11 += 4;
v17 = v22;
*(_BYTE *)v12 = ((signed int)v22 >> 4) | 4 * v21;
v18 = v23;
*((_BYTE *)v12 + 1) = 16 * v17 | ((signed int)v23 >> 2);
*((_BYTE *)v12 + 2) = (v18 << 6) | v24;
v12 = (char *)v12 + 3;
}
v19 = (void *)operator new[](v13);
memmove(v19, v9, v13);
if ( v9 )
operator delete[]((void *)v9);
memcpy((void *)(v1 + 60), v19, v13);
if ( v19 )
operator delete[](v19);
sub_548C(v1);
return 1;
}
signed int __fastcall sub_53E4(int a1)
{
if ( !*(_DWORD *)(a1 + 52)
|| (v1 = *(const char **)(a1 + 56)) == 0
|| (v2 = strlen(*(const char **)(a1 + 52)) - 6, v3 = strlen(v1), v2 > 0xE)
|| v3 - 12 > 0x12 )
{
*(_BYTE *)_cxa_allocate_exception(1) = 1;
_cxa_throw();
}
return 1;
}
v2 = *(_DWORD *)(v1 + 56);
if ( *(_BYTE *)(v2 + 3) != 45 || *(_BYTE *)(v2 + 7) != 45 || *(_BYTE *)(v2 + 11) != 45 )
{
*(_BYTE *)_cxa_allocate_exception(1) = 1;
_cxa_throw();
}
sub_5430(v1);
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: