菜鸟 学注册机编写之 “MD5”
测试环境
系统: xp sp3
调试器 :od 1.10
sc_office_2003_pro
高手不要见笑,仅供小菜玩乐,有不对或不足的地方还请多多指教,不胜感激!
一:定位关键CALL
1. 因为该软件是word插件,所以用OD载入word.exe,F9运行,运行后如下图:

2. 点击按钮”Save As PDF”出现如下界面

3. 点击”Register”随便输入用户名与注册码,如下图:

4.点击 “暂停” 点击 “K” ,来到如下图的地方

5.选择”MessageBoxExW” 右键 “显示调用”,然后在函数尾下好断点,F9运行,点”确定”,就会被断下

6.接下来就是一直F8单步走,来到如下图的地方

7.往上找就能找到关键跳与关键CALL,如下图

8.在关键CALL下好断点后重新载入OD, F9运行,随便输入用户名与注册码,接着就是分析算法了
二:算法分析
1.首先将注册码中含有小写字母转换成大写
1010EC3B 8BC6 mov eax,esi 1010EC3D :391E cmp word ptr ds:[esi],bx ; ---将字母转换成大写
010EC40 1B je short doc2pdf.1010EC5D010EC42 0FB708 movzx ecx,word ptr ds:[eax] ; 判断并取字符
010EC45 83F9 cmp ecx,0x61 ; ECX小于a 就跳
010EC48 0B jb short doc2pdf.1010EC55010EC4A 83F9 7A cmp ecx,0x7A ; ECX大于z 就跳
010EC4D ja short doc2pdf.1010EC55010EC4F 83C1 E0 add ecx,-0x20 ; 满足条件就将ECX and -0x20
010EC52 : mov word ptr ds:[eax],cx ; 存放
010EC55 83C0 add eax,0x2 1010EC58 : cmp word ptr ds:[eax],bx 1010EC5B ^ E5 jnz short doc2pdf.1010EC42 ; 判断是否完成
010EC5D 33C0 xor eax,eax 1010EC5F E9 E2000000 jmp doc2pdf.1010ED46
2.分析关键 call doc2pdf.100182D0 , F7跟进
E8 25F0FFFF call <doc2pdf.strcat> ;用户名与固定字符串拼接
001741A E8 F1F3FEFF call <doc2pdf.MtoB> ; 将用户名中字母转换成大写
010EC3D :391E cmp word ptr ds:[esi],bx ; ---将字母转换成大写
010EC40 1B je short doc2pdf.1010EC5D010EC42 0FB708 movzx ecx,word ptr ds:[eax] ; 判断并取字符
010EC45 83F9 cmp ecx,0x61 ; ECX小于a 就跳
010EC48 0B jb short doc2pdf.1010EC55010EC4A 83F9 7A cmp ecx,0x7A ; ECX大于z 就跳
010EC4D ja short doc2pdf.1010EC55010EC4F 83C1 E0 add ecx,-0x20 ; 满足条件就将ECX and -0x20
010EC52 : mov word ptr ds:[eax],cx ; 存放
010EC55 83C0 add eax,0x2 1010EC58 : cmp word ptr ds:[eax],bx 1010EC5B ^ E5 jnz short doc2pdf.1010EC42 ; 判断是否完成
010EC5D 33C0 xor eax,eax 1010EC5F E9 E2000000 jmp doc2pdf.1010ED46 1001744B E8 A0280000 call <doc2pdf.WideCharToMultiByte> ; 将用户名宽字符转换成单字符
001745E E8 FD280000 call <doc2pdf.Remove_digital> ; 去掉用户输入用户名中包含的数字
0019D60 <doc2pd> push ebp 10019D61 8BEC mov ebp,esp 10019D63 push esi 10019D64 8B75 mov esi,dword ptr ss:[ebp+0x8] 10019D67 85F6 test esi,esi 10019D69 je short doc2pdf.10019DA20019D6B 8B55 0C mov edx,dword ptr ss:[ebp+0xC] 10019D6E 85D2 test edx,edx 10019D70 je short doc2pdf.10019DA20019D72 8A0A mov cl,byte ptr ds:[edx] 10019D74 8BC6 mov eax,esi 10019D76 84C9 test cl,cl 10019D78 je short doc2pdf.10019D9F0019D7A 8D9B lea ebx,dword ptr ds:[ebx] 10019D80 80F9 cmp cl,0x61 ; 判断字符a
0019D83 7C jl short doc2pdf.10019D8A0019D85 80F9 7A cmp cl,0x7A ; 判断字符z
0019D88 7E 0A jle short doc2pdf.10019D940019D8A 80F9 cmp cl,0x41 ; 字符A
0019D8D 7C jl short doc2pdf.10019D970019D8F 80F9 5A cmp cl,0x5A ; 字符Z
0019D92 7F jg short doc2pdf.10019D970019D94 880E mov byte ptr ds:[esi],cl 10019D96 inc esi 10019D97 8A4A mov cl,byte ptr ds:[edx+0x1] 10019D9A inc edx 10019D9B 84C9 test cl,cl 10019D9D ^ E1 jnz short doc2pdf.10019D800019D9F 5E pop esi 10019DA0 5D pop ebp 10019DA1 C3 retn001746D E8 7E280000 call <doc2pdf.WideCharToMultiByte> ; 将字串"f4hguNAg"转换成单字符 E8 5D8F0F00 call <doc2pdf.strcat> ; 用户名去掉数字与固定字符串连接
01103E7 <doc2pd> 8BFF mov edi,edi 101103E9 push ebp 101103EA 8BEC mov ebp,esp 101103EC 8B4D mov ecx,dword ptr ss:[ebp+0x8] 101103EF push esi 101103F0 push edi 101103F1 85C9 test ecx,ecx 101103F3 je short doc2pdf.101103FC01103F5 8B7D 0C mov edi,dword ptr ss:[ebp+0xC] 101103F8 85FF test edi,edi 101103FA jnz short doc2pdf.1011040F01103FC E8 B00F0000 call doc2pdf.101113B1 6A push 0x16 5E pop esi mov dword ptr ds:[eax],esi E8 B4490000 call doc2pdf.10114DBF011040B 8BC6 mov eax,esi 1011040D EB jmp short doc2pdf.011040F 8B55 mov edx,dword ptr ss:[ebp+0x10] 85D2 test edx,edx jnz short doc2pdf.1011041B C601 mov byte ptr ds:[ecx],0x0 ^ EB E1 jmp short doc2pdf.101103FC011041B 8BF1 mov esi,ecx 1011041D 803E cmp byte ptr ds:[esi],0x0 ; 判断用户是否为0 je short doc2pdf. inc esi 4F dec edi ^ F7 jnz short doc2pdf.1011041D 85FF test edi,edi ^ EC je short doc2pdf.011042A 2BF2 sub esi,edx 1011042C 8A02 mov al,byte ptr ds:[edx] 1011042E mov byte ptr ds:[esi+edx],al ; ----字符串f4hguNAg与用户名连接 inc edx 84C0 test al,al je short doc2pdf. 4F dec edi ^ F3 jnz short doc2pdf.1011042C 85FF test edi,edi 1011043B jnz short doc2pdf.1011044E011043D C601 mov byte ptr ds:[ecx],0x0 E8 6C0F0000 call doc2pdf.101113B1 6A push 0x22 pop ecx mov dword ptr ds:[eax],ecx 1011044A 8BF1 mov esi,ecx 1011044C ^ EB B8 jmp short doc2pdf.011044E 33C0 xor eax,eax 5F pop edi 5E pop esi 5D pop ebp C3 retn
拼接完成后得到字符串 “TESTf4hguNAg”
将拼接完成后的字符传入函数进行计算, F7跟进,观察函数发下如下图所示特征

貌似MD5计算,我们直接让该函数走完,看它会出什么结果,发现函数执行完后与我们用工具直接对字符串” TESTf4hguNAg”进行MD5的结果是一样的。如下图

然后将计算得到的MD5值转换成字符,并且将小写字母转换成大写,如下图

3.查找并替换MD5中的字符
100183E2 6A 5A push 0x5A ; Z
00183E4 6A push 0x31 ;
00183E6 8D8D 44FEFFFF lea ecx,dword ptr ss:[ebp-0x1BC] 100183EC E8 6FE3FEFF call <doc2pdf.Find_and_Replace> ; 查找第1个参数,找到则用第2个替换
1替换成Z
2替换成W
0替换成K
3替换成T
8替换成P
7替换成S
<doc2pd> push ebp
8BEC mov ebp,esp
83EC sub esp,0x8
:8B45 mov ax,word ptr ss:[ebp+0x8]
1000676A push ebx
1000676B push edi
1000676C 33FF xor edi,edi
1000676E 8BD9 mov ebx,ecx
897D F8 mov dword ptr ss:[ebp-0x8],edi
:3B45 0C cmp ax,word ptr ss:[ebp+0xC]
je short doc2pdf.100067EB
8B03 mov eax,dword ptr ds:[ebx]
1000677B push esi
1000677C 8B70 F4 mov esi,dword ptr ds:[eax-0xC]
1000677F 32C9 xor cl,cl
3BF7 cmp esi,edi
7E jle short doc2pdf.100067EA
:8B55 mov dx,word ptr ss:[ebp+0x8]
: cmp word ptr ds:[eax+edi*],dx ; 比较MD5值中是否有传进的第1个参数
000678D jnz short doc2pdf.100067C6000678F 84C9 test cl,cl
jnz short doc2pdf.100067BB
C645 FF mov byte ptr ss:[ebp-0x1],0x1
85F6 test esi,esi
5B js short doc2pdf.100067F6000679B 8B03 mov eax,dword ptr ds:[ebx] ; ----MD5值地址
000679D 8B50 F8 mov edx,dword ptr ds:[eax-0x8]
100067A0 B9 mov ecx,0x1
100067A5 2B48 FC sub ecx,dword ptr ds:[eax-0x4]
100067A8 2BD6 sub edx,esi
100067AA 0BCA or ecx,edx ; 0xA
00067AC 7D jge short doc2pdf.100067B600067AE push esi
100067AF 8BCB mov ecx,ebx
100067B1 E8 BAEDFFFF call doc2pdf.00067B6 8B03 mov eax,dword ptr ds:[ebx] ; ---MD5值地址
00067B8 8A4D FF mov cl,byte ptr ss:[ebp-0x1]
100067BB :8B55 0C mov dx,word ptr ss:[ebp+0xC] ; ---函数传进来的第2个参数
00067BF FF45 F8 inc dword ptr ss:[ebp-0x8]
100067C2 : mov word ptr ds:[eax+edi*],dx ; 将传进的第2个参数替换掉MD5中查到的值
00067C6 8D7C3F lea edi,dword ptr ds:[edi+edi+0x2]
100067CA D1FF sar edi,00067CC 3BFE cmp edi,esi ; 判断是否查找结束
00067CE ^ 7C B5 jl short doc2pdf.00067D0 84C9 test cl,cl
100067D2 je short doc2pdf.100067EA00067D4 85F6 test esi,esi
100067D6 1E js short doc2pdf.100067F600067D8 8B03 mov eax,dword ptr ds:[ebx]
100067DA 3B70 F8 cmp esi,dword ptr ds:[eax-0x8]
100067DD 7F jg short doc2pdf.100067F600067DF F4 mov dword ptr ds:[eax-0xC],esi
100067E2 8B03 mov eax,dword ptr ds:[ebx]
100067E4 33C9 xor ecx,ecx
100067E6 :890C70 mov word ptr ds:[eax+esi*],cx
100067EA 5E pop esi
100067EB 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
100067EE 5F pop edi
100067EF 5B pop ebx
100067F0 8BE5 mov esp,ebp
100067F2 5D pop ebp
100067F3 C2 retn 0x8
//--获得注册码
1001844B E8 90D9FEFF call <doc2pdf.Get12Char> ; --获取MD5替换后前12字节
6A 0C push 0xC
8D8D 38FEFFFF lea ecx,dword ptr ss:[ebp-0x1C8]
push ecx
8BCB mov ecx,ebx
1001845B C645 FC mov byte ptr ss:[ebp-0x4],0x2
1001845F E8 7CD9FEFF call <doc2pdf.Get12Char> ; --获取用户输入注册码12字节
8B00 mov eax,dword ptr ds:[eax]
4.比较注册码,如下图

