吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 43690|回复: 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.

2

2


LibXL 可以原格式读写 Excel ,不需要电脑安装 Office, 具体使用请参照官网的文档:http://www.libxl.com/documentation.html
好久没练手了, 这次分析下算法. 看下 libxl.dll 中的导出函数 xlBookSetKeyA(BookHandle handle, const char* name, const char* key);
很容易找到关键地方。编写个测试 exe 进入 xlBookSetKey 开始调试。我只简单描述下关键地方.
[Asm] 纯文本查看 复制代码
1
2
3
4
5
6
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
第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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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, 下载次数: 1684)
用法:
见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 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

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

 楼主| 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()

1.png

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

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#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

 楼主| 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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
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] 纯文本查看 复制代码
1
call xlBookSetKeyPrivate(book,"GCCG","windows-282123090cc0e6036db16b60a1o3p0h9")


4.png 5.png 6.png

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

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


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

本版积分规则

返回列表

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

GMT+8, 2025-9-1 22:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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