Ericky的一个crackme的分析
2017-03-30 10:53
190 查看
本文转载自一枚无混淆无反调试keygenme
JEB载入。
跟进注册按钮的点击事件。
先判断注册码是否为空,不为空则调用JNI.EatRice()方法,定义如下。
这是一个native函数并且是静态方法,两个参数分别是string类型的注册码和int类型的注册码长度。从代码中可以看出这个函数在libxy.so中,所以接下来我们来分析libxy.so。IDA载入libxy.so,找到Java_by_Ericky_crackme01_JNI_EatRice()方法,双击进入,可以看到这段代码还是比较长的。
很明显可以发现汇编窗口的代码多于F5之后的代码。
这其实是因为IDA在反编译so的时候会出现一些识别错误,只需要人为修正一下就好。回到反编译窗口, 按一下空格来查看Graph View。可以看到IDA识别出了两个入口,很明显左边才是入口,右边那个应该是中间一个地方识别出错导致调用图断开。
红框选中的地方识别有点问题。
单击红框中任意指令,然后如图点击Edit->Functions->Remove function tail。
点击完后会发现Graph View发生了变化。
这次单击里面的BL指令,然后如图点击Edit->others->Force BL call。
那么现在就可以看到整个函数的逻辑就恢复了,大概一看还是比较好理解的。
F5反编译出来的代码也已经比较合理。
然后我们来处理一下结构体的识别还有命名等初始工作。导入JNI.h,修正第一个参数为JNIEnv*类型,修改第一个变量为env。那么a3,a4的类型分别是jstring和jint,分别修正并重新命名为regCode和regCodeLength。同时这是一个静态方法,第二个参数可以不用管。关于这些IDA识别的问题在另外一篇博客中已经说得很清楚了-那些年使用IDA的事防止F5错误优化。然后开始读代码,v4位注册码长度,四个变量初始化为0,接着调用sub_10C4()。双击进入sub_10C4(),来修正一下,第一个参数是JNIEnv*, 第二个参数是jstring。修正完类型和重命名之后,可以看到有些函数识别出来了。
但是这时候看着还不是很爽,如下所示,每一个env函数都点击一遍。
结果如下,这下子看着好多了。
代码比较简单,就是将Java的String类型的字符串转为byte类型, 然后重新进行取值返回。
如果不熟悉的话可以跟进sub_12AC(),就是一个调用函数的操作。
那么现在我们可以回到最开始,这就是一个jstringtobyte的方法,修改一下返回的结果。
可以看到前两位的判断写在了if里,一个是88,一个是35。
并且还有一个条件,注册码长度是7,不满足直接返回失败。接下来第三位注册码赋值给v8,同时注册码首地址赋值给v32,也就是v32的值就是注册码数组的首地址,重命名一下,v33就当做一个临时变量好了。下面进入一个while(1)的循环,这个循环起始会执行两次,当第一次执行完的时候v9自减1,第二次在if那里就会break。下面的if其实可以缩减一下,因为异或不同为1,相同为0。
计算第三位注册码的代码如下。
第四位注册码的校验代码如下。
计算第四位注册码的代码如下。
第五位注册码的校验代码如下。
计算第五位注册码的代码如下。
接下来第六位和第七位注册码混在了一起。可以看到最后if有两个条件判断, 第一个v22参数由前面while(1)里校验第六位注册码的代码决定, 第二个v24参数由后面校验第七位注册码的代码决定。
计算第六位注册码的代码如下。
第七位注册码的校验在sub_1238里。
计算第七位注册码的代码如下。
整个代码运行的结果如下。
JEB载入。
跟进注册按钮的点击事件。
先判断注册码是否为空,不为空则调用JNI.EatRice()方法,定义如下。
这是一个native函数并且是静态方法,两个参数分别是string类型的注册码和int类型的注册码长度。从代码中可以看出这个函数在libxy.so中,所以接下来我们来分析libxy.so。IDA载入libxy.so,找到Java_by_Ericky_crackme01_JNI_EatRice()方法,双击进入,可以看到这段代码还是比较长的。
很明显可以发现汇编窗口的代码多于F5之后的代码。
这其实是因为IDA在反编译so的时候会出现一些识别错误,只需要人为修正一下就好。回到反编译窗口, 按一下空格来查看Graph View。可以看到IDA识别出了两个入口,很明显左边才是入口,右边那个应该是中间一个地方识别出错导致调用图断开。
红框选中的地方识别有点问题。
单击红框中任意指令,然后如图点击Edit->Functions->Remove function tail。
点击完后会发现Graph View发生了变化。
这次单击里面的BL指令,然后如图点击Edit->others->Force BL call。
那么现在就可以看到整个函数的逻辑就恢复了,大概一看还是比较好理解的。
F5反编译出来的代码也已经比较合理。
int __fastcall Java_by_Ericky_crackme01_JNI_EatRice(JNIEnv *env, int a2, jstring regCode, jint regLength) { jint v4; // r4@1 signed int v5; // r6@1 _BYTE *byte_code; // r5@1 char v7; // r3@4 unsigned __int8 v8; // r2@4 signed int v9; // r5@4 signed int v10; // r7@4 unsigned __int8 v11; // r6@9 signed int v12; // r4@9 signed int v13; // r5@9 signed int v14; // r7@12 unsigned __int8 v15; // r3@14 signed int i; // r5@14 unsigned int v17; // r6@16 int v18; // r4@22 signed int v19; // r7@22 int v20; // r5@24 unsigned int v21; // r4@24 signed int v22; // r5@26 int v23; // r0@27 int v24; // r0@27 signed int v26; // r4@33 signed int v27; // r3@35 int v28; // r3@37 signed int v29; // r2@37 char v30; // [sp+0h] [bp-28h]@22 signed int v31; // [sp+4h] [bp-24h]@7 _BYTE *v32; // [sp+8h] [bp-20h]@4 _BYTE *v33; // [sp+10h] [bp-18h]@4 v4 = regLength; v5 = 0; byte_4004 = 0; byte_4008 = 0; byte_400C = 0; byte_4010 = 0; byte_code = jstringtobyte(env, regCode); if ( *byte_code != 88 || byte_code[1] != 35 || v4 != 7 ) { j_j_sleep(3u); return 0; } v33 = j_j_malloc(1u); v7 = 35; *v33 = 35; v8 = byte_code[2]; v32 = byte_code; v33[1] = v8; v9 = -1; v10 = 63689; while ( 1 ) { v5 = (unsigned __int8)v7 + v5 * v10; if ( v9 == -2 ) break; v10 *= 378551; v7 = v33[-v9--]; } v31 = 1; if ( ((v5 + (v5 >> 31)) ^ (v5 >> 31)) == 2020122470 ) byte_4004 = 1; *v33 = v8; v11 = v32[3]; v33[1] = v11; v12 = -1; v13 = 1315423911; while ( 1 ) { v13 ^= ((unsigned int)v13 >> 2) + 32 * v13 + v8; if ( v12 == -2 ) break; v8 = v33[-v12--]; } v14 = 0; if ( ((v13 + (v13 >> 31)) ^ (v13 >> 31)) == 1532463978 ) byte_4008 = 1; *v33 = v11; v15 = v32[4]; v33[1] = v15; for ( i = -1; ; --i ) { v17 = v11 + 16 * v14; v14 = v17 & 0xF0000000 ? ((v17 & 0xF0000000) >> 24) ^ v17 & 0xFFFFFFF : v17; if ( i == -2 ) break; v11 = v33[-i]; } if ( ((v14 + (v14 >> 31)) ^ (v14 >> 31)) == 728 ) byte_400C = 1; *v33 = v15; v30 = v32[5]; v33[1] = v30; v18 = 0; v19 = -1; while ( 1 ) { v20 = v15 + v18; v21 = v15 + v18; if ( v20 & 0xF0000000 ) v21 = ((v20 & 0xF0000000) >> 24) ^ v20; v22 = ((v20 | 0xFFFFFFF) ^ 0xF0000000) & v21; if ( v19 == -2 ) break; v15 = v33[-v19--]; v18 = 16 * v21; } *v33 = v30; v33[1] = v32[6]; v23 = sub_1238(v33, 2); v24 = (v23 + (v23 >> 31)) ^ (v23 >> 31); if ( ((v22 + (v22 >> 31)) ^ (v22 >> 31)) == 960 && v24 == 789320428 ) { byte_4010 = 1; LABEL_32: v31 = 0; goto LABEL_33; } if ( byte_4010 ) goto LABEL_32; LABEL_33: v26 = 1; if ( byte_4008 ) v26 = 0; v27 = 1; if ( byte_4004 ) v27 = 0; v28 = v27 | v26; v29 = 1; if ( byte_400C ) v29 = 0; return ~(v28 | v29 | v31) & 1; }
然后我们来处理一下结构体的识别还有命名等初始工作。导入JNI.h,修正第一个参数为JNIEnv*类型,修改第一个变量为env。那么a3,a4的类型分别是jstring和jint,分别修正并重新命名为regCode和regCodeLength。同时这是一个静态方法,第二个参数可以不用管。关于这些IDA识别的问题在另外一篇博客中已经说得很清楚了-那些年使用IDA的事防止F5错误优化。然后开始读代码,v4位注册码长度,四个变量初始化为0,接着调用sub_10C4()。双击进入sub_10C4(),来修正一下,第一个参数是JNIEnv*, 第二个参数是jstring。修正完类型和重命名之后,可以看到有些函数识别出来了。
但是这时候看着还不是很爽,如下所示,每一个env函数都点击一遍。
结果如下,这下子看着好多了。
代码比较简单,就是将Java的String类型的字符串转为byte类型, 然后重新进行取值返回。
如果不熟悉的话可以跟进sub_12AC(),就是一个调用函数的操作。
那么现在我们可以回到最开始,这就是一个jstringtobyte的方法,修改一下返回的结果。
可以看到前两位的判断写在了if里,一个是88,一个是35。
并且还有一个条件,注册码长度是7,不满足直接返回失败。接下来第三位注册码赋值给v8,同时注册码首地址赋值给v32,也就是v32的值就是注册码数组的首地址,重命名一下,v33就当做一个临时变量好了。下面进入一个while(1)的循环,这个循环起始会执行两次,当第一次执行完的时候v9自减1,第二次在if那里就会break。下面的if其实可以缩减一下,因为异或不同为1,相同为0。
计算第三位注册码的代码如下。
第四位注册码的校验代码如下。
计算第四位注册码的代码如下。
第五位注册码的校验代码如下。
计算第五位注册码的代码如下。
接下来第六位和第七位注册码混在了一起。可以看到最后if有两个条件判断, 第一个v22参数由前面while(1)里校验第六位注册码的代码决定, 第二个v24参数由后面校验第七位注册码的代码决定。
计算第六位注册码的代码如下。
第七位注册码的校验在sub_1238里。
计算第七位注册码的代码如下。
整个代码运行的结果如下。
相关文章推荐
- 终于找到一个最适合新手的Crackme(算法分析+注册机)(转载)
- CrackMe技术等级自测3级一个CrackMe分析
- 一个通过异常处理进行验证的crackme分析
- 一个CrackMe核心代码的不完整分析
- 一个CrackMe的分析
- 一个含有crc32算法的CrackMe分析
- 一个简单的CrackMe分析
- 一个简单CrackMe分析+keyGen编写
- 一个简单的CrackMe分析
- 一个用汇编写的crackme分析,隐藏函数调用方面做的很好,很喜欢这个CM
- 新手论坛中的的一个CrackMe_0008的分析
- 一个菜单示例分析(wxPython)
- 一个Linux病毒原型分析
- 一个方向控制射击小游戏的代码分析!(AS1.0)
- 一个用汇编写的引导区病毒例程,有时间可以分析一下,对各位学习汇编的朋友很有帮助!
- 一个用C#写的词法分析程序
- WINDOWS编程入门一个初级问题的分析
- 一个简单的IAL分析(红外遥控)
- 设计一个图书借阅管理系统需要如何分析
- JPetStore项目分析——分析一个典型J2EE应用web层的实现