破解 crackme(“不可逆“函数)

系统 : Windows xp

程序 : crackme

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

要求 : 注册机编写

使用工具 : IDA Pro & OD

可在“PEDIY CrackMe 2007”中查找关于此程序的讨论,标题为“简单分析crackme算法之一”。

运行程序,在Help-》Register菜单项中注册,输入测试用户名密码。程序提示错误,错误字串为:“No luck there, mate!”。打开IDA载入程序,通过字串表定位错误字串,并通过交叉参考在关键算法处下断:

00401209   > \6A 00         push    0                                ; /lParam = NULL
0040120B   .  68 53124000   push    00401253                         ; |DlgProc = CRACKME.00401253
00401210   .  FF75 08       push    dword ptr [ebp+8]                ; |hOwner
00401213   .  68 15214000   push    00402115                         ; |pTemplate = "DLG_REGIS"
00401218   .  FF35 CA204000 push    dword ptr [4020CA]               ; |hInst = 00400000
0040121E   .  E8 7D020000   call    <jmp.&USER32.DialogBoxParamA>    ; \DialogBoxParamA
00401223   .  83F8 00       cmp     eax, 0
00401226   .^ 74 BE         je      short 004011E6
00401228   .  68 8E214000   push    0040218E                         ;  用户名入栈
0040122D   .  E8 4C010000   call    0040137E                         ;  根据用户名进行一些操作得出一个值
00401232   .  50            push    eax
00401233   .  68 7E214000   push    0040217E                         ;  序列号入栈
00401238   .  E8 9B010000   call    004013D8                         ;  根据序列号进行一些操作得出一个值
0040123D   .  83C4 04       add     esp, 4                           ;  平衡堆栈
00401240   .  58            pop     eax
00401241   .  3BC3          cmp     eax, ebx                         ;  F(用户名) == F(序列号)?
00401243   .  74 07         je      short 0040124C

40137E处汇编代码:

0040137E  /$  8B7424 04     mov     esi, dword ptr [esp+4]           ;  取用户名
00401382  |.  56            push    esi
00401383  |>  8A06          /mov     al, byte ptr [esi]
00401385  |.  84C0          |test    al, al                          ;  如果迭代结束
00401387  |.  74 13         |je      short 0040139C                  ;  跳出循环
00401389  |.  3C 41         |cmp     al, 41                          ;  字符小于0x41,则提示错误
0040138B  |.  72 1F         |jb      short 004013AC
0040138D  |.  3C 5A         |cmp     al, 5A                          ;  如果字符大于等于5A,
0040138F  |.  73 03         |jnb     short 00401394                  ;  则转化字符为大写
00401391  |.  46            |inc     esi                             ;  循环变量自增
00401392  |.^ EB EF         |jmp     short 00401383
00401394  |>  E8 39000000   |call    004013D2
00401399  |.  46            |inc     esi                             ;  循环变量自增
0040139A  |.^ EB E7         \jmp     short 00401383
0040139C  |>  5E            pop     esi                              ;  取用户名
0040139D  |.  E8 20000000   call    004013C2
004013A2  |.  81F7 78560000 xor     edi, 5678
004013A8  |.  8BC7          mov     eax, edi                         ;  异或结果保存在eax里
004013AA  |.  EB 15         jmp     short 004013C1
004013AC  |>  5E            pop     esi
004013AD  |.  6A 30         push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004013AF  |.  68 60214000   push    00402160                         ; |Title = "No luck!"
004013B4  |.  68 69214000   push    00402169                         ; |Text = "No luck there, mate!"
004013B9  |.  FF75 08       push    dword ptr [ebp+8]                ; |hOwner
004013BC  |.  E8 79000000   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  |.  74 05         |je      short 004013D1                  ;  跳出循环
004013CC  |.  03FB          |add     edi, ebx                        ;  累加字符值
004013CE  |.  46            |inc     esi                             ;  循环变量自增
004013CF  |.^ EB F5         \jmp     short 004013C6
004013D1  \>  C3            retn                                     ;  结果保存在edi
004013D2  /$  2C 20         sub     al, 20
004013D4  |.  8806          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 04     mov     esi, dword ptr [esp+4]           ;  取序列号
004013E2  |>  B0 0A         /mov     al, 0A
004013E4  |.  8A1E          |mov     bl, byte ptr [esi]
004013E6  |.  84DB          |test    bl, bl                          ;  如果迭代结束
004013E8  |.  74 0B         |je      short 004013F5                  ;  则跳出循环
004013EA  |.  80EB 30       |sub     bl, 30                          ;  将字符转化为它对应的数字
004013ED  |.  0FAFF8        |imul    edi, eax
004013F0  |.  03FB          |add     edi, ebx
004013F2  |.  46            |inc     esi                             ;  循环变量自增
004013F3  |.^ EB ED         \jmp     short 004013E2
004013F5  |>  81F7 34120000 xor     edi, 1234                        ;  结果与0x1234异或
004013FB  |.  8BDF          mov     ebx, edi                         ;  存入ebx
004013FD  \.  C3            retn

以上就是关键处代码,通过观察不难发现,该程序采用的是非明码比较(F(用户名)=F(序列号))。这样的程序我们用高级语言写出F(用户名),再算出F(序列号)的逆算法即可。

