逆向入门(43)程序逆向篇-tsrh-crackme
没壳
不过需要先去个NAG
想着先进调试器吧,结果一进调试器就退出了,F8
追了下
这里改一下jne
,就变成了和直接运行一样的效果,先有NAG
然后再正常启动
查了一个getlasterror
,看来是不允许多开了
接下来找nag
,直接f9
运行到弹窗的时候,这个时候搜索字符串
有大量地方调用了403000
这个内存地址,并且字符串显示的就是nag
,接下来给这个内存地址下硬段,重新加载一下,再运行就断下来了
一直运行到ret
以后跟下去
就定位到这里了,这里有个je
判断跳一个MeseageBoxA
,直接改了下eax
的值,尝试一下
最终是正常绕过了,先patch
一个
这样就搞定了去NAG
,再接着找
看一手字符串
找到了对应位置
下个断,追一下,发现序列号前四个字节必须为tsrh
再往后追就看到了这么一段,
这个函数其实做了一堆操作,看着不是很复杂,现在就是不想看了。往IDA
里面丢吧
定位了这样一段,发现在前面还少分析了一个sub_4011f3
函数
做了一个格式化,a1
是eax
,从OD
看了下,就是用户名的长度
所以这一串最后得到了一个
String
是tsrh-2008-
字符串,前四个字符已经分析过了,接下来分析第二个条件
这一段也有点奇怪,伪代码显示没有参数,但是上一段又传了相加以后值进去,突然又多了个奇怪的v5
出来
不过函数作用还是好理解的,也可以写出这一段的代码出来
int len = strlen(username);// 1. 初始化序列号sprintf(serial, "tsrh-%d-", len + 2003);int current_length = strlen(serial);// 2. 处理用户名中的每个字符for (int i = 0; i < len; i++) {unsigned char c = username[i];unsigned char v4 = c + 12;int value = (2 * (int)v4 - 17 - current_length) ^ (int)v4;// 将值格式化为大写十六进制并追加char hex[9];sprintf(hex, "%X", value);strcat(serial, hex);current_length += strlen(hex);}int total_length = current_length;
运算结果相同
再接着往下看
这里的伪代码有点坑,对应的汇编在这
其实在第一次赋值以后,后面的内容都被截断了,所以40129C
处的edx
只有第一次是正常读到了值,后面读到的数值都是0
,注意这里的0
不是数字0
,如果是数字0
则会显示为48
的,最后注册机显示如下:
#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <string.h>
#include <ctype.h>void generate_serial(const char* username, char* serial) {int len = strlen(username);// 1. 初始化序列号sprintf(serial, "tsrh-%d-", len + 2003);int current_length = strlen(serial);// 2. 处理用户名中的每个字符for (int i = 0; i < len; i++) {unsigned char c = username[i];unsigned char v4 = c + 12;int value = (2 * (int)v4 - 17 - current_length) ^ (int)v4;// 将值格式化为大写十六进制并追加char hex[9];sprintf(hex, "%X", value);strcat(serial, hex);current_length += strlen(hex);}int esi = 1;bool first = true;int edx = 0;// 3. 调整序列号的特定位置(关键修正)while(true){printf("esi: %d\t", esi);if (!username[esi -1]) break;int eax = username[esi - 1] + 1;if (first) {edx = serial[esi + 0xB];first = false;}else {edx = NULL;}printf("edx:%d\t", edx);eax = eax ^ edx;while (eax < 0x41) eax += 0x8;while (eax > 90) eax -= 0x3;esi += 0x9;serial[esi] = eax;serial[esi + 1] = NULL;printf("%s,%d\n", serial, serial[esi + 1]);esi -= 0x8;if (esi == 0x10) break;}}int main() {char username[256];char serial[256];printf("用户名注册机 (长度>=5)\n");while (1) {printf("\n请输入用户名 (输入quit退出): ");fgets(username, sizeof(username), stdin);// 移除换行符username[strcspn(username, "\n")] = 0;if (strcmp(username, "quit") == 0) {break;}int len = strlen(username);if (len < 5) {printf("错误: 用户名长度必须至少5个字符\n");continue;}// 生成序列号generate_serial(username, serial);printf("生成的序列号: %s\n", serial);}return 0;
}
写是写得粗糙一点啦,其实还可以再优化,不过这样就够了
搞定,现在做一个题时间花得真久啊,利用好ida
加快速度