破解 crackme(“不可逆“函数)
系统 : Windows xp
程序 : crackme
程序下载地址 :http://pan.baidu.com/s/1i41oh9r
要求 : 注册机编写
使用工具 : IDA Pro & OD
可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“简单分析crackme算法之一”。
运行程序,在Help-》Register菜单项中注册,输入测试用户名密码。程序提示错误,错误字串为:“No luck there, mate!”。打开IDA载入程序,通过字串表定位错误字串,并通过交叉参考在关键算法处下断:
> \6A push ; /lParam = NULL
0040120B . push ; |DlgProc = CRACKME.00401253
. FF75 push dword ptr [ebp+] ; |hOwner
. push ; |pTemplate = "DLG_REGIS"
. FF35 CA204000 push dword ptr [4020CA] ; |hInst = 00400000
0040121E . E8 7D020000 call <jmp.&USER32.DialogBoxParamA> ; \DialogBoxParamA
. 83F8 cmp eax,
.^ BE je short 004011E6
. 8E214000 push 0040218E ; 用户名入栈
0040122D . E8 4C010000 call 0040137E ; 根据用户名进行一些操作得出一个值
. push eax
. 7E214000 push 0040217E ; 序列号入栈
. E8 9B010000 call 004013D8 ; 根据序列号进行一些操作得出一个值
0040123D . 83C4 add esp, ; 平衡堆栈
. pop eax
. 3BC3 cmp eax, ebx ; F(用户名) == F(序列号)?
. je short 0040124C
40137E处汇编代码:
0040137E /$ 8B7424 mov esi, dword ptr [esp+] ; 取用户名
|. push esi
|> 8A06 /mov al, byte ptr [esi]
|. 84C0 |test al, al ; 如果迭代结束
|. |je short 0040139C ; 跳出循环
|. 3C |cmp al, ; 字符小于0x41,则提示错误
0040138B |. 1F |jb short 004013AC
0040138D |. 3C 5A |cmp al, 5A ; 如果字符大于等于5A,
0040138F |. |jnb short ; 则转化字符为大写
|. |inc esi ; 循环变量自增
|.^ EB EF |jmp short
|> E8 |call 004013D2
|. |inc esi ; 循环变量自增
0040139A |.^ EB E7 \jmp short
0040139C |> 5E pop esi ; 取用户名
0040139D |. E8 call 004013C2
004013A2 |. 81F7 xor edi,
004013A8 |. 8BC7 mov eax, edi ; 异或结果保存在eax里
004013AA |. EB jmp short 004013C1
004013AC |> 5E pop esi
004013AD |. 6A push ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004013AF |. push ; |Title = "No luck!"
004013B4 |. push ; |Text = "No luck there, mate!"
004013B9 |. FF75 push dword ptr [ebp+] ; |hOwner
004013BC |. E8 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004013C1 \> C3 retn
004013C2 /$ 33FF xor edi, edi
004013C4 |. 33DB xor ebx, ebx
004013C6 |> 8A1E /mov bl, byte ptr [esi]
004013C8 |. 84DB |test bl, bl ; 如果迭代结束
004013CA |. |je short 004013D1 ; 跳出循环
004013CC |. 03FB |add edi, ebx ; 累加字符值
004013CE |. |inc esi ; 循环变量自增
004013CF |.^ EB F5 \jmp short 004013C6
004013D1 \> C3 retn ; 结果保存在edi
004013D2 /$ 2C sub al,
004013D4 |. mov byte ptr [esi], al
004013D6 \. C3 retn
4013D8处汇编代码:
004013D8 /$ 33C0 xor eax, eax
004013DA |. 33FF xor edi, edi
004013DC |. 33DB xor ebx, ebx
004013DE |. 8B7424 mov esi, dword ptr [esp+] ; 取序列号
004013E2 |> B0 0A /mov al, 0A
004013E4 |. 8A1E |mov bl, byte ptr [esi]
004013E6 |. 84DB |test bl, bl ; 如果迭代结束
004013E8 |. 0B |je short 004013F5 ; 则跳出循环
004013EA |. 80EB |sub bl, ; 将字符转化为它对应的数字
004013ED |. 0FAFF8 |imul edi, eax
004013F0 |. 03FB |add edi, ebx
004013F2 |. |inc esi ; 循环变量自增
004013F3 |.^ EB ED \jmp short 004013E2
004013F5 |> 81F7 xor edi, ; 结果与0x1234异或
004013FB |. 8BDF mov ebx, edi ; 存入ebx
004013FD \. C3 retn
以上就是关键处代码,通过观察不难发现,该程序采用的是非明码比较(F(用户名)=F(序列号))。这样的程序我们用高级语言写出F(用户名),再算出F(序列号)的逆算法即可。
打开http://www.cnblogs.com/ZRBYYXDM/p/5115596.html中搭建的框架,修改OnBtnDecrypt函数如下:
void CKengen_TemplateDlg::OnBtnDecrypt()
{
// TODO: Add your control notification handler code here
CString str;
GetDlgItemText( IDC_EDIT_NAME,str ); //获取用户名字串基本信息。
int len = str.GetLength();
bool StrIsOk = true; for ( int i = ; i != len ; i++ ){
if ( str[i] < 0x41 ){
StrIsOk = false;
break;
}
} if ( StrIsOk ){ //格式控制。
str.MakeUpper(); //转化为大写。 unsigned int sum = ;
int i;
for ( i = ; i != len ; i++ )
sum += str[i]; sum ^= 0x5678; /*
//模拟F(序列号)
CString Serial = "1234";
unsigned int res = 0,num = 0;
int al = 0xA;
for ( i = 0 ; i != len ; i++ ){
num = Serial[i] - 0x30;
res *= al;
res += num;
} res ^= 0x1234;
*/ //写出F(序列号)的逆算法
/*
一开始想的是进行异或操作后,逆向整个for循环,类似于从最后一个元素Serial[len]反推,
res-=num;res/=al;这样,但发现要求的就是num的值,感觉该函数根本不可逆。
想来想去只好翻书看看有没有求解方法,发现程序与《解密与解密》P107处的Serial程序算法居然一样。
原来F(序列号)中的for循环只是将字串转化为了它对应的十进制数!最后做了一个异或而已。
也就是说,将F(用户名)的结果与0x1234进行异或,得出的就是本来的序列号!
通过这次破解,我知道了逆向不一定要微观上一步步反推,还可以从宏观上判断函数到底做了什么。
*/ str.Format( "%d",( sum ^ 0x1234 ) );
SetDlgItemText( IDC_EDIT_PASSWORD,str );
}
else
MessageBox( "用户名格式错误!" );
}
再在OnInitDialog中添加此代码修改标题:SetWindowText(_T("CRACKME_Keygen"));
运行效果:

