〇〇木一 发表于 2013-12-16 10:27

【吾爱2013CM大赛解答】--KeyGenMe-- a070458 -- 算法分析-注册机编写[〇〇木一]

本帖最后由 〇〇木一 于 2013-12-16 12:41 编辑

【文章标题】: 【吾爱2013CM大赛解答】--KeyGenMe-- a070458 -- 算法分析[〇〇木一]
【文章作者】: 〇〇木一
【软件名称】: KeyGenMe-- a070458
【下载地址】: http://www.52pojie.cn/thread-228709-1-1.html
【操作平台】: win 7
第一次写的代码有点小错误现在已经改好了。
分析这个算法真是搞得我蛋蛋碎光了..

不用说,首先先找到他比较验证的的地方,这个很好找中断回溯,按钮事件,API断点随便可以找到。
00401DA0   .>push -0x1
00401DA2   .>push KeyGenMe.004025B0                   ;SE 处理程序安装
00401DA7   .>mov eax,dword ptr fs:
00401DAD   .>push eax
00401DAE   .>mov dword ptr fs:,esp
00401DB5   .>sub esp,0x14
00401DB8   .>push ebx
00401DB9   .>push ebp
00401DBA   .>mov ebp,ecx
00401DBC   .>push esi
00401DBD   .>push edi
00401DBE   .>lea ecx,dword ptr ss:
00401DC2   .>call <jmp.&MFC42.#540>
00401DC7   .>lea ecx,dword ptr ss:
00401DCB   .>mov dword ptr ss:,0x0
00401DD3   .>call <jmp.&MFC42.#540>
00401DD8   .>push KeyGenMe.0040403C                   ;UNICODE "5"
00401DDD   .>lea ecx,dword ptr ss:
00401DE1   .>mov byte ptr ss:,0x1
00401DE6   .>call <jmp.&MFC42.#941>
00401DEB   .>push KeyGenMe.00404038                   ;UNICODE "2"
00401DF0   .>lea ecx,dword ptr ss:
00401DF4   .>call <jmp.&MFC42.#941>
00401DF9   .>push KeyGenMe.00404034                   ;UNICODE "P"
00401DFE   .>lea ecx,dword ptr ss:
00401E02   .>call <jmp.&MFC42.#941>
00401E07   .>push KeyGenMe.00404030                   ;UNICODE "o"
00401E0C   .>lea ecx,dword ptr ss:
00401E10   .>call <jmp.&MFC42.#941>
00401E15   .>push KeyGenMe.0040402C                   ;UNICODE "J"
00401E1A   .>lea ecx,dword ptr ss:
00401E1E   .>call <jmp.&MFC42.#941>
00401E23   .>push KeyGenMe.00404028                   ;UNICODE "i"
00401E28   .>lea ecx,dword ptr ss:
00401E2C   .>call <jmp.&MFC42.#941>
00401E31   .>push KeyGenMe.00404024                   ;UNICODE "e"
00401E36   .>lea ecx,dword ptr ss:
00401E3A   .>call <jmp.&MFC42.#941>                   ;组成"52PoJie"字串
00401E3F   .>push 0x1
00401E41   .>mov ecx,ebp
00401E43   .>call <jmp.&MFC42.#6334>                  ;取文本框内容
00401E48   .>mov eax,dword ptr ss:
00401E4B   .>lea esi,dword ptr ss:
00401E4E   .>mov eax,dword ptr ds:
00401E51   .>cdq
00401E52   .>sub eax,edx
00401E54   .>sar eax,1
00401E56   .>push eax
00401E57   .>call <jmp.&MFC42.#823>
00401E5C   .>mov ecx,dword ptr ss:
00401E5F   .>add ebp,0x64
00401E62   .>mov edi,eax
00401E64   .>add esp,0x4
00401E67   .>mov eax,dword ptr ds:
00401E6A   .>test eax,eax
00401E6C   .>je short KeyGenMe.00401EB9               ;1 l
00401E6E   .>mov edx,dword ptr ds:
00401E70   .>mov eax,dword ptr ds:
00401E73   .>test eax,eax
00401E75   .>je short KeyGenMe.00401EB9               ;2 l
00401E77   .>push ecx
00401E78   .>mov ecx,esp
00401E7A   .>mov dword ptr ss:,esp
00401E7E   .>push esi
00401E7F   .>call <jmp.&MFC42.#535>
00401E84   .>call KeyGenMe.004012D0                   ;判断注册码是否为16进制字串(要大写)
00401E89   .>add esp,0x4
00401E8C   .>test al,al
00401E8E   .>je short KeyGenMe.00401EB9
00401E90   .>mov eax,dword ptr ds:
00401E92   .>mov eax,dword ptr ds:         ;取注册码长度
00401E95   .>mov ecx,eax
00401E97   .>and ecx,0x80000001
00401E9D   .>jns short KeyGenMe.00401EA4
00401E9F   .>dec ecx
00401EA0   .>or ecx,0xFFFFFFFE
00401EA3   .>inc ecx
00401EA4   >>jnz short KeyGenMe.00401EB9
00401EA6   .>mov edx,dword ptr ss:
00401EA9   .>mov ecx,dword ptr ds:         ;取用户名长度
00401EAC   .>cmp ecx,0x5
00401EAF   .>jl short KeyGenMe.00401EB9               ;>=5
00401EB1   .>lea ecx,dword ptr ds:
00401EB5   .>cmp eax,ecx
00401EB7   .>je short KeyGenMe.00401EC4               ;注册码长度必须为[用户名长度]*2+2
00401EB9   >>call dword ptr ds:             ;KeyGenMe.004019B0
00401EBF   .>jmp KeyGenMe.00401FBA
00401EC4   >>push eax
00401EC5   .>push edi
00401EC6   .>push ecx
00401EC7   .>mov ecx,esp
00401EC9   .>mov dword ptr ss:,esp
00401ECD   .>push esi
00401ECE   .>call <jmp.&MFC42.#535>
00401ED3   .>call KeyGenMe.00401360                   ;注册码转为16进制
00401ED8   .>mov edx,dword ptr ds:
00401EDA   .>mov eax,dword ptr ds:
00401EDD   .>cdq
00401EDE   .>sub eax,edx
00401EE0   .>sar eax,1
00401EE2   .>push eax
00401EE3   .>push edi
00401EE4   .>call KeyGenMe.00401260                   ;并转化为链表形式
00401EE9   .>mov bl,byte ptr ds:               ;链表头(注册码前两位16进制值)
00401EEB   .>mov esi,dword ptr ds:         ;esi-next
00401EEE   .>push eax
00401EEF   .>mov byte ptr ss:,bl
00401EF3   .>call <jmp.&MFC42.#825>
00401EF8   .>mov edi,dword ptr ss:
00401EFC   .>add esp,0x18
00401EFF   .>lea eax,dword ptr ss:
00401F03   .>push edi
00401F04   .>push esi
00401F05   .>push ecx
00401F06   .>mov ecx,esp
00401F08   .>mov dword ptr ss:,esp
00401F0C   .>push eax
00401F0D   .>call <jmp.&MFC42.#535>
00401F12   .>call KeyGenMe.004013D0                   ;对注册码的运算1
00401F17   .>add esp,0xC
00401F1A   .>push edi
00401F1B   .>push ecx
00401F1C   .>mov ecx,esp
00401F1E   .>mov dword ptr ss:,esp
00401F22   .>push ebp
00401F23   .>call <jmp.&MFC42.#535>
00401F28   .>push ecx
00401F29   .>lea edx,dword ptr ss:
00401F2D   .>mov ecx,esp
00401F2F   .>mov dword ptr ss:,esp
00401F33   .>push edx
00401F34   .>mov byte ptr ss:,0x2
00401F39   .>call <jmp.&MFC42.#535>
00401F3E   .>lea eax,dword ptr ss:
00401F42   .>mov byte ptr ss:,0x1
00401F47   .>push eax
00401F48   .>call KeyGenMe.00401430                   ;对用户名的运算1
00401F4D   .>add esp,0x10
00401F50   .>push eax
00401F51   .>lea ecx,dword ptr ss:
00401F55   .>mov byte ptr ss:,0x3
00401F5A   .>call <jmp.&MFC42.#858>
00401F5F   .>lea ecx,dword ptr ss:
00401F63   .>mov byte ptr ss:,0x1
00401F68   .>call <jmp.&MFC42.#800>
00401F6D   .>mov ecx,dword ptr ss:
00401F71   .>mov eax,dword ptr ds:
00401F74   .>lea ecx,dword ptr ss:
00401F78   .>push eax
00401F79   .>push 0x0
00401F7B   .>call <jmp.&MFC42.#2915>
00401F80   .>push eax
00401F81   .>call KeyGenMe.00401260
00401F86   .>push eax
00401F87   .>call KeyGenMe.004011D0                   ;对用户名的运算2
00401F8C   .>push esi
00401F8D   .>mov ebp,eax
00401F8F   .>call KeyGenMe.004011D0                   ;对注册码的运算2
00401F94   .>push edi
00401F95   .>push ebp
00401F96   .>mov esi,eax
00401F98   .>call KeyGenMe.004015D0                   ;对用户名的运算3
00401F9D   .>inc bl
00401F9F   .>mov edi,eax
00401FA1   .>push ebx
00401FA2   .>push esi
00401FA3   .>call KeyGenMe.004015D0                   ;对注册码的运算3
00401FA8   .>push eax
00401FA9   .>push edi
00401FAA   .>call KeyGenMe.004017A0                   ;判断最后操作后两字是否相等
00401FAF   .>add esp,0x28                           ;如果eax==1,则正确
00401FB2   .>inc eax
00401FB3   .>call dword ptr ds:
00401FBA   >>lea ecx,dword ptr ss:
00401FBE   .>mov byte ptr ss:,0x0
00401FC3   .>call <jmp.&MFC42.#800>
00401FC8   .>lea ecx,dword ptr ss:
00401FCC   .>mov dword ptr ss:,-0x1
00401FD4   .>call <jmp.&MFC42.#800>
00401FD9   .>mov ecx,dword ptr ss:
00401FDD   .>pop edi
00401FDE   .>pop esi
00401FDF   .>pop ebp
00401FE0   .>mov dword ptr fs:,ecx
00401FE7   .>pop ebx
00401FE8   .>add esp,0x20
00401FEB   .>retn


