014-Splish 的 write up
1 . 程序的执行
程序执行的时候依旧会有一个烦人的Nag弹窗如下图:
有两种验证方式,第一种是Hard Coded模式,如下图:
第二种方式是name/serial模,如下图:
以上都是错误提示。
还有一些文件相关信息如下图:
2. 查壳
程序无壳
3. 分析
- 首先我们要来破解这个烦人的Nag弹窗,将程序拖入OD打开,按F9运行到程序的入口点00401000,然后F8单步执行到00401079这位置又一个函数调用call
执行这个函数call后Nag弹窗就出现了,所以这个函数就是Nag弹窗的调用函数,我们可以直接NOP掉这个函数,也可以F9进入这个函数主体,在头部第一行retn,也就是这个函数刚执行就返了什么也没做。最后右键——>复制到可执行文件——>选择,弹出一个新的页面后,继续右键——>保存文件。
- 分析第一种验证方式,Hard Coded模式,OD中智能搜索字符串如下图:
然后双击跟踪标黄的字符串,来到函数主体在0040135D下断点,然后让程序执行到这里,GetWindowsTextA是获取用户输入的内容储存到的地址为00403215,其中地址00401653保存的是硬编码字符串HardCoded,注释如下图:
所以第一种验证方式的硬编码序列号就是HardCoded
- 分析第二种验证方式,name/serial模式,搜索字符串后跟踪最后一个错误提示字符串,来到函数体往上看,然后在004015E4下断点,让程序执行到这,可以根据获取用户输入的API函数GetWindowTextA知道,00403242保存的是获取到的serial,00401693储存的是获取到的name。函数的返回值都是字符串的长度,具体过程如下图:
4. 注册机的编写
1.算法的分析:
首先name和serial的长度必须一致;
name通过一段处理:依次取name的每个字符,然后除以0xA后得的余数再和初始为0的充当循环计数器的ebx异或,然后再加2,再和0xA对比,如果大于等于0xA则要先减去0xA然后将得到得结果保存,如果小于则跳转结果直接保存,每次结果的保存都是将这一次的结果保存到上一次保存结果的后一个字节。
serial经过一段处理:依次取serial的每一字符,然后除以0xA后得到的余数直接保存,每次结果的保存都是将这一次的结果保存到上一次保存结果的后一个字节。
最后的对比算法就是讲name和serial的处理后的结果进行依次取单个字节的对比,如果都一样则顺序执行提示成功,反之则会在不一样得地方跳转提示错误。
2.注册机的编写思路
其实就是讲name进行算法复现之后,再将得到的结果进行serial逆向复现,得到的字符串就是注册码。
3.源代码如下:
#include<stdio.h> #include<string.h> void generatekey(static char name[], int length); void dispose(); int main() { dispose(); system("pause"); return 0; } void dispose() { char name[50] = { 0 }; int length = 0; char* p; p = &name; printf("please input you name:"); scanf("%s", name); length = strlen(name); for (int i = 0; i < length; i++) { int n = 0; n = ((name[i] % 0xA) ^ i)+2; if (n >= 0xA) { *(p+i) = n - 0xA; } else { *(p + i) = n; } } generatekey(p,length); return 0; } void generatekey(char *p,int length) { char serial[50] = { 0 }; char* b; b = &serial; for (int i = 0; i < length; i++) { *(b+i) = *(p+i) + 3*0xA; //由于注册码必须是字符类型所以0xA要乘以3 } printf("you serial is:%s\n",b); return 0; }
4.运行结果如图所示: