160 个 CrackMe 之 112 - BaSiLik 和 138 - Sortof 的p-code代码算法分析和注册机实现

本帖最后由 solly 于 2019-7-3 13:20 编辑

160 个 CrackMe 之 112 - BaSiLik 是一个 VB6 p-code 程序。并且使用 upx 1.0.1 打包压缩了,在其反调试代码中还有这方面的检查。
启动 CrackMe 后,如下图:



这个 Unique 码,是根据机器硬盘的信息生成的。另外还要输入用户名,公司名,序列号,一起进行验证。
用 VB Decompiler 打开,可以看到主要调用在 Form.Load() 和 cmdCheck_Click()中。如下两图所示:



以及:



具体的代码如下:[Visual Basic] 纯文本查看 复制代码

Private Sub Form_Load() '404420
  'Data Table: 4030F8
  loc_4043FC: Proc_1_5_404640()  ' SmartCheck 检查,通过 FindWindow("NMSCMW50", 0) 检查
  loc_404401: Proc_1_8_404C24()  ' crack 文件改名和 unpack 检查(文件大小检查)
  loc_404406: Proc_1_6_404A48()  ' w32dasm8 检查,这个检查有问题,没有 %windir%\\w32dasm8.ini 文件也报安装了 W32Dasm,是由于UAC权限不够的原因导致的。
  loc_40440B: Proc_1_4_404580()  ' Registry Monitor 检查,通过 FindWindow("RegmonClass", 0) 检查
  loc_404410: Proc_1_3_404810()  ' IDA 检查。通过注册表检查,注册表项 "HKEY_CURRENT_USER\Software\Datarescue\IDA"
  loc_404415: Proc_1_8_404C24()  ' 再一次crack 文件改名和 unpack 检查(文件大小检查)
  loc_40441A: Proc_1_2_405180()  ' GetVolumeInformationA("C:\")
  loc_40441F: Exit Sub
End Sub

以及:
[Visual Basic] 纯文本查看 复制代码

Private Sub cmdCheck_Click() '404474
  'Data Table: 4030F8
  loc_404450: Proc_1_5_404640()  ' SmartCheck 检查,通过 FindWindow("NMSCMW50", 0) 检查
  loc_404455: Proc_1_8_404C24()  ' crack 文件改名和 unpack 检查(文件大小检查)
  loc_40445A: Proc_1_6_404A48()  ' w32dasm8 检查,这个检查有问题,没有 %windir%\\w32dasm8.ini 文件也报安装了 W32Dasm,是由于UAC权限不够的原因导致的。
  loc_40445F: Proc_1_4_404580()  ' Registry Monitor 检查,通过 FindWindow("RegmonClass", 0) 检查
  loc_404464: Proc_1_3_404810()  ' IDA 检查。通过注册表检查,注册表项 "HKEY_CURRENT_USER\Software\Datarescue\IDA"
  loc_404469: Proc_1_7_404720()  ' SoftICE 检查。扫描 C 盘根目录文件,将每个文件通过调用 Proc_1_9_404920() 进行处理,就是检查 Autoexec.bat 文件中有没有包含 winice.exe 的命令行,这个检查会引起文件访问冲突,导致 Run-time error '70'。
  loc_40446E: Proc_1_1_404EAC()  ' 对输入的用户名,公司名和序列号进行检查,只有这些数据的长度都大于8个字符时,才进行序列号验证,验证函数为 Proc_1_0_405730()。
  loc_404473: Exit Sub
End Sub

我们主要分析其序列号验证过程,其它反调试代码不在这说明。
主要有两个过程,一个是生成 Unique 码(Proc_1_2_405180()),另一个是序列号验证(Proc_1_1_404EAC())。
我们通过 VB Decompiler 静态分析,Proc_1_2_405180() 反编译代码如下:
[Visual Basic] 纯文本查看 复制代码