-------------------------------------------------------------------------------------------------------------------
后记:
在测试注册机时发现了一个问题,当输入的字串长度过长,注册机算出的序列号是错误的。反复确认算法无误之后,怀疑是CRACKME中的字串有“猫腻”。这里,对GetDlgItemText下断点:
004012B5 |. 6A 0B |push 0B ; /Count = B (11.)
004012B7 |. 8E214000 |push 0040218E ; |Buffer = CRACKME.0040218E
004012BC |. E8030000 |push 3E8 ; |ControlID = 3E8 (1000.)
004012C1 |. FF75 |push dword ptr [ebp+] ; |hWnd
004012C4 |. E8 |call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
对比GetDlgItemText的定义:
int GetDlgItemText( HWND hDlg , int nID, LPTSTR lpStr, int nMaxCount) const;
nID 指定了要获取其标题的控件的整数标识符。 lpStr 指向要接收控件的标题或文本的缓冲区。 nMaxCount 指定了要拷贝到lpStr的字符串的最大长度(以字节为单位)。如果字符串比nMaxCount要长,它将被截断。 rString 对一个CString对象的引用。
nMaxCount 在程序中被设为11,实际保存的字符也就是10个。怪不得过长的用户名算出的序列号是错误的。这里,我们将OnBtnDecrypt函数的if ( StrIsOk )判断语句做个改动,在开始处增加一行代码:str = str.Left( 10 );就可以解决问题。