1010EB5D 8BFF mov edi,edi
1010EB5F push ebp
1010EB60 8BEC mov ebp,esp
1010EB62 833D 78EA1810 >cmp dword ptr ds:[0x1018EA78],0x0
1010EB69 push esi
1010EB6A jnz short doc2pdf.1010EBD5010EB6C 8B75 mov esi,dword ptr ss:[ebp+0x8]
1010EB6F 85F6 test esi,esi
1010EB71 jnz short doc2pdf.1010EB8A010EB73 E8 call doc2pdf.101113B1010EB78 C700 mov dword ptr ds:[eax],0x16
1010EB7E E8 3C620000 call doc2pdf.10114DBF010EB83 B8 FFFFFF7F mov eax,0x7FFFFFFF
1010EB88 EB 5B jmp short doc2pdf.1010EBE5010EB8A 8B4D 0C mov ecx,dword ptr ss:[ebp+0xC]
1010EB8D 85C9 test ecx,ecx
1010EB8F ^ E2 je short doc2pdf.1010EB73010EB91 2BF1 sub esi,ecx
1010EB93 0FB7040E movzx eax,word ptr ds:[esi+ecx] ; 取MD5后生成的注册码
1010EB97 83F8 cmp eax,0x41 ; A
1010EB9A 0D jb short doc2pdf.1010EBA9010EB9C 83F8 5A cmp eax,0x5A ; Z
1010EB9F ja short doc2pdf.1010EBA9010EBA1 83C0 add eax,0x20 ; 转换成小写
1010EBA4 0FB7D0 movzx edx,ax ; 给值dx
1010EBA7 EB jmp short doc2pdf.1010EBAB010EBA9 8BD0 mov edx,eax
1010EBAB 0FB701 movzx eax,word ptr ds:[ecx] ; 取用户输入的注册码
1010EBAE 83F8 cmp eax,0x41 ; A
1010EBB1 0B jb short doc2pdf.1010EBBE010EBB3 83F8 5A cmp eax,0x5A ; Z
1010EBB6 ja short doc2pdf.1010EBBE010EBB8 83C0 add eax,0x20 ; 转换成小写
1010EBBB 0FB7C0 movzx eax,ax
1010EBBE 83C1 add ecx,0x2
1010EBC1 :85D2 test dx,dx ; 判断是否为零
1010EBC4 je short doc2pdf.1010EBCB010EBC6 :3BD0 cmp dx,ax ; 比较注册码
1010EBC9 ^ C8 je short doc2pdf.1010EB93010EBCB 0FB7C8 movzx ecx,ax
1010EBCE 0FB7C2 movzx eax,dx
1010EBD1 2BC1 sub eax,ecx
1010EBD3 EB jmp short doc2pdf.1010EBE5010EBD5 6A push 0x0
1010EBD7 FF75 0C push dword ptr ss:[ebp+0xC]
1010EBDA FF75 push dword ptr ss:[ebp+0x8]
1010EBDD E8 78FEFFFF call doc2pdf.1010EA5A010EBE2 83C4 0C add esp,0xC
1010EBE5 5E pop esi
1010EBE6 5D pop ebp
1010EBE7 C3 retn
总结
1. 将用户输入的注册码中小写字母转换成大写
2. 将用户名中数字去掉并将字母转换成大写
3. 将用户名与固定字符拼接
4. 将拼接后的字符进行MD5计算并且将值转换成字符
5. 查找替换MD5字符
6. 取MD5前12字节做注册码
注册机编写
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include "md5.h" /****************************************************************************
函数名称: hex_to_str
函数功能: 十六进制转字符串
输入参数: ptr 字符串 buf 十六进制 len 十六进制字符串的长度。
输出参数: 无
*****************************************************************************/ void hex_to_str(char *ptr,unsigned char *buf,int len)
{
int i=;
for(i = ; i < len; i++)
{
sprintf(ptr, "%02x",buf[i]);
ptr += ;
}
} /*
MD5: 转换成大写的MD5值
Val: 要查找到值
RpVal: 要替换的值
*/
void FindVal_Replace(char* MD5, char Val, char RpVal)
{ int i = ; if (NULL == MD5 || == Val || == RpVal)
{
return;
} for (i=; i<strlen(MD5); i++)
{
if ( Val == MD5[i] )
{
MD5[i] = RpVal;
}
}
} int main(int argc, char* argv[])
{
char UserName[] = {};
char License[] = {};
char BigStrName[] = {};
char MD5[] = {}; //与用户名拼凑
char *ConstString = "f4hguNAg"; MD5_CTX context;
long dtLength;
char szHash[] = {};
TCHAR szBuffer[] = {};
int i = ;
int n = ;
char j = ;
printf("---------doc2pdf2 V5.0注册机-------\n\n"); printf("请输入用户名: ");
scanf("%s",UserName);
if ( strlen(UserName) >= )
{
printf("用户名不能超过240位\n");
return -;
} for (i=; i<strlen(UserName); i++)
{
//--是数字
if (isdigit(UserName[i]) != )
{
continue;
}
else
{
//--是字母
if ( isalpha(UserName[i])!=)
{
//--判断是大小写并转换成大写
if(UserName[i]>='a'&& UserName[i]<='z')
{
BigStrName[i] = UserName[i] - ;
continue;
}
} }
} //--用户名与固定字符拼凑并计算MD5值
strcat(BigStrName,ConstString);
// strncpy(BigStrName+strlen(BigStrName), ConstString, strlen(ConstString)); //计算MD5值
MD5Init(&context);
MD5Update(&context, BigStrName, strlen(BigStrName));
MD5Final(szHash, &context); //--将MD5值转换成字符
hex_to_str(MD5, szHash, strlen(szHash)); //--将MD5字符串转换成大写
for (n=; n<strlen(MD5); n++)
{
//--判断是大小写并转换成大写
if(MD5[n]>='a'&& MD5[n]<='z')
{
MD5[n] -= ;
continue;
}
} //--查找并替换掉MD5字符
FindVal_Replace(MD5, '', 'Z');//1替换成Z FindVal_Replace(MD5, '', 'W');//2替换成W FindVal_Replace(MD5, '', 'K');//0替换成K FindVal_Replace(MD5, '', 'T');//3替换成T FindVal_Replace(MD5, '', 'P');//8替换成P FindVal_Replace(MD5, '', 'S');//7替换成S //-拷贝注册码
strncpy(License, MD5, ); printf("注册码:%s\n",License);
system("pause"); return ;
}
测试注册机
输入用户名 test 生成注册码

