新手破解练习Crackme160之160 - Torn@do.3

  1. 脱壳
    PEiD查看可知有ASPack1.08.02的壳, 需要先脱壳, xp下使用PEiD通用脱壳插件脱壳成功~ 或使用ASPack UnPacker脱壳(也需要xp下才会成功), 后者脱壳完文件较小, 手动ESP定律脱壳也是可以的(OD载入程序后, 5次F8来到pushad下一行, 右侧ESP变红, 即可添加硬件断点了)

  2. 正常破解
    OD重新载入脱壳后程序, 搜索界面可以发现有3个字符串, 3个.key文件, 和1个注册表相关, 没有成功失败关键词, 从文件名CrAcKmE.KEY可定位到004015A5, 向上找到方法开头, 再向上找到调用00401BB0, 看到一堆的call, 大概可以判断这里就是关键位置了~ 在入口00401B90处下断点~
    F9运行程序, 在断点处停下~ 经分析可知00401B92~00401BE2都是无用的, 下面开始就有一堆的je命令, 而且都是跳到相同的地方, 所以00401D18处肯定就是失败的分支了~
    00401BEC处判断是否存在文件"REGISTRATION.DAT"
    00401BFE处判断此文件长度是否为1024
    00401C22处验证文件0~9位为: 06 0A 15 07 13 10 0A 72 0C 00
    00401C34处验证10~16位为: 07 20 34 3E 09 07 0A
    00401C46处验证17~20位为: 08 00 00 05
    00401C58处验证21~37位为: 08 04 00 12 0A 12 03 12 02 2C 43 08 02 2A 0A 44 54
    00401C6A处验证80~83位转为年份[80]100+[81] >=1999, [82]100+83>=本年
    00401C7C处验证84位为时<=0x17, 85位为分<=0x3B
    00401C8E处验证208~296位为: "SUPPORT THE SOFTWARE AUTHORS BY BUYING THE PROGRAMS IF YOU USE THEM AFTER CRACKING THEM!"
    00401CAA处验证0~99的和(sum ^ 1999) / 10 = [944位] < 128
    00401CAA处验证[945]
    00401CC6处验证[946]
    00401CD4处验证[947]
    00401CE2处验证[948]
    00401CF0处验证[949]
    00401CFE处验证[1023]='R'

下面是solly大佬的注册机代码:

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <windows.h>
 
int checkValue1 = 0;  /// 0x0040D1A8
int checkValue2 = 0;  /// 0x0040D1AC
int checkValue3 = 0;  /// 0x0040D1B0
int checkValue4 = 0;  /// 0x0040D1B4
int checkValue5 = 0;  /// 0x0040D1B8
 
int checkCode1 = 0;  /// 0x0040EA94
int checkCode2 = 0;  /// 0X0040EABC
 
char ProductID[256];  /// 操作系统ID,Windows9x系列才有,Windows7以后无此注册表键值
 
char regFile[1024];
 
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
 
BOOL IsWow64();
int makeRegistryFile();
int getProductID(char * defaultID);
int makeRegInfo();
int saveRegInfo();
 
int main(int argc, char** argv) {
         
        memset(ProductID, 0, 256);
        memset(regFile, 0, 1024);
 
/**
Windows 32位系统
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion]
"ProductID"="12345-12345678-1234-5678"
 
Windows 64位系统
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion]
"ProductID"="12345-12345678-1234-5678"
**/
        char productID[] = "12345-12345678-1234-5678"; /// 注册表键值
        getProductID(productID);
         
        makeRegInfo();
        saveRegInfo();
         
        return 0;
}
 
