qq465881818 发表于 2025-1-20 15:26

初级难度的Crackme,有余力的可以逆向出算法


初级难度的Crackme,有余力的可以逆向出算法。

qq465881818 发表于 2025-1-23 10:32

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;
}

CCKmax123 发表于 2025-1-22 23:09

来分享一下破解的方法吧
首先我们使用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
就行

qq465881818 发表于 2025-1-20 21:51

通过网盘分享的文件:Crackme.rar
链接: https://pan.baidu.com/s/1TYIvdj2mmWKQR9mpHi8QxA 提取码: 52pj


不知道为什么附件无法下载,补个附件吧

爱飞的猫 发表于 2025-1-21 00:01

序列号既要等于 `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
```

dkyueya 发表于 2025-1-21 00:17

可以可以非常好感谢

Hmily 发表于 2025-1-21 10:46

qq465881818 发表于 2025-1-20 21:51
通过网盘分享的文件:Crackme.rar
链接: https://pan.baidu.com/s/1TYIvdj2mmWKQR9mpHi8QxA 提取码: 52pj
...

表丢数据了,已修复,可以下载了。

yy67283080 发表于 2025-1-21 11:54

学习了学习了

mixiaotuan666 发表于 2025-1-22 15:30

学习学习,不知道能不能成功

qq465881818 发表于 2025-1-23 07:27

CCKmax123 发表于 2025-1-22 23:09
来分享一下破解的方法吧
首先我们使用StudyPE来查看程序的基本信息



如果ida静态爆破只改cmovz就可以,但是只是输出的字符串爆破了。而没有真正爆破

wax20089 发表于 2025-1-23 10:21


感谢分享
页: [1] 2
查看完整版本: 初级难度的Crackme,有余力的可以逆向出算法