Public Sub Proc_1_2_405180
  'Data Table: 402C8C
  loc_404F05: Me(40) = CStr(Space(&H100))
  loc_404F1F: Me(60) = CStr(Space(&H100))
  loc_404F36: var_A0 = Me(60)
  loc_404F85: Me(64) = GetVolumeInformationA("C:\", Me(40), Len(Me(40)), Me(44))
  loc_404FC3: Me(40) = CStr(Left(Me(40), (InStr(1, Me(40), vbNullString, 0) - 1)))
  loc_404FFC: Me(60) = CStr(Left(Me(60), (InStr(1, Me(60), vbNullString, 0) - 1)))
  loc_405026: Me(48) = CStr(Trim(Hex(Me(44))))
  loc_405062: Me(48) = CStr(String((8 - Len(Me(48))), "0") & CVar(Me(48)))
  loc_4050B3: Me(48) = CStr(Left(Me(48), 4) & "-" & Right(Me(48), 4))
  loc_4050E3: Me(48) = Replace(Me(48), "-", vbNullString, 1, -1, 0)
  loc_4050F3: Me(48) = StrReverse(Me(48))
  loc_40515C: Set var_148 = MemVar_406008.Text4
  loc_405162: frmMain.Text4.Text = CStr(Left(Me(60), 1) & "54-" & CVar(Me(48)) & "-05" & Right(Me(60), 1))
  loc_40517C: Exit Sub
End Sub

其中除了有一行反编译不正确其它基本还是正确的,翻译成 VB 代码如下:
[Visual Basic] 纯文本查看 复制代码

Private Declare Function GetVolumeInformation Lib "kernel32.dll" _
                                Alias "GetVolumeInformationA" _
                                (ByVal p1 As String, _
                                 ByVal p2 As String, _
                                 ByVal p3 As Long, _
                                 ByRef p4 As Long, _
                                 ByRef p5 As Long, _
                                 ByRef p6 As Long, _
                                 ByVal p7 As String, _
                                 ByVal p8 As Long) As Boolean

Public Function getUnique()
  Dim result As Boolean
  Dim nVolumeNameSize As Long, lpVolumeSerialNumber As Long, p2 As Long, p3 As Long
  Dim lpVolimeNameBuffer As String
  Dim lpFileSystemNameBuffer As String
  Dim s1, s2, s3 As String
  
  nVolumeNameSize = 255
  lpVolimeNameBuffer = Space(256)
  lpFileSystemNameBuffer = Space(256)
  lpVolumeSerialNumber = 0
  
  result = GetVolumeInformation("C:\", lpVolimeNameBuffer, nVolumeNameSize, lpVolumeSerialNumber, p2, p3, lpFileSystemNameBuffer, nVolumeNameSize)
  If lpVolumeSerialNumber <> 0 Then
      's1 = Left(lpVolimeNameBuffer, (InStr(1, lpVolimeNameBuffer, vbNullChar, vbBinaryCompare) - 1)) '去掉'\0'及后面的空格符
      s2 = Left(lpFileSystemNameBuffer, (InStr(1, lpFileSystemNameBuffer, vbNullChar, vbBinaryCompare) - 1)) '去掉'\0'及后面的空格符,文件系统格式:"NTFS","FAT32" 等。
      
      s3 = Trim(Hex(lpVolumeSerialNumber)) '序列号转成 Hex 格式字符串
      s3 = String(8 - Len(s3), "0") & s3
      's3 = Left(s3, 4) & "-" & Right(s3, 4)
      's3 = Replace(s3, "-", vbNullString, 1, -1, vbBinaryCompare)
      s3 = StrReverse(s3) '反转换序列号字符串
      ' 返回 Unique 字符串
      getUnique = Left(s2, 1) & "54-" & s3 & "-05" & Right(s2, 1)
      
  Else
      getUnique = ""
  End If

End Function

主要用到了磁盘C:\的序列号和文件系统格式(如 "NTFS","FAT32"等)。CrackMe 这段代码参考了以下地址的 Example 部分,连没有用到的代码都复制过来了(上面代码注释掉的部分):
http://www.jasinskionline.com/wi ... umeinformation.html

另一个过程 Proc_1_1_404EAC() 先验证输入的信息是否合法(输入信息的长度要大于或等于8),然后调用 Proc_1_0_405730() 验证序列号,这个验证过程(Proc_1_0_405730())内容如下:
[Visual Basic] 纯文本查看 复制代码

Public Sub Proc_1_0_405730
  'Data Table: 402C8C
  Dim var_D0 As Integer
  Dim var_E4 As Variant
  Dim var_88 As TextBox
  loc_4051E4: Set var_88 = MemVar_406008.Text4
  loc_40520C: Me(68) = Replace(frmMain.Text4.Text, "-", vbNullString, 1, -1, 0)
  loc_40521C: Me(76) = CStr(0)
  loc_405230: For var_90 = 1 To CInt(Len(Me(68))): Me(96) = var_90 'Integer
  loc_405257:   Me(72) = CStr(Mid$(Me(68), CLng(Me(96)), 1))
  loc_405279:   Me(76) = CStr((CDbl(Asc(Me(72))) + CDbl(Me(76))))
  loc_405284: Next var_90 'Integer
  loc_40528D: Me(80) = CStr(0)
  loc_4052A6: Set var_88 = MemVar_406008.Text1
  loc_4052BC: For var_D4 = 1 To CInt(Len(frmMain.Text1.Text)): Me(98) = var_D4 'Integer
  loc_4052CE:   Set var_88 = MemVar_406008.Text1
  loc_4052F6:   Me(84) = CStr(Mid$(CVar(frmMain.Text1.Text), CLng(Me(98)), 1))
  loc_40531D:   Me(80) = CStr((CDbl(Asc(Me(84))) + CDbl(Me(80))))
  loc_405328: Next var_D4 'Integer
  loc_405331: Me(88) = CStr(0)
  loc_40534A: Set var_88 = MemVar_406008.Text2
  loc_405360: For var_E8 = 1 To CInt(Len(frmMain.Text2.Text)): Me(100) = var_E8 'Integer
  loc_405372:   Set var_88 = MemVar_406008.Text2
  loc_40539A:   Me(92) = CStr(Mid$(CVar(frmMain.Text2.Text), CLng(Me(100)), 1))
  loc_4053C1:   Me(88) = CStr((CDbl(Asc(Me(92))) + CDbl(Me(88))))
  loc_4053CC: Next var_E8 'Integer
  loc_4053DD: Set var_88 = MemVar_406008.Text1
  loc_405424: Me(104) = CStr(Mid$(CVar(Replace(frmMain.Text1.Text, " ", vbNullString, 1, -1, 0)), 4, 2))
  loc_405449: Set var_88 = MemVar_406008.Text2
  loc_405490: Me(108) = CStr(Mid$(CVar(Replace(frmMain.Text2.Text, " ", vbNullString, 1, -1, 0)), 5, 3))
  loc_4054B5: Set var_88 = MemVar_406008.Text4
  loc_4054FC: Me(112) = CStr(Mid$(CVar(Replace(frmMain.Text4.Text, " ", vbNullString, 1, -1, 0)), 5, 3))
  loc_405521: Set var_88 = MemVar_406008.Text3
  loc_40552F: var_E4 = CVar(frmMain.Text3.Text) 'String
  loc_40558C: var_D0 = Ucase(CVar("34" & Me(112) & "-" & Me(76) & StrReverse(Me(80)) & "-" & Me(108) & Me(88) & "-" & Me(104)))
  loc_4055B7: If CBool(var_E4 <> var_D0) Then
  loc_4055D3:   MsgBox "Incorrect Serial Number!", 0, var_D0, var_E4, var_11C
  loc_4055EF:   Set var_88 = MemVar_406008.Text1
  loc_4055F5:   frmMain.Text1.Text = vbNullString
  loc_405609:   Set var_88 = MemVar_406008.Text2
  loc_40560F:   frmMain.Text2.Text = vbNullString
  loc_405623:   Set var_88 = MemVar_406008.Text3
  loc_405629:   frmMain.Text3.Text = vbNullString
  loc_405631:   Exit Sub
  loc_405635: Else
  loc_405646:   (0).Visible = %x1b
  loc_405659:   Set var_88 = MemVar_406008.Text2
  loc_40565F:   frmMain.Text2.Visible = False
  loc_405672:   Set var_88 = MemVar_406008.Text3
  loc_405678:   frmMain.Text3.Visible = False
  loc_40568B:   Set var_88 = MemVar_406008.Text4
  loc_405691:   frmMain.Text4.Visible = False
  loc_4056A4:   Set var_88 = MemVar_406008.Label1
  loc_4056AA:   frmMain.Label1.Visible = False
  loc_4056BD:   Set var_88 = MemVar_406008.Label2
  loc_4056C3:   frmMain.Label2.Visible = False
  loc_4056D6:   Set var_88 = MemVar_406008.Label3
  loc_4056DC:   frmMain.Label3.Visible = False
  loc_4056EF:   Set var_88 = MemVar_406008.Label4
  loc_4056F5:   frmMain.Label4.Visible = False
  loc_405708:   Set var_88 = MemVar_406008.cmdCheck
  loc_40570E:   frmMain.cmdCheck.Visible = False
  loc_405721:   Set var_88 = MemVar_406008.Label5
  loc_405727:   frmMain.Label5.Visible = True
  loc_40572F: End If
  loc_40572F: Exit Sub
End Sub

跟据以上反编译代码,实现序列号的计算过程如下:
[Visual Basic] 纯文本查看 复制代码

Public Function getSerial(unique As String, name As String, company As String) As String
  Dim i As Long, j As Long, k As Long
  Dim s1 As String, s2 As String, s3 As String, s4 As String
  Dim s5 As String, s6 As String, s7 As String, s8 As String
  
  Dim ss1 As Long, ss2 As Long, ss3 As Long
  
  s1 = Replace(unique, "-", vbNullString, 1, -1, vbBinaryCompare)
  
  ss1 = 0
  For i = 1 To Len(s1)
    ss1 = ss1 + Asc(Mid(s1, i, 1))
  Next i
  
  ss2 = 0
  For i = 1 To Len(name)
    ss2 = ss2 + Asc(Mid(name, i, 1))
  Next i
  
  ss3 = 0
  For i = 1 To Len(company)
    ss3 = ss3 + Asc(Mid(company, i, 1))
  Next i
  
  s3 = Replace(name, " ", vbNullString, 1, -1, vbBinaryCompare)
  s4 = Mid(s3, 4, 2)
  
  s5 = Replace(company, " ", vbNullString, 1, -1, vbBinaryCompare)
  s6 = Mid(s5, 5, 3)
  
  s7 = Replace(unique, " ", vbNullString, 1, -1, vbBinaryCompare)
  s8 = Mid(s7, 5, 3)
  
  getSerial = UCase("34" & s8 & "-" & CStr(ss1) & StrReverse(ss2) & "-" & s6 & ss3 & "-" & s4)
  
  ' clipboard
  VB.Clipboard.Clear
  VB.Clipboard.SetText getSerial, vbCFText
  
End Function

生成序列号后,返回界面输入:



点“Check it!”,得到成功信息提示:

实现的注册机的界面如下:



也是用 VB6 完成的。

下面针对 CrackMe 的问题进行相应的修改,让其可以在最新系统上可以正常运行,前面的反编译代码我也进行了注释,下面是修改内容:
[Visual Basic] 纯文本查看 复制代码

'(1)
' 函数  loc_404469: Proc_1_7_404720(),会引起错误:Run-time error '70': Permission denied
' 可以将此函数中的 For 循环的开始值改大(loc_4046DA: push 1 ),从而不进入循环来避免出错。
' 004046DA  F4 01 AD 1A 74 FF FE 63 6E FF 96 00 04 68 FF 93
' 将 push 01 改成 push 7F, C 盘根目录一般不会有127个以上的文件吧(文件中的位置:0x000046DA)
' 004046DA  F4 7F AD 1A 74 FF FE 63 6E FF 96 00 04 68 FF 93

'(2)
' 将文件名改名判断patch掉
' 00404AD3  1C 89 00 27 F4 FE 27 34 FF 27 54 FF F5 00 00 00
' 改成(文件中的位置:0x00004AD3)
' 00404AD3  1E 89 00 27 F4 FE 27 34 FF 27 54 FF F5 00 00 00

'(3)
' 将文件大小判断patch掉
' 00404BDC  1C 92 01 27 F4 FE 27 34 FF 27 54 FF F5 00 00 00
' 改成(文件中的位置:0x00004BDC)
' 00404BDC  1E 92 01 27 F4 FE 27 34 FF 27 54 FF F5 00 00 00

'(4) 
' 函数 loc_404406: Proc_1_6_404A48() 由于 UAC 限制,需要管理员权限才能正常运行,也Patch掉
' 004049FE  1C DC 00 27 F4 FE 27 14 FF 27 34 FF F5 00 00 00
' 改成(文件中的位置:0x000049FE)
' 004049FE  1E DC 00 27 F4 FE 27 14 FF 27 34 FF F5 00 00 00

改完后,对比一下修改是否正确:[HTML] 纯文本查看 复制代码

I:\Downloads\crack\112_BaSiLiK>fc /b CrackMe_unpacked_cracked.exe CrackMe_unpacked.exe
正在比较文件 CrackMe_unpacked_cracked.exe 和 CRACKME_UNPACKED.EXE
000046DB: 7F 01
000049FE: 1E 1C
00004AD3: 1E 1C
00004BDC: 1E 1C

修改过程中用的二进制工具 UltraEditor。通过上面的反编译可以找到指令地址,在OD数据区可以找到指令数据,如下图:



上面的 1C 就是要修改的指令,复制出指令数据,直接在 UltraEditor 中搜索即可,不用去计算RAV之类的了:



可以搜到指令在文件中的位置:



然后直接修改保存就可以了。

完毕!!!

THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
  • 管埋员

    昵称

  • 取消

    请填写用户信息: