zoukankan      html  css  js  c++  java
  • emu8086注册算法分析及KeyGen实现

    from:http://www.2cto.com/Article/201204/127992.html

    【文章作者】: NoAir
    【软件名称】: emu8086 v4.08
    【保护方式】: 有点戏剧性
    【编写语言】: Visual Basic
    【软件介绍】: 一款优秀的8086汇编IDE,支持可视化调试,内置FASM
    【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
    --------------------------------------------------------------------------------
    【详细过程】
      仅以此文纪念一下emu8086,现在官网不能打开了,软件也不更新了,用emu8086编写16位汇编程序挺方便的,图形化的操作模式,支持调试,还有一些模板以及虚拟设备供操作。我把emu8086 v4.08和KeyGen及src都上传到了本地。
     
      写完KeyGen之后才发现以前有位朋友发过一篇关于emu8086破解的文章,但是这不影响本文的分析,本文主要分析emu8086另外一种注册算法,有兴趣的朋友就当温习一下VB的逆向,走马观花一下吧。
     
      如何找关键点,这个不用说了,直接搜索字符串,然后回溯就看得见了
     
      下面步入正题,为什么说是戏剧性呢,看看下面的代码就知道:
      005DA83A   .  test edx,edx
      005DA83C   .  je short emu8086.005DA850                ; 戏剧性的je,如果前3位是112
      005DA83E   .  mov dword ptr ss:[ebp-4],4
      005DA845   .  mov word ptr ss:[ebp-24],0FFFF           ; 返回值为-1
      005DA84B   .  jmp emu8086.005DAAA5                     ; 注册成功
     
      分析完戏剧性的代码后,下面开始分析另一种注册算法:
      005DAA12   .  mov dword ptr ss:[ebp-4],10
      005DAA19   .  mov ecx,dword ptr ss:[ebp+C]
      005DAA1C   .  mov edx,dword ptr ds:[ecx]
      005DAA1E   .  mov dword ptr ss:[ebp-64],edx
      005DAA21   .  mov dword ptr ss:[ebp-6C],8
      005DAA28   .  mov eax,dword ptr ss:[ebp+10]
      005DAA2B   .  push eax
      005DAA2C   .  mov ecx,dword ptr ss:[ebp+8]            ;  用户名
      005DAA2F   .  mov edx,dword ptr ds:[ecx]
      005DAA31   .  push edx
      005DAA32   .  lea eax,dword ptr ss:[ebp-3C]
      005DAA35   .  push eax
      005DAA36   .  call emu8086.005DAAF0                   ;  注册码计算
     
      上面有一行mov dword ptr ss:[ebp-4],10
      Dim state as integer
      state=10
      作者代码中频频出现类似的赋值语句,估计是用于判断语句执行到哪一行了吧,类似的语句可以全部忽略了。
     
      进入5DAAF0,
      005DAAF0   $  push ebp
      005DAAF1   .  mov ebp,esp
      005DAAF3   .  sub esp,18
      005DAAF6   .  push <jmp.&MSVBVM60.__vbaExceptHandler>      ;  SE 处理程序安装
      ............................
      005DAB35   .  mov edx,dword ptr ss:[ebp+C]
      005DAB38   .  lea ecx,dword ptr ss:[ebp-38]
      005DAB3B   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化name=用户名
      ............................
      005DAB57   .  mov edx,emu8086.00450CA4                     ;  abcdefghijklmnopqrstuvwxyz
      005DAB5C   .  lea ecx,dword ptr ss:[ebp-5C]
      005DAB5F   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化str1
      005DAB6C   .  mov edx,emu8086.00450CE0                     ;  qw10pasdfghjklzxcvbnmertyu
      005DAB71   .  lea ecx,dword ptr ss:[ebp-28]
      005DAB74   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化str2
      005DAB81   .  mov edx,emu8086.00450D1C                     ;  z9rtasdf01823asjfsd1234346gfhplmasdr613412qwerx
      005DAB86   .  lea ecx,dword ptr ss:[ebp-2C]
      005DAB89   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化str3
      005DAB96   .  mov edx,emu8086.00450D80                     ;  jkaserkkn837c3frtqzx
      005DAB9B   .  lea ecx,dword ptr ss:[ebp-50]
      005DAB9E   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化str4
      005DABAB   .  mov edx,emu8086.004376EC
      005DABB0   .  lea ecx,dword ptr ss:[ebp-4C]
      005DABB3   .  call dword ptr ds:[<&MSVBVM60.__vbaStrCopy>] ;  初始化key为空字符串
      ...........................
      005DABD9   .  push ecx
      005DABDA   .  lea edx,dword ptr ss:[ebp-6C]
      005DABDD   .  push edx
      005DABDE   .  call dword ptr ds:[<&MSVBVM60.rtcUpperCaseVar>]  ;  用户名转换成大写,保存到[ebp-58]
      ...........................
      005DABF0   .  lea ecx,dword ptr ss:[ebp-58]
      005DABF3   .  call dword ptr ds:[<&MSVBVM60.__vbaStrMove>] ;  MSVBVM60.__vbaStrMove
     
      005DAC09   .  lea ecx,dword ptr ss:[ebp-58]                ;  FINSOS
      005DAC0C   .  push ecx
      005DAC0D   .  call emu8086.00548830                        ;  用户名翻转
      {
        00548875   .  push eax                                     ; 用户名
        00548876   .  call dword ptr ds:[<&MSVBVM60.__vbaLenBstr>] ; 得到用户名长度,用户名是用unicode编码的
        0054887C   .  mov ecx,eax
        0054887E   .  call dword ptr ds:[<&MSVBVM60.__vbaI2I4>]    ; 用户名长度转换成long型
        00548884   .  mov esi,eax
        00548886   >  mov eax,1
        0054888B   .  cmp si,ax
        0054888E   .  jl short emu8086.005488F6
        .......................................
        005488B4   .  call dword ptr ds:[<&MSVBVM60.rtcMidCharVar>];截取最后第i字符,i初始为用户名长度,循环自减
        ;esi--
        005488F4   .  jmp short emu8086.00548886
      }
     
      005DAC24   .  mov word ptr ss:[ebp-24],1                   ;  i=1
      005DAC31   .  mov word ptr ss:[ebp-34],1                   ;  j=1
      005DAC3E   .  mov word ptr ss:[ebp-54],0                   ;  flag 初始化0
      005DAC4B   .  movsx esi,word ptr ss:[ebp-24]               ;  i 循环体
      005DAC4F   .  mov edx,dword ptr ss:[ebp-58]
      005DAC52   .  push edx                                     ;  用户名name
      005DAC53   .  call dword ptr ds:[<&MSVBVM60.__vbaLenBstr>] ;  __vbaLenBstr
      005DAC59   .  xor ebx,ebx
      005DAC5B   .  cmp esi,eax
      005DAC5D   .  setg bl
      005DAC60   .  movsx esi,word ptr ss:[ebp-34]
      005DAC64   .  mov eax,dword ptr ss:[ebp-50]
      005DAC67   .  push eax                                     ; str4
      005DAC68   .  call dword ptr ds:[<&MSVBVM60.__vbaLenBstr>] ; __vbaLenBstr
      005DAC6E   .  xor ecx,ecx
      005DAC70   .  cmp esi,eax
      005DAC72   .  setg cl
      005DAC75   .  or ebx,ecx
      005DAC77   .  test ebx,ebx
      005DAC79   .  jnz emu8086.005DAF65                         ; for (i=1;i<=user_len && j<=0x14;i++)
      {
      005DACCE   .  call dword ptr ds:[<&MSVBVM60.#632>]           ;  rtcMidCharVar截取name中第i个字符
      005DACEA   .  call dword ptr ds:[<&MSVBVM60.__vbaInStrVar>]  ;  查找str1中索引位置u_index
      005DACF0   .  push eax
      005DACF1   .  call dword ptr ds:[<&MSVBVM60.__vbaI2Var>]     ;  MSVBVM60.__vbaI2Var
      005DAD21   .  jle emu8086.005DAF02                           ;  u_index小于0,说明没搜索到 因此不是字母
     
      005DAD2E   .  cmp word ptr ss:[ebp-54],1                     ;  判断flag是否为1
      005DAD33   .  jnz emu8086.005DADE4
      ;if flag==0
      {
      005DAD88   .  call dword ptr ds:[<&MSVBVM60.#632>]           ; rtcMidCharVar截取str2中第u_index个字符
      ;接下来保存字符到key中,并修改flag为1
      005DAE58   .  mov edx,eax                                    ;  第u_index个字符
      005DAE5A   .  lea ecx,dword ptr ss:[ebp-4C]
      005DAE5D   .  call dword ptr ds:[<&MSVBVM60.__vbaStrMove>]   ;  保存key中
      005DAE84   .  mov word ptr ss:[ebp-54],1                     ;  flag 赋值为1
      }
      ;else
      {
      ........   .  call dword ptr ds:[<&MSVBVM60.#632>]           ; rtcMidCharVar截取str3中第u_index个字符
      ;接下来保存字符到key中,并修改flag为0
      }
      005DAE91   .  mov dx,word ptr ss:[ebp-34]                    ;  j++
      005DAE95   .  add dx,1
      005DAE9F   .  mov word ptr ss:[ebp-34],dx
     
      005DAEAA   .  lea eax,dword ptr ss:[ebp-28]
      005DAEAD   .  push eax
      005DAEAE   .  call <emu8086.move>                            ;  move(str2),move函数的功能是把字符串尾字符移动到首位
      005DAEC5   .  lea ecx,dword ptr ss:[ebp-2C]
      005DAEC8   .  push ecx
      005DAEC9   .  call <emu8086.move>                            ;  move(str3)
      005DAEE0   .  cmp word ptr ss:[ebp-54],1                     ;  flag为1
      005DAEE5   .  jnz short emu8086.005DAF02
      {
      005DAEEE   .  lea edx,dword ptr ss:[ebp-28]
      005DAEF1   .  push edx
      005DAEF2   .  call <emu8086.move>                            ;  move(str2)
      }
      005DAF09   .  lea eax,dword ptr ss:[ebp-50]
      005DAF0C   .  push eax
      005DAF0D   .  call <emu8086.move>                            ;  move(str4)
      005DAF24   .  movsx ecx,word ptr ss:[ebp-54]
      005DAF28   .  test ecx,ecx
      005DAF2A   .  jnz short emu8086.005DAF47                     ;  flag为0
      {
      005DAF33   .  lea edx,dword ptr ss:[ebp-50]
      005DAF36   .  push edx
      005DAF37   .  call <emu8086.move>                            ;  move(str4)
      }
      005DAF4E   .  mov ax,word ptr ss:[ebp-24]                    ;  i ++
      005DAF52   .  add ax,1
      005DAF5C   .  mov word ptr ss:[ebp-24],ax
      005DAF60   .^ jmp emu8086.005DAC44
     
      ;move函数(char* str)
      {
      005DB234   .  call dword ptr ds:[<&MSVBVM60.#632>]           ;  rtcMidCharVar截取str最后一个字符
      005DB244   .  mov edx,eax
      005DB246   .  lea ecx,dword ptr ss:[ebp-24]
      005DB2AF   .  mov word ptr ss:[ebp-28],dx                    ;  m++ 截取位置
      005DB2B3   >  mov ax,word ptr ss:[ebp-28]
      005DB2B7   .  cmp ax,word ptr ss:[ebp-94]                    ;  str长度
      005DB2BE   .  jg emu8086.005DB35A
      {
      005DB30A   .  call dword ptr ds:[<&MSVBVM60.#632>]           ;  rtcMidCharVar循环向后移动字符
      005DB355   .^ jmp emu8086.005DB29E
      }
      }
     
      ;主循环结束
      005DAF6C   . movsx esi,word ptr ss:[ebp-34]                 ;  j
      005DAF70   . mov ecx,dword ptr ss:[ebp-50]                  ;  str4
      005DAF73   . push ecx                                       ;  str4
      005DAF74   . call dword ptr ds:[<&MSVBVM60.__vbaLenBstr>]   ;  得到str4长度
      005DAF7A   . cmp esi,eax                                    ;  判断是否大于j
      005DAF7C   . jg emu8086.005DB039
      {
      005DAFD1   . call dword ptr ds:[<&MSVBVM60.#632>]           ;  rtcMidCharVar
      005DAFF8   . lea ecx,dword ptr ss:[ebp-4C]                  ;  4C是result?
      005DAFFB   . call dword ptr ds:[<&MSVBVM60.__vbaStrMove>]   ;  MSVBVM60.__vbaStrMove
      005DB022   . mov dx,word ptr ss:[ebp-34]
      005DB026   . add dx,1                                       ;  j++
      005DB030   . mov word ptr ss:[ebp-34],dx
      005DB034   .^jmp emu8086.005DAF65                           ;  循环填充key
      }
     
      005DB040   .  mov eax,dword ptr ss:[ebp+10]                  ;  g_count是0x64
      005DB043   .  mov cx,word ptr ds:[eax]
      005DB046   .  sub cx,1                                       ;  g_count-1得到0x63
      005DB050   .  mov word ptr ss:[ebp-C4],cx
      005DB057   .  mov word ptr ss:[ebp-C0],1
      005DB060   .  mov word ptr ss:[ebp-24],1
      005DB066   .  jmp short emu8086.005DB07D
      005DB068   >  mov dx,word ptr ss:[ebp-24]
      005DB06C   .  add dx,word ptr ss:[ebp-C0]                    ;  i++
      005DB079   .  mov word ptr ss:[ebp-24],dx
      005DB07D   >  mov ax,word ptr ss:[ebp-24]
      005DB081   .  cmp ax,word ptr ss:[ebp-C4]                    ; &nbsp  005DB088   .  jg short emu8086.005DB0AE                      ;  循环0x63-i次
      {
      005DB08A   .  mov dword ptr ss:[ebp-4],29
      005DB091   .  lea ecx,dword ptr ss:[ebp-4C]
      005DB094   .  push ecx
      005DB095   .  call <emu8086.move>                            ;  循环move(key)
      005DB09A   .  mov edx,eax
      005DB0AC   .^ jmp short emu8086.005DB068
      }
     
      最后得到key,下面是纯C代码:调用keygen(szName,szKey,g_count);
     
    代码:
      //move功能是把字符串尾字符移动到首位
      void move(char* str){
        char temp;
        unsigned char len=0;
        while(*(str+len)) len++;
        temp=*(str+len-1);
        while(len){
          *(str+len-1)=*(str+len-2);
          len--;
        }
        *str=temp;
      }
      void keygen(char* name,char* key,unsigned char g_count){
        //初始化变量
        char str1[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //常量字符串,长度0x1A
        char str2[]="QW10PASDFGHJKLZXCVBNMERTYU";
        char str3[]="Z9RTASDF01823ASJFSD1234346GFHPLMASDR613412QWERX";
        char str4[]="JKASERKKN837C3FRTQZX";
        unsigned char i=1,j=1,user_len=-1,k=0; //user_len为name的长度
        BOOL flag=0,gbk_flag=0; //flag为交替标志,gbk_flag用于GBK编码的处理
        char u_char; //欲搜索的字符
        short u_index=0; //索引位置
       
        //用户名转换成大写
        while (++user_len,*name) *name++=*name>=0x61&&*name<=0x7A?*name-0x20:*name;
        //用户名翻转
        for ((i=0,name-=user_len);i<(int)user_len/2;i++)
        {
          *(char*)(name+i)^=*(char*)(name+user_len-i-1);
          *(char*)(name+user_len-i-1)^=*(char*)(name+i);
          *(char*)(name+i)^=*(char*)(name+user_len-i-1);
        }
        //主循环
        for (i=1;i<=user_len && j<=0x14;i++)
        {
          //在str1中搜索字符u_char,得到索引位置u_index
          u_index=0;
          u_char=*(name+i-1);
     
          while(u_index<0x1A){
            if (u_char==*(str1+u_index)){
              break;
            }
            u_index++;
          }
          u_index++; //最后还要加1,因为初始为0
     
          if (u_index<=0x1A){ //如果在str1中搜索到了u_char
            if (flag==1){
              *(key+k)=*(str2+u_index-1);
              k++;
              flag=0; //flag交替
            }
            else{ //等效于if flag==0
              *(key+k)=*(str3+u_index-1);
              k++;
              flag=1; //flag交替
            }
            j++; //j为当前key的长度
            move(str2);
            move(str3);
          }
          //GBK中文处理,摆脱name为unicode编码的限制
          if(u_char&0x80 && gbk_flag==0){gbk_flag=1;continue;}
          gbk_flag=0;
     
          if (flag==1){
            move(str2);
          }
          move(str4);
          if (flag==0)
          {
            move(str4);
          }
        }
        //如果key的长度小于0x14,则用str4补齐,直到j大于0x14
        do
        {
          if (j>0x14){
            break;
          }
          *(key+j-1)=*(str4+j-1);
          j++;
        } while(j<=0x14);
        i=0;
        g_count--;
        //如果name长度小于等于g_count-1,则循环移动key,直到i大于g_count-1
        do
        {
          if (i>(g_count-1)){
            break;
          }
          move(key);
          i++;
        } while(i<=g_count); //其中的0x63是g_count-1
      }

  • 相关阅读:
    枚举-完美立方
    list
    undefined reference to `typeinfo for xxx 报错
    bubble排序
    Iframe跨域传值
    Iframe------父子页面传值
    LDAP 概念
    覆盖equals()要覆盖HashCode()
    HashSet和TreeSet的实现与原理
    jvm调优
  • 原文地址:https://www.cnblogs.com/tk091/p/2456168.html
Copyright © 2011-2022 走看看