吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 42341|回复: 85
上一主题 下一主题
收起左侧

[原创] LibXL 算法分析(附注册机)

  [复制链接]
跳转到指定楼层
楼主
GCCG 发表于 2016-12-22 21:33 回帖奖励
本帖最后由 GCCG 于 2017-1-15 14:25 编辑

【文章标题】: LibXL 算法分析(附注册机)
【文章作者】: GCCG
【软件名称】: LibXL
【下载地址】: http://www.libxl.com
【加壳方式】: 无加壳
【编写语言】: Visual C++
【使用工具】: OllyDbg
【操作平台】: windows
【软件介绍】: LibXL is a library that can read and write Excel files. It doesn't require Microsoft Excel and .NET framework, combines an easy to use and powerful features.



LibXL 可以原格式读写 Excel ,不需要电脑安装 Office, 具体使用请参照官网的文档:http://www.libxl.com/documentation.html
好久没练手了, 这次分析下算法. 看下 libxl.dll 中的导出函数 xlBookSetKeyA(BookHandle handle, const char* name, const char* key);
很容易找到关键地方。编写个测试 exe 进入 xlBookSetKey 开始调试。我只简单描述下关键地方.
[Asm] 纯文本查看 复制代码
10032640  /$  55            push    ebp                              ;  xlBookSetKey 函数入口
10032641  |.  8BEC          mov     ebp, esp
10032643  |.  6A FF         push    -0x1
10032645  |.  68 CA4D3810   push    10384DCA
1003264A  |.  64:A1 0000000>mov     eax, dword ptr fs:[0]
10032650  |.  50            push    eax

下面 是对用户名,注册码长度判断
[Asm] 纯文本查看 复制代码
10032687  |.  85DB          test    ebx, ebx                         ;  用户名是否为空?
10032689  |.  0F84 C2040000 je      10032B51
1003268F  |.  85C0          test    eax, eax                         ;  注册码是否为空?
10032691  |.  0F84 BA040000 je      10032B51
10032697  |.  50            push    eax
10032698  |.  8D4D 98       lea     ecx, dword ptr [ebp-0x68]
1003269B  |.  E8 B02DFDFF   call    10005450                         ;  求注册码长度
100326A0  |.  837D AC 28    cmp     dword ptr [ebp-0x54], 0x28       ;  注册码长度 是否 为 40 位?
100326A4  |.  C645 FC 01    mov     byte ptr [ebp-0x4], 0x1
100326A8  |.  C686 44030000>mov     byte ptr [esi+0x344], 0x0
100326AF  |.  8D4D 98       lea     ecx, dword ptr [ebp-0x68]
100326B2  |.  0F85 94040000 jnz     10032B4C
100326B8  |.  6A 08         push    0x8



[Asm] 纯文本查看 复制代码
100327C4  |.  E8 67D0FFFF   call    1002F830                         ;  用户名字符串 翻转
100327C9  |.  56            push    esi
100327CA  |.  E8 01083300   call    10362FD0
100327CF  |.  83C4 14       add     esp, 0x14
100327D2  |.  6A FF         push    -0x1
100327D4  |.  6A 00         push    0x0
100327D6  |.  8D8D 7CFFFFFF lea     ecx, dword ptr [ebp-0x84]
100327DC  |.  51            push    ecx
100327DD  |.  8B8D ECFEFFFF mov     ecx, dword ptr [ebp-0x114]
100327E3  |.  81C1 A4090000 add     ecx, 0x9A4
100327E9  |.  E8 A2EBFCFF   call    10001390
100327EE  |.  83EC 1C       sub     esp, 0x1C
100327F1  |.  8D95 7CFFFFFF lea     edx, dword ptr [ebp-0x84]
100327F7  |.  8BCC          mov     ecx, esp
100327F9  |.  89A5 E8FEFFFF mov     dword ptr [ebp-0x118], esp
100327FF  |.  52            push    edx
10032800  |.  E8 4BEDFCFF   call    10001550
10032805  |.  8D85 28FFFFFF lea     eax, dword ptr [ebp-0xD8]
1003280B  |.  50            push    eax
1003280C  |.  E8 2F750300   call    10069D40                         ;  翻转后的用户名, 求 MD5 值
10032811  |.  83C4 20       add     esp, 0x20



下面一段代码 取出32位注册码的第1,3,5,7,9,11,13,15,17,19,21,23,25位,并将取出的字符连接成字符串