int getProductID(char * defaultID) {
        /// "12345-12345678-1234-5678" ===> "6789:26789:;<=267892:;<="
         
        char key[]  = "ProductId";
        char subKey[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
        HKEY h  = HKEY_LOCAL_MACHINE;  /// 0x80000002
        HKEY hKey = (HKEY)0xFFFFFFFF;
        DWORD keyType, cbData = 0, n = 0;
        DWORD s = RegOpenKeyExA(h, subKey, 0, KEY_READ, &hKey);
        if(s == ERROR_SUCCESS) {
                s = RegQueryValueExA(hKey, key, NULL, NULL, NULL, &cbData); /// 返回缓冲区大小
                if(s == ERROR_SUCCESS) {
                        if(cbData>255) {
                                cbData = 255; //// 防止溢出
                        }
                        n = cbData;
                        s = RegQueryValueExA(hKey, key, NULL, &keyType, (LPBYTE)ProductID, &cbData);
                }       
        }
        RegCloseKey(hKey);
        if(n<=0) {
                strcpy(ProductID, defaultID);
                printf("ERROR: ProductID is NOT EXISTS in Registry.\n");
                makeRegistryFile();  //// 生成注册表文件
        }
         
        return 0;
}
 
int makeRegistryFile() {
        char registry_x86[] = "Windows Registry Editor Version 5.00\n\n[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion]\n\"ProductID\"=\"12345-12345678-1234-5678\"\n";
        char registry_x64[] = "Windows Registry Editor Version 5.00\n\n[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion]\n\"ProductID\"=\"12345-12345678-1234-5678\"\n";
        char * reg = NULL;
        if(IsWow64()) {
                reg = registry_x64; //// 64位系统
        } else {
                reg = registry_x86; //// 32位系统
        }
        FILE * f = fopen("ProductID.reg", "w");
        int n = fwrite(reg, strlen(reg), 1, f);
        fflush(f);
        fclose(f);
         
        if(n==1) {
                printf("Make registry file successed, please import registry file: ProductID.reg\n");
        }
         
        return 0;
}
 
BOOL IsWow64() {
        BOOL bIsWow64 = FALSE;
        //IsWow64Process is not available on all supported versions of Windows.
        //Use GetModuleHandle to get a handle to the DLL that contains the function
        //and GetProcAddress to get a pointer to the function if available.
        fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
        if(NULL != fnIsWow64Process)
        {
                if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
                {
                        //handle error
                        printf("get os bit error\n"); /// 出错了
                }
        }
        return bIsWow64;
}
 
int makeRegInfo() {
/// call    00401A30     ; 判断注册文件内容 file_content[153] 开始的null结尾的字符串长度大于3字节, 小于 31 字节
/// 字符串内容不限,只要长度大于3字节, 小于 31 字节即可。
    char * p1 = & regFile[153];
    strcpy(p1, "[Cracked by solly, 2019-07-11.]"); /// 注意:长度不能大于31个字符,否则会栈缓冲溢出,覆盖函数返回地址。
 
/// call    00401E90     ; 判断 注册文件 前10字节必须为 06 0A 15 07 13 10 0A 72 0C 00
    regFile[0] = 0x06;
    regFile[1] = 0x0A;
    regFile[2] = 0x15;
    regFile[3] = 0x07;
    regFile[4] = 0x13;
    regFile[5] = 0x10;
    regFile[6] = 0x0A;
    regFile[7] = 0x72;
    regFile[8] = 0x0C;
    regFile[9] = 0x00;
 
/// call    00401F80     ; 注册文件第11~17字节判断,必须等于串:07 20 34 3E 09 07 0A
    regFile[10] = 0x07;
    regFile[11] = 0x20;
    regFile[12] = 0x34;
    regFile[13] = 0x3E;
    regFile[14] = 0x09;
    regFile[15] = 0x07;
    regFile[16] = 0x0A;
 
/// call    00402130     ; 注册文件第18~21字节判断,必须等于串:08 00 00 05
    regFile[17] = 0x08;
    regFile[18] = 0x00;
    regFile[19] = 0x00;
    regFile[20] = 0x05;
 
/// call    00402260     ; 注册文件第22~38字节判断:08 04 00 12 0A 12 03 12 02 2C 43 08 02 2A 0A 44 54
    regFile[21] = 0x08;
    regFile[22] = 0x04;
    regFile[23] = 0x00;
    regFile[24] = 0x12;
    regFile[25] = 0x0A;
    regFile[26] = 0x12;
    regFile[27] = 0x03;
    regFile[28] = 0x12;
    regFile[29] = 0x02;
    regFile[30] = 0x2C;
    regFile[31] = 0x43;
    regFile[32] = 0x08;
    regFile[33] = 0x02;
    regFile[34] = 0x2A;
    regFile[35] = 0x0A;
    regFile[36] = 0x44;
    regFile[37] = 0x54;
 
/// call    004025B0     ; 注册文件第81~84字节处理,转换成时间的年份(file_content[82]*100 + file_content[83])),大于或等于 1999,
/// 实际上 (file_content[82]*100 + file_content[83]) > 2019(系统当前年份) 才可以。
/// 以下填充的是 9999-12-31
    regFile[80] = 0x1F;  // 31   /// 日
    regFile[81] = 0x0C;  // 12   /// 月
    regFile[82] = 0x63;  // 99   /// 年
    regFile[83] = 0x63;  // 99   /// 年
 
/// call    00402790     ; 检查 file_content[84] <= 0x17, file_content[85] <= 0x3B
    regFile[84] = 0x17;  // 23   /// 时
    regFile[85] = 0x3B;  // 59   /// 分
    //regFile[86] = 0x3B;  // 59   /// 秒,可不填充,没有用到
    regFile[86] = 0x1E;  // 30   /// 秒,不能填充 0x3B,因为刚好会导致后面的检查码为 0x1A,引起 fread()函数出错,读取文件不完整
 
/// call    004028A0     ; file_content[208]~file_content[296] 为固定字符串:
/// "SUPPORT THE SOFTWARE AUTHORS BY BUYING THE PROGRAMS IF YOU USE THEM AFTER CRACKING THEM!"
    char * p2 = & regFile[208];
    strcpy(p2, "SUPPORT THE SOFTWARE AUTHORS BY BUYING THE PROGRAMS IF YOU USE THEM AFTER CRACKING THEM!");
 
/// call    004029A0     ; file_content[336] 开始为 ProductID 的加密字符串
    int n = strlen(ProductID); /// 注册表中的产品ID(明文)
    for(int i=0; i<n; i++) {
            regFile[336 + i] = ProductID[i] + 5;  /// 保存密文,加密就是 ASCII 码 + 0x05
        }
         
/// call    00402AC0     ; 注册文件前100字节校验和检查,
/// 并且 ((checkSum xor 1999)/10) 小于 128,等于 file_content[944] 的值
        int sum1 = 0;
        for(int i=0; i<100; i++) {    //// 0x64
                sum1 += (int)regFile[i];
        }
        int check1 = checkCode1 * checkCode1;
        int check2 = (checkCode2 >= 10) ? checkCode2 : 10;
        sum1 = ((sum1 ^ 1999) | check1) / check2;
         
        int j = 0x30;
        while(sum1 > 127) {
                sum1 -= 127;
                regFile[j++] = -127; //// 校正校验值 < 128
        }
         
 
        checkValue1 = sum1;
        regFile[944] = sum1;       
         
/// call    00402BE0     ; 同上一函数,并加上验证 file_content[945] 的值
    int sum2 = sum1 * sum1 / 0x54;
        checkValue2 = sum2;
        regFile[945] = sum2;       
     
/// call    00402D10     ; 功能同上一函数,校验和与file_content[946]比较
    int sum3 = 0;
    for(int i=0; i<384; i++) {   /// 0x180
            sum3 += (int)regFile[i];
        }
//        int k = 0x130;
//        while(sum3 > 127) {
//                sum3 -= 127;
//                regFile[k++] = -127; //// 校正校验值 < 128
//        }
        sum3 = (sum3 ^ (sum2 * sum1)) / 534; /// 0x216;
     
        checkValue3 = sum3;
        regFile[946] = sum3;       
     
///  call    00402E60     ; 对前面3个校验和进行校验,校验结果等于 file_content[947] 的值
    int sum4 = (checkValue1 + checkValue2 + checkValue3);
        sum4 *= (checkValue3 / checkValue2);
        sum4 *= (checkValue1 / checkValue2);
        sum4 /= 10;
         
        checkValue4 = sum4;
        regFile[947] = sum4;
 
/// call    00402F70      ; 注册文件前384字节校验和检查,校验结果等于 file_content[948] 的值
    int sum5 = 0;
    for (int i=0; i<384; i++)  {   /// 0x180
            sum5 += (int)regFile[i];
        }
        sum5 = (sum5 ^ 0xFF) / 500;  /// 0x01F4
 
        checkValue5 = sum5;
        regFile[948] = sum5;
 
/// call    00403080     ; 对前5次校验结果的和进行校验,
/// file_content[949] == sqrt(sum(checkSum1+checkSum2+checkSum3+checkSum4+checkSum5))
    int sum6 = checkValue1 + checkValue2 + checkValue3 + checkValue4 + checkValue5;
    sum6 = (int)sqrt(sum6);
     
    regFile[949] = sum6;
 
/// call    00403190      ; 检查注册文件的最后一个字符 file_content[1023] 为 'R', 即 0x52
    regFile[1023] = 'R';   /// 0x52
}
 
int saveRegInfo() {
        FILE * f = fopen("REGISTRATION.DAT", "wb");
        size_t n = fwrite(regFile, 1024, 1, f);
        fflush(f);
        fclose(f);
        if(n == 1) {
                printf("save registration data file successed! \ncopy \"REGISTRATION.DAT\" to directory of CrackMe.\n");
        } else {
                printf("save registration data file failured!\n");
        }
}

 
 
 
这是160个软件part1
这是160个软件part2

1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-08-27 17:34  hankerstudio  阅读(32)  评论(0)    收藏  举报