初级难度的Crackme,有余力的可以逆向出算法
初级难度的Crackme,有余力的可以逆向出算法。 CrackMe 源码公布
#include <iostream>
#include <string>
#include <windows.h>
#include <ctime>
#include <vector>
#include <algorithm>
#include <intrin.h>
// 检测是否运行在VMware中
bool isRunningInVM() {
// 使用CPUID指令检测VMware
int cpuInfo = { 0 };
__cpuid(cpuInfo, 0x40000000); // VMware的CPUID叶子号
// VMware的CPUID返回值特征
const char* vmwareSignature = "VMwareVMware";
if (memcmp(cpuInfo + 1, vmwareSignature, 12) == 0) {
return true;
}
return false;
}
// 动态生成密钥
std::string generateKey(int seed) {
srand(seed);
std::string key;
for (int i = 0; i < 16; ++i) {
key += (char)(rand() % 26 + 'A'); // 生成随机大写字母
}
return key;
}
// 多层加密函数
std::string encrypt(const std::string& input, const std::string& key) {
std::string output = input;
for (size_t i = 0; i < output.size(); ++i) {
output = output ^ key; // 使用密钥进行异或加密
}
return output;
}
// 反调试函数
void antiDebug() {
if (IsDebuggerPresent()) {
std::cout << "Debugger detected! Exiting..." << std::endl;
ExitProcess(1);
}
}
// 动态代码生成
void generateAndExecuteCode() {
std::vector<unsigned char> code = {
0xB8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1
0xC3 // ret
};
// 分配可执行内存
void* execMem = VirtualAlloc(nullptr, code.size(), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (execMem == nullptr) {
std::cerr << "Failed to allocate executable memory!" << std::endl;
return;
}
// 复制代码到可执行内存
memcpy(execMem, code.data(), code.size());
// 执行生成的代码
int(*func)() = (int(*)())execMem;
int result = func();
// 释放内存
VirtualFree(execMem, 0, MEM_RELEASE);
if (result != 1) {
std::cout << "Dynamic code execution failed! Exiting..." << std::endl;
ExitProcess(1);
}
}
// 多阶段验证
bool multiStageValidation(const std::string& serial) {
// 第一阶段验证
std::string key1 = generateKey(0xDEADBEEF);
std::string validSerial1 = encrypt("correct_serial", key1);
std::string encryptedInput1 = encrypt(serial, key1);
if (encryptedInput1 != validSerial1) {
return false;
}
// 第二阶段验证
std::string key2 = generateKey(0xCAFEBABE);
std::string validSerial2 = encrypt("another_serial", key2);
std::string encryptedInput2 = encrypt(serial, key2);
if (encryptedInput2 != validSerial2) {
return false;
}
return true;
}
// 反内存转储
void antiMemoryDump() {
// 使用随机填充内存,防止内存转储
std::vector<char> buffer(1024 * 1024); // 1MB
std::generate(buffer.begin(), buffer.end(), []() { return rand() % 256; });
}
int main() {
// 反调试
antiDebug();
// 自校验
// selfCheck();
// 动态代码生成
generateAndExecuteCode();
// 反内存转储
antiMemoryDump();
// 提示用户输入序列号
std::string serial;
std::cout << "Enter serial key: ";
std::cin >> serial;
// 多阶段验证
// 使用条件运算符替代 if-else
std::cout << (multiStageValidation(serial)
? "Congratulations! You have entered the correct serial key."
: "Invalid serial key. Try again.")
<< std::endl;
system("pause");
return 0;
} 来分享一下破解的方法吧
首先我们使用StudyPE来查看程序的基本信息
发现没有加壳,然后先运行,查看输入错误时的输出
Enter serial key: 1
Invalid serial key. Try again.
提取关键字符串"Invalid serial key. Try again."
打开ida通过字符串,我们可以定位到主要函数:
当然我们往上翻一翻就可以发现存在反调试检测
这里需要留意一下
查看验证部分就可以得到主要验证代码:
.text:0000000140001B1A lea rdx, aEnterSerialKey ; "Enter serial key: "
.text:0000000140001B21 mov rcx, cs:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::ostream std::cout
.text:0000000140001B28 call sub_140001DC0
.text:0000000140001B2D lea rdx,
.text:0000000140001B32 mov rcx, cs:?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A ; std::istream std::cin
.text:0000000140001B39 call sub_140001FE0
.text:0000000140001B3E lea rcx,
.text:0000000140001B43 call yanzheng
.text:0000000140001B48 lea rcx, aCongratulation ; "Congratulations! You have entered the c"...
.text:0000000140001B4F lea rdx, aInvalidSerialK ; "Invalid serial key. Try again."
.text:0000000140001B56 test al, al
.text:0000000140001B58 cmovnzrdx, rcx
.text:0000000140001B5C mov rcx, cs:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::ostream std::cout
.text:0000000140001B63 call sub_140001DC0
.text:0000000140001B68 mov rcx, rax
其中:
.text:0000000140001B56 test al, al
.text:0000000140001B58 cmovnzrdx, rcx
是我们需要特殊关注的,
我们直接把cmovnz改成mov即可成功破解该程序,(同时把test al,al)nop掉,
好的到此我们就破解完毕了,如果你没有反反调试的插件可以自己手过一下反调试把
jz short loc_140001A77
直接改成
jmp short loc_140001A77
就行 通过网盘分享的文件:Crackme.rar
链接: https://pan.baidu.com/s/1TYIvdj2mmWKQR9mpHi8QxA 提取码: 52pj
不知道为什么附件无法下载,补个附件吧 序列号既要等于 `correct_serial` 还要等于 `another_serial`?
```cpp
bool check_serial_140001640(const std::string& serial) {
std::string rand_dat = GenerateRand_140001290(0xDEADBEEF);
std::string serial_xor_rand = XorString_140001340(serial, rand_dat);
std::string check = XorString_140001340(std::string("correct_serial"), rand_dat);
if (serial_xor_rand == check) {
rand_dat = GenerateRand_140001290(0xCAFEBABE);
serial_xor_rand = XorString_140001340(serial, rand_dat);
check = XorString_140001340(std::string("another_serial"), rand_dat);
return check == serial_xor_rand;
}
return false;
}
```
直接爆破算了
```
crackme.exe+1640:
mov eax, 1
ret
``` 可以可以非常好感谢 qq465881818 发表于 2025-1-20 21:51
通过网盘分享的文件:Crackme.rar
链接: https://pan.baidu.com/s/1TYIvdj2mmWKQR9mpHi8QxA 提取码: 52pj
...
表丢数据了,已修复,可以下载了。 学习了学习了 学习学习,不知道能不能成功 CCKmax123 发表于 2025-1-22 23:09
来分享一下破解的方法吧
首先我们使用StudyPE来查看程序的基本信息
如果ida静态爆破只改cmovz就可以,但是只是输出的字符串爆破了。而没有真正爆破
感谢分享
页:
[1]
2