注册成功

样本及注册机源码下载
http://yunpan.cn/cAFbdqsBEYEyr (提取码:2967)
菜鸟 学注册机编写之 “MD5”的更多相关文章
- 菜鸟 学注册机编写之 Android app
0x00前言 环境及工具: 手机 Nexus 4(己root) 系统版本 Android 5.01 工具 AndroidKiller_V1.2 关于Android平台app注册机的编 ...
- 菜鸟 学注册机编写之 “RSA”
测试环境 系统: xp sp3 调试器 :od 1.10 RSA简单介绍 选取两个别人不知道的大素数p, q. 公共模n = p*q 欧拉值φ(n) = (p-1)(q-1) 选取公匙(加密匙) e ...
- 菜鸟 学注册机编写之 “sha1”
1. 首先运行程序随便输入用户与注册码如下图所示: 2.将程序载入OD, 下MessageBoxA函数断点, F9运行程序, 程序运行后随便输入用户名与注册码,点"OK"后断下,F ...
- 010 Editor 8.0.1 之 逆向分析及注册机编写
前言一.工具及软件介绍二.逆向分析2.1.找到提示错误注册弹窗2.2.分析跳转处代码2.3.=2D 函数分析2.3.1.获取注册码处分析2.3.2.3处分支分析2.3.2.1.9C情况2.3.2.2. ...
- 010 Editor v8.0.1(32 - bit) 算法逆向分析、注册机编写
010 Editor 的逆向分析整体算下来还是比较简单的,将程序拖入OD,通过字符串搜索定位到核心代码,经过分析,主要是如下图所示的两个关键函数,返回正确的值,才算是注册成功. 00409C9B 这个 ...
- 用C#.NET编写软件注册机
验证注册码是保护软件产品产权的常用手段.一般过程如下, 1. 软件发行者收集用户特有的信息: 2. 根据用户特有的信息,使用注册机生成注册码并把注册码发给客户: 3. 向软件导入注册码,由软件自 ...
- OD 实验(十八) - 简单注册机的编写
程序: 运行 这是一个注册机 随便输入点内容,点击 Check 弹出错误的对话框 逆向: 用 OD 载入程序 在文本框处下断点 按 Alt+B 查看断点 这个断点在动态链接库那里 跑一下程序,输入内容 ...
- 【转】破解Source Insight 3.5.0072过程 附:安装软件+注册机
转载地址:http://blog.csdn.net/qs_hud/article/details/8884867 注册机及软件下载地址:http://download.csdn.net/detail/ ...
- 菜鸟学自动化测试(八)----selenium 2.0环境搭建(基于maven)
菜鸟学自动化测试(八)----selenium 2.0环境搭建(基于maven) 2012-02-04 13:11 by 虫师, 11419 阅读, 5 评论, 收藏, 编辑 之前我就讲过一种方试来搭 ...
随机推荐
- R: 数据结构、数据类型的描述。
################################################### 问题:数据结构..类型 18.4.27 有哪些数据结构.类型?? 各自有什么特点? 解决方案 ...
- (转自精通Python设计模式)Python设计模式之创建型模式——2.建造者模式
建造者模式将一个复杂对象的构造过程与其表现分离,这样,同一个构造过程可用于创建多个不同的表现. 我们来看个实际的例子,假设我们想要创建一个HMTL页面生成器,HTML页面的基本结构(构造组件)通常是一 ...
- kali linux学习笔记之系统定制及优化(附:中文输入法设置)
fix update flash plugin on kali rolling author:@kerker 0x00设置软件源 root@kali:~# vim /etc/apt/sources.l ...
- PHP开源系统学习之fluxbb_1
最近一直忙于做项目,虽说做了点新东西.感觉自己进步不是很大,总体水平还是跟半年前差不多,想到的东西跟以前差不多,写出来的东西也跟以前差不多.只是现在做的东西多些,比以前敢做了. 近期准备利用点时间,读 ...
- 在Android中使用Protocol Buffers(中篇)
本文来自网易云社区. FlatBuffers 编码原理 FlatBuffers的Java库只提供了如下的4个类: ./com/google/flatbuffers/Constants.java ./c ...
- JsonParse类
using System.Data; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using Syst ...
- [CentOS7] minimal安装后 出现 没有ifconfig 无法ping 无法yum could not retrieve mirrorlist http://mirrorlist.centos.org/
刚以minimal方式安装完CentOS,打算看下ip,结果ifconfig没找到(后来得知可以用ip addr查看本机ip) 于是yum grouplist, 结果出现could not retri ...
- wxpython实现文件拖拽
我想让wx.grid里面的单元格能够支持文件拖拽,实现起来挺简单的,共分3步: 1.创建一个wx.FileDropTarget子类的对象,并把要支持拖拽的控件传给它的构造函数,此处是grid 2.调用 ...
- Android代码笔记
1. 如何监听Android的短信收发,自动填充验证码? getContentResolver().registerContentObserver(Uri.parse(SMS_URI_ALL), tr ...
- Mac安装vue
Mac安装vue 一.安装brew 打开终端运行以下命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com ...