系统 : Windows xp

程序 : TDC‘s keygenme

程序下载地址 :http://pan.baidu.com/s/1gdWyt6z

要求 : 脱壳 & 注册机编写

使用工具 :OD & IDA & PEID & LordPE & Import REC

可在“PEDIY CrackMe 2007”中查找关于此程序的分析,标题为“TDC.Crackme10算法分析”。

首先了解一下壳是什么:

作者编好软件后,编译成exe可执行文件。

1.有一些版权信息需要保护起来,不想让别人随便改动,如作者的姓名等,即为了保护软件不被破解,通常都是采用加壳来进行保护。

2.需要把程序搞的小一点,从而方便使用。于是,需要用到一些软件,它们能将exe可执行文件压缩,

3.在黑客界给木马等软件加壳脱壳以躲避杀毒软件。     

                                                --源自百度百科

简单说来,壳就是用来防止破解者对于程序文件的非法修改。壳又分为压缩壳、加密壳。他们的应用范围也不尽相同,压缩壳主要用来压缩程序文件的体积,对于破解者来说强度不大。而加密壳以加密保护为重点,用尽了各种反跟踪技术,保护重点是在OEP(程序入口点)的隐藏和IAT(输入表)的加密上。

这篇博文中我们来尝试破解一个被压缩壳保护、带有简单反调试的程序。

将程序拖入PEID查看状态:

显示该程序加了upx壳,可以利用网上的脱壳机来脱壳。这里,为了加深印象,我们尝试手动脱壳。od载入程序,断在外壳处:

 > $              pushad
. BE mov esi,
. 8DBE 0090FDFF lea edi, dword ptr [esi+FFFD9000]
0044633C . push edi
0044633D . 83CD FF or ebp, FFFFFFFF
. EB jmp short

单步执行pushad之后,esp指向0012FFA4 ,键入命令hr 12FFA4下硬件断点,F9运行程序断在此处

   .- E9 73ABFBFF   jmp     0040100B

单步执行跳转进入OEP:

0040100B    6A 0A           push    0A
0040100D B90B0000 push 0BB9
FF35 push dword ptr []
E8 call ; jmp to kernel32.FindResourceA
0040101D A3 1C624000 mov dword ptr [40621C], eax
FF35 1C624000 push dword ptr [40621C]
FF35 push dword ptr []
0040102E E8 call 0040133A ; jmp to kernel32.LoadResource
A3 mov dword ptr [], eax
E8 C3FFFFFF call
0040103D FF35 1C624000 push dword ptr [40621C]
FF35 push dword ptr []
E8 F8020000 call ; jmp to kernel32.SizeofResource
0040104E A3 mov dword ptr [], eax
FF35 push dword ptr []
E8 E2020000 call ; jmp to kernel32.SetHandleCount
0040105E 8BF0 mov esi, eax
A1 mov eax, dword ptr []
83C0 add eax,
push eax
6A push
0040106B E8 C4020000 call ; jmp to kernel32.GlobalAlloc
A3 mov dword ptr [], eax

此时单击菜单Debug->hardware breakpoints删除之前设置的硬件断点。

打开LordPE选择keygenme并单击右键选择“完整转存”:

保存dump文件之后,再打开输入表重建工具Import REC附加到keygenme:

填写OEP为“0000100B”,依次单击“自动查找IAT”、“获取输入表”:

最后,单击“修复转存文件”,选中之前的dump文件,则脱壳成功。

脱壳成功之后我们用IDA载入程序,shift + F12查看字符串表:

发现提示成功的字串“Congratulations! You are now level 2! :-)”,双击定位,通过交叉引用来到调用它的位置并向上翻找出关键算法:

TDC0:                 cmp     dword ptr [ebp+0Ch], 111h
TDC0: jnz loc_401292
TDC0:0040118E cmp dword ptr [ebp+10h], 3E9h
TDC0: jnz loc_40125C
TDC0:0040119B push 33h
TDC0:0040119D push offset dword_40622C
TDC0:004011A2 push 7D1h
TDC0:004011A7 push dword ptr [ebp+]
TDC0:004011AA call GetDlgItemTextA
TDC0:004011AF imul eax,
TDC0:004011B2 cmp eax, 0FAh
TDC0:004011B7 ja loc_401246
TDC0:004011BD cmp eax, 1Eh
TDC0:004011C0 jb loc_401246
TDC0:004011C6 push
TDC0:004011C8 push
TDC0:004011CA push 7D2h
TDC0:004011CF push dword ptr [ebp+]
TDC0:004011D2 call GetDlgItemInt
;省略一部分关键代码:

这里,选中关键代码,单击“视图”->"图表"->"流程图"显示关键算法的流程:

可以直观的看出,关键算法处用了不少分支语句,程序中肯定加了不少对输入的判断。

打开OD载入程序,输入命令"bp 004011AA",F9运行,程序断在此处:

0040119B    6A            push
0040119D 2C624000 push 0040622C ; ASCII "pediy"
004011A2 D1070000 push 7D1
004011A7 FF75 push dword ptr [ebp+]
004011AA E8 AF010000 call <jmp.&user32.GetDlgItemTextA>
004011AF 6BC0 imul eax, eax, ; 用户名字串长度*5
004011B2 3D FA000000 cmp eax, 0FA ; 高于0xFA?
004011B7 0F87 ja ; 提示Name must be between 5 and 51 length
004011BD 83F8 1E cmp eax, 1E ; 低于0x1E?
004011C0 0F82 jb ; 提示Name must be between 5 and 51 length
004011C6 6A push
004011C8 6A push
004011CA D2070000 push 7D2
004011CF FF75 push dword ptr [ebp+]
004011D2 E8 call <jmp.&user32.GetDlgItemInt> ; 获取序列号
004011D7 A3 5F624000 mov dword ptr [40625F], eax ; 并保存
004011DC 2C624000 push 0040622C ; 用户名入栈
004011E1 E8 C2000000 call 004012A8

跟入4012A8:

004012A8                  push    ebp
004012A9 8BEC mov ebp, esp
004012AB 803D B4124000 C>cmp byte ptr [4012B4], 0CC ; 检测断点,发现则跳转出错
004012B2 je short
004012B4 33C0 xor eax, eax
004012B6 33C9 xor ecx, ecx
004012B8 803D D4124000 C>cmp byte ptr [4012D4], 0CC ; 检测断点,发现则跳转出错
004012BF je short
004012C1 33D2 xor edx, edx
004012C3 8B55 mov edx, dword ptr [ebp+] ; 取用户名字串
004012C6 8A02 mov al, byte ptr [edx] ; 迭代字串
004012C8 84C0 test al, al ; 迭代完毕?
004012CA je short 004012D4 ; 则跳转
004012CC 03C8 add ecx, eax ; 累加
004012CE C1C1 rol ecx, ; 循环左移8位
004012D1 inc edx ; 循环变量自增
004012D2 ^ EB F2 jmp short 004012C6
004012D4 83F1 xor ecx, ; 结果与2异或
004012D7 83E9 sub ecx,
004012DA 81F1 xor ecx, ; 结果与1337异或
004012E0 push esi
004012E1 :8B35 >mov si, word ptr [] ; 获取当前系统年份
004012E8 :03CE add cx, si ; 加入cx
004012EB 803D FA124000 C>cmp byte ptr [4012FA], 0CC ; 检测断点,发现则跳转出错
004012F2 je short
004012F4 5E pop esi
004012F5 A1 5F624000 mov eax, dword ptr [40625F] ; 获取序列号
004012FA 3BC1 cmp eax, ecx ; 与F(用户名)的结果是否一致?
004012FC jnz short ; 否则置406263为1
004012FE 33C0 xor eax, eax
EB 0E jmp short
33C0 xor eax, eax
inc eax
EB jmp short
C605 >mov byte ptr [],
0040130E EB jmp short
C605 >mov byte ptr [],
C9 leave
C2 retn

该子程序布下了简单的反调试,众所周知,断点的原理是将指定地址的指令替换为int 3中断,int 3的十六进制表示为0CC。通过实时检测载入内存的指令是否是0CC,就可以判断自身有没有被调试。在不改动程序文件的条件下,我们只能尽量少下断点,避免触发反调试。

回到剩下的关键算法:

004011E6    803D  >cmp     byte ptr [],
004011ED je short
004011EF 85C0 test eax, eax
004011F1 jnz short 0040120A
004011F3 push ; ASCII "Congratulations! You are now level 2! :-)"
004011F8 D2070000 push 7D2
004011FD FF75 push dword ptr [ebp+]
E8 call <jmp.&user32.SetDlgItemTextA>
E9 jmp 004012A2
0040120A 803D 1C124000 C>cmp byte ptr [40121C], 0CC
1F je short
803D C>cmp byte ptr [], 0CC
0040121A je short
0040121C 6A push
0040121E D9604000 push 004060D9 ; ASCII "Sorry, that is incorrect my mate. Try again."
D2070000 push 7D2
FF75 push dword ptr [ebp+]
0040122B E8 4C010000 call <jmp.&user32.SetDlgItemTextA>
EB jmp short 004012A2
push ; ASCII "Debugger detected, check cancelled!"
D2070000 push 7D2
0040123C FF75 push dword ptr [ebp+]
0040123F E8 call <jmp.&user32.SetDlgItemTextA>
EB 5C jmp short 004012A2
push ; ASCII "Name must be between 5 and 51 length"
0040124B D2070000 push 7D2
FF75 push dword ptr [ebp+]
E8 call <jmp.&user32.SetDlgItemTextA>

至此,程序算法流程已经分析完毕。马上动手编写注册机。

我们直接打开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(); if ( len <= && len >= ){ //格式控制。
unsigned int sum = ; for ( int i = ; i != len ; i++ ){
sum += str[i];
sum = ( sum >> ( - ) ) | ( sum << ); //循环左移8位
} sum = ( (sum ^ ) - 0x50 ) ^ 0x1337; SYSTEMTIME st;
CString strDate,strTime;
GetLocalTime(&st); //获取系统时间
int year = st.wYear; __asm{ //为了防止进位内嵌汇编进行低位相加。
push eax;
push ebx; mov eax,year;
mov ebx,sum; add bx,ax;
mov sum,ebx; pop ebx;
pop eax;
} CString PassWord;
PassWord.Format( "%u",sum );
SetDlgItemText( IDC_EDIT_PASSWORD,PassWord );
}
else
MessageBox( "用户名格式错误!" );

再在OnInitDialog中添加此代码修改标题:SetWindowText(_T("TDC‘s keygenme_Keygen"));

运行效果:

至此,TDC‘s keygenme的破解就完成了。

PS:情人节到了,愿天下情侣可以天长地久,也希望和我一样的单身汪不要气馁,多多努力,争取早日脱单。

祝诸君,胸中沟壑自成!