[Asm] 纯文本查看 复制代码
100328E0  |> /83FE 20       /cmp     esi, 0x20
100328E3  |. |73 43         |jnb     short 10032928
100328E5  |. |83FE 1A       |cmp     esi, 0x1A
100328E8  |. |73 1B         |jnb     short 10032905
100328EA  |. |56            |push    esi
100328EB  |. |8D8D F0FEFFFF |lea     ecx, dword ptr [ebp-0x110]
100328F1  |. |E8 6A730300   |call    10069C60
100328F6  |. |0FB600        |movzx   eax, byte ptr [eax]
100328F9  |. |50            |push    eax                             ; /Arg1
100328FA  |. |8D8D 0CFFFFFF |lea     ecx, dword ptr [ebp-0xF4]       ; |
10032900  |. |E8 6BD5FFFF   |call    1002FE70                        ; \libxl.1002FE70
10032905  |> |8D4E 01       |lea     ecx, dword ptr [esi+0x1]
10032908  |. |51            |push    ecx
10032909  |. |8D8D F0FEFFFF |lea     ecx, dword ptr [ebp-0x110]
1003290F  |. |E8 4C730300   |call    10069C60
10032914  |. |0FB610        |movzx   edx, byte ptr [eax]
10032917  |. |52            |push    edx                             ; /Arg1
10032918  |. |8D8D 44FFFFFF |lea     ecx, dword ptr [ebp-0xBC]       ; |
1003291E  |. |E8 4DD5FFFF   |call    1002FE70                        ; \libxl.1002FE70
10032923  |. |83C6 02       |add     esi, 0x2
10032926  |.^\EB B8         \jmp     short 100328E0



对上一步取出的字符串 求 MD5,并截取 前 16 位,比较 md5 值的 前 16 位 是否是 3f8bfcaff330c39f
[Asm] 纯文本查看 复制代码
1003298E  |.  8038 33       cmp     byte ptr [eax], 0x33             ;  3
10032991  |.  0F85 41010000 jnz     10032AD8
10032997  |.  6A 01         push    0x1
10032999  |.  8D4D D0       lea     ecx, dword ptr [ebp-0x30]
1003299C  |.  E8 BF720300   call    10069C60
100329A1  |.  8038 66       cmp     byte ptr [eax], 0x66             ;  f
100329A4  |.  0F85 2E010000 jnz     10032AD8
100329AA  |.  6A 02         push    0x2
100329AC  |.  8D4D D0       lea     ecx, dword ptr [ebp-0x30]
100329AF  |.  E8 AC720300   call    10069C60
100329B4  |.  8038 38       cmp     byte ptr [eax], 0x38             ;  8
100329B7  |.  0F85 1B010000 jnz     10032AD8
100329BD  |.  6A 03         push    0x3
100329BF  |.  8D4D D0       lea     ecx, dword ptr [ebp-0x30]
100329C2  |.  E8 99720300   call    10069C60
100329C7  |.  8038 62       cmp     byte ptr [eax], 0x62             ;  b
100329CA  |.  0F85 08010000 jnz     10032AD8
100329D0  |.  6A 04         push    0x4
100329D2  |.  8D4D D0       lea     ecx, dword ptr [ebp-0x30]
100329D5  |.  E8 86720300   call    10069C60
100329DA  |.  8038 66       cmp     byte ptr [eax], 0x66             ;  f
...............................
...............................


以下代码, 可知注册码第 27, 29, 31 位满足关系
[Asm] 纯文本查看 复制代码

1002EE13 |. 0FBE71 1C movsx esi, byte ptr [ecx+0x1C]
1002EE17 |. 81C6 79070000 add esi, 0x779
1002EE1D |. 83F8 1E cmp eax, 0x1E
1002EE20 |. 73 09 jnb short 1002EE2B
1002EE22 |. E8 6B3C3300 call 10362A92
1002EE27 |. 8B4424 24 mov eax, dword ptr [esp+0x24]
1002EE2B |> 8B4C24 14 mov ecx, dword ptr [esp+0x14]
1002EE2F |. 396C24 28 cmp dword ptr [esp+0x28], ebp
1002EE33 |. 73 04 jnb short 1002EE39
1002EE35 |. 8D4C24 14 lea ecx, dword ptr [esp+0x14]
1002EE39 |> 57 push edi
1002EE3A |. 0FBE79 1E movsx edi, byte ptr [ecx+0x1E]
1002EE3E |. 83EF 69 sub edi, 0x69
1002EE41 |. 83F8 1A cmp eax, 0x1A
1002EE44 |. 73 05 jnb short 1002EE4B
1002EE46 |. E8 473C3300 call 10362A92
1002EE4B |> 8B4424 18 mov eax, dword ptr [esp+0x18]
1002EE4F |. 396C24 2C cmp dword ptr [esp+0x2C], ebp
1002EE53 |. 73 04 jnb short 1002EE59
1002EE55 |. 8D4424 18 lea eax, dword ptr [esp+0x18]
1002EE59 |> 0FBE50 1A movsx edx, byte ptr [eax+0x1A]
1002EE5D |. 8D8C37 87F8FF>lea ecx, dword ptr [edi+esi-0x779]
1002EE64 |. 3BD1 cmp edx, ecx
1002EE66 |. 75 28 jnz short 1002EE90
1002EE68 |. 81FE DD070000 cmp esi, 0x7DD
1002EE6E |. 7E 0F jle short 1002EE7F
1002EE70 |. 81FE DF070000 cmp esi, 0x7DF
1002EE76 |. 7C 18 jl short 1002EE90
1002EE78 |. 75 0D jnz short 1002EE87
1002EE7A |. 83FF 03 cmp edi, 0x3
1002EE7D |. EB 06 jmp short 1002EE85
1002EE7F |> 81FE DC070000 cmp esi, 0x7DC



