Thend 发表于 2013-12-17 17:18

【吾爱2013CM大赛解答】-- KeyGenMe2013 -- loudy 追码分析 + 部分算法详解

[文章标题]: 【吾爱2013CM大赛解答】--KeyGenMe2013 -- loudy 追码分析 + 部分算法详解
[作者信息]: 0n1y3nd
[操作平台]: Win7 Sp1 & Windows XP Sp3
[使用工具]: OD & IDA
[软件名称]:KeyGenMe2013 -- loudy
[下载地址]: 【吾爱2013CM大赛题目】-- KeyGenMe2013 -- loudy   http://www.52pojie.cn/thread-228429-1-1.html
正文:
查壳,无壳。是MFC写的程序。
载入OD,直接查找MFC的按钮事件特征码:FF 55 14 EB 7F FF 75 0C,下好断点。
补充下:MFC程序的按钮事件特征码:
RELEASE
特征码:FF 55 14 EB 7F FF 75 0C
特征码来源:MFC42.DLL
DEBUG
特征码:FF 55 FC E9 48 04 00 00 33 C9
特征码来源:MFC42D.DLL
F9运行,输入测试的数据:
123456789
abcdefgh
点击按钮,成功断下
F7进去:
004015E0   .51            push ecx
004015E1   .53            push ebx
004015E2   .56            push esi
004015E3   .57            push edi
004015E4   .8BF1          mov esi,ecx
004015E6   .6A 01         push 0x1
004015E8   .E8 EA910100   call KeyGenMe.0041A7D7            ;取得用户名
004015ED   .8B46 60       mov eax,dword ptr ds:
004015F0   .8D5E 60       lea ebx,dword ptr ds:
004015F3   .68 B0E04200   push KeyGenMe.0042E0B0
004015F8   .50            push eax
004015F9   .E8 188A0000   call KeyGenMe.0040A016
004015FE   .83C4 08       add esp,0x8
00401601   .85C0          test eax,eax
00401603   .74 77         je XKeyGenMe.0040167C
00401605   .8B46 68       mov eax,dword ptr ds:
00401608   .8D7E 68       lea edi,dword ptr ds:
0040160B   .68 B0E04200   push KeyGenMe.0042E0B0
00401610   .50            push eax
00401611   .E8 008A0000   call KeyGenMe.0040A016
00401616   .83C4 08       add esp,0x8
00401619   .85C0          test eax,eax
0040161B   .74 5F         je XKeyGenMe.0040167C
0040161D   .51            push ecx
0040161E   .8BCC          mov ecx,esp
00401620   .896424 10   mov dword ptr ss:,esp
00401624   .53            push ebx
00401625   .E8 016B0100   call KeyGenMe.0041812B
0040162A   .8B4E 5C       mov ecx,dword ptr ds:
0040162D   .E8 6E010000   call KeyGenMe.004017A0
00401632   .51            push ecx
00401633   .8BCC          mov ecx,esp
00401635   .896424 10   mov dword ptr ss:,esp
00401639   .57            push edi
0040163A   .E8 EC6A0100   call KeyGenMe.0041812B
0040163F   .8B4E 5C       mov ecx,dword ptr ds:
00401642   .E8 A9010000   call KeyGenMe.004017F0
00401647   .8B4E 5C       mov ecx,dword ptr ds:
0040164A   .E8 F1010000   call KeyGenMe.00401840            ;算法call
0040164F   .85C0          test eax,eax
00401651   .6A 00         push 0x0
00401653   .68 0CC14200   push KeyGenMe.0042C10C
00401658   .75 11         jnz XKeyGenMe.0040166B            ;关键跳
0040165A   .68 ECC04200   push KeyGenMe.0042C0EC
0040165F   .8BCE          mov ecx,esi
00401661   .E8 158A0100   call KeyGenMe.0041A07B            ;错误calll
00401666   .5F            pop edi
00401667   .5E            pop esi
00401668   .5B            pop ebx
00401669   .59            pop ecx
0040166A   .C3            retn
0040166B   >68 D8C04200   push KeyGenMe.0042C0D8
00401670   .8BCE          mov ecx,esi
00401672   .E8 048A0100   call KeyGenMe.0041A07B            ;正确call
00401677   .5F            pop edi
00401678   .5E            pop esi
00401679   .5B            pop ebx
0040167A   .59            pop ecx
0040167B   .C3            retn