破解 crackme(“不可逆“函数)的更多相关文章
- 破解 CrackMe#1 [UBC] by bRaINbuSY
系统 : Windows xp 程序 : CrackMe#1 程序下载地址 :http://pan.baidu.com/s/1nuagj6h 要求 : 编写注册机 使用工具 :IDA & OD ...
- 软件破解入门(暴力破解CrackMe)
---恢复内容开始--- 所谓暴力破解,就是通过修改汇编代码进而控制程序的运行流程,达到不需注册码也能正常使用软件的目的.相对于解出算法进而编写注册机,暴破的技术含量是比较低的.但也正是因为一本05年 ...
- 破解 crackme(完全拆解警告窗口)
系统 : Windows xp 程序 : crackme 程序下载地址 :http://pan.baidu.com/s/1kUrbcAr 要求 : 注册机编写 & 去除Nag窗口 使用工具 : ...
- obdg反汇编破解crackme
obdg是一个反汇编软件 直接将要反汇编的exe文件拖入或者file->open打开文件,等待一段时间就会显示出来 界面中分别为汇编代码(程序内存内容),寄存器内容,数据内存内容,栈内容 代码界 ...
- 如何通过Python暴力破解网站登陆密码
首先申明,该文章只可以用于交流学习,不可以用于其他用途,否则后果自负. 现在国家对网络安全的管理,越来越严,但是还是有一些不法网站逍遥法外,受限于国内的人力.物力,无法对这些网站进行取缔. 今天演示的 ...
- 分享总结:更好地CodeReview
代码质量分享 2016_06_24_舒琴_代码质量.key For 代码提交人 基本原则 Review时机: 对于普通bugfix或优化,CodeReview最迟要 ...
- 逆向project实战--Acid burn
0x00 序言 这是第二次破解 crackme 小程序,感觉明显比第一次熟练.破解过程非常顺利,差点儿是分分钟就能够找到正确的 serial,可是我们的目标是破解计算过程.以下将具体介绍. 0x01 ...
- 【转】PHP代码审计
PHP代码审计 目录 1. 概述3 2. 输入验证和输出显示3 2.1 命令注入4 2.2 跨站脚本4 2.3 文件包含5 2.4 代码注入5 2.5 SQL注入6 2.6 XPath注入6 2.7 ...
- CodeReview实践与总结
CodeReview 是大型软件工程中公认的必不可少的保证工程质量的重要手段之一.但凡正规软件作战军团都是非常重视 CodeReview 的作用和意义的.那么,如何做好 CodeReview 呢?这里 ...
随机推荐
- 用Visual C#向access添加数据
(1)创建并打开一个OleDbConnection对象. (2)创建一个插入一条记录的SQL语句. (3)创建一个OleDbCommand对象. (4)通过此OleDbCommand对象完成对插入一条 ...
- 张艾迪(创始人):发明Global.World.224C的天才
Eidyzhang: Genius.Founder.CEO.23 I 世界级最高级创始人.世界最高级FounderCEO 出生在亚洲中国.Eidyzhang 拥有黑色头发白色皮肤(20岁)大学辍学生. ...
- 张艾迪(创始人):世界级天才女孩Eidyzhang
让整个世界与我们一同解读世界第一天才:Eidyzhang 她改变了整个世界.她的故事也激励了整个世界的不论亚洲.欧洲.非洲.南美州.北美洲.南极洲 天才Eidyzhang的故事激励了整个世界不论黑人. ...
- 166. Fraction to Recurring Decimal -- 将除法的商表示成字符串(循环节用括号表示)
Given two integers representing the numerator and denominator of a fraction, return the fraction in ...
- JavaScript之模块化编程
前言 模块是任何大型应用程序架构中不可缺少的一部分,模块可以使我们清晰地分离和组织项目中的代码单元.在项目开发中,通过移除依赖,松耦合可以使应用程序的可维护性更强.与其他传统编程语言不同,在当前Jav ...
- SqlFunctions 可以在EF种调用sqlserver的函数
在EF5环境下,首先添加EF环境,在引用中添加Syste.Data.Entity,再添加命名空间 using System.Data.Objects.SqlClient; 然后写一个控制器测试 pub ...
- Mysql date_sub函数使用
mysql中内置函数date_add和date_sub能对指定的时间进行增加或减少一个指定的时间间隔,语法如下: DATE_ADD(date,INTERVAL expr type) DATE_SUB( ...
- [Js]瀑布流
描述: 1.每个图片宽度都一样,高度不一样 思路: 1.算出一共有几列(通过视窗总宽度/单个图片宽度得出) 2.根据一共几列*单个图片宽度,设置外围总宽度并水平居中(注:这个宽度应该是计算出来的,而不 ...
- js基础之面向对象
一.基本概念 Array类 ————> 不具备实际的功能,只能用来构造对象 arr对象 ————> 有实际的功能,被类给构造出来 如:var arr=new Array(); proto ...
- Phonegap hello world 不容易啊~!
今天一个项目要用phonegap,当初就是觉得phonegap配置太tmd的麻烦了,所以转头appcan,但今天项目必须用-- 先是看到官方说用nodejs装,tmd的,总是重复同一个错误,安装不起, ...