由上面可得知 注册码第27, 29, 31 位 满足以下关系
[Asm] 纯文本查看 复制代码

第29个字符串 d  0x64 + 0x779 = 0x7DD   -> ESI

第31个字符串 o  0x6F-0x69  = 0x6       -> EDI

第27个字符串 j  0x6A                   


ESI + EDI - 0x779 = 0x6A

if  ESI <= 0x7DD then
     if ESI < 0x7DC then
           [ebx+0x9F8]= 0x1   失败
     else
          [ebx+0x99C]= 0  成功
    end if
else
     if ESI < 0x7DF then
          [ebx+0x9F8]= 0x1  失败 
    else 
         if ESI != 0x7DF then
            [ebx+0x99C]= 0  成功
         else
              if EDI < 0x3 then
                  [ebx+0x9F8]= 0x1  失败
             else
                  [ebx+0x99C]= 0 成功
             end if
         end if    
     end if
end if


算法总结:
1. 注册码格式:windows-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(windows- 后面 32 位)

2. 32位注册码的第1,3,5,7,9,11,13,15,17,19,21,23,25位是固定值, 分别是  22200ce06b66a

3. 32位注册码的第2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,30, 32位是:用户名字符串,经过翻转, 求出 MD5 值, 然后 取 前 16 位

4. 32位注册码的第27, 29, 31 位满足以下关系:

    (1)   ASC(29位)+ASC(31位)-0x69 = ASC(27位字母)

    (2)  ASC(29位) >= 0x63  并且  ASC(29位) 不能等于 0x65,  而且 当 ASC(29位) = 0x66 时,ASC(31位) >=0x6C