很容易的发现爆破点,00401658   . /75 11         jnz XKeyGenMe.0040166B            ;关键跳 改成JMP即可爆破。
算法call:0040164A   .E8 F1010000   call KeyGenMe.00401840            ;算法call00401840/$55            push ebp
00401841|.8BEC          mov ebp,esp
00401843|.83E4 F8       and esp,0xFFFFFFF8
00401846|.83EC 28       sub esp,0x28
00401849|.53            push ebx
0040184A|.55            push ebp
0040184B|.56            push esi
0040184C|.57            push edi
0040184D|.8BF1          mov esi,ecx
0040184F|.6A 00         push 0x0
00401851|.E8 0D6D0100   call KeyGenMe.00418563            ;取机器码
00401856|.6A 00         push 0x0
00401858|.8D4E 08       lea ecx,dword ptr ds:
0040185B|.8BD8          mov ebx,eax
0040185D|.E8 016D0100   call KeyGenMe.00418563            ;取用户名
00401862|.6A 00         push 0x0
00401864|.8D4E 04       lea ecx,dword ptr ds:
00401867|.8BF8          mov edi,eax
00401869|.E8 F56C0100   call KeyGenMe.00418563            ;取注册码
0040186E|.8BE8          mov ebp,eax
00401870|.6A 01         push 0x1
00401872|.896C24 20   mov dword ptr ss:,ebp
00401876|.E8 E85F0100   call KeyGenMe.00417863            ;返回0
0040187B|.8BF0          mov esi,eax
0040187D|.8A03          mov al,byte ptr ds:            ;机器码第一位
0040187F|.83C4 04       add esp,0x4
00401882|.C74424 20 000>mov dword ptr ss:,0x0
0040188A|.84C0          test al,al
0040188C|.C74424 24 000>mov dword ptr ss:,0x0
00401894|.C74424 28 000>mov dword ptr ss:,0x0
0040189C|.C74424 2C 000>mov dword ptr ss:,0x0
004018A4|.74 7C         je XKeyGenMe.00401922
004018A6|>0FBE4B 01   /movsx ecx,byte ptr ds:    ;机器码第二位给ecx第三位
004018AA|.0FBEC0      |movsx eax,al                     ;机器码第一位给eax第二位
004018AD|.894424 10   |mov dword ptr ss:,eax    ;eax存入0012F8B8
004018B1|.DB4424 10   |fild dword ptr ss:       ;机器码第一位8的assii的 10进制 存入ST0中
004018B5|.894C24 10   |mov dword ptr ss:,ecx    ;机器码的第二位存入0012F8B8
004018B9|.DD5C24 30   |fstp qword ptr ss:       ;将ST0弹出
004018BD|.DB4424 10   |fild dword ptr ss:       ;机器码的第二位C的十进制 67 压入ST0
004018C1|.8B4C24 34   |mov ecx,dword ptr ss:    ;404C0000 赋值 给ecx
004018C5|.DD5C24 10   |fstp qword ptr ss:       ;弹出ST0
004018C9|.8B5424 14   |mov edx,dword ptr ss:    ;4050C000 赋值给 EDX
004018CD|.8B4424 10   |mov eax,dword ptr ss:    ;0 赋值给 eax
004018D1|.52            |push edx                           ;压栈 4050C000
004018D2|.8B5424 34   |mov edx,dword ptr ss:    ;0赋值给 EDX
004018D6|.50            |push eax                           ;0 压栈
004018D7|.68 32545E40   |push 0x405E5432                  ;压栈 405E5432
004018DC|.68 87A757CA   |push 0xCA57A787                  ;压栈 CA57A787
004018E1|.51            |push ecx                           ;压栈 404C0000
004018E2|.52            |push edx                           ;压栈 0
004018E3|.8BCE          |mov ecx,esi
004018E5|.E8 D6030000   |call KeyGenMe.00401CC0             ;机器码的第一位 和 121.3456 运算
004018EA|.83EC 08       |sub esp,0x8                        ;第一次得到的结果是 6793.67359999
004018ED|.8BCE          |mov ecx,esi
004018EF|.DD1C24      |fstp qword ptr ss:
004018F2|.E8 19020000   |call KeyGenMe.00401B10             ;1B10
004018F7|.DD5C24 30   |fstp qword ptr ss:       ;返回6860.6735
004018FB|.8B4424 34   |mov eax,dword ptr ss:
004018FF|.8B4C24 30   |mov ecx,dword ptr ss:
00401903|.8B5424 24   |mov edx,dword ptr ss:
00401907|.50            |push eax
00401908|.8B4424 24   |mov eax,dword ptr ss:
0040190C|.51            |push ecx
0040190D|.52            |push edx
0040190E|.50            |push eax
0040190F|.8BCE          |mov ecx,esi
00401911|.E8 FA010000   |call KeyGenMe.00401B10             ;1B10   第一个参数是6860第二个参数是0
00401916|.8A43 01       |mov al,byte ptr ds:       ;al 赋值 成机器码第二位 C
00401919|.43            |inc ebx
0040191A|.DD5C24 20   |fstp qword ptr ss:       ;6860.6735存入 0012F8C8
0040191E|.84C0          |test al,al
00401920|.^ 75 84         \jnz XKeyGenMe.004018A6
00401922|>8A07          mov al,byte ptr ds:            ;用户名算法
00401924|.84C0          test al,al
00401926|.74 7C         je XKeyGenMe.004019A4
00401928|>0FBE57 01   /movsx edx,byte ptr ds:
0040192C|.0FBEC8      |movsx ecx,al
0040192F|.894C24 10   |mov dword ptr ss:,ecx
00401933|.DB4424 10   |fild dword ptr ss:
00401937|.895424 10   |mov dword ptr ss:,edx
0040193B|.DD5C24 30   |fstp qword ptr ss:
0040193F|.DB4424 10   |fild dword ptr ss:
00401943|.8B5424 34   |mov edx,dword ptr ss:
00401947|.DD5C24 10   |fstp qword ptr ss:
0040194B|.8B4424 14   |mov eax,dword ptr ss:
0040194F|.8B4C24 10   |mov ecx,dword ptr ss:
00401953|.50            |push eax
00401954|.8B4424 34   |mov eax,dword ptr ss:
00401958|.51            |push ecx
00401959|.68 9EEE9240   |push 0x4092EE9E
0040195E|.68 17B7D100   |push 0xD1B717
00401963|.52            |push edx
00401964|.50            |push eax
00401965|.8BCE          |mov ecx,esi
00401967|.E8 54030000   |call KeyGenMe.00401CC0             ;1CC0
0040196C|.83EC 08       |sub esp,0x8
0040196F|.8BCE          |mov ecx,esi
00401971|.DD1C24      |fstp qword ptr ss:
00401974|.E8 97010000   |call KeyGenMe.00401B10             ;1B10
00401979|.DD5C24 30   |fstp qword ptr ss:
0040197D|.8B4C24 34   |mov ecx,dword ptr ss:
00401981|.8B5424 30   |mov edx,dword ptr ss:
00401985|.8B4424 2C   |mov eax,dword ptr ss:
00401989|.51            |push ecx
0040198A|.8B4C24 2C   |mov ecx,dword ptr ss:
0040198E|.52            |push edx
0040198F|.50            |push eax
00401990|.51            |push ecx
00401991|.8BCE          |mov ecx,esi
00401993|.E8 78010000   |call KeyGenMe.00401B10             ;1B10
00401998|.8A47 01       |mov al,byte ptr ds:
0040199B|.47            |inc edi
0040199C|.DD5C24 28   |fstp qword ptr ss:
004019A0|.84C0          |test al,al
004019A2|.^ 75 84         \jnz XKeyGenMe.00401928             ;用户名生成了578387
004019A4|>8B5424 2C   mov edx,dword ptr ss:
004019A8|.8B4424 28   mov eax,dword ptr ss:
004019AC|.8B4C24 24   mov ecx,dword ptr ss:
004019B0|.52            push edx
004019B1|.8B5424 24   mov edx,dword ptr ss:
004019B5|.50            push eax
004019B6|.51            push ecx
004019B7|.52            push edx
004019B8|.8BCE          mov ecx,esi
004019BA|.E8 51010000   call KeyGenMe.00401B10            ;1B10
004019BF|.DD5C24 20   fstp qword ptr ss:
004019C3|.8BCE          mov ecx,esi
004019C5|.E8 A6060000   call KeyGenMe.00402070
004019CA|.8B4424 24   mov eax,dword ptr ss:
004019CE|.8B4C24 20   mov ecx,dword ptr ss:
004019D2|.83EC 08       sub esp,0x8
004019D5|.DD1C24      fstp qword ptr ss:
004019D8|.50            push eax
004019D9|.51            push ecx
004019DA|.8BCE          mov ecx,esi
004019DC|.E8 DF020000   call KeyGenMe.00401CC0
004019E1|.E8 32870000   call KeyGenMe.0040A118
004019E6|.8BC8          mov ecx,eax
004019E8|.BE 08000000   mov esi,0x8
004019ED|>8D7E 07       /lea edi,dword ptr ds:
004019F0|.8BC1          |mov eax,ecx
004019F2|.33D2          |xor edx,edx
004019F4|.F7F7          |div edi
004019F6|.33D2          |xor edx,edx
004019F8|.8BF8          |mov edi,eax
004019FA|.8BC1          |mov eax,ecx
004019FC|.F7F6          |div esi
004019FE|.33D2          |xor edx,edx
00401A00|.03C7          |add eax,edi
00401A02|.BF 1A000000   |mov edi,0x1A
00401A07|.F7F7          |div edi                            ;这一步 算出edx
00401A09|.8A442E F8   |mov al,byte ptr ds:   ;取注册码
00401A0D|.80C2 41       |add dl,0x41
00401A10|.3AC2          |cmp al,dl                        ;关键比较
00401A12|.0F85 AC000000 |jnz KeyGenMe.00401AC4            ;点1
00401A18|.46            |inc esi
00401A19|.8D56 F8       |lea edx,dword ptr ds:
00401A1C|.83FA 04       |cmp edx,0x4
00401A1F|.^ 7C CC         \jl XKeyGenMe.004019ED            ;比较前四位
00401A21|.807D 04 2D    cmp byte ptr ss:,0x2D      ;注册码每四位 的间隔 -
00401A25|.74 0A         je XKeyGenMe.00401A31
00401A27|.33C0          xor eax,eax
00401A29|.5F            pop edi
00401A2A|.5E            pop esi
00401A2B|.5D            pop ebp
00401A2C|.5B            pop ebx
00401A2D|.8BE5          mov esp,ebp
00401A2F|.5D            pop ebp
00401A30|.C3            retn
00401A31|>B8 08000000   mov eax,0x8
00401A36|.BB 05000000   mov ebx,0x5
00401A3B|.2BC5          sub eax,ebp
00401A3D|.8D75 05       lea esi,dword ptr ss:
00401A40|.8D3C89      lea edi,dword ptr ds:
00401A43|.894424 10   mov dword ptr ss:,eax
00401A47|.EB 04         jmp XKeyGenMe.00401A4D
00401A49|>8B4424 10   /mov eax,dword ptr ss:
00401A4D|>8D2C30         lea ebp,dword ptr ds:
00401A50|.8BC1          |mov eax,ecx
00401A52|.33D2          |xor edx,edx
00401A54|.F7F5          |div ebp
00401A56|.BD 1A000000   |mov ebp,0x1A
00401A5B|.8BC2          |mov eax,edx
00401A5D|.33D2          |xor edx,edx
00401A5F|.03C7          |add eax,edi
00401A61|.F7F5          |div ebp
00401A63|.8A06          |mov al,byte ptr ds:
00401A65|.80C2 41       |add dl,0x41
00401A68|.3AC2          |cmp al,dl                        ;追码点2
00401A6A|.75 58         |jnz XKeyGenMe.00401AC4
00401A6C|.43            |inc ebx
00401A6D|.03F9          |add edi,ecx
00401A6F|.46            |inc esi
00401A70|.83FB 09       |cmp ebx,0x9                        ;第五位到第八位 注册码的比较
00401A73|.^ 7C D4         \jl XKeyGenMe.00401A49
00401A75|.8B7C24 1C   mov edi,dword ptr ss:
00401A79|.807F 09 2D    cmp byte ptr ds:,0x2D      ;间隔符号-
00401A7D|.74 0A         je XKeyGenMe.00401A89
00401A7F|.33C0          xor eax,eax
00401A81|.5F            pop edi
00401A82|.5E            pop esi
00401A83|.5D            pop ebp
00401A84|.5B            pop ebx
00401A85|.8BE5          mov esp,ebp
00401A87|.5D            pop ebp
00401A88|.C3            retn
00401A89|>BE 5D000000   mov esi,0x5D
00401A8E|>8D5E 02       /lea ebx,dword ptr ds:
00401A91|.8BC1          |mov eax,ecx
00401A93|.33D2          |xor edx,edx
00401A95|.F7F3          |div ebx
00401A97|.8BC1          |mov eax,ecx
00401A99|.8BDA          |mov ebx,edx
00401A9B|.33D2          |xor edx,edx
00401A9D|.F7F6          |div esi
00401A9F|.33D2          |xor edx,edx
00401AA1|.03C3          |add eax,ebx
00401AA3|.BB 1A000000   |mov ebx,0x1A
00401AA8|.F7F3          |div ebx
00401AAA|.8A4437 AD   |mov al,byte ptr ds:
00401AAE|.80C2 41       |add dl,0x41
00401AB1|.3AC2          |cmp al,dl                        ;追码点3
00401AB3|.75 0F         |jnz XKeyGenMe.00401AC4
00401AB5|.46            |inc esi
00401AB6|.8D46 AD       |lea eax,dword ptr ds:
00401AB9|.83F8 0E       |cmp eax,0xE                        ;第九位到第十二位注册码的比较
00401ABC|.^ 7C D0         \jl XKeyGenMe.00401A8E
00401ABE|.807F 0E 2D    cmp byte ptr ds:,0x2D      ;间隔符号 -
00401AC2|.74 0A         je XKeyGenMe.00401ACE
00401AC4|>33C0          xor eax,eax
00401AC6|.5F            pop edi
00401AC7|.5E            pop esi
00401AC8|.5D            pop ebp
00401AC9|.5B            pop ebx
00401ACA|.8BE5          mov esp,ebp
00401ACC|.5D            pop ebp
00401ACD|.C3            retn
00401ACE|>BE 0F000000   mov esi,0xF
00401AD3|>8BC1          mov eax,ecx
00401AD5|.33D2          xor edx,edx
00401AD7|.F7F6          div esi
00401AD9|.8BC1          mov eax,ecx
00401ADB|.8BDA          mov ebx,edx
00401ADD|.33D2          xor edx,edx
00401ADF|.F7F6          div esi
00401AE1|.33D2          xor edx,edx
00401AE3|.03C3          add eax,ebx
00401AE5|.BB 1A000000   mov ebx,0x1A
00401AEA|.F7F3          div ebx
00401AEC|.8A043E      mov al,byte ptr ds:
00401AEF|.80C2 41       add dl,0x41
00401AF2|.3AC2          cmp al,dl                           ;追码点4
00401AF4|.^ 75 CE         jnz XKeyGenMe.00401AC4
00401AF6|.46            inc esi
00401AF7|.83FE 13       cmp esi,0x13                        ;第十三位到第十六位注册码比较
00401AFA|.^ 7C D7         jl XKeyGenMe.00401AD3
00401AFC|.5F            pop edi
00401AFD|.B8 01000000   mov eax,0x1
00401B02|.5E            pop esi
00401B03|.5D            pop ebp
00401B04|.5B            pop ebx
00401B05|.8BE5          mov esp,ebp
00401B07|.5D            pop ebp
00401B08\.C3            retn

