新手破解练习Crackme160之160 - Torn@do.3
-
脱壳
PEiD查看可知有ASPack1.08.02的壳, 需要先脱壳, xp下使用PEiD通用脱壳插件脱壳成功~ 或使用ASPack UnPacker脱壳(也需要xp下才会成功), 后者脱壳完文件较小, 手动ESP定律脱壳也是可以的(OD载入程序后, 5次F8来到pushad下一行, 右侧ESP变红, 即可添加硬件断点了) -
正常破解
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");
}
}
1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号