zoukankan      html  css  js  c++  java
  • 一个.net KeygenMe简单分析

    一个.net KeygenMe简单分析

    【文章标题】: foxabu的KeygenMe1的简单分析
    【文章作者】: hawking
    【作者邮箱】: rich_hawking@hotmail.com
    软件名称】: NativeClrMixedKeygenMe.exe
    【软件大小】: 52.0k
    下载地址】: http://bbs.pediy.com/showthread.php?s=&threadid=40887
    【编写语言】: .net
    【使用工具】: reflector PEBrowseDbg PEiD
    【操作平台】: win2k sp4
    【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
    --------------------------------------------------------------------------------
    【详细过程】
      foxabu兄台的这个KeygenMe没有加壳,甚至都没有作混淆处理,算法其实也超简单。正好适合我这样喜欢.net的菜鸟把玩。
      一、静态分析
      用reflector打开,很容易就定位到注册按钮的代码
      private unsafe void button_tryreg_Click(object sender, EventArgs e)
      {
          $ArrayType$$$BY0PP@D e$$$bypp@d;
          string s = this.textBox_reg.Text;
          string text = this.textBox_machineCode.Text;
          lpMachineCode = (sbyte modopt(IsSignUnspecifiedByte)*) Marshal.StringToHGlobalAnsi(text).ToPointer();
          int num2 = text.Length / 2;
          if ((s.Length >= num2) && native_decode1((sbyte modopt(IsSignUnspecifiedByte)*) Marshal.StringToHGlobalAnsi(s).ToPointer(), (sbyte modopt(IsSignUnspecifiedByte)*) &e$$$bypp@d, 0xff))
          {
              MessageBox.Show("\u6ce8\u518c\u6210\u529f^_^");
              this.button_tryreg.Enabled = false;
          }
          else
          {
              MessageBox.Show("\u597d\u50cf\u5931\u8d25\u4e86\u54e6,\u7ee7\u7eed\u54e6~\u5176\u5b9e\u5f88\u7b80\u5355\u7684");
          }
      }
      从上面这段代码可以看出,注册码的长度必须大于等于机器码长度的一半。而且程序会把取到的注册码和一个Array数组及0xFF作为参数,传递给一个native方法native_decode1。
      [return: MarshalAs(UnmanagedType.U1)]
      [PreserveSig, MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType=MethodCodeType.Native), SuppressUnmanagedCodeSecurity]
      public static unsafe bool modopt(CallConvCdecl) native_decode1(sbyte modopt(IsSignUnspecifiedByte)*, sbyte modopt(IsSignUnspecifiedByte)*, int);
      可以看出这个native方法会返回一个bool值,从名称看是解码用的。要注册成功,这里必须得返回true。但是这个是native方法,所以reflector分析不出来这个方法具体做了些什么。
      
      再看看reflector里还有没有什么有用的信息。
      private void FormMain_Load(object sender, EventArgs e)
      {
          this.textBox_machineCode.Text = GetmachineCode();
      }
      
      internal static unsafe string GetmachineCode()
      {
          sbyte modopt(IsSignUnspecifiedByte)* numPtr2 = (sbyte modopt(IsSignUnspecifiedByte)*) Marshal.StringToHGlobalAnsi(Environment.MachineName + Environment.UserName).ToPointer();
          sbyte modopt(IsSignUnspecifiedByte)* numPtr = (sbyte modopt(IsSignUnspecifiedByte)*) Marshal.AllocHGlobal(0xff).ToPointer();
          native_encode(numPtr2, numPtr, 0xff);
          IntPtr pUnk = new IntPtr(numPtr2);
          Marshal.Release(pUnk);
          IntPtr ptr = new IntPtr(numPtr);
          return Marshal.PtrToStringAnsi(ptr);
      }
      
      [PreserveSig, MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType=MethodCodeType.Native), SuppressUnmanagedCodeSecurity]
      public static unsafe void modopt(CallConvCdecl) native_encode(sbyte modopt(IsSignUnspecifiedByte)*, sbyte modopt(IsSignUnspecifiedByte)*, int);
       
      这里我们可以看出机器码其实是将系统环境变量中的MachineName和UserName组合起来,再经由native方法native_encode编码得到的。
       
      [return: MarshalAs(UnmanagedType.U1)]
      internal static unsafe bool modopt(CallConvCdecl) decodeAndCompare(sbyte modopt(IsSignUnspecifiedByte)* str)
      {
          int num2 = stackalloc byte[__CxxQueryExceptionSize()];
          IntPtr ptr2 = new IntPtr(lpMachineCode);
          string text2 = Marshal.PtrToStringAnsi(ptr2);
          IntPtr ptr = new IntPtr(str);
          string s = Marshal.PtrToStringAnsi(ptr);
          try
          {
              s = Encoding.ASCII.GetString(Convert.FromBase64String(s), 0, Convert.FromBase64String(s).Length);
          }
          catch when (?)
          {
              uint num = 0;
              __CxxRegisterExceptionObject((void*) Marshal.GetExceptionPointers(), (void*) num2);
              try
              {
                  try
                  {
                      return false;
                  }
                  catch when (?)
                  {
                  }
                  if (num != 0)
                  {
                      throw;
                  }
              }
              finally
              {
                  __CxxUnregisterExceptionObject((void*) num2, (int) num);
              }
          }
          return ((s == text2) ? ((bool modopt(CallConvCdecl)) true) : ((bool modopt(CallConvCdecl)) false));
      }
      
      还有上面这个方法,从名称看是用于解码并比较的。具体作用就是将传入的参数s看作Base64String,通过Convert.FromBase64String转换成byte数组,然后再通过Encoding.ASCII编码成ASCII字符串。并将得到的这个字符串和机器码作比较,相同则返回true。
      刚开始我就是因为没好好在reflector中找找有用的信息,忽略了这个方法,所以白花了不少冤枉功夫。
      
      二、动态调试
      用OD调试.net程序是一件很痛苦的事,这里我们使用PEBrowse进行动态调试。
      打开PEBrowse,载入NativeClrMixedKeygenMe.exe。不断F5并忽略碰到的异常,直到程序完全跑起来。
      菜单中选择View-->Modules Only,使左侧的树型控件只显示Modules。
      依次展开左侧的模块列表NativeClrMixedKeygenMe.exe--->.NET Methods--->NativeClrMixedKeygenMe.FormMain
      在button_tryreg_Click方法上下断点。输入注册码1234567890,点注册按钮
      Disassembly of JITTED NativeClrMixedKeygenMe.FormMain::button_tryreg_Click (06000078) at 0x04AEB9C8
        ; Stack Size (in BYTES): 288 (0x00000120)
        ; Number of Parameters: 1
        ; Local Variables Size (in BYTES): 272 (0x00000110)
        ; Prologue Size (in BYTES): 35 (0x23)
        ; Standard Frame
        0x4AEB9C8: 6A00                 PUSH        0x0   断在这里              
        0x4AEB9CA: 6A00                 PUSH        0x0                 
        0x4AEB9CC: 6A00                 PUSH        0x0                 
        0x4AEB9CE: 68107A0C04           PUSH        0x40C7A10           
        0x4AEB9D3: E8D856510B           CALL        0x100010B0         
        0x4AEB9D8: 55                   PUSH        EBP                 
        0x4AEB9D9: 8BEC                 MOV         EBP,ESP            
        0x4AEB9DB: 57                   PUSH        EDI                 
        0x4AEB9DC: 56                   PUSH        ESI                 
        0x4AEB9DD: 53                   PUSH        EBX                 
        0x4AEB9DE: 81EC10010000         SUB         ESP,0x110           
        0x4AEB9E4: C745F0C7C6C8C7       MOV         DWORD PTR [EBP-0x10],0xC7C8C6C7; VAR:0x10
        ; end of prologue
        0x4AEB9EB: 8BF1                 MOV         ESI,ECX            
        ; IL_0000: ldarg.0
        ; IL_0001: ldfld textBox_reg
        ; IL_0006: callvirt  System.Windows.Forms.TextBox::get_Text()
        ; IL_000B: stloc.1
        ;...............................................................
        ;...............................................................
        ; IL_0046: ldloca.s 0x05
        ; IL_0048: call  System.IntPtr::ToPointer()
        ; IL_004D: ldloca.s 0x04
        ; IL_004F: ldc.i4 0x000000FF
        ; IL_0054: call native_decode1
        ; IL_0059: stloc.2
        0x4AEBA41: 68FF000000           PUSH        0xFF               
        0x4AEBA46: 8D95F0FEFFFF         LEA         EDX,[EBP-0x110]     ; VAR:0x110
        0x4AEBA4C: 8B8DECFEFFFF         MOV         ECX,DWORD PTR [EBP-0x114]; VAR:0x114
        0x4AEBA52: E8CD84F400           CALL        0x5A33F24                  ;一路F10来到这里,然后F11跟进           
        0x4AEBA57: 25FF000000           AND         EAX,0xFF            
        ; IL_005A: ldloc.2
        ; IL_005B: brfalse.s IL_0076
        0x4AEBA5C: 741B                 JZ          0x4AEBA79           ; (*+0x1D) 爆破的话修改这里
        ; IL_005D: ldstr ""
        ; IL_0062: call  System.Windows.Forms.MessageBox::Show()
        ; IL_0067: pop
      
      
      
      Disassembly of 0x004019D0 in NativeClrMixedKeygenMe.exe
        ; Section: .text
        0x4019D0: 6AFF                 PUSH        0xFF                 
        0x4019D2: 68D83C4000           PUSH        0x403CD8             ; .text:0x8B 0x54 0x24 0x08
        0x4019D7: 64A100000000         MOV         EAX,DWORD PTR FS:[0x0]
        0x4019DD: 50                   PUSH        EAX                  
        0x4019DE: 51                   PUSH        ECX                  
        0x4019DF: 53                   PUSH        EBX                  
        0x4019E0: 56                   PUSH        ESI                  
        0x4019E1: 57                   PUSH        EDI                  
        0x4019E2: A11CB04000           MOV         EAX,DWORD PTR [0x40B01C]; .data:0x4E 0xE6 0x40 0xBB
        0x4019E7: 33C4                 XOR         EAX,ESP              
        0x4019E9: 50                   PUSH        EAX                  
        0x4019EA: 8D442414             LEA         EAX,[ESP+0x14]      
        0x4019EE: 64A300000000         MOV         DWORD PTR FS:[0x0],EAX
        0x4019F4: 90                   NOP                              
        0x4019F5: 8B442424             MOV         EAX,DWORD PTR [ESP+0x24]
        0x4019F9: 50                   PUSH        EAX                  
        0x4019FA: 8D4C2414             LEA         ECX,[ESP+0x14]      
        0x4019FE: E81D010000           CALL        0x401B20                        ;将传入的注册码转换成string            
        0x401A03: 33DB                 XOR         EBX,EBX                       ;i = 0      
        0x401A05: 895C241C             MOV         DWORD PTR [ESP+0x1C],EBX
        0x401A09: 8D4C2410             LEA         ECX,[ESP+0x10]      
        0x401A0D: E8AE010000           CALL        0x401BC0                      ;取转换后的string的长度      
        0x401A12: 85C0                 TEST        EAX,EAX                     
        0x401A14: 8B742428             MOV         ESI,DWORD PTR [ESP+0x28]
        0x401A18: 7E29                 JLE         0x401A43             ; (*+0x2B)  
        0x401A1A: 8B7C242C             MOV         EDI,DWORD PTR [ESP+0x2C]
        0x401A1E: 8BFF                 MOV         EDI,EDI              
        0x401A20: 53                   PUSH        EBX                  ; <==0x00401A41(*+0x21)
        0x401A21: 8D4C2414             LEA         ECX,[ESP+0x14]      
        0x401A25: E876010000           CALL        0x401BA0                        ;取转换后的string中的某一位(substring(i,1))            
        0x401A2A: 3BFB                 CMP         EDI,EBX                      ;只处理前0xFF位
        0x401A2C: 7E05                 JLE         0x401A33             ; (*+0x7)  
        0x401A2E: 2AC3                 SUB         AL,BL                           ;substring(i,1) - i            
        0x401A30: 880433               MOV         BYTE PTR [EBX+ESI],AL        ;保存计算后的结果
        0x401A33: 8D4C2410             LEA         ECX,[ESP+0x10]       ; <==0x00401A2C(*-0x7)
        0x401A37: 83C301               ADD         EBX,0x1                     ;i++         
        0x401A3A: E881010000           CALL        0x401BC0            
        0x401A3F: 3BD8                 CMP         EBX,EAX              
        0x401A41: 7CDD                 JL          0x401A20             ; (*-0x21)  
        0x401A43: 8D4C2410             LEA         ECX,[ESP+0x10]       ; <==0x00401A18(*-0x2B)
        0x401A47: E874010000           CALL        0x401BC0            
        0x401A4C: 56                   PUSH        ESI                  
        0x401A4D: C6043000             MOV         BYTE PTR [EAX+ESI],0x0
        0x401A51: E86AFFFFFF           CALL        0x4019C0                        ;关键call F11跟进            
        0x401A56: 83C404               ADD         ESP,0x4              
        0x401A59: 8AD8                 MOV         BL,AL               
        0x401A5B: C744241CFFFFFFFF     MOV         DWORD PTR [ESP+0x1C],0xFFFFFFFF
        0x401A63: 8D4C2410             LEA         ECX,[ESP+0x10]      
        0x401A67: E8F4000000           CALL        0x401B60            
        0x401A6C: 8AC3                 MOV         AL,BL               
        0x401A6E: 8B4C2414             MOV         ECX,DWORD PTR [ESP+0x14]
        0x401A72: 64890D00000000       MOV         DWORD PTR FS:[0x0],ECX
        0x401A79: 59                   POP         ECX                  
        0x401A7A: 5F                   POP         EDI                  
        0x401A7B: 5E                   POP         ESI                  
        0x401A7C: 5B                   POP         EBX                  
        0x401A7D: 83C410               ADD         ESP,0x10            
        0x401A80: C3                   RET                              
      
      在左侧模块列表中的decodeAndCompare方法上下断点。F5中断
      Disassembly of JITTED decodeAndCompare (06000042) at 0x04AEBAC0
        ; Stack Size (in BYTES): 76 (0x0000004C)
        ; Number of Parameters: 0
        ; Local Variables Size (in BYTES): 60 (0x0000003C)
        ; Prologue Size (in BYTES): 48 (0x30)
        ; Standard Frame
        0x4AEBAC0: 6A00                 PUSH        0x0                 
        0x4AEBAC2: 6A00                 PUSH        0x0                 
        0x4AEBAC4: 6A00                 PUSH        0x0                 
        0x4AEBAC6: 68D0379000           PUSH        0x9037D0            
        0x4AEBACB: E8E055510B           CALL        0x100010B0         
        0x4AEBAD0: 55                   PUSH        EBP                 
        0x4AEBAD1: 8BEC                 MOV         EBP,ESP            
        0x4AEBAD3: 57                   PUSH        EDI                 
        0x4AEBAD4: 56                   PUSH        ESI                 
        0x4AEBAD5: 53                   PUSH        EBX                 
        0x4AEBAD6: 83EC3C               SUB         ESP,0x3C            
        0x4AEBAD9: 33C0                 XOR         EAX,EAX            
        0x4AEBADB: 8945C0               MOV         DWORD PTR [EBP-0x40],EAX; VAR:0x40
        0x4AEBADE: 8945BC               MOV         DWORD PTR [EBP-0x44],EAX; VAR:0x44
        0x4AEBAE1: 8965F0               MOV         DWORD PTR [EBP-0x10],ESP; VAR:0x10
        0x4AEBAE4: 33C0                 XOR         EAX,EAX            
        0x4AEBAE6: 8945E4               MOV         DWORD PTR [EBP-0x1C],EAX; VAR:0x1C
        0x4AEBAE9: C745B8C7C6C8C7       MOV         DWORD PTR [EBP-0x48],0xC7C8C6C7; VAR:0x48
        ; end of prologue
        0x4AEBAF0: 8BF1                 MOV         ESI,ECX            
        ; IL_0000: call __CxxQueryExceptionSize
        ; IL_0005: localloc
        ; IL_0007: stloc.2
        0x4AEBAF2: E85D84F400           CALL        0x5A33F54           
        0x4AEBAF7: 85C0                 TEST        EAX,EAX            
        0x4AEBAF9: 7421                 JZ          0x4AEBB1C           ; (*+0x23)
        0x4AEBAFB: 83C003               ADD         EAX,0x3            
        0x4AEBAFE: 83E0FC               AND         EAX,0xFC            
        0x4AEBB01: F7D8                 NEG         EAX                 
        0x4AEBB03: 03C4                 ADD         EAX,ESP            
        0x4AEBB05: 7202                 JB          0x4AEBB09           ; (*+0x4)
        0x4AEBB07: 33C0                 XOR         EAX,EAX            
        0x4AEBB09: 852424               TEST        DWORD PTR [ESP],ESP         ; <==0x04AEBB05(*-0x4), 0x04AEBB18(*+0xF)
        0x4AEBB0C: 8BD4                 MOV         EDX,ESP            
        0x4AEBB0E: 81EA00100000         SUB         EDX,0x1000         
        0x4AEBB14: 8BE2                 MOV         ESP,EDX            
        0x4AEBB16: 3BE0                 CMP         ESP,EAX            
        0x4AEBB18: 73EF                 JAE         0x4AEBB09           ; (*-0xF)
        0x4AEBB1A: 8BE0                 MOV         ESP,EAX            
        0x4AEBB1C: 8965F0               MOV         DWORD PTR [EBP-0x10],ESP; VAR:0x10        ; <==0x04AEBAF9(*-0x23)
        0x4AEBB1F: 8945D0               MOV         DWORD PTR [EBP-0x30],EAX; VAR:0x30
        ; IL_0008: ldloca.s 0x06
        ; IL_000A: ldsfld lpMachineCode
        ; IL_000F: call  System.IntPtr::.ctor()
        0x4AEBB22: A170CA4000           MOV         EAX,DWORD PTR [0x40CA70]
        0x4AEBB27: 8945C4               MOV         DWORD PTR [EBP-0x3C],EAX; VAR:0x3C
        ; IL_0014: ldloc.s 0x06
        ; IL_0016: call  System.Runtime.InteropServices.Marshal::PtrToStringAnsi()
        ; IL_001B: stloc.s 0x05
        0x4AEBB2A: 8B4DC4               MOV         ECX,DWORD PTR [EBP-0x3C]; VAR:0x3C
        0x4AEBB2D: E86657CEFF           CALL        0x47D1298           ; (0x047D1298)
        0x4AEBB32: 8945BC               MOV         DWORD PTR [EBP-0x44],EAX; VAR:0x44
        ; IL_001D: ldloca.s 0x04
        ; IL_001F: ldarg.0
        ; IL_0020: call  System.IntPtr::.ctor()
        0x4AEBB35: 8975C8               MOV         DWORD PTR [EBP-0x38],ESI; VAR:0x38        ;跟到这里,双击ESI寄存器可以看见里面保存的是刚刚经过计算后的注册码字符串
        ; IL_0025: ldloc.s 0x04
        ; IL_0027: call  System.Runtime.InteropServices.Marshal::PtrToStringAnsi()
        ; IL_002C: stloc.1
        0x4AEBB38: 8B4DC8               MOV         ECX,DWORD PTR [EBP-0x38]; VAR:0x38
        0x4AEBB3B: E85857CEFF           CALL        0x47D1298           ; (0x047D1298)
        0x4AEBB40: 8945C0               MOV         DWORD PTR [EBP-0x40],EAX; VAR:0x40
        ; IL_002D: call  System.Text.Encoding::get_ASCII()
        ; IL_0032: ldloc.1
        ; IL_0033: call  System.Convert::FromBase64String()
        ; IL_0038: ldc.i4.0
        ; IL_0039: ldloc.1
        ; IL_003A: call  System.Convert::FromBase64String()
        ; IL_003F: ldlen
        ; IL_0040: callvirt  System.Text.Encoding::GetString()
        ; IL_0045: stloc.1
        ; IL_0046: leave.s IL_0095
        0x4AEBB43: 833D3014DA0100       CMP         DWORD PTR [0x1DA1430],0x0
        0x4AEBB4A: 7523                 JNE         0x4AEBB6F           ; (*+0x25)
        0x4AEBB4C: B98CA32D04           MOV         ECX,0x42DA38C      
        0x4AEBB51: E8C664E0FB           CALL        0x8F201C            
        0x4AEBB56: 8BF0                 MOV         ESI,EAX            
        0x4AEBB58: 8BCE                 MOV         ECX,ESI            
        0x4AEBB5A: BA9F4E0000           MOV         EDX,0x4E9F         
        0x4AEBB5F: E8645779FF           CALL        0x42812C8           ; (0x042812C8)
        0x4AEBB64: 8D153014DA01         LEA         EDX,[0x1DA1430]     
        0x4AEBB6A: E8B77E3875           CALL        mscorwks.dll!DllUnregisterServerInternal + 0x0206          ; (0x79E73A26)
        0x4AEBB6F: 8B353014DA01         MOV         ESI,DWORD PTR [0x1DA1430]        ; <==0x04AEBB4A(*-0x25)
        0x4AEBB75: 8B4DC0               MOV         ECX,DWORD PTR [EBP-0x40]; VAR:0x40
        0x4AEBB78: FF1504D14803         CALL        DWORD PTR [0x348D104]
        0x4AEBB7E: 8BF8                 MOV         EDI,EAX            
        0x4AEBB80: 6A00                 PUSH        0x0                 
        0x4AEBB82: 8B4DC0               MOV         ECX,DWORD PTR [EBP-0x40]; VAR:0x40
        0x4AEBB85: FF1504D14803         CALL        DWORD PTR [0x348D104]
        0x4AEBB8B: FF7004               PUSH        DWORD PTR [EAX+0x4]
        0x4AEBB8E: 8BCE                 MOV         ECX,ESI            
        0x4AEBB90: 8BD7                 MOV         EDX,EDI            
        0x4AEBB92: 8B01                 MOV         EAX,DWORD PTR [ECX]
        0x4AEBB94: FF90DC000000         CALL        DWORD PTR [EAX+0xDC]
        0x4AEBB9A: 8945C0               MOV         DWORD PTR [EBP-0x40],EAX; VAR:0x40
        0x4AEBB9D: E99D000000           JMP         0x4AEBC3F           
        ;...............................................................
        ;...............................................................
        0x4AEBC8B: 5B                   POP         EBX                 
        0x4AEBC8C: 5E                   POP         ESI                 
        0x4AEBC8D: 5F                   POP         EDI                 
        0x4AEBC8E: 5D                   POP         EBP                 
        0x4AEBC8F: C3                   RET                             
      三、算法及注册机
      算法超简单,只要了解.net的都不成问题。这里就不赘述了。
    复制内容到剪贴板
    代码:
    trcode.Text = System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(tmcode.Text)) ;
      byte[] buffer = System.Text.Encoding.ASCII.GetBytes(trcode.Text);
      for ( int i = 0 ; i < buffer.Length ; i++ )
      {
              if ( i < 0xFF )
              {
                      buffer[i] = (byte)(buffer[i] + i) ;
              }
      }
      trcode.Text = System.Text.Encoding.Default.GetString(buffer);
    --------------------------------------------------------------------------------
    【经验总结】
      .net的软件如果没有经过混淆,托管方法用reflector就可以分析的八九不离十。再结合动态调试工具,就算其中夹杂着一
      些非托管代码,难度也不是很大。
      tankaiha兄的.net方面文章字字玑珠,像我这样的菜鸟应该仔细研读。关于PEBrowse可以参见tankaiha的《【原创】用
      PEBrowse对.Net程序进行动态调试》一文(http://bbs1.pediy.com/showthread.php?s=&threadid=24646
  • 相关阅读:
    git-将dev代码合并到test
    java中一句话取到用split()截后的最后一个值
    shiro重定向或会话失效后NginxURL地址无效,以及浏览器控制台Mixed Content: The page at ‘https://XXX’ was loaded over HTTPS, but requested an insecure错误
    Linux 查找Nginx配置文件位置命令
    Linux 常用命令(个人暂时用到的)
    代理模式
    【Vue自学笔记(四)】天气案例
    【Vue自学笔记(三)】网络请求的简单使用
    【Vue自学笔记】案例
    【Vue自学笔记(二)】Vue指令
  • 原文地址:https://www.cnblogs.com/cxd4321/p/1218528.html
Copyright © 2011-2022 走看看