通过上面算法call中四个追码点,即可追踪到正确的注册码。
算法没有分析完,只分析了其中一个小部分算法,后面大致算法都差不多,区别的是里面的一些细节。
再分析,我觉得就是体力活了。
对004018E5|.E8 D6030000   |call KeyGenMe.00401CC0             ;机器码的第一位 和 121.3456 运算这个小算法call的详细分析:
整体描述:这个函数有两个参数,设为参数1和参数2,四次循环计算得到一些值。最后一次计算下这些值,返回一个double类型的数。
OD中的代码就不贴了,又臭又长。下面是IDA分析的。很清晰明了。
double __stdcall ICC0(double First_Parameter, double Second_Parameter)
{
double FirstResult; // st7@1
signed int FirstRound; // ecx@1
signed int SecondRound; // ecx@8
double SecondResult; // st7@8
signed int ThirdRound; // ecx@15
double ThirdResult; // st6@15
signed int FourthRound; // ecx@22
double FourthResult; // st4@22
double v11; // @8
double EndSecond; // @15
double EndFirst; // @8

FirstResult = 0.0;
FirstRound = 0;
do                                          // 第一次 循环算法
{
    if ( FirstRound % 3 )
    {
      if ( FirstRound % 3 == 1 )                // firstparameter是机器码的第一位;secondparameter是之前压栈的第一个
      FirstResult = FirstResult + First_Parameter * Second_Parameter * 0.125;// 第 3*n + 1 次执行这个
      else
      FirstResult = FirstResult - (First_Parameter - Second_Parameter) * 1.526781234;// 第3*n + 2 次执行这个
    }
    else
    {
      FirstResult = FirstResult + (First_Parameter + Second_Parameter) * 0.3333333333333333;// 第 3*n 次是执行这个
    }
    ++FirstRound;
}
while ( FirstRound < 300 );
EndFirst = FirstResult;                     // 上次循环得到的值 传给V13
SecondRound = 0;
v11 = FirstResult * First_Parameter;          // 上次循环得到的值 * 机器码 传给V11
SecondResult = 0.0;                           // 第二次大循环的结果保存在这个里面
do                                          // 第二次 循环算法
{
    if ( SecondRound % 3 )
    {
      if ( SecondRound % 3 == 1 )
      SecondResult = SecondResult + First_Parameter * Second_Parameter * 0.1111111111111111;
      else
      SecondResult = SecondResult - (First_Parameter - Second_Parameter) * 1.526741234;
    }
    else
    {
      SecondResult = SecondResult + (First_Parameter + Second_Parameter) * 0.25;
    }
    ++SecondRound;
}
while ( SecondRound < 400 );
ThirdRound = 0;
EndSecond = v11 / SecondResult;               // V11 是第一个循环得到的值*第一个参数
ThirdResult = 14.0;
do                                          // 第三次 循环算法
{
    if ( ThirdRound % 3 )
    {
      if ( ThirdRound % 3 == 1 )
      ThirdResult = ThirdResult + First_Parameter * Second_Parameter * 0.1428571428571428;
      else
      ThirdResult = ThirdResult - (First_Parameter - Second_Parameter) * 1.529781234;
    }
    else
    {
      ThirdResult = ThirdResult + (First_Parameter + Second_Parameter) * 0.2;
    }
    ++ThirdRound;
}
while ( ThirdRound < 500 );
FourthRound = 0;
FourthResult = 35.0;                        // 初始值 35.0
do                                          // 第四次 循环算法
{
    if ( FourthRound % 3 )
    {
      if ( FourthRound % 3 == 1 )
      FourthResult = FourthResult + First_Parameter * Second_Parameter * 0.25;
      else
      FourthResult = FourthResult - (First_Parameter - Second_Parameter) * 1.426781234;
    }
    else
    {
      FourthResult = FourthResult + (First_Parameter + Second_Parameter) * 0.1666666666666667;
    }
    ++FourthRound;
}
while ( FourthRound < 600 );
return (SecondResult * Second_Parameter * EndSecond / EndFirst * ThirdResult / ThirdResult / FourthResult
      - 1.00234
      + 1.00234)
       * FourthResult;
}
还有个小算法call:00401911|.E8 FA010000   |call KeyGenMe.00401B10             ;这个里面的算法和上面那个几乎一样。就没再去花大力气分析了。

提供一组:
0n1y3nd
VIFR-AEDC-WIAZ-IKGN

















页: [1]
查看完整版本: 【吾爱2013CM大赛解答】-- KeyGenMe2013 -- loudy 追码分析 + 部分算法详解