新人第一次发一个简单的CM【注册码方式】
说明:今天突发奇想想用纯win32 api做一个窗口程序,又突然想到了吾爱破解论坛上面的破解区,于是就写了个这个CrackMe。
小白第一次做CM,希望大家多多支持,大佬轻点喷。。
这是程序界面,目前账号只支持纯英文输入(本人水平有限,时间不够,才写的这样)
提示:字符串为明码,可通过od字符串查找查看。
欢迎大家踊跃尝试,有什么问题可以联系我讨论交流,当然,每日的1Cb免费的哦:lol(疯狂暗示)
附件: 稍微弄了一下,这个用的算是挺普遍的算法模式了。
代码:
验证流程:
```
def GetVerifictionForUsername(username):
username = str.encode(username)
for i in range(0, len(username)):
byte = username
if byte < 65:
return 1
if byte > 90:
username = username[:i] + bytes() + username
username_sum = 0
for i in range(0, len(username)):
username_sum += username
username_verify = username_sum ^ 0x1357
return username_verify
def GetVerifictionForReg(reg):
reg_sum = 0
for i in range(0, len(reg)):
byte = ord(reg) - 48
reg_sum = 10 * reg_sum + byte
reg_verify = reg_sum ^ 0x2468
return reg_verify
def CheckReg(username, reg):
return GetVerifictionForUsername(username) == GetVerifictionForReg(reg)
```
根据上面逆推出的注册机:
```
def KeyGen(username):
username_verifiction = GetVerifictionForUsername(username)
reg_sum = username_verifiction ^ 0x2468
results = []
FindReg(results, reg_sum)
#测试注册码
for i in range(0, len(results)):
reg = results
assert CheckReg(username, reg)
print("username_verifiction = " + str(username_verifiction))
print("reg_verifiction = " + str(GetVerifictionForReg(results)))
return results
#其实这段算是暴力枚举
def FindReg(result, reg_sum, n=-1, rs=[]):
if reg_sum < 0:
return
if n != -1:
#assert (reg_sum - n) % 10 == 0
reg_sum = (reg_sum - n) // 10# 可以确定能整除
rs.append(int(n + 48))
if reg_sum == 0:
rs.reverse()
result.append(bytes(rs).decode())
return
singel_digits = reg_sum % 10# 确保减去最后一位后能被10整除
# n belongs to
min_digits = 0
max_digits = 6 if singel_digits > 8 else 7
for i in range(min_digits, max_digits + 1):
new_rs = copy.deepcopy(rs)
FindRegLoop(result, reg_sum, i * 10 + singel_digits, new_rs)
return
``` 本帖最后由 迷雾 于 2019-7-4 13:03 编辑
先上效果
本人渣渣一枚,大神们勿喷,lz的程序没加密我就直接ida f5了.
INT_PTR __stdcall DialogFunc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
char v5; // dl
void (__stdcall *v6)(UINT); // ebx
int v7; // ecx
char *v8; // ebx
char v9; // al
int v10; // esi
int v11; // eax
int v12; // esi
CHAR v13; // al
CHAR *v14; // edx
int v15; // ecx
CHAR v16; // al
HWND v17; // eax
HWND v18; // eax
HWND v19; // eax
HWND v20; // eax
HICON v21; // eax
signed int v22; //
CHAR String; //
char Dst; //
CHAR String2; //
__int16 v26; //
CHAR v27; //
int v28; //
__int16 v29; //
CHAR v30; //
__int16 v31; //
char v32; //
v26 = 33;
v28 = 565626318;
v29 = 33;
*(_OWORD *)String2 = xmmword_D52128; // 对应的字符串为 "恭喜你,成功"
v31 = -24157;
*(_OWORD *)v27 = xmmword_D5213C;
v32 = 0;
*(_OWORD *)v30 = xmmword_D52154;
memset(Dst, 0, 0x64u);
memset(&String, 0, 0x64u);
if ( Msg == 0x10 ) // WM_CLOSE
{
DestroyWindow(hWnd);
return 0;
}
if ( Msg == 272 ) // WM_INITDIALOG
{
v21 = LoadIconA(hInstance, (LPCSTR)0x69);
SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v21); // WM_SETICON
SendDlgItemMessageA(hWnd, 1003, 0xC5u, 0x50u, 0);
return 0;
}
if ( Msg != 273 ) // WM_COMMAND
return 0;
if ( (unsigned __int16)wParam == 1007 )
{
v22 = GetDlgItemTextA(hWnd, 1003, Dst, 101);// UserName
GetDlgItemTextA(hWnd, 1004, &String, 101);// PassWord
v5 = Dst;
v6 = (void (__stdcall *)(UINT))MessageBeep;
if ( Dst && v22 >= 5 ) // if userName!=0 && length(userName)>=5
{
v7 = 0;
v8 = Dst; // userName
if ( v22 <= 0 ) // length(userName)
{
LABEL_15:
v10 = 0;
if ( v5 ) // v5=首字符
{
do
{
v11 = v5; // 移到下一个字符,v5=下一字符
v5 = *++v8;
v10 += v11;
}
while ( *v8 );
}
v12 = v10 ^ 0x1357; // v10=所有字符ascii码之和
}
else // if userName==0 || length(userName)<5
{
while ( 1 )
{
v9 = Dst; // 如果用户名是数字,跳出循环
if ( v9 < 65 )
break; // 如果ASCI大于90(判断小写字母?)
if ( v9 > 90 ) // 转为大写字母
Dst = v9 - 32;
if ( ++v7 >= v22 ) // 索引下移,这里应该是v7++吧?,先移动下一再判断是否到达结尾
{
v5 = Dst; // v5=首字符
goto LABEL_15;
}
} // 如果有数字跳出循环设置这个标记
v12 = 1;
}
v13 = String; // PassWord
v14 = &String; // Pointer to PassWord
v15 = 0;
if ( String ) // 将每一个密码字符-48('0')转为数字 然后放到缓冲区v14中,v15为每一次转换出的数字加上上一次的转换的数字*10
{
do
{
v16 = v13 - 48;
*v14++ = v16;
v15 = v16 + 10 * v15;
v13 = *v14; // 这个v13好像没什么卵用
}
while ( *v14 );
}
if ( v12 == (v15 ^ 0x2468) ) // 如果用户名有数字的话这里v12==1
{
lstrcpyA(Text, String2); // 密码正确 "恭喜你,成功"
v17 = GetDlgItem(hWnd, 1003);
EnableWindow(v17, 0);
v18 = GetDlgItem(hWnd, 1004);
EnableWindow(v18, 0);
}
else
{
lstrcpyA(Text, v27); // 密码错误
}
v19 = GetDlgItem(hWnd, 1004);
SetFocus(v19);
v6 = (void (__stdcall *)(UINT))MessageBeep;
}
else
{
lstrcpyA(Text, v30); // 长度不对
v20 = GetDlgItem(hWnd, 1003);
SetFocus(v20);
MessageBeep(0);
}
v6(0);
MessageBoxA(hWnd, Text, "CrackMe", 0);
}
else if ( (unsigned __int16)wParam == 1008 )
{
SendMessageA(hWnd, 0x10u, 0, 0);
return 1;
}
return 1;
}
//根据这个枚举出5位数字下的一个正确密码
#include <iostream>
using namespace std;
int func(char *p)
{
int a=0, b=0, c=0;
char buf = { 0 };
int i = 0;
do
{
a = *p - '0';
buf = a;
c = a + 10 * c;
p++;
} while (*p);
return c;
}
int main()
{
char a, b, c, d, e;
char buf = { 0 };
for (a = '0'; a <= '9'; a++)
for (b = '0'; b <= '9'; b++)
for (c = '0'; c <= '9'; c++)
for (d = '0'; d <= '9'; d++)
for (e = '0'; e <= '9'; e++)
{
buf = a;
buf = b;
buf = c;
buf = d;
buf = e;
int ret = func(buf);
if ((ret^0x2468) == 1)
{
cout << "find" << endl;
cout << a << b << c << d << e << "ret:" << ret << endl;
}
}
return 0;
}
find
09321ret:9321
hbwwt 发表于 2019-3-23 22:05
不明白有啥用哦
大佬。。。你都注册这么久了。我实在很难跟你解释这个有啥用。。。:rggrg
直接下了MessageBox断点 跌宕起伏 发表于 2019-3-24 02:55
直接下了MessageBox断点
哈哈,还能这么玩的么,阔以 天阶 发表于 2019-3-23 23:05
感谢楼主辛苦分享!也请楼主给我这样的新人普及下该程序的作用及使用方法!谢谢!
这个东西就是拿着练习逆向技术的。。如何分析程序保护,以及如何破解程序的注册机制,当然,由于编写者都不怎么专业,比起市面上的辅助这些少了很多检测技术,所以适合练手。 跌宕起伏 发表于 2019-3-24 02:55
直接下了MessageBox断点
考虑不周了,当时想用个对话框来提示信息的,哈哈,为了省事儿直接用的messagebox,没想到这么容易就被爆破了 不明白有什么用的 看帖子上面的蓝字 那不是有介绍吗 那么多的坑让我这样的小白去跳,有意思吗
monvvv 发表于 2019-3-24 13:04
稍微弄了一下,这个用的算是挺普遍的算法模式了。
代码:
很强啊,老哥,哈哈哈,基本上和我写的注册机一样了:lol