新手破解练习Crackme160之159 - Torn@do.2
-
脱壳
这个程序有壳, 需要先脱壳, ESP定律手动脱壳~ OD载入程序, F8运行一次, 来到第二行, 此时ESP值变红, 右键这个红值, 选择"HW break [ESP]"下好硬件断点, F9运行19次来到00401F096 jmp eax这里(中间也都是到这里), F8进入程序区域00403560, 删除硬件断点(菜单->调试->硬件断点), 00403560这行右键使用OllyDump, 此时用OllyDump的方式2脱壳成功~ -
正常破解
OD重新载入脱壳后程序, 搜索界面找到成功关键词定位到0040148D处, 由此可向上找按钮事件入口004021D5处, 可下断点, 接着便一步步向下跟踪对应算法~
1). 00401D02处可得算法:
s[0] ^ 0x54 = 0x1D
s[1] ^ 0x49 = 0xD
s[2] ^ 0x44 = 0x7
s[3] ^ 0x39 = 0xD
s[4] ^ 0x39 = 0x9
反向运算得系列号0~4位为: IDC40
2). 00401D36处可得算法:
s[6] ^ 0x54 = 0x11
s[7] ^ 0x52 = 0x6
s[8] ^ 0x45 = 0x7
s[9] ^ 0x53 = 0x1F
反向运算得系列号6~9位为: ETBL
3). 00401D52处可得算法:
取当前时间=>month * day + hour * minute - 0x20 + year = time2
计算结果与系列号的后4位进行对比(也就是后4位即为这个时间值)
4). 00401D80处获取注册时间 这个需要读取注册表, 值为time1
5). 00401DA8处用户名与公司名的验证
sum = 用户名循环每一位*2601之和 + 公司名循环每一位之和
sum1 = ((sum * 11) ^2 + CheckRegOwner[0]) * 111998
code = (long) (sum1 - sin(sum1) * 1999)
所以最终的系列号为: IDC40-ETBL-code-time1-time2 (中间的-号可以任意)
由于系列号跟时间有关系的, 所以生成了系列号后需要快速注册~
上面需要是分析完了, 注册时间部分由于需要注册表操作, 放弃了, 所以没有实际注册成功过~
下面是solly大佬的注册机代码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <windows.h>
union CBData{
DWORD n;
byte buffer[256];
};
CBData readKey(HKEY hKey, char * path, char * key);
void getRegInfo();
void getPart1();
void getPart2();
long getRegTimeStamp(int index);
long getCheckRegOwner();
long getCheck(char * name, char * company, int index);
void getCurrDateTime(int index);
bool testSoftICE95();
bool testSoftICENT();
char sn[48];
CBData data;
long nFirstInstallDateTime = 0;
long nLenOfFirstInstallDateTime = 0;
char sFirstInstallDateTime[128];
char RegisteredOwner[128];
char RegisteredOrganization[128];
char ProductId[128];
int main(int argc, char** argv) {
memset(sn, 0, 48);
memset(sFirstInstallDateTime, 0, 128);
memset(RegisteredOwner, 0, 128);
memset(RegisteredOrganization, 0, 128);
memset(ProductId, 0, 128);
getRegInfo();
getPart1();
sn[5] = '-';
getPart2();
sn[10] = '-';
char name[] = "solly88";
char company[] = "ite company";
int n = getCheck(name, company, 11);
sn[10+n+1] = '-';
int m = getRegTimeStamp(10+n+2);
sn[10+n+2+m] = '-';
/// 最后4字节为当前时间检查
getCurrDateTime(10+n+3+m);
printf("\n SN = %s\n", sn);
system("pause");
return 0;
}
void getPart1() {
sn[1] = 0x0D ^ 0x49;
sn[2] = 0x07 ^ 0x44;
sn[3] = 0x0D ^ 0x39;
sn[0] = 0x1D ^ 0x54;
sn[4] = 0x09 ^ 0x39;
}
void getPart2() {
sn[7] = 0x06 ^ 0x52;
sn[8] = 0x07 ^ 0x45;
sn[9] = 0x1F ^ 0x53;
sn[6] = 0x11 ^ 0x54;
}
/**
***/
/// FirstInstallTime
long getRegTimeStamp(int index) {
/// 0040BF90: 1702516
//long a = 1702505;
////
//long FirstInstallDateTime = 1702516; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win10
//long FirstInstallDateTime = 6617404; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98
//long FirstInstallDateTime = 6682940; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98_unpacked
long FirstInstallDateTime = nFirstInstallDateTime; /// 正常时是一个 Timestamp
long a = FirstInstallDateTime - tanh(FirstInstallDateTime) * 11.0; /// 当在win10下取的是地址时,这里是固定值 1702505
//char str_a[8];
sprintf(sFirstInstallDateTime, "%d", a);
long n = strlen(sFirstInstallDateTime);
for(int i=0; i<n; i++ ) {
sn[index + i] = sFirstInstallDateTime[i];
}
return n;
}
long getCheckRegOwner() { // Proc_00401590 和 Proc_00401540
long sum1 = 0;
long sum2 = 0;
long n = strlen(RegisteredOwner);
for(int i=1; i<n; i++) {
sum1 += i*2;
sum2 += RegisteredOwner[i-1];
}
//printf("check reg owner: %d - %d\n", sum1, sum2);
return sum1 ^ sum2;
}
long getCheck(char * name, char * company, int index) { /// Proc_004015E0
long checkbase = getCheckRegOwner();
long sum = 0;
int n = strlen(name);
for(int i=0; i<n-1; i++) {
sum += name[i] * 2601;
}
int m = strlen(company);
for(int i=0; i<m-1; i++) {
sum += company[i];
}
double x = sum * 11;
int code1 = (long)sqrt(x);
////
//printf("check code1: %d, %d\n", sum, code1);
long a = code1 + checkbase;
long c = a * 111998;
double y = c - sin(c) * 1999.0;
long code2 = (long)y;
//printf("check code2: %d\n", code2);
char code_str[12];
sprintf(code_str, "%d", code2);
int len = strlen(code_str);
for(int i=0; i<len; i++) {
sn[index+i] = code_str[i];
}
return len;
}
bool testSoftICE95() {
HANDLE h = CreateFile("\\\\.\\SICE",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
return true;
}
return false;
}
bool testSoftICENT() {
HANDLE h = CreateFile("\\\\.\\NTICE",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
return true;
}
return false;
}
/// Current date and time
void getCurrDateTime(int index) {
long a = RegisteredOwner[0];
time_t timer;
struct tm * st;
time(&timer);
st = localtime(&timer);
long t = (st->tm_year + 1900) + ((st->tm_mon + 1) * st->tm_mday - a) + st->tm_hour * st->tm_min;
///// SoftICE 检查,修正时间检查值(基本无用)
bool isExistsSICE95 = testSoftICE95();
bool isExistsSICENT = testSoftICENT();
if (isExistsSICE95) {
t += 0x143;
}
if (isExistsSICENT) {
t += 0x271;
}
char str_t[12];
itoa(t, str_t, 10);
sn[index] = str_t[0];
sn[index+1] = str_t[1];
sn[index+2] = str_t[2];
sn[index+3] = str_t[3];
///
//printf("time: %d-%d-%d %d:%d\n", st->tm_year+1900, st->tm_mon+1, st->tm_mday, st->tm_hour, st->tm_min) ;
}
CBData readKey(HKEY hKey, char * path, char * key) {
HKEY h = (HKEY)-1;
DWORD cbData;
DWORD regType = -1;
data.n = 1;
long s = RegOpenKeyEx(hKey, path, 0, KEY_READ, &h);
if( s != ERROR_SUCCESS) {
data.n = -1;
return data;
}
s = RegQueryValueEx(h, key, NULL, NULL, NULL, &cbData);
if(s == ERROR_SUCCESS) {
RegQueryValueEx(h, key, NULL, & regType, data.buffer, &cbData);
}
RegCloseKey(h);
return data;
}
void getRegInfo() {
char subKey[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
char key1[] = "FirstInstallDateTime";
char key2[] = "RegisteredOwner";
char key3[] = "RegisteredOrganization";
char key4[] = "ProductId";
CBData cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key1);
nFirstInstallDateTime = cb.n;
struct tm * tm_reg = localtime((time_t *)&nFirstInstallDateTime);
sprintf(sFirstInstallDateTime, "%lu", nFirstInstallDateTime);
nLenOfFirstInstallDateTime = strlen(sFirstInstallDateTime);
printf(" DateTime: %d-%d-%d %d:%d:%d\n", tm_reg->tm_year + 1900, tm_reg->tm_mon + 1,
tm_reg->tm_mday, tm_reg->tm_hour, tm_reg->tm_min, tm_reg->tm_sec);
printf("Timestamp: %d, len=%d\n", nFirstInstallDateTime, nLenOfFirstInstallDateTime);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key2);
strcpy(RegisteredOwner, (char *)cb.buffer);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key3);
strcpy(RegisteredOrganization, (char *)cb.buffer);
////
cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key4);
strcpy(ProductId, (char *)cb.buffer);
printf(" ProductId: %s\n", ProductId);
printf(" RegisteredOwner: %s\n", RegisteredOwner);
printf("RegisteredOrganization: %s\n", RegisteredOrganization);
}
1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号