深入底层逆向分析TDC‘s keygenme(手脱压缩壳)的更多相关文章

  1. 简单脱壳教程笔记(2)---手脱UPX壳(1)

    本笔记是针对ximo早期发的脱壳基础视频教程,整理的笔记. ximo早期发的脱壳基础视频教程 下载地址如下: http://down.52pojie.cn/%E5%90%BE%E7%88%B1%E7% ...

  2. 【个人笔记】ximo早期发的脱壳教程——手脱UPX壳

    [个人笔记]ximo早期发的脱壳教程--手脱UPX壳   壳分为两种:压缩壳和加密壳,UPX是一种很简单的压缩壳.   手脱UPX壳: 工具:ExeinfoPE.OD 对象:rmvbfix 方法1:单 ...

  3. 填坑专记-手脱FSG壳

      妈呀,脱FGS壳真的是坎坷颇多,多亏吾爱破解前辈们的帮忙.我一定要记录下来,省的以后再无法解决.   已经查看是FSG壳了.找到入口也容易了.重点就是脱壳并修复好它. 脱壳   OEP为:   使 ...

  4. 简单脱壳教程笔记(8)---手脱EZIP壳

    本笔记是针对ximo早期发的脱壳基础视频教程,整理的笔记.本笔记用到的工具下载地址: http://download.csdn.net/detail/obuyiseng/9466056 EZIP壳 : ...

  5. <逆向学习第三天>手动脱FSG壳,修复IAT。

    其实对于简单的壳来说,脱壳常用的方法也无非是那几种,但是每种有每种的好处,具体使用那种方法视情况而定,我今天学习的这个壳很简单,但是重点在于修复IAT. 一.查壳: FSG 2.0的壳. 二.脱壳: ...

  6. 手脱UPX壳的方法

    0X00    了解 upx UPX作为一款元老级PE加密壳,在以前的那个年代盛行,著名病毒[熊猫烧香]就是使用这款加密壳. 0X01    单步跟踪法 就是使用ollydbg加载程序后,按F8进行单 ...

  7. 手脱无名壳tslgame_rl

    1.使用Detect It Easy查壳,该壳未显示出壳信息,至于为何有壳,我们使用IDA打开,查看其的导入表,其中没有太多函数使用: 2.我们使用x32dbg打开,运行至入口点,此处没有pushad ...

  8. 手脱PESpin壳【06.exe】

    1.查壳 2.LoradPE工具检查 一方面可以用LoradPE工具查看重定位,另一方面也可获取一些详细信息 3.查找OEP ①未发现pushad 开始未发现pushad,进行单步步入,很快就能找到p ...

  9. 手脱NsPacK壳

    1.查壳 使用PEiD未能检测到壳信息,这时,我们更换其他工具 从图中可以看到壳的信息为[NsPacK(3.x)[-]] 2.百度壳信息 北斗程序压缩(Nspack)是一款压缩壳.主要的选项是:压缩资 ...

随机推荐

  1. Node.js 的module 系统

    相较于原生的JavaScript,不同的JavaScript文件之间很难共享变量.有鉴于此,Node.js在JavaScript的基础上进行了扩充,引入了require,exports,module三 ...

  2. ExtJs Column 显示文字内容过长 使用Tootip显示全部内容

    { text: 'Column Header Blah', dataIndex: 'blah', renderer: function(value, metaData, record, rowIdx, ...

  3. Maven进价:Maven的安装和目录结构

    一.在windows上安装Maven 1.下载 下载地址:http://maven.apache.org/download.html 下载最新版本 maven3.2.5 2.解压 解压地址:F:\Ja ...

  4. Unity 摄像机Clear Flags和Culling Mask属性用途详解

    原文地址:http://blog.csdn.net/tanmengwen/article/details/8798231 1.简述两个属性 1.1 Clear Flags 清除标记 每个相机在渲染时会 ...

  5. DDD:Strategic Domain Driven Design with Context Mapping

    Introduction Many approaches to object oriented modeling tend not to scale well when the application ...

  6. excel导入记录

    use DangJianSELECT vale1, value2 into Table2 from Table1 select COUNT(*) from tmpdangyuan where 手机号 ...

  7. web前端学习路线与书籍推荐

    什么是web前端? 在以前,通俗的讲是网页制作,在现在,哼哼,可以参考这篇文章 http://tieba.baidu.com/p/4817153404 那么如果高效优雅的学习web呢? 注:以下纯属个 ...

  8. python之IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  9. CSS中的rem

    为什么会使用rem呢?主要还是浏览器和设备的大小不一. 这样就涉及到页面布局的不统一啦,先说说pc中的多栏布局吧,多栏布局有三种基本的实现方式:固定宽度.流动.弹性,下面我们就分别说说这三种布局吧. ...

  10. [Solution] DI原理解析及Castle、Unity框架使用

    本节目录 DI介绍 DI基本原理 DI框架 Castle Windsor Unity Autofac Spring.Net DI介绍 控制反转(Inversion of Control,英文缩写为Io ...