逆向入门(41)程序逆向篇-crackme
0x01 crackme
无壳
打开以后,发现挺特别
需要新建一个key.dat
有了以后就提示不对,上od
看看
这里应该是有一个爆破点,接着往上找
这里是读完以后的,下个断一步步看吧
注释挺长的,但是实际上只用了key.dat
的前三位一直运算,最后相乘运算的结果和0x2A8BF4
相等就行,但是试了下程序居然崩了,接着再往下看
这里有个call esi
,而刚刚好esi
的地址就是刚刚转换后key
的首地址,看来得让这个地方能够正常call
,还得继续往上再看一段代码了
但是上面的代码好像不影响esi
,这里把他改成常规的函数头试试
push ebp ; 0x55
mov ebp,esp ; 0x8b 0xec
经验证确实为0x2a8bf4
写出注册机
int main() {char str1[256] = { 0 };str1[0] = 0x55 ^ 3 ^ 0x54 ^ 0x1e ^ 0;str1[1] = 0x8b ^ 3 ^ 0x4d ^ 0xbf ^ 0;str1[2] = 0xec ^ 3 ^ 0x47 ^ 0xa2 ^ 0;printf("%x,%x,%x,%x", str1[0], str1[1], str1[2]);return 0;
}
将结果写入到16
进制的key.dat
中,发现程序闪退
原因发现这里进入了死循环,这里是将算好的前三位放入到新的内存地址中,一直碰到0x20
才会停止,所以在刚刚的代码基础之上还得再加一个字符作为终止符,这位就是第4
位,处理经过以下流程
用这一部分 计算好的key1
去和key4
异或最后的结果是0x20
int main() {char str1[256] = { 0 };str1[0] = 0x55 ^ 0x1e ^ 0x54^ 4 ;str1[1] = 0x8b ^ 0xbf ^ 0x4d^ 4 ;str1[2] = 0xec ^ 0xa2 ^ 0x47^ 4 ;char tmp_str0 = str1[0] ^ 0x54 ^ 4;str1[3] = 0x20 ^ tmp_str0 ^ 4;printf("%x,%x,%x,%x", str1[0], str1[1], str1[2], str1[3]);return 0;
}
可以了
但是这里用户名还没有显示名出来,用户应该应该是移动到了这一部分放着了
所以,最后的注册机可以写成带有用户名的
#include <iostream>
#include <string>int main() {std::string username;printf("用户名: ");std::getline(std::cin, username);int nameLen = username.length();int totalLen = nameLen + 4;char str1[256] = { 0 };str1[0] = 0x55 ^ 0x1e ^ 0x54^ totalLen;str1[1] = 0x8b ^ 0xbf ^ 0x4d^ totalLen;str1[2] = 0xec ^ 0xa2 ^ 0x47^ totalLen;char tmp_str0 = str1[0] ^ 0x54 ^ totalLen;str1[3] = 0x20 ^ tmp_str0 ^ totalLen;printf("%02x %02x %02x %02x", str1[0], str1[1], str1[2], str1[3]);for (int i = 0; i < nameLen; i+=3){username[i] ^= str1[i + 1] ^ 0x4d; //因为第4位是个空白的,所以整体后移了一位username[i+1] ^= str1[i + 2] ^ 0x47;username[i+2] ^= str1[i] ^ 0x5d;}for (int i = 0; i < nameLen; i++){printf(" %02x", username[i]);}return 0;
}
但是结果仍然有点问题
排查原因发现是因为在下列代码异或的时候,即使长度不够也会继续异或得到值,总是要取被3
字节整的数才可以
同时调整了了一下字符输出的方式,并直接生成key.dat
文件
#include <iostream>
#include <fstream> int main() {char username[255] = {0};printf("用户名: ");std::cin.getline(username, 255);int nameLen = strlen(username);int totalLen = nameLen + 4 ;int realLen = totalLen % 3 == 0 ? totalLen : (totalLen + 3 - (totalLen % 3));char str1[256] = { 0 };str1[0] = 0x55 ^ 0x1e ^ 0x54^ realLen;str1[1] = 0x8b ^ 0xbf ^ 0x4d^ realLen;str1[2] = 0xec ^ 0xa2 ^ 0x47^ realLen;char tmp_str0 = str1[0] ^ 0x54 ^ realLen;str1[3] = 0x20 ^ tmp_str0 ^ realLen;for (int i = 0; i < realLen - 4; i+=3){str1[i + 4] = username[i] ^ str1[1] ^ realLen ^ 0x4d ^ realLen; //因为第4位是个空白的,所以整体后移了一位str1[i + 5] = username[i+1] ^ str1[2] ^ realLen ^ 0x47 ^ realLen;str1[i + 6] = username[i+2] ^ str1[0] ^ realLen ^ 0x54 ^ realLen;}for (int i = 0; i < realLen; i++){printf("%02x ", str1[i]);}// 写入到 key.dat 文件std::ofstream keyFile("key.dat", std::ios::binary);if (keyFile.is_open()) {keyFile.write(str1, realLen);keyFile.close();std::cout << "已写入 key.dat 文件" << std::endl;}else {std::cerr << "无法创建 key.dat 文件" << std::endl;}return 0;
}
最后运行结果完美,终于搞定了,断断续续看了5
天才写完