-
-
[原创]密码学CrackMe之BlowFish算法CM分析
-
发表于: 2007-10-12 14:27 5149
-
【文章标题】: BlowfishCrackMe.exe分析过程
【文章作者】: coolstar14
【使用工具】: IDA, Peid
【软件名称】: BlowfishCrackMe.exe
【软件大小】: 204KB
【下载地址】: http://bbs.pediy.com/attachment.php?attachmentid=6585&d=1183561757
【软件介绍】: 用BlowFish作为校验算法的CrackMe。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
具体过程:
Ida反汇编, Strings参考, 看到 '恭喜你, 注册码正确!'字样, 查看引用位置, 定位到关键点如下:
在此之前, 是判断两个编辑框不能输入为空等等的操作.
.text:00407255 loc_407255: ; CODE XREF: DialogFunc+12Dj
.text:00407255 lea eax, [ebp+var_310]
.text:0040725B push 0 ; int
.text:0040725D push eax ; char *
.text:0040725E lea ecx, [ebp+inputSn]
.text:00407264 push offset s_Windrand ; "WindRand"
.text:00407269 push ecx ; inputSn
.text:0040726A mov [ebp+var_4], 0
.text:00407271 call sub_406F70 ;获得输入内容和明码比较前, 就这一个函数了, 关键调用.
.text:00407271
.text:00407276 add esp, 10h
.text:00407279 lea edx, [ebp+var_310]
.text:0040727F lea eax, [ebp+InputName]
.text:00407285 push edx ; int
.text:00407286 push eax ; lpString2
.text:00407287 call sub_407030 ;如果做过WindRand密码学的CM, 很容易知道, 这个是比较函数.
.text:00407287
.text:0040728C add esp, 8
.text:0040728F cmp eax, 1
.text:00407292 push 40h ; uType
.text:00407294 push offset Caption ; "注册提示"
.text:00407299 jnz short loc_4072BA
.text:00407299
.text:0040729B push offset s_ZUgmVSI ; "恭喜你,注册码正确!"
.text:004072A0 push esi ; hWnd
.text:004072A1 call ds:MessageBoxA
.text:004072A7 xor eax, eax
.text:004072A9 mov ecx, [ebp+var_C]
Peid 插件 Kanal检查加密算法, 发现Blowfish_s_init在426168, 被地址401372使用, 可以怀疑401372所在函数sub_4010A0是Blowfins_init了.
bp 4010a0 中断它, 运行, 观察堆栈.
0:000> bp 4010a0
*** WARNING: Unable to verify checksum for image00400000
*** ERROR: Module load completed but symbols could not be loaded for image00400000
0:000> g
Breakpoint 0 hit
eax=0012f6e0 ebx=77d6ae36 ecx=003c2138 edx=00000000 esi=00070510 edi=0012f87b
eip=004010a0 esp=0012f6c8 ebp=0012f74c iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
image00400000+0x10a0:
004010a0 64a100000000 mov eax,dword ptr fs:[00000000h] fs:003b:00000000=0012f728
0:000> dds esp L4
0012f6c8 00406f41 image00400000+0x6f41 函数返回地址
0012f6cc 0012f6f0 第一个参数, 查看内容为 WindRand
0012f6d0 00000038 第二个参数, 长度56
0012f6d4 0012f6e0
OK, BlowFish 密钥获得, 长度为56的串, 前面部分为WindRand,不足部分补0.
这儿补充一下, blowfish_init函数key是需要补齐56位的, 不要直接想当然的使用WindRand做为Key, 最初我在这上面是花了不少无用功的.
关键函数:
.text:00406F70 ; int __cdecl sub_406F70(char *inputSn,char *,char *,int)
.text:00406F70 sub_406F70 proc near ; CODE XREF: DialogFunc+171p
.text:00406F70
.text:00406F70 inputSn = dword ptr 8
.text:00406F70 WindRand = dword ptr 0Ch
.text:00406F70 outbuf = dword ptr 10h
.text:00406F70 arg_C = dword ptr 14h
.text:00406F70
.text:00406F70 push ebp
.text:00406F71 mov ebp, esp
.text:00406F73 mov eax, [ebp+WindRand]
.text:00406F76 mov ecx, [ebp+arg_C]
.text:00406F79 push ebx
.text:00406F7A push esi
.text:00406F7B push edi
.text:00406F7C push eax ; char *
.text:00406F7D push ecx ; int
.text:00406F7E call sub_406E50 ; 内有前面分析到的对sub_4010A0 blowfish_init 的调用
.text:00406F7E
.text:00406F83 mov edi, [ebp+inputSn]
.text:00406F86 mov ebx, eax ;sub_406e50调用结果存储到ebx. 从后面分析, 406e50应该是初始化了一个类或结构.
.text:00406F88 or ecx, 0FFFFFFFFh
.text:00406F8B xor eax, eax
.text:00406F8D add esp, 8
.text:00406F90 repne scasb
.text:00406F92 not ecx
.text:00406F94 dec ecx ; ecx = strlen(inputSn)
.text:00406F95 mov esi, ecx
.text:00406F97 shr esi, 1
.text:00406F99 mov eax, esi
.text:00406F9B add eax, 3
.text:00406F9E and al, 0FCh
.text:00406FA0 call __alloca_probe
.text:00406FA0
.text:00406FA5 mov edx, [ebp+inputSn]
.text:00406FA8 mov eax, esp
.text:00406FAA push esi
.text:00406FAB push eax
.text:00406FAC push edx
.text:00406FAD mov [ebp+WindRand], eax
.text:00406FB0 call sub_406E00 ; inputSn-->Hex
.text:00406FB0
.text:00406FB5 lea eax, [esi+1]
.text:00406FB8 add esp, 0Ch
.text:00406FBB mov [ebp+inputSn], eax
.text:00406FBE add eax, 3
.text:00406FC1 and al, 0FCh
.text:00406FC3 call __alloca_probe
.text:00406FC3
.text:00406FC8 mov eax, [ebx] ;eax指向前面怀疑为类的地址
.text:00406FCA mov ecx, ebx
.text:00406FCC mov edi, esp
.text:00406FCE call dword ptr [eax+18h] ; 调用了一个类的函数, 具体做什么的, 不太清楚
.text:00406FD1 mov eax, [ebp+WindRand]
.text:00406FD4 mov edx, [ebx] ;edx 指向前面怀疑为类的地址
.text:00406FD6 push esi
.text:00406FD7 push edi
.text:00406FD8 push eax
.text:00406FD9 mov ecx, ebx
.text:00406FDB call dword ptr [edx+0Ch] ; 调用了一个类的函数, blowfish_de(in, out, len)
.text:00406FDE mov eax, [ebp+inputSn]
.text:00406FE1 mov byte ptr [edi+esi], 0
.text:00406FE5 add eax, 3
.text:00406FE8 and al, 0FCh
.text:00406FEA call __alloca_probe
.text:00406FEA
.text:00406FEF or ecx, 0FFFFFFFFh
.text:00406FF2 xor eax, eax
.text:00406FF4 repne scasb
.text:00406FF6 not ecx
.text:00406FF8 sub edi, ecx
.text:00406FFA mov edx, esp
.text:00406FFC mov eax, ecx
.text:00406FFE mov esi, edi
.text:00407000 mov edi, edx
.text:00407002 push edx ; lpString2
.text:00407003 shr ecx, 2
.text:00407006 rep movsd
.text:00407008 mov ecx, eax
.text:0040700A and ecx, 3
.text:0040700D rep movsb
.text:0040700F mov ecx, [ebp+outbuf]
.text:00407012 push ecx ; lpString1
.text:00407013 call ds:lstrcpyA
.text:00407019 lea esp, [ebp-0Ch]
.text:0040701C pop edi
.text:0040701D pop esi
.text:0040701E pop ebx
.text:0040701F pop ebp
.text:00407020 retn
.text:00407020
.text:00407020 sub_406F70 endp
.text:00407020
关键函数比较简单而且清晰, 与BlowFish算法也相符. 引用一段:
7baK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4m8W2k6r3W2&6i4K6u0W2j5$3!0E0i4K6u0r3N6s2g2@1L8%4u0A6j5h3I4Q4x3V1k6U0K9r3q4H3y4W2)9J5c8V1y4Z5j5i4l9$3i4K6u0V1x3#2)9J5k6o6k6Q4x3X3g2Z5N6r3@1`.
用BlowFish算法解密,同样也需要两个过程。
1.密钥预处理
2.信息解密
可以看到这儿是把我们输入的序列号转为16进制解密, 解密后的结果放置到输出缓冲区, 用于在sub_406F70调用后, 使用sub_407030与输入的用户名比较, 如果相符即注册成功.
获得注册码, 我们需要做的是:
BlowFins_Encrypt(用户名) 用户名需补齐被8整除, 结果转为16进制字符串表示即OK.
注册机借用 PEDIY CrackMe2007 包中 加密算法\ blowfish\ happytown 23th crackme 中所带的注册机的实现代码, 稍微修改一下以符合本CM的要求.
CrackMe2007 可以从论坛置顶(110K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0T1M7K6q4Q4x3X3g2H3k6h3c8A6P5g2)9J5k6h3y4G2L8g2)9J5c8Y4y4Z5L8%4N6@1K9s2u0W2j5h3c8Q4x3X3g2H3K9s2m8Q4x3@1k6@1i4K6y4p5y4o6V1#2z5o6k6Q4x3U0W2Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8e0k6Q4z5o6W2Q4b7V1g2Q4c8e0g2Q4z5o6S2Q4b7U0m8Q4x3V1x3`. 一层层点击进入, 即可找到happytown 23th 的注册机, 修改其main函数如下即可.
string nameStr;
cout << "Enter your name here:" << endl;
cin >> nameStr;
// BLOWFISH算法实现如下:
unsigned char bfKey[56];
memset(bfKey, 0, 56);
memcpy(bfKey, "WindRand", 8); // 密钥
int lenFix = nameStr.size();
unsigned char Text[1024]; // 源串
memset(Text, 0, 1024); // 这里是把源串补足部分全填0了. 如果不填0, 只需要保证字符串结尾处有个0, 后面的内容是随便填充的,得出的注册码也会不同.
memcpy(Text, nameStr.c_str(), lenFix);
if(lenFix % 8)
lenFix = lenFix + (8-lenFix%8);
CBlowFish myBlowFish(bfKey, 56); // bushfish_init
unsigned char out[1024] = {0x0}; // 目的缓冲区
myBlowFish.Encrypt(Text, out, lenFix); // lenFix需为8的倍数, 不足补0
char bResult[1024] = {0x0};
CharStr2HexStr(out, bResult, lenFix);
cout << "\n"
<< "Your serial number is:"
<< "\n"
<< bResult
<< "\n\n";
一组符合的注册码:
coolstar14
05F4D42F5CC84A798BAC0B0CCF9E80AB
另外因为有填充字节的存在, 注册码并不唯一, 如下这一组也是可以的.
coolstar14
05F4D42F5CC84A7987214C3FB6D9501C
最后感谢WindRand大侠提供的加密算法系列的简单CM, 当我恰好想了解BlowFish时有例子可以做. 另:WindRand大侠是要求深入到加密算法中的, 这个... 偶功力实在不够而且深入到一个成熟的算法中个人觉得也没有太大必要的吧.
【文章作者】: coolstar14
【使用工具】: IDA, Peid
【软件名称】: BlowfishCrackMe.exe
【软件大小】: 204KB
【下载地址】: http://bbs.pediy.com/attachment.php?attachmentid=6585&d=1183561757
【软件介绍】: 用BlowFish作为校验算法的CrackMe。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
具体过程:
Ida反汇编, Strings参考, 看到 '恭喜你, 注册码正确!'字样, 查看引用位置, 定位到关键点如下:
在此之前, 是判断两个编辑框不能输入为空等等的操作.
.text:00407255 loc_407255: ; CODE XREF: DialogFunc+12Dj
.text:00407255 lea eax, [ebp+var_310]
.text:0040725B push 0 ; int
.text:0040725D push eax ; char *
.text:0040725E lea ecx, [ebp+inputSn]
.text:00407264 push offset s_Windrand ; "WindRand"
.text:00407269 push ecx ; inputSn
.text:0040726A mov [ebp+var_4], 0
.text:00407271 call sub_406F70 ;获得输入内容和明码比较前, 就这一个函数了, 关键调用.
.text:00407271
.text:00407276 add esp, 10h
.text:00407279 lea edx, [ebp+var_310]
.text:0040727F lea eax, [ebp+InputName]
.text:00407285 push edx ; int
.text:00407286 push eax ; lpString2
.text:00407287 call sub_407030 ;如果做过WindRand密码学的CM, 很容易知道, 这个是比较函数.
.text:00407287
.text:0040728C add esp, 8
.text:0040728F cmp eax, 1
.text:00407292 push 40h ; uType
.text:00407294 push offset Caption ; "注册提示"
.text:00407299 jnz short loc_4072BA
.text:00407299
.text:0040729B push offset s_ZUgmVSI ; "恭喜你,注册码正确!"
.text:004072A0 push esi ; hWnd
.text:004072A1 call ds:MessageBoxA
.text:004072A7 xor eax, eax
.text:004072A9 mov ecx, [ebp+var_C]
Peid 插件 Kanal检查加密算法, 发现Blowfish_s_init在426168, 被地址401372使用, 可以怀疑401372所在函数sub_4010A0是Blowfins_init了.
bp 4010a0 中断它, 运行, 观察堆栈.
0:000> bp 4010a0
*** WARNING: Unable to verify checksum for image00400000
*** ERROR: Module load completed but symbols could not be loaded for image00400000
0:000> g
Breakpoint 0 hit
eax=0012f6e0 ebx=77d6ae36 ecx=003c2138 edx=00000000 esi=00070510 edi=0012f87b
eip=004010a0 esp=0012f6c8 ebp=0012f74c iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
image00400000+0x10a0:
004010a0 64a100000000 mov eax,dword ptr fs:[00000000h] fs:003b:00000000=0012f728
0:000> dds esp L4
0012f6c8 00406f41 image00400000+0x6f41 函数返回地址
0012f6cc 0012f6f0 第一个参数, 查看内容为 WindRand
0012f6d0 00000038 第二个参数, 长度56
0012f6d4 0012f6e0
OK, BlowFish 密钥获得, 长度为56的串, 前面部分为WindRand,不足部分补0.
这儿补充一下, blowfish_init函数key是需要补齐56位的, 不要直接想当然的使用WindRand做为Key, 最初我在这上面是花了不少无用功的.
关键函数:
.text:00406F70 ; int __cdecl sub_406F70(char *inputSn,char *,char *,int)
.text:00406F70 sub_406F70 proc near ; CODE XREF: DialogFunc+171p
.text:00406F70
.text:00406F70 inputSn = dword ptr 8
.text:00406F70 WindRand = dword ptr 0Ch
.text:00406F70 outbuf = dword ptr 10h
.text:00406F70 arg_C = dword ptr 14h
.text:00406F70
.text:00406F70 push ebp
.text:00406F71 mov ebp, esp
.text:00406F73 mov eax, [ebp+WindRand]
.text:00406F76 mov ecx, [ebp+arg_C]
.text:00406F79 push ebx
.text:00406F7A push esi
.text:00406F7B push edi
.text:00406F7C push eax ; char *
.text:00406F7D push ecx ; int
.text:00406F7E call sub_406E50 ; 内有前面分析到的对sub_4010A0 blowfish_init 的调用
.text:00406F7E
.text:00406F83 mov edi, [ebp+inputSn]
.text:00406F86 mov ebx, eax ;sub_406e50调用结果存储到ebx. 从后面分析, 406e50应该是初始化了一个类或结构.
.text:00406F88 or ecx, 0FFFFFFFFh
.text:00406F8B xor eax, eax
.text:00406F8D add esp, 8
.text:00406F90 repne scasb
.text:00406F92 not ecx
.text:00406F94 dec ecx ; ecx = strlen(inputSn)
.text:00406F95 mov esi, ecx
.text:00406F97 shr esi, 1
.text:00406F99 mov eax, esi
.text:00406F9B add eax, 3
.text:00406F9E and al, 0FCh
.text:00406FA0 call __alloca_probe
.text:00406FA0
.text:00406FA5 mov edx, [ebp+inputSn]
.text:00406FA8 mov eax, esp
.text:00406FAA push esi
.text:00406FAB push eax
.text:00406FAC push edx
.text:00406FAD mov [ebp+WindRand], eax
.text:00406FB0 call sub_406E00 ; inputSn-->Hex
.text:00406FB0
.text:00406FB5 lea eax, [esi+1]
.text:00406FB8 add esp, 0Ch
.text:00406FBB mov [ebp+inputSn], eax
.text:00406FBE add eax, 3
.text:00406FC1 and al, 0FCh
.text:00406FC3 call __alloca_probe
.text:00406FC3
.text:00406FC8 mov eax, [ebx] ;eax指向前面怀疑为类的地址
.text:00406FCA mov ecx, ebx
.text:00406FCC mov edi, esp
.text:00406FCE call dword ptr [eax+18h] ; 调用了一个类的函数, 具体做什么的, 不太清楚
.text:00406FD1 mov eax, [ebp+WindRand]
.text:00406FD4 mov edx, [ebx] ;edx 指向前面怀疑为类的地址
.text:00406FD6 push esi
.text:00406FD7 push edi
.text:00406FD8 push eax
.text:00406FD9 mov ecx, ebx
.text:00406FDB call dword ptr [edx+0Ch] ; 调用了一个类的函数, blowfish_de(in, out, len)
.text:00406FDE mov eax, [ebp+inputSn]
.text:00406FE1 mov byte ptr [edi+esi], 0
.text:00406FE5 add eax, 3
.text:00406FE8 and al, 0FCh
.text:00406FEA call __alloca_probe
.text:00406FEA
.text:00406FEF or ecx, 0FFFFFFFFh
.text:00406FF2 xor eax, eax
.text:00406FF4 repne scasb
.text:00406FF6 not ecx
.text:00406FF8 sub edi, ecx
.text:00406FFA mov edx, esp
.text:00406FFC mov eax, ecx
.text:00406FFE mov esi, edi
.text:00407000 mov edi, edx
.text:00407002 push edx ; lpString2
.text:00407003 shr ecx, 2
.text:00407006 rep movsd
.text:00407008 mov ecx, eax
.text:0040700A and ecx, 3
.text:0040700D rep movsb
.text:0040700F mov ecx, [ebp+outbuf]
.text:00407012 push ecx ; lpString1
.text:00407013 call ds:lstrcpyA
.text:00407019 lea esp, [ebp-0Ch]
.text:0040701C pop edi
.text:0040701D pop esi
.text:0040701E pop ebx
.text:0040701F pop ebp
.text:00407020 retn
.text:00407020
.text:00407020 sub_406F70 endp
.text:00407020
关键函数比较简单而且清晰, 与BlowFish算法也相符. 引用一段:
7baK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4m8W2k6r3W2&6i4K6u0W2j5$3!0E0i4K6u0r3N6s2g2@1L8%4u0A6j5h3I4Q4x3V1k6U0K9r3q4H3y4W2)9J5c8V1y4Z5j5i4l9$3i4K6u0V1x3#2)9J5k6o6k6Q4x3X3g2Z5N6r3@1`.
用BlowFish算法解密,同样也需要两个过程。
1.密钥预处理
2.信息解密
可以看到这儿是把我们输入的序列号转为16进制解密, 解密后的结果放置到输出缓冲区, 用于在sub_406F70调用后, 使用sub_407030与输入的用户名比较, 如果相符即注册成功.
获得注册码, 我们需要做的是:
BlowFins_Encrypt(用户名) 用户名需补齐被8整除, 结果转为16进制字符串表示即OK.
注册机借用 PEDIY CrackMe2007 包中 加密算法\ blowfish\ happytown 23th crackme 中所带的注册机的实现代码, 稍微修改一下以符合本CM的要求.
CrackMe2007 可以从论坛置顶(110K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0T1M7K6q4Q4x3X3g2H3k6h3c8A6P5g2)9J5k6h3y4G2L8g2)9J5c8Y4y4Z5L8%4N6@1K9s2u0W2j5h3c8Q4x3X3g2H3K9s2m8Q4x3@1k6@1i4K6y4p5y4o6V1#2z5o6k6Q4x3U0W2Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8e0k6Q4z5o6W2Q4b7V1g2Q4c8e0g2Q4z5o6S2Q4b7U0m8Q4x3V1x3`. 一层层点击进入, 即可找到happytown 23th 的注册机, 修改其main函数如下即可.
string nameStr;
cout << "Enter your name here:" << endl;
cin >> nameStr;
// BLOWFISH算法实现如下:
unsigned char bfKey[56];
memset(bfKey, 0, 56);
memcpy(bfKey, "WindRand", 8); // 密钥
int lenFix = nameStr.size();
unsigned char Text[1024]; // 源串
memset(Text, 0, 1024); // 这里是把源串补足部分全填0了. 如果不填0, 只需要保证字符串结尾处有个0, 后面的内容是随便填充的,得出的注册码也会不同.
memcpy(Text, nameStr.c_str(), lenFix);
if(lenFix % 8)
lenFix = lenFix + (8-lenFix%8);
CBlowFish myBlowFish(bfKey, 56); // bushfish_init
unsigned char out[1024] = {0x0}; // 目的缓冲区
myBlowFish.Encrypt(Text, out, lenFix); // lenFix需为8的倍数, 不足补0
char bResult[1024] = {0x0};
CharStr2HexStr(out, bResult, lenFix);
cout << "\n"
<< "Your serial number is:"
<< "\n"
<< bResult
<< "\n\n";
一组符合的注册码:
coolstar14
05F4D42F5CC84A798BAC0B0CCF9E80AB
另外因为有填充字节的存在, 注册码并不唯一, 如下这一组也是可以的.
coolstar14
05F4D42F5CC84A7987214C3FB6D9501C
最后感谢WindRand大侠提供的加密算法系列的简单CM, 当我恰好想了解BlowFish时有例子可以做. 另:WindRand大侠是要求深入到加密算法中的, 这个... 偶功力实在不够而且深入到一个成熟的算法中个人觉得也没有太大必要的吧.
赞赏
他的文章
- call $+5是啥意思? 12544
- [原创]od shift+f4 示例. 22075
- [求助]设置符号表后, 调试时超慢, 正常吗? 3747
- [建议]论坛应该有个自己的图标. 3817
- [建议]首页中工具下载的页面中, 补全对应工具的作者网站的链接. 3573
赞赏
雪币:
留言: