破解 crackme(完全拆解警告窗口)
系统 : Windows xp
程序 : crackme
程序下载地址 :http://pan.baidu.com/s/1kUrbcAr
要求 : 注册机编写 & 去除Nag窗口
使用工具 : IDA Pro & OD
可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“Pj一个超简单的Crackme,适合像我一样的新手~_~”。
运行该程序,发现一开始就给了我们一个大大的警告窗口:
这不找抽吗?载入IDA查看字串表,发现字串“Patch Me if you can”,双击定位到定义位置,再双击交叉引用来到调用处。发现程序调用MessageBox来显示窗口,OD载入程序,将call MessageBox函数这一行改为add esp 10:
运行程序:
咦?我保存了的啊,什么还是显示了Nag窗口?而且我的断点也失效了?
初步判断,该程序开始运行时,进行清除断点的工作。并且,对载入内存的MessageBox部分代码进行了还原。
想要去除Nag窗口,可能就需要书后面的反跟踪以及打补丁的技巧。这里,我们暂时忍一下,先放过它。
重新返回字串表,发现该程序没有错误提示。。。找到成功注册的提示,向上翻找定位关键代码:
. C705 643C4000>mov dword ptr [403C64], <jmp.&user32.GetWindowTextA> ; 将函数地址存入 403C64
. 832D 643C4000>sub dword ptr [403C64],
0040122A > FF010000 push 1FF ; 循环两次读入用户名和密码。
0040122F . 83FB cmp ebx, ; 用户名存入403054,序列号403654
. 0D jnz short
. push ; ASCII "pediy"
. FF35 4C304000 push dword ptr [40304C]
0040123F . EB 0B jmp short 0040124C
> push ; ASCII "1111111111"
. FF35 push dword ptr []
0040124C > 83FB cmp ebx,
0040124F . je short
. 643C4000>add dword ptr [403C64],
> FF15 643C4000 call dword ptr [403C64] ; <jmp.&user32.GetWindowTextA>
0040125E . inc ebx
0040125F . 83FB cmp ebx,
.^ 7C C6 jl short 0040122A
. C705 703C4000>mov dword ptr [403C70], <jmp.&kernel32.lstrlenA>
0040126E . FF0D 703C4000 dec dword ptr [403C70] ; crackme.004016DC
. C705 683C4000>mov dword ptr [403C68], <jmp.&user32.GetWindowTextLeng>
0040127E . FF05 683C4000 inc dword ptr [403C68] ; crackme.00401670
. FF35 4C304000 push dword ptr [40304C]
0040128A . FF0D 683C4000 dec dword ptr [403C68] ; crackme.00401670
. FF15 683C4000 call dword ptr [403C68] ; <jmp.&user32.GetWindowTextLengthA>
. 83F8 cmp eax, ; 用户名是否小于5?
. 0F8C jl 004013E2 ; 是则跳转至出错代码
0040129F . 83F8 cmp eax, ; 用户名是否大于等于8?
004012A2 . 0F8D 3A010000 jge 004013E2 ; 是则跳转至出错代码
004012A8 . 8BC8 mov ecx, eax
004012AA . 890D 543C4000 mov dword ptr [403C54], ecx ; 长度存入内存
004012B0 . 33DB xor ebx, ebx
004012B2 . 8D35 lea esi, dword ptr [] ; 取用户名
004012B8 . 8D3D lea edi, dword ptr [] ; 开辟内存储存密钥
004012BE > 8A4431 FF mov al, byte ptr [ecx+esi-] ; 倒序迭代字串
004012C2 . 80F9 cmp cl, ; 长度为4?
004012C5 . je short 004012DA ; 是则存储‘-’字符并结束本次循环
004012C7 . 3C 4D cmp al, 4D ; 是否小于0x4D?
004012C9 . 7C jl short 004012CF
004012CB . 2C sub al, ; 大于0x4D则减去0x11
004012CD . EB jmp short 004012D1
004012CF > add al,
004012D1 > 32C1 xor al, cl ; 处理过的字符值 ^ 长度
004012D3 . xor al, ; 处理过的字符值^2
004012D5 . 88043B mov byte ptr [ebx+edi], al ; 保存密钥
004012D8 . EB jmp short 004012DE
004012DA > C6043B 2D mov byte ptr [ebx+edi], 2D
004012DE > inc ebx ; 指向下一个存储单元
004012DF .^ E0 DD loopdne short 004012BE ; 类似loop,另外测试ZF标志位是否为1则退出循环
004012E1 . 8D35 lea esi, dword ptr [] ; 取序列号
004012E7 . 8D3D lea edi, dword ptr [] ; 开辟内存储存新密钥
004012ED . 8B0D 543C4000 mov ecx, dword ptr [403C54] ; 长度存入ecx
004012F3 . 33DB xor ebx, ebx
004012F5 . C705 5C3C4000>mov dword ptr [403C5C], <jmp.&kernel32.lstrcatA>
004012FF . 832D 5C3C4000>sub dword ptr [403C5C],
. C705 783C4000>mov dword ptr [403C78], 0040207F ; ASCII ":-)"
. C705 7C3C4000>mov dword ptr [403C7C], ; ASCII "Correct Serial"
0040131A . 832D 783C4000>sub dword ptr [403C78],
. 832D 7C3C4000>sub dword ptr [403C7C],
> 80F9 cmp cl, ; 长度为4?
0040132B . je short ; 是则存储‘-’字符并结束本次循环
0040132D . 8A4431 FF mov al, byte ptr [ecx+esi-] ; 倒序迭代密钥
. 3C 4D cmp al, 4D ; 是否小于0x4D?
. 7C jl short ; 小于0x4D则加上0x15
. 2C sub al, ; 大于0x4D则减去0x11
. EB jmp short 0040133B
> add al,
0040133B > 32C1 xor al, cl ; 处理过的字符值 ^ 长度
0040133D . xor al, ; 处理过的字符值^2
0040133F . 88043B mov byte ptr [ebx+edi], al ; 保存密钥
. EB jmp short
> C6043B 2D mov byte ptr [ebx+edi], 2D
> inc ebx ; 指向下一个存储单元
.^ E0 DD loopdne short ; 类似loop,另外测试ZF标志位是否为1则退出循环
0040134B . C705 603C4000>mov dword ptr [403C60], <jmp.&user32.MessageBoxA> ; Entry address
. 832D 603C4000>sub dword ptr [403C60],
0040135C . push ; ASCII "o-RT\"
. push ; ASCII "L-@B]o-RT\"
. 5C3C4000>add dword ptr [403C5C], ; ↓将旧密钥连接到新密钥后面
0040136D . FF15 5C3C4000 call dword ptr [403C5C] ; <jmp.&kernel32.lstrcatA>
. push ; ASCII "L-@B]o-RT\"
. FF05 703C4000 inc dword ptr [403C70] ; crackme.004016DC
0040137E . FF15 703C4000 call dword ptr [403C70] ; <jmp.&kernel32.lstrlenA>
. A3 743C4000 mov dword ptr [403C74], eax ; ↑算出密钥长度↓算出输入的序列号长度
. push ; ASCII "1111111111"
0040138E . FF15 703C4000 call dword ptr [403C70] ; <jmp.&kernel32.lstrlenA>
. 3B05 743C4000 cmp eax, dword ptr [403C74] ; 长度一样?
0040139A . jnz short 004013E2
0040139C . FF35 543C4000 push dword ptr [403C54] ; 长度入栈
004013A2 . push ; ASCII "L-@B]o-RT\"
004013A7 . push ; ASCII "1111111111"
004013AC . E8 9F000000 call ; 字串是否相等?
004013B1 . 83F8 cmp eax, ; 不相等则跳转出错
004013B4 . 2C je short 004013E2 ; 相等则提示成功
这是一个F(用户名)=序列号的例子,我们将F(用户名)用高级语言写出来即可完成注册机。
打开http://www.cnblogs.com/ZRBYYXDM/p/5115596.html中搭建的框架,为CKengen_TemplateDlg添加成员函数CreateSerial:
CString CKengen_TemplateDlg::CreateSerial(CString str)
{
CString res = "";
int len = str.GetLength(); int i = len - ,count = len;
for ( ; i != - ; i--,count-- ){
if ( count == ){
res += '-';
continue;
} if ( str[i] < 0x4D ) //小于0x4D
str.SetAt( i,str[i] + 0x15 );
else
str.SetAt( i,str[i] - 0x11 ); str.SetAt( i,str[i] ^ ( i+ ) ^ );
res += str[i];
} return res;
}
并修改OnBtnDecrypt如下:
void CKengen_TemplateDlg::OnBtnDecrypt()
{
// TODO: Add your control notification handler code here
CString str;
GetDlgItemText( IDC_EDIT_NAME,str ); //获取用户名字串基本信息。
int len = str.GetLength(); if ( len >= && len < ){ //格式控制。
CString Temp = CreateSerial( str ); //第一个密钥
CString Serial = CreateSerial( Temp ); //第二个密钥 Serial += Temp; SetDlgItemText( IDC_EDIT_PASSWORD,Serial );
}
else
MessageBox( "用户名格式错误!" );
}
再在OnInitDialog中添加此代码修改标题:SetWindowText(_T("CRACKME_Keygen"));
运行效果:
-------------------------------------------------------------------------------------------------------------------
后记:看了pediy crackme 2007中的原破文受了启发,既然反跟踪和恢复MessageBox函数都是作者之前实现的,那找到它nop掉不就行了?这里,一步步跟踪开头的代码:发现调用401477子程序之后,MessageBox被恢复了:
>/$ 6A push ; /pModule = NULL
|. E8 B7060000 call <jmp.&kernel32.GetModuleHandleA> ; \GetModuleHandleA
|. A3 mov dword ptr [], eax
0040100C |. E8 A1060000 call <jmp.&kernel32.GetCommandLineA> ; [GetCommandLineA
|. A3 mov dword ptr [], eax
|. 6A 0A push 0A
|. FF35 push dword ptr []
0040101E |. 6A push
|. FF35 push dword ptr [] ; crackme.00400000
|. E8 call
0040102B |. push eax ; /ExitCode
0040102C \. E8 7B060000 call <jmp.&kernel32.ExitProcess> ; \ExitProcess
/$ push ebp
|. 8BEC mov ebp, esp
|. 83C4 B0 add esp, -
E8 3B040000 call
我们nop掉它就OK了^▼^
但运行保存后的程序,单击check之后会出错,这又是为什么?帖子评论里就有牛人来讲解了:
程序一开始调用4次WriteProcessMemory恢复40103C处的机器码
并在按下check后调用ReadProcessMemory检查自身一大段机器码动态SMC 值得学习
原来的确运用了补丁技术,而且断点失效并非我一开始推测的断点全部清除。我们都知道断点其实就是int 3指令,WriteProcessMemory恢复了MessageBox的机器码,自然就覆盖了断点的int 3指令,所以MessageBox处的断点失效而注册算法的断点没有失效。
现在,我们重新调整一下思路。如果光是nop掉对于重写自身代码的子程序没有用,那么干脆连检测自身代码的子程序也patch掉好了。
跟入401477:
/$ C705 803C4000>mov dword ptr [403C80], <jmp.&kernel32.GetCurrentProcessId>
|. 832D 803C4000>sub dword ptr [403C80],
|. 843C4000>add dword ptr [403C84],
0040148F |. 843C4000>add dword ptr [403C84], <jmp.&kernel32.OpenProcess>
|. 803C4000>add dword ptr [403C80],
004014A0 |. C705 883C4000>mov dword ptr [403C88], <jmp.&kernel32.WriteProcessMemory>
004014AA |. FF05 883C4000 inc dword ptr [403C88]
004014B0 |. FF15 803C4000 call dword ptr [403C80] ; <jmp.&kernel32.GetCurrentProcessId>
004014B6 |. 832D 843C4000>sub dword ptr [403C84],
004014BD |. push eax
004014BE |. 6A push
004014C0 |. FF0F1F00 push 1F0FFF
004014C5 |. FF15 843C4000 call dword ptr [403C84]
004014CB |. A3 9C3C4000 mov dword ptr [403C9C], eax
004014D0 |. FF0D 883C4000 dec dword ptr [403C88]
004014D6 |. FF35 A03C4000 push dword ptr [403CA0]
004014DC |. 6A push
004014DE |. push
004014E3 |. 3C104000 push 0040103C
004014E8 |. FF35 9C3C4000 push dword ptr [403C9C]
004014EE |. FF15 883C4000 call dword ptr [403C88]
004014F4 |. C705 A03C4000>mov dword ptr [403CA0], ; ↑重写MessageBox的Style参数部分
004014FE |. FF35 A03C4000 push dword ptr [403CA0]
|. 6A push
|. push ; ASCII "h50@"
0040150B |. 3E104000 push 0040103E
|. FF35 9C3C4000 push dword ptr [403C9C]
|. FF15 883C4000 call dword ptr [403C88]
0040151C |. C705 A03C4000>mov dword ptr [403CA0], ; ↑重写MessageBox的Title参数部分
|. FF35 A03C4000 push dword ptr [403CA0]
0040152C |. 6A push
0040152E |. 8D204000 push 0040208D ; ASCII "h!0@"
|. push
|. FF35 9C3C4000 push dword ptr [403C9C]
0040153E |. FF15 883C4000 call dword ptr [403C88]
|. C705 A03C4000>mov dword ptr [403CA0], ; ↑重写MessageBox的Text参数部分
0040154E |. FF35 A03C4000 push dword ptr [403CA0]
|. 6A push
|. push
0040155B |. push
|. FF35 9C3C4000 push dword ptr [403C9C]
|. FF15 883C4000 call dword ptr [403C88]
0040156C |. C705 A03C4000>mov dword ptr [403CA0], ; ↑重写MessageBox的hOwner参数部分
|. FF35 A03C4000 push dword ptr [403CA0]
0040157C |. 6A push
0040157E |. push
|. 4A104000 push 0040104A
|. C705 8C3C4000>mov dword ptr [403C8C], <jmp.&kernel32.ReadProcessMemory>
|. FF35 9C3C4000 push dword ptr [403C9C]
|. FF15 883C4000 call dword ptr [403C88]
0040159E |. 832D 8C3C4000>sub dword ptr [403C8C], ; ↑重写MessageBox的Call部分
这里子程序的作用只有重写,那么我们可以按照之前的方法直接nop掉他的Call。(Flag
然后,对于ReadProcessMemory下断点,单击check,然后返回用户领空:
004015B3 /$ C705 943C4000>mov dword ptr [403C94],
004015BD |. BB mov ebx, <ModuleEntryPoint>
004015C2 |. FF15 803C4000 call dword ptr [403C80] ; <jmp.&kernel32.GetCurrentProcessId>
004015C8 |. push eax
004015C9 |. 6A push
004015CB |. FF0F1F00 push 1F0FFF
004015D0 |. FF15 843C4000 call dword ptr [403C84]
004015D6 |. A3 9C3C4000 mov dword ptr [403C9C], eax
004015DB |> 6A /push
004015DD |. 6A |push
004015DF |. 983C4000 |push 00403C98
004015E4 |. |push ebx ; 程序入口点
004015E5 |. FF35 9C3C4000 |push dword ptr [403C9C]
004015EB |. FF15 8C3C4000 |call dword ptr [403C8C] ; ReadProcessMemory
004015F1 |. |inc ebx ; 循环读取程序在内存中的数据
004015F2 |. C705 A43C4000>|mov dword ptr [403CA4], 004016BC
004015FC |. 8B15 983C4000 |mov edx, dword ptr [403C98]
|. 81FB |cmp ebx, ; 第一次循环?
|. |jnz short ; 不是则跳转
0040160A |. 943C4000 |mov dword ptr [403C94], edx ; 是则赋值给存放结果的内存
|> 81FB DD200600 |cmp ebx, 620DD
|. |je short
|. 83C2 |add edx, ; 异或变量+4
0040161B |. 943C4000>|xor dword ptr [403C94], ; 进行异或
|. 943C4000 |xor dword ptr [403C94], edx
|> 81FB 2A164000 |cmp ebx, 0040162A ; 检测40100-40162A处的程序
0040162E |.^ AB \jnz short 004015DB ; 检测完则循环结束。
|. 813D 943C4000>cmp dword ptr [403C94], 0C0 ; 校验异或值是否正确?
0040163A |. je short ; 不正确的话将直接退出进程
0040163C |. 6A push ; /ExitCode = 0
0040163E |. E8 call <jmp.&kernel32.ExitProcess> ; \ExitProcess
|> FF35 9C3C4000 push dword ptr [403C9C] ; /hObject = NULL
|. E8 call <jmp.&kernel32.CloseHandle> ; \CloseHandle
0040164E |. 33C0 xor eax, eax
\. C3 retn
这里,读取对程序自身一大段代码,并取值与其异或,全部读取完毕之后,取其校验异或值与正确的校验值进行比较。如果不正确将直接退出进程,这将引发一个错误。
以下流程图描述了程序的结构:
接下来,我尝试了按照之前的方法把重写MB的程序call给nop掉,然后jump到MB之后的代码中,最后,修改检测patch子程序的跳转指令。做完之后,尝试启动,OD会提示你程序尝试访问0000内存,引发了异常,这实际上是应用程序崩溃了。
经过一番研究之后,我推导出nop重写mb的子程序引发了该错误。肯定在该子程序中有其他代码而我一时忽略了,现在只能进入子程序,将修改MBstyle参数的WriteProcessMemory函数清除掉,在该子程序返回后,立刻将style参数部分改成跳转指令,最后,我们修改检测patch子程序的跳转指令。这样,Nag窗口就被我们完全地拆解了。
破解 crackme(完全拆解警告窗口)的更多相关文章
- xp系统打开软件程序总是弹出警告窗口,很烦人对不,怎么办呢?进来看
为了不浪费比较着急的朋友的的时间,先把解决方案说了,下面我在细说: 细说: 今天装了个xp的虚拟机,为了不在xp里重复装真机(win7的)里已经有的软件,就把我的工具盘共享给了虚拟机,大部分软件都可以 ...
- JavaScript中的3种弹出式消息提醒(警告窗口,确认窗口,信息输入窗口)的命令是什么?
1.Alert()显示带有一段文字和一个确认按钮的警告窗口; 2.Confirm()显示带有一段文字以及确认和取消按钮的确认窗口; 3.Prompt()显示可提示用户输入的对话框.
- iOS 学习笔记 九 (2015.04.02)IOS8中使用UIAlertController创建警告窗口
1.IOS8中使用UIAlertController创建警告窗口 #pragma mark - 只能在IOS8中使用的,警告窗口- (void)showOkayCancelAlert{ NSSt ...
- [Xcode 实际操作]四、常用控件-(10)动作表样式警告窗口的使用
目录:[Swift]Xcode实际操作 本文将演示动作表单窗口的使用. 动作表单可以给用户展现一系列的选项, 和警告窗口不同的是,动作表单的展示形式和设备的尺寸有关. 在项目导航区,打开视图控制器的代 ...
- [Xcode 实际操作]四、常用控件-(9)普通警告窗口的使用
目录:[Swift]Xcode实际操作 本文将演示警告窗口的使用方法. 警告窗口不仅可以给用户展现提示信息,还可以提供若干选项供用户选择. 在项目导航区,打开视图控制器的代码文件[ViewContro ...
- [Swift通天遁地]一、超级工具-(15)使用SCLAlertView制作强大的Alert警告窗口和Input编辑窗口
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- 关闭AnyConnect登录安全警告窗口
一.问题描述:使用AnyConnect client连接时,如何关闭的安全警告窗口? 二.原因分析: AnyConnect Server(ASA)和AnyConect client(PC)上没有受 ...
- 软件破解入门(暴力破解CrackMe)
---恢复内容开始--- 所谓暴力破解,就是通过修改汇编代码进而控制程序的运行流程,达到不需注册码也能正常使用软件的目的.相对于解出算法进而编写注册机,暴破的技术含量是比较低的.但也正是因为一本05年 ...
- 破解 CrackMe#1 [UBC] by bRaINbuSY
系统 : Windows xp 程序 : CrackMe#1 程序下载地址 :http://pan.baidu.com/s/1nuagj6h 要求 : 编写注册机 使用工具 :IDA & OD ...
随机推荐
- Populating Next Right Pointers in Each Node II [Leetcode]
Problem Description http://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ ...
- C语言实现统计字符个数
#include<stdio.h> int main() { int sz[10]={0},zm[26]={0},z[26]={0},i,space=0,e=0,t=0; ...
- SecureCRT快捷键
ctrl + a : 移动光标到行首ctrl + e :移动光标到行尾crtl + b: 光标前移1个字符crtl + f : 光标后移1个字符 crtl + h : 删除光标之前的一个字符c ...
- netty4 连通步骤
转载:http://xw-z1985.iteye.com/blog/1973205 服务端依次发生的步骤 建立服务端监听套接字ServerSocketChannel,以及对应的管道pipeline: ...
- VS构建工具介绍
VS构建工具介绍 我们都知道C/C++源代码要生成可执行的.exe程序,需要经过编译.链接的过程.你在VS工具中只需要选择菜单Build或按一下F5可以编译.链接.运行了,其实IDE帮我隐藏了好多的具 ...
- J2EE开发实战基础系列一 HelloWorld【转】
开始咱们的第一个程序,首先是配置环境,按照上一章所描述的方式下载开发工具,然后配置Java环境变量,给大家看下具体的结构: 环境变量配置OK的提示,如上图. Eclipse和Tomcat的文件目录 ...
- eclipse常用的字体
1.consolas 2.Segoe Script 3.Segoe Print 4.Courier New
- Matrix-Tree定理
感觉又学到了一个利器! 感谢Vfleaking神犇,传送门 http://vfleaking.blog.163.com/blog/static/1748076342013112523651955/ ...
- ASP.NET的运行原理与运行机制
在Asp.net4和4.5中,新增了WebPages Framework,编写页面代码使用了新的Razor语法,代码更加的简洁和符合Web标准,编写方式更接近于PHP和以前的Asp,和使用WebFor ...
- [Js]基础知识
一.JavaScript组成 1.ECMAScript 解释器.翻译(提供功能有限,如加减乘除,定义变量.函数等) 几乎没有兼容性问题 2.DOM 有一些兼容性问题 3.BOM(用的少,交互 ...