分析可以得到,用户名和注册码都是经过3次运算得到值后比较是否相等
因为这里运算后不是以普通的每个元素相邻的字符串形式,而是链表模式
struct XXX
{
      char value;
      XXX *next;
}
这样就很难看到直观的数据,很难分析
但是可以发现因为next指针的地址都在value的地址+4,所以可以用个小脚本来获取直观的数据
mov mem,XXXXXXXX
mov long,0
mov tmp,eax
loop:
mov ,,1
inc long
mov tmp,
cmp tmp,0
jne loop
pause
pause

获取直观数据后就可以了解个大概
下面是测试的数据:

用户名:
11111
第一次运算后:
E1 D1 30 2D 4A
第二次运算后:
0E 01 0D 01 03 00 02 0D 04 0A
第三次运算后:
0E 0D 01 03 01 02 00 04 0D 0A


注册码:
222222222222
转化为16进制后:
22 22 22 22 22 22
第一次运算后:
F4 ED 50 2B 46
第二次运算后:
0F 04 0E 0D 05 00 02 0B 04 06
第三次运算后:
0F 0E 05 04 02 0D 04 00 06 0B

最后只要它们第3次运算后的值相等就成功了

然后可以一步步的解决:

对用户名的运算1:
00401F48   .>call KeyGenMe.00401430                   ;对用户名的运算1
00401430/$ >push -0x1
00401432|. >push KeyGenMe.0040250F                   ;SE 处理程序安装
00401437|. >mov eax,dword ptr fs:
0040143D|. >push eax
0040143E|. >mov dword ptr fs:,esp
00401445|. >sub esp,0xC
00401448|. >push ebx
00401449|. >push esi
0040144A|. >push edi
0040144B|. >mov dword ptr ss:,0x0
00401453|. >lea ecx,dword ptr ss:
00401457|. >mov dword ptr ss:,0x2
0040145F|. >call <jmp.&MFC42.#540>
00401464|. >mov eax,dword ptr ss:
00401468|. >xor esi,esi
0040146A|. >xor edi,edi
0040146C|. >mov byte ptr ss:,0x3
00401471|. >mov ecx,dword ptr ds:
00401474|. >test ecx,ecx
00401476|. >jle short KeyGenMe.004014DC
00401478|. >mov edx,dword ptr ss:
0040147C|. >mov bl,byte ptr ss:            ;传进的参数[注册码的第一个值]
00401480|> >/mov cl,byte ptr ds:            ;逐个取用户名字符值
00401483|. >|mov al,byte ptr ds:            ;逐个取"52PoJie"字符串
00401486|. >|xor al,cl                               ;异或
00401488|. >|cmp al,bl
0040148A|. >|mov byte ptr ss:,al
0040148E|. >|jb short KeyGenMe.00401494
00401490|. >|sub al,bl                               ;减
00401492|. >|jmp short KeyGenMe.004014AE
00401494|> >|mov eax,dword ptr ss:
00401498|. >|mov edx,dword ptr ss:
0040149C|. >|and eax,0xFF
004014A1|. >|and edx,0xFF
004014A7|. >|sub eax,edx                           ;减
004014A9|. >|add eax,0xFF
004014AE|> >|mov byte ptr ss:,al
004014B2|. >|mov bl,cl
004014B4|. >|mov eax,dword ptr ss:
004014B8|. >|lea ecx,dword ptr ss:
004014BC|. >|push eax
004014BD|. >|mov byte ptr ss:,bl
004014C1|. >|call <jmp.&MFC42.#940>
004014C6|. >|mov edx,dword ptr ss:
004014CA|. >|inc esi
004014CB|. >|cmp esi,dword ptr ds:
004014CE|. >|jl short KeyGenMe.004014D2            ;超过从头开始
004014D0|. >|xor esi,esi
004014D2|> >|mov eax,dword ptr ss:
004014D6|. >|inc edi
004014D7|. >|cmp edi,dword ptr ds:
004014DA|.^>\jl short KeyGenMe.00401480
004014DC|> >mov esi,dword ptr ss:
004014E0|. >lea ecx,dword ptr ss:
004014E4|. >push ecx
004014E5|. >mov ecx,esi
004014E7|. >call <jmp.&MFC42.#535>
004014EC|. >mov ebx,0x1
004014F1|. >mov dword ptr ss:,ebx
004014F5|. >lea ecx,dword ptr ss:
004014F9|. >mov byte ptr ss:,0x2
004014FE|. >call <jmp.&MFC42.#800>
00401503|. >lea ecx,dword ptr ss:
00401507|. >mov byte ptr ss:,bl
0040150B|. >call <jmp.&MFC42.#800>
00401510|. >lea ecx,dword ptr ss:
00401514|. >mov byte ptr ss:,0x0
00401519|. >call <jmp.&MFC42.#800>
0040151E|. >mov ecx,dword ptr ss:
00401522|. >mov eax,esi
00401524|. >pop edi
00401525|. >pop esi
00401526|. >pop ebx
00401527|. >mov dword ptr fs:,ecx
0040152E|. >add esp,0x18
00401531\. >retn


其中有一个参数是注册码16进制的第一个值
这样就可以写代码了

string dealT1(string t0,string t1,char t2h)//用户名第1次运算,需要注册码16进制的前两位
{
      int i=0;
      int i0=0;
      int th=t2h;
      th&=0xFF;
      string rs="";
      while(t1)
      {
                int tmp=t1;
                int tmp1=t0;
                tmp&=0xFF;
                tmp1&=0xFF;
                tmp^=tmp1;
                tmp-=th;
                if(tmp<0)
                {
                        tmp&=0xFF;
                        tmp--;
                }
                char tmp3=tmp;
                rs+=tmp3;
                th=t1;
                i0++;
                if(i0==7)
                        i0=0;
                i++;
      }
      return rs;
}
第二次运算只是将第一次运算结果的高位低位分离
CALL在004011D0
转化为代码为
string deal2(string s)//运算的第2次,高位低位分开
{
      string str="";
      int i=0;
      while(i<s.length())
      {
                int v=s;
                v&=0xFF;
                char c1=v/16;
                char c2=v%16;
                str+=c1;
                str+=c2;
                i++;
      }
      return str;
}

用户名的第3次运算为将第2次结果重新排序
004016FF|> \8B7C24 1C   mov edi,dword ptr ss:          ;案例 0 --> 分支 0040160C
00401703|.57            push edi
00401704|.E8 37FEFFFF   call KeyGenMe.00401540
00401709|.99            cdq
0040170A|.2BC2          sub eax,edx
0040170C|.83C4 04       add esp,0x4
0040170F|.D1F8          sar eax,1
00401711|.83F8 01       cmp eax,0x1
00401714|.7E 4F         jle short KeyGenMe.00401765
00401716|.8D68 FF       lea ebp,dword ptr ds:
00401719|>6A 01         /push 0x1                              ;取第一个元素
0040171B|.57            |push edi
0040171C|.E8 2FFEFFFF   |call KeyGenMe.00401550
00401721|.6A 08         |push 0x8
00401723|.8BFA          |mov edi,edx
00401725|.8806          |mov byte ptr ds:,al
00401727|.E8 EC090000   |call <jmp.&MFC42.#823>                  ;删除
0040172C|.33C9          |xor ecx,ecx
0040172E|.8946 04       |mov dword ptr ds:,eax
00401731|.8908          |mov dword ptr ds:,ecx
00401733|.6A 02         |push 0x2                              ;取第二个元素
00401735|.8948 04       |mov dword ptr ds:,ecx
00401738|.8B76 04       |mov esi,dword ptr ds:
0040173B|.57            |push edi
0040173C|.E8 0FFEFFFF   |call KeyGenMe.00401550
00401741|.6A 08         |push 0x8
00401743|.8BD8          |mov ebx,eax
00401745|.8BFA          |mov edi,edx
00401747|.E8 CC090000   |call <jmp.&MFC42.#823>                  ;删除
0040174C|.33D2          |xor edx,edx
0040174E|.8946 04       |mov dword ptr ds:,eax
00401751|.8910          |mov dword ptr ds:,edx
00401753|.83C4 18       |add esp,0x18
00401756|.8950 04       |mov dword ptr ds:,edx
00401759|.881E          |mov byte ptr ds:,bl
0040175B|.8B76 04       |mov esi,dword ptr ds:
0040175E|.4D            |dec ebp
0040175F|.^ 75 B8         \jnz short KeyGenMe.00401719             ;循环直到都取完
00401761|.8B5C24 10   mov ebx,dword ptr ss:
00401765|>6A 01         push 0x1
00401767|.57            push edi
00401768|.E8 E3FDFFFF   call KeyGenMe.00401550
0040176D|.6A 08         push 0x8
0040176F|.8BFA          mov edi,edx
00401771|.8806          mov byte ptr ds:,al
00401773|.E8 A0090000   call <jmp.&MFC42.#823>
00401778|.33C9          xor ecx,ecx
0040177A|.8946 04       mov dword ptr ds:,eax
0040177D|.8908          mov dword ptr ds:,ecx
0040177F|.6A 01         push 0x1
00401781|.8948 04       mov dword ptr ds:,ecx
00401784|.8B76 04       mov esi,dword ptr ds:
00401787|.57            push edi
00401788|.E8 C3FDFFFF   call KeyGenMe.00401550
0040178D|.83C4 14       add esp,0x14
00401790|.895424 14   mov dword ptr ss:,edx
00401794|.8806          mov byte ptr ds:,al
00401796|>5F            pop edi                                  ;分支 0040160C 默认案例
00401797|.5E            pop esi
00401798|.8BC3          mov eax,ebx
0040179A|.5D            pop ebp
0040179B|.5B            pop ebx
0040179C|.83C4 08       add esp,0x8
0040179F\.C3            retn