以下是注册机源码的关键部分(使用 PowerBASIC 语言
[Visual Basic] 纯文本查看 复制代码
function GetRegCode(byval hWnd as dword, byref edtstr as asciiz) as STRING
        local i as LONG
        local oMD5 as iMD5
        Dim bReg(32) as BYTE
        local sName as asciiz * 260
        local szMd5 as ASCIIZ * 40
        local szChar as ASCIZ * 10
        dim p as byte ptr
        dim pRegCode as ASCIIZ ptr
        if CheckIsDBCS(edtstr) = 1 THEN
                MessageBox hWnd, "用户名不能包含中文。", "提示!", %MB_OK or %MB_ICONEXCLAMATION
        END IF
        
        for i = len(edtstr) to 1 step -1
                sName = sName & Mid$(edtstr, i, 1)
        NEXT
        oMD5 = class "MD5"
        szMd5 = LCASE$(oMD5.calc(sName))
        ARRAY ASSIGN bReg() = &H32,&H00,&H32,&H00,&H32,&H00,&H30,&H00,&H30,&H00,&H63,&H00,&H65,&H00,&H30,&H00,&H36,&H00,&H62,&H00,&H36,&H00,&H36,&H00,&H61,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00
        p = varptr(szMd5)
        for i = 1 to 31
                bReg(i) = @p
                p=p+1
                i=i+1
        NEXT
        szChar = GetThreeChar()
        p = varptr(szChar)
        bReg(26) = @p
        p = p+1
        bReg(28) = @p
        p = p+1
        bReg(30) = @p
        
        pRegCode = varptr(bReg(0))
        
        function = "windows-" & @pRegCode
END FUNCTION

function GetThreeChar() as STRING
        local char27 as ASCIIZ * 2
        local char29 as ASCIIZ * 2
        local char31 as ASCIIZ * 2
        
        char29 = Get29()
        char31 = Get31(char29)
        char27 = chr$(ASC(char29) + ASC(char31) - 105)

        function = char27 & char29 & char31
END FUNCTION

function Get29() as string
        local char29 as ASCIIZ * 2
        randomize
        char29 = chr$(int(rnd*24 + 99))
        if asc(char29) = 101 THEN  ' e
                Get29()
        END IF

        function = char29
END FUNCTION

function Get31(byref char as asciiz) as STRING
        local char31 as ASCIIZ * 2
        randomize
        char31 = chr$(int(rnd*26 + 202- ASC(char)))
        if ASC(char) <> 102 THEN
                if ASC(char31) >= 97 and ASC(char31) < 123 THEN
                        function = char31
                else
                        Get31(char)
                END IF
        else
                if ASC(char31) >= 108 and ASC(char31) < 123 THEN
                        function = char31
                else
                        Get31(char)
                END IF
        END IF
END FUNCTION


--------------------------------------------------------------------------------
【版权声明】: 本文原创于吾爱破解论坛, 转载请注明作者并保持文章的完整, 谢谢!

附一张注册机截图:(帖子附件包含注册机,以及注册机的 PowerBASIC 源码 ){:1_912:}
(提示:杀软可能会误报, 不信者可以自己编译。)



注册机+源码:
Keygen for LibXL.rar (124 KB, 下载次数: 1582)
用法:
见30楼:http://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=566985&pid=14784663

点评

整体逻辑十分清晰。然而有些没有分析到。比如前缀Windows。而有些分析过程缺少,例如给出md5值如何倒推几位。如果这些过程写上了,我觉得精华都没问题了。谢谢楼主了。  发表于 2016-12-23 18:26

免费评分

参与人数 18威望 +1 吾爱币 +2 热心值 +17 收起 理由
C-ARan + 1 + 1 热心回复!
mp502195855 + 1 热心回复!
onoffon + 1 谢谢@Thanks!
xwei9277 + 1 谢谢@Thanks!
longavailable + 1 谢谢@Thanks!
howsk + 1 用心讨论,共获提升!
610100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zz0147 + 1 我很赞同!
lai524 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
KaQqi + 1 热心回复!
苏紫方璇 + 1 6的飞起
Hmily + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
挥汗如雨 + 1 我很赞同!
allcam + 1 鼓励转贴优秀软件安全工具和文档!
palmer680 + 1 璋㈣阿@Thanks锛?
zzcn2008 + 1 用心讨论,共获提升!
Tomatoman + 1 用心讨论,共获提升!
Sound + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 30#
 楼主| GCCG 发表于 2016-12-27 12:23 |楼主
本帖最后由 GCCG 于 2016-12-28 12:20 编辑
longavailable 发表于 2016-12-26 20:31
非常感谢大神的分享
有个非常弱的问题,生成的key怎么用?
是在调用程序(比如官方example)中加入:

重要提示:官方例子中的 example.xls 本身已经是第一行被锁定,你要测试就把那个EXCEL恢复正常, 然后再注册后的EXE读写它, 就不会出现试用信息了。如果注册码不对,即使你把之前的EXCEL恢复正常, 也会出现试用信息。另外一个要注意的是用户名区分大小写

先用下图两个函数创建一个实例句柄

xls 格式的 Excel 用 xlCreateBook()

xlsx 格式的 Excel 用 xlCreateXMLBook()



例如下面一段C代码(官方例子,我加了“注册的函数 xlBookSetKey”):

[C] 纯文本查看 复制代码
#include <stdio.h>
#include <conio.h>
#include "libxl.h"

int main()
{
    BookHandle book = xlCreateBook();
    if(book) 
    {   
        xlBookSetKey(book,L"GCCG",L"windows-282123090cc0e6036db16b60a1o3p0h9");   //注册
        if(xlBookLoad(book, L"example.xls")) 
        {
            SheetHandle sheet = xlBookGetSheet(book, 0);
            if(sheet)
            {                
                double d = xlSheetReadNum(sheet, 3, 1, 0);
                xlSheetWriteNum(sheet, 3, 1, d * 2, 0);
                xlSheetWriteStr(sheet, 4, 1, L"new string", 0);     
            }

            if(xlBookSave(book, L"example.xls")) printf("\nFile example.xls has been modified.\n");
        } 

        xlBookRelease(book);
    }

    printf("\nPress any key to exit...");
    _getch();

    return 0;
}

然后用 book 这个实例句柄变量,读写Excel 即可。 调用LibXL 库函数之前,一定要先注册,创建了实例句柄之后,就要调用注册函数, 然后再用其他函数。


@longavailable

来自 37#
 楼主| GCCG 发表于 2016-12-28 10:46 |楼主
本帖最后由 GCCG 于 2016-12-28 12:09 编辑
longavailable 发表于 2016-12-27 22:01
http://pan.baidu.com/s/1kVe7c8Z

注册名 借用了大神的名号,注册码也是您对应的那个

我找到原因了,  是 fortran模块声明文件不对, 导致转了两次 unicode, 出错了。

解决方案,需要以下步骤:

1.  删掉 libxl.f90 文件中的 xlBookSetKey 函数
[Asm] 纯文本查看 复制代码
  

 subroutine xlBookSetKey(handle,name,key)
            type(BookHandle) handle
            character(*) name,key
            integer i,ii,iii
            integer(2),allocatable,dimension(:) :: buff1,buff2
            i=len(name)
            ii=len(key)
            allocate(buff1(i+1),buff2(ii+1))
            iii = MBConvertMBToUnicode(name,buff1)
            iii = MBConvertMBToUnicode(key,buff2)
            buff1(i+1)=0
            buff2(ii+1)=0
            call xlBookSetKeyPrivate(handle,buff1,buff2)
            deallocate(buff1,buff2)
 end subroutine


2. 修改 xlBookSetKeyPrivate 函数声明 为以下形式。
[Asm] 纯文本查看 复制代码
 
 subroutine xlBookSetKeyPrivate(handle,name,key)
        !DEC$ATTRIBUTES C, DLLIMPORT, ALIAS:'_xlBookSetKeyA' :: xlBookSetKeyPrivate
        !DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: name
        !DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: key
        import
        type(BookHandle) handle
        character(*) name, key
end subroutine


3. 直接调用  xlBookSetKeyPrivate
[Asm] 纯文本查看 复制代码
call xlBookSetKeyPrivate(book,"GCCG","windows-282123090cc0e6036db16b60a1o3p0h9")




附一个修改好的 libxl.f90 文件, 替换官方文档例子中  libxl.f90 文件即可

libxl.f90 文件http://pan.baidu.com/s/1dEEuTNV  密码:lyan


来自 79#
 楼主| GCCG 发表于 2019-11-15 12:46 |楼主
菜鸡想学破解 发表于 2019-10-25 22:40
请问大佬那个16位MD5是怎么逆出来是固定值的

.MD5 不可逆。在分析算法之前,我找到一个外国佬的正版注册码,通过OD分析程序,我知道了一部分注册码字符是固定值,就这样。
推荐
Fris 发表于 2018-11-23 13:31
本帖最后由 Fris 于 2019-4-29 16:07 编辑

注册算法还没改,经测试试用于最新版本3.8.5
推荐
xwei9277 发表于 2016-12-27 12:58
注册成功!!!!!太厉害了!!!
推荐
 楼主| GCCG 发表于 2016-12-23 19:06 来自手机 |楼主
cqr2287 发表于 2016-12-23 18:27
整体逻辑十分清晰。然而有些没有分析到。比如前缀Windows。而有些分析过程缺少,例如给出md5值如何倒推几位 ...

确实没怎么注释,主要是懒得写了, 我分析代码时的 “记录”比较详细,但是比较杂乱,也不想整理了。有成果了就好了,我已经总结了算法,并给出代码的关键地方,留点悬念给有心的人自己分析一遍能学到蒙多东西,说的再多,不如自己亲自练习。

免费评分

参与人数 1热心值 +1 收起 理由
610100 + 1 热心回复!

查看全部评分

沙发
zhangbaida 发表于 2016-12-22 21:40
分析的很到位呀,支持了
3#
wuaipojie 发表于 2016-12-22 21:47
用不上 ,帮顶
4#
Sound 发表于 2016-12-22 22:45
一般也常用 PowerBasic + FireFly   :)
5#
Tomatoman 发表于 2016-12-22 22:59
分析得很到位,谢谢
6#
zzcn2008 发表于 2016-12-22 23:07
谢谢分享,看看源码!
7#
palmer680 发表于 2016-12-23 07:30
学习学习
8#
ysz 发表于 2016-12-23 08:19
感谢 楼主分享
9#
allcam 发表于 2016-12-23 08:38
牛人正研究算法注册机研究一下!
10#
神的子民 发表于 2016-12-23 16:18
正好需要。谢谢了哦
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-28 22:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表