打开http://www.cnblogs.com/ZRBYYXDM/p/5115596.html中搭建的框架,修改OnOk函数如下:

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 = 0 ; i != len ; i++ ){
        if ( str[i] < 0x41 ){
            StrIsOk = false;
            break;
        }
    }

    if ( StrIsOk ){                                            //格式控制。
        str.MakeUpper();                                    //转化为大写。

        unsigned int sum = 0;
        int i;
        for ( i = 0 ; 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"));

运行效果:

时间: 2024-10-06 09:35:11

破解 crackme(“不可逆“函数)的相关文章

破解 CrackMe#1 [UBC] by bRaINbuSY

系统 : Windows xp 程序 : CrackMe#1 程序下载地址 :http://pan.baidu.com/s/1nuagj6h 要求 : 编写注册机 使用工具 :IDA & OD 可在看雪论坛中查找关于此程序的破文:http://bbs.pediy.com/showthread.php?t=29063 IDA载入程序,找出提示破解成功的字串“You cracked the UBC CrackMe#1 ! Please send your solution to [email pro

软件破解入门(暴力破解CrackMe)

所谓暴力破解,就是通过修改汇编代码进而控制程序的运行流程,达到不需注册码也能正常使用软件的目的.相对于解出算法进而编写注册机,暴破的技术含量是比较低的.但也正是因为一本05年的杂志上介绍“暴力破解”的文章,让我入了这个大坑.近来想重拾调试器,就先从最简单的CrackMe入手,熟练一下各工具方法. 下载CrackMe3文件(我用的是看雪<加密与解密>中的CFF CrackMe #3 程序  http://pan.baidu.com/s/1dD9v9x3 ). 1.查看此程序是否加壳.加壳的话还得

破解 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

单片机 防破解 技术论述

单片机防破解,近几年专门针对于产品设计,最终在产品程序加密这一块,发现是一个非常实际的问题,公司研发产品几十万,竞争对手花几万破解复制你的产品,而其他竞争对手能够使用更低的成本复制已经被破解的产品,让你的产品在短短1个月内成为烂大街的货:在这种市场风气下非常阻碍具备创新能力公司的发展:因此在3个月各种询问以及沟通过程中,从如何破解单片机系统到如何防止破解进行说明,希望能够帮助具有相同需求的朋友:在此利用市场上破解率最高的STM32单片机来说明.一.破解单片机系统,分为两步:1.从单片机中将二进制

《C++黑客编程揭秘与防范》(第二版)

本书是<C++黑客编程揭秘与防范>的升级版,在前书的基础上新添加了一些内容,同时也删除了一些过时的内容.本书以Win32应用层下安全开发为中心,介绍Windows系统下的安全开发. 本书介绍了操作系统的相关操作,比如进程.线程.注册表等知识.当读者掌握了关于进程.线程.注册表等相关的开发知识后,就可以把一些常规的操作进程.注册表.文件等用代码进行实现,这样,一些日常的操作可与学习的编程知识相结合.除了操作的知识外,本书还介绍了关于网络应用程序的开发,了解Winsock的开发后,读者就会明白在应

Android 逆向实战(一)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; color: #000000 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; color: #000000; min-height: 13.0px } span.s1 { } 现在很多 apk 在开发中为了保证代码不被轻易逆向出来会对关键代码采用 ndk开发的方式. 什么是 Androi

2016/12/3-问鼎杯线上赛6-2逆向分析

这道题目的文件给我们的是一个压缩包a2ia8-6-2.rar,解压之后得到一个crackme.exe和readme.txt 打开readme.txt可以看到对我们目标的描述. 从这里我们知道,这个就是逆向当中很平常的求serial计算算法(或者更具提示暴力跑?这里我们分析来逆向算法), 并且我们也知道了8位name,还有4位不知道,得到name = "{hdu?b???0_}"但是我们可以根据序列号来计算出来. 拿到一个程序之后,首先使用PEID来查壳,这道题目没有壳,先运行一遍(这里

逆向工程实战--Acid burn

0x00 序言 这是第二次破解 crackme 小程序,感觉明显比第一次熟练,破解过程很顺利,几乎是分分钟就可以找到正确的 serial,但是我们的目标是破解计算过程,下面将详细介绍. 0x01 初次运行 刚开始拿到 crackme 先运行程序,看看有哪些明显的特征,或者有哪些任务需要完成: 双击程序后弹框,显然第一个任务就是把这个框框弄掉,我们继续运行: 这个小程序比上次的要复杂,有两个 serial ,我们先看看左边的: 不出意外,猜错了,有明显的弹框和失败字符串作为特征,我们接着看右边的:

Android学习心得(11) --- MAC下Android反编译(3)

我在博客上发表一些我的Android学习心得,希望对大家能有帮助. 在前一章我们学习了反编译. 这一章再次学习一下两个demo. 两个demo下载地址 KeygenMe#1.apk crackme0a.apk 链接: http://pan.baidu.com/s/1kTs11Tt 密码: davk KeygenMe#1.apk 1.首先在模拟器安装测试 由于模拟器检测不到wifi mac地址,所以会报错. 我们首先需要将检测代码跳过 先通过dex2jar和jd-gui查看源代码进行分析 查看了m