写成代码很简单:
string dealT1_1(string s)//用户名第3次运算,
{
      string s0=s;
      string str="";
      while(s0.length()!=0)
      {
                str+=s0;
                s0.erase(0,1);
                if(s0.length()==1)
                {
                        str+=s0;
                        s0.erase(0,1);
                }
                else
                {
                        str+=s0;
                        s0.erase(1,1);
                }

      }
      return str;
}
然后就是注册码第3次运算的逆运算了
先看看正运算:
0040161C|.8B7424 1C   mov esi,dword ptr ss:          ;案例 1 --> 分支 0040160C
00401620|.56            push esi
00401621|.E8 1AFFFFFF   call KeyGenMe.00401540
00401626|.99            cdq
00401627|.2BC2          sub eax,edx
00401629|.6A 01         push 0x1                                 ;先取第1个
0040162B|.8BE8          mov ebp,eax
0040162D|.56            push esi
0040162E|.D1FD          sar ebp,1
00401630|.83ED 02       sub ebp,0x2
00401633|.E8 18FFFFFF   call KeyGenMe.00401550
00401638|.6A 02         push 0x2                                 ;再取第3个
0040163A|.52            push edx
0040163B|.8803          mov byte ptr ds:,al
0040163D|.E8 0EFFFFFF   call KeyGenMe.00401550
00401642|.6A 08         push 0x8
00401644|.894424 28   mov dword ptr ss:,eax
00401648|.8BFA          mov edi,edx
0040164A|.E8 C90A0000   call <jmp.&MFC42.#823>                   ;删除
0040164F|.33D2          xor edx,edx
00401651|.8943 04       mov dword ptr ds:,eax
00401654|.8910          mov dword ptr ds:,edx
00401656|.83C4 18       add esp,0x18
00401659|.8950 04       mov dword ptr ds:,edx
0040165C|.8B73 04       mov esi,dword ptr ds:
0040165F|.8A4424 10   mov al,byte ptr ss:
00401663|.83FD 01       cmp ebp,0x1
00401666|.8806          mov byte ptr ds:,al
00401668|.7C 46         jl short KeyGenMe.004016B0
0040166A|>6A 08         /push 0x8
0040166C|.E8 A70A0000   |call <jmp.&MFC42.#823>                  ;删除
00401671|.33C9          |xor ecx,ecx
00401673|.8946 04       |mov dword ptr ds:,eax
00401676|.8908          |mov dword ptr ds:,ecx
00401678|.6A 03         |push 0x3                              ;取第3个
0040167A|.8948 04       |mov dword ptr ds:,ecx
0040167D|.8B76 04       |mov esi,dword ptr ds:
00401680|.57            |push edi
00401681|.E8 CAFEFFFF   |call KeyGenMe.00401550
00401686|.6A 08         |push 0x8
00401688|.8BFA          |mov edi,edx
0040168A|.8806          |mov byte ptr ds:,al
0040168C|.E8 870A0000   |call <jmp.&MFC42.#823>                  ;删除
00401691|.33D2          |xor edx,edx
00401693|.8946 04       |mov dword ptr ds:,eax
00401696|.8910          |mov dword ptr ds:,edx
00401698|.6A 01         |push 0x1                              ;取第一个
0040169A|.8950 04       |mov dword ptr ds:,edx
0040169D|.8B76 04       |mov esi,dword ptr ds:
004016A0|.57            |push edi
004016A1|.E8 AAFEFFFF   |call KeyGenMe.00401550
004016A6|.83C4 18       |add esp,0x18
004016A9|.4D            |dec ebp
004016AA|.8806          |mov byte ptr ds:,al
004016AC|.8BFA          |mov edi,edx
004016AE|.^ 75 BA         \jnz short KeyGenMe.0040166A             ;循环直到取完
004016B0|>6A 08         push 0x8
004016B2|.E8 610A0000   call <jmp.&MFC42.#823>
004016B7|.33C9          xor ecx,ecx
004016B9|.8946 04       mov dword ptr ds:,eax
004016BC|.8908          mov dword ptr ds:,ecx
004016BE|.6A 02         push 0x2
004016C0|.8948 04       mov dword ptr ds:,ecx
004016C3|.8B76 04       mov esi,dword ptr ds:
004016C6|.57            push edi
004016C7|.E8 84FEFFFF   call KeyGenMe.00401550
004016CC|.6A 08         push 0x8
004016CE|.8BFA          mov edi,edx
004016D0|.8806          mov byte ptr ds:,al
004016D2|.E8 410A0000   call <jmp.&MFC42.#823>
004016D7|.33D2          xor edx,edx
004016D9|.8946 04       mov dword ptr ds:,eax
004016DC|.8910          mov dword ptr ds:,edx
004016DE|.6A 01         push 0x1
004016E0|.8950 04       mov dword ptr ds:,edx
004016E3|.8B76 04       mov esi,dword ptr ds:
004016E6|.57            push edi
004016E7|.E8 64FEFFFF   call KeyGenMe.00401550
004016EC|.83C4 18       add esp,0x18
004016EF|.8806          mov byte ptr ds:,al
004016F1|.8BC3          mov eax,ebx
004016F3|.895424 14   mov dword ptr ss:,edx
004016F7|.5F            pop edi
004016F8|.5E            pop esi
004016F9|.5D            pop ebp
004016FA|.5B            pop ebx
004016FB|.83C4 08       add esp,0x8
004016FE|.C3            retn

逆运算代码为:
string dealT2_1(string s)//注册码第3次运算的逆运算
{
      string s0=s;
      string str="";
      int i=s0.length()-1;
      str+=s0;
      str+=s0;
      i-=2;
      while(i>1)
      {
                str.insert(0,s0,i,1);
                i--;
                str.insert(2,s0,i,1);
                i--;
      }
      str.insert(1,s0,1,1);
      str.insert(0,s0,0,1);
      return str;
}
然后是第二次运算的逆运算
就是奇数变高位,偶数变低位
string deal2_1(string s)//第2次运算的逆运算
{
      string str="";
      int i=0;
      while(i<s.length())
      {
                char c=s*16;
                c+=s;
                str+=c;
                i+=2;
      }
      return str;
}
最后就是注册码第一次运算的逆运算了:
先看看call:

; 参数有注册码16进制的第一个,注册码第二位开始的链表,"52PoJie"
004013D0/$8B4C24 08   mov ecx,dword ptr ss:
004013D4|.8B4424 04   mov eax,dword ptr ss:
004013D8|.56            push esi
004013D9|.33F6          xor esi,esi
004013DB|>33D2          /xor edx,edx
004013DD|.8A1406      |mov dl,byte ptr ds:   ;逐个取"52PoJie"字符
004013E0|.8BC2          |mov eax,edx
004013E2|.33D2          |xor edx,edx
004013E4|.8A11          |mov dl,byte ptr ds:         ;逐个取注册码的16进制
004013E6|.33C2          |xor eax,edx                      ;异或
004013E8|.8B5424 10   |mov edx,dword ptr ss:;这个参数是注册码的前1位16进制
004013EC|.81E2 FF000000 |and edx,0xFF
004013F2|.2BC2          |sub eax,edx                      ;相减
004013F4|.79 05         |jns short KeyGenMe.004013FB      ;符号问题
004013F6|.05 FF000000   |add eax,0xFF
004013FB|>8A11          |mov dl,byte ptr ds:
004013FD|.8801          |mov byte ptr ds:,al
004013FF|.8B4424 08   |mov eax,dword ptr ss:
00401403|.8B49 04       |mov ecx,dword ptr ds:
00401406|.885424 10   |mov byte ptr ss:,dl
0040140A|.46            |inc esi
0040140B|.3B70 F8       |cmp esi,dword ptr ds:   ;超出"52PoJie"长度,从头开始
0040140E|.7C 02         |jl short KeyGenMe.00401412
00401410|.33F6          |xor esi,esi
00401412|>85C9          |test ecx,ecx
00401414|.^ 75 C5         \jnz short KeyGenMe.004013DB      ;直到取完
00401416|.8D4C24 08   lea ecx,dword ptr ss:
0040141A|.E8 E10C0000   call <jmp.&MFC42.#800>
0040141F|.5E            pop esi
00401420\.C3            retn

这个的逆运算是我的最蛋疼的了,因为这个符号问题
string dealT2_2(string s,string t0,char t2h)//注册码第一次运算的逆运算
{
      string s0=s;
      string str="";
      str+=t2h;
      int i=0;
      int i0=0;
      int tmp;
      while(i<s0.length())
      {
                int p0=str;
                tmp=s0;
                tmp+=p0;
                tmp^=t0;
                int p1=tmp^t0;
                p1=p1&0xFF;
                int p2=p0&0xFF;
                p1=p1-p2;
                if(p1<0)
                {
                        tmp=s0;
                        tmp&=0xFF;
                        tmp+=p0;
                        tmp++;
                        tmp^=t0;
                }
                str+=tmp;
               
                i++;
                i0++;
                if(i0==7)
                        i0=0;
               
      }
      return str;
}

所以注册机就可以完成了,先输入用户名,再输入一个两位的16进制数作为注册码的前两位
一个用户名有很多个注册码。









注册机:

代码文件:

vc6工程:

brack 发表于 2013-12-16 10:28

厉害...膜拜算法牛.学习了.

258239234 发表于 2013-12-16 10:37

头彻底晕了,高手啊

Cari丶 发表于 2013-12-16 11:01

感谢分析。内容有待消化。膜拜算法牛

bambooqj 发表于 2013-12-16 11:44

师傅 你太流弊了。。。

xjun 发表于 2013-12-16 11:54

我是来膜拜的,感谢大牛分享精彩文章。

Ylca 发表于 2013-12-16 11:57

xjun 发表于 2013-12-16 11:54 static/image/common/back.gif
我是来膜拜的,感谢大牛分享精彩文章。

膜拜xjun大牛 !!

YooGa 发表于 2013-12-16 12:03

唉,好复杂的样子

20120427 发表于 2013-12-16 17:21

{:1_932:}膜拜大牛

87412598 发表于 2013-12-16 17:24

楼主辛苦了、
页: [1] 2
查看完整版本: 【吾爱2013CM大赛解答】--KeyGenMe-- a070458 -- 算法分析-注册机编写[〇〇木一]