VB共享軟件防破解設計技術初探(二)
作者:愛琴海[SCG] 2008/09/06 (轉載請保留該信息)
上個篇我粗略的講了以下幾個內容:
1、 文件完整性,防止被非法修改
2、 運行時的校驗,防止被LOADER
3、 反調試,防止動態跟蹤和掛接
4、 防靜態反彙編分析
5、 註冊碼系統(算法部分,核心內容)
6、 加殼防脫殼
7、 隱蔽性設計
8、 另闢蹊徑
列表在這裡是為了提醒初學VB發佈共享軟件的朋友,在設計VB防破解的時候,不要出現「水桶效應」,也就是說,設計如水桶,任何一個角落缺失都將導致無法全部盛滿水。
而這個水桶的捆圈恐怕就是保護文件完整性,防止修改了。
週末了,今天有點時間。趕快寫好,等下吃晚飯,練練琴,然後陪陪女朋友。
接下去,我們將開始具體至微的講解第1、2兩個內容,剩下的老規矩:日後有空,有時間,有精力,有能力的話接著寫。
1、 文件完整性,可採用CRC32或者MD5或者哈希算法等,計算出文件的加密值,在適當的時候進行對比,判斷文件被修改與否。當然那也可以加猛殼來防止文件 非法修改。還有簡單點的檢查文件最後修改時間,看看是否是你自己設置好的時間,如果不是,則很有可能被修改過;也可以檢測文件大小,往往壓縮殼被脫掉後, 文件的大小會增加;保護殼被脫掉後,文件大小會變小,我們可以根據這個設置好臨界值來檢測有沒有被脫殼。常用的還有故意設計好關於算法方面的陷阱,如果是 破解者會主動掉進你的陷阱,而事實上,這個跳轉除非爆破,不然在算法上是永遠也無法到達的,這樣就檢出破解者在修改程序流程。你可以無聲無息的程序死掉, 不要直接退出,不然會被追蹤到退出函數。
還有內存鏡像校驗,是為了防止普通的修改內存和普通斷點問題。
我們就具體演示3種VB程序的完整性校驗設計。
第一種是VB的CRC32自校驗設計,包含過程,代碼和所有工程文件及演示;
第二種是VB程序的時間檢測法則,包括過程,代碼和所有工程文件及演示;
第三種是VB程序的文件大小檢測法則,包括過程,代碼和所有工程文件及演示。
其實還有些檢測的辦法,但是原理跟我們即將大曝光的三種辦法差不多,都是衍生的吧。
第二章 第一講
VB的CRC32自校驗設計
來來來…大家跟我一起做運動,抖抖手啊,抖抖腳啊,做做深呼吸,本講將會有點長,力求做到簡單明了,容易明白,學完馬上上手,學會應用的要求,我會具體點講,不會像某些高人敝帚自珍,當然如果有錯誤的地方還請大家多多幫忙糾正,謝謝
首先來簡單複習下何謂CRC32
CRC校驗實用程序庫 在數據存儲和數據通訊領域,為了保證數據的正確,就不得不採用檢錯的手段。在諸多檢錯手段中,CRC是最著名的一種。CRC的全稱是循環冗餘校驗,其特點 是:檢錯能力極強,開銷小,易於用編碼器及檢測電路實現。從其檢錯能力來看,它所不能發現的錯誤的幾率僅為0.0047%以下。
有查表和計算法,我們可以在程序中自動生成碼表來查表計算,方便和快速
為了快速帶過原理筆墨,節省點時間吃飯,我把網路上的一篇介紹《探究CRC32算法實現原理》引述過來,原文地址:
http://www.diybl.com/course/6_system...1/134331.html#
以下是引用部分——————————————————————————————
基於不重造輪子的原則,本文儘量不涉及網絡上遍地都是的資料。
What's CRC ?
簡而言之,CRC是一個數值。該數值被用於校驗數據的正確性。CRC數值簡單地說就是通過讓你需要做
處理的數據除以一個常數而得到的餘數。當你得到這個數值後你可以將這個數值附加到你的數據後,
當數據被傳送到其他地方後,取出原始數據(可能在傳送過程中被破壞)與附加的CRC數值,然後將這裡
的原始數據除以之前那個常數(約定好的)然後得到新的CRC值。比較兩個CRC值是否相等即可確認你的
數據是否在傳送過程中出現錯誤。
那麼,如何讓你的數據除以一個常數?方法是對你的數據進行必要的編碼處理,逐字節處理成數字。
那麼這個常數是什麼?你不必關注它是什麼,也不需要關注它是如何獲得的。當你真的要動手寫一個
CRC的實現算法時,我可以告訴你,CRC的理論學家會告訴你。不同長度的常數對應著不同的CRC實現算法。
當這個常數為32位時,也就是這裡所說的CRC32。
以上內容你不必全部理解,因為你需要查閱其他資料來獲取CRC完整的理論介紹。
The mathematics behind CRC ?
很多教科書會把CRC與多項式關聯起來。這裡的多項式指的是係數為0或1的式子,例如:
a0 + a1*x + a2*x^2 + ... + an*x^n。其中a0, a1, ..., an要麼為0要麼為1。我們並不關注x取什麼值。
(如果你要關注,你可以簡單地認為x為2) 這裡把a0, a1, ..., an的值取出來排列起來,就可以表示比特
流。例如1 + x + x^3所表示的比特流就為:1101。部分資料會將這個順序顛倒,這個很正常。
什麼是生成多項式?
所謂的生成多項式,就是上面我所說的常數。注意,在這裡,一個多項式就表示了一個比特流,也就是一堆
1、0,組合起來最終就是一個數值。例如CRC32算法中,這個生成多項式為:
c(x) = 1 + x + x^2 + x^4 + x^5 + x^7 + x^8 + x^10 + x^11 + x^12 + x^16 + x^22 + x^23 + x^26 + x^32。
其對應的數字就為:11101101101110001000001100100000(x^32在實際計算時隱含給出,因此這裡沒有包含它
的係數),也就是0xEDB88320(多項式對應的數字可能顛倒,顛倒後得到的是0x04C11DB7,其實也是正確的)。
由此可以看出,CRC值也可以看成我們的數據除以一個生成多項式而得到的餘數。
如何做這個除法?
套用大部分教科書給出的計算方法,因為任何數據都可以被處理成純數字,因此,在某種程度上說,我們可以
直接開始這個除法。儘管事實上這並不是標準的除法。例如,我們的數據為1101011011(方便起見我直接給二進制
表示了,從這裡也可以看出,CRC是按bit進行計算的),給定的生成多項式(對應的值)為10011。通常的教科書
會告訴我們在進行這個除法前,會把我們的數據左移幾位(生成多項式位數-1位),從而可以容納將來計算得到
的CRC值(我上面所說的將CRC值附加到原始數據後)。但是為什麼要這樣做?我也不知道。(不知道的東西不能含糊
而過)那麼,除法就為:
1100001010
_______________
10011 ) 11010110110000 附加了幾個零的新數據
10011......... 這裡的減法(希望你不至於忘掉小學算術)是一個異或操作
-----.........
10011........
10011........
-----........
00001....... 逐bit計算
00000.......
-----.......
00010......
00000......
-----......
00101.....
00000.....
-----.....
01011....
00000....
-----....
10110...
10011...
-----...
01010..
00000..
-----..
10100.
10011.
-----.
01110
00000
-----
1110 = 這個餘數也就是所謂的CRC值,通常又被稱為校驗值。
希望進行到這裡,你可以獲取更多關於CRC的感性認識。而我們所要做的,也就是實現一個CRC的計算算法。
說白了,就是提供一個程序,給定一段數據,以及一個生成多項式(對於CRC32算法而言該值固定),然後
計算得出上面的1110餘數。
The simplest algorithm.
最簡單的實現算法,是一種模擬算法。我們模擬上面的除法過程,遵從網上一份比較全面的資料,我們設定
一個變量register。我們逐bit地將我們的數據放到register中。然後判斷register最高位是否為1,如果是
則與生成多項式異或操作,否則繼續處理。這個過程簡單地模擬了上述除法過程:
引用到此結束—————————————————————————————————
看來大家選擇CRC32作為數據校驗是有原因的,速度快,代價小,檢錯能力比較大。VB軟件作者對CRC32有個認識就好了。
我們編寫VB的CRC32自校驗程序思路如下:
1、 計算出目標文件除掉末尾8字節後的所有數據的CRC32值
2、 將上面計算出來的結果儲存在目標程序的末尾8個字節裡
3、 主體程序內置計算自身除掉末尾8字節後的所有數據的CRC32值的功能代碼
4、 主體程序讀取末尾8字節內容與計算的CRC32值比較,不一致說明被修改
由1、2點我們發現,如果手動來添加CRC32值將是件麻煩的事情,所以一般我們都會寫一個具備計算要求的CRC32值,及把該值添加到目標程序指定位置的程序,幫我們節省時間和體力。
為了方便記憶和理解,在這裡我將它命名為VB-CRC32 注射器,顧名思義,即將計算出來的CRC32注射到目標程序裡。
那麼執行自校驗的程序我稱它為VB-CRC32 主體程序。大家記住了哦,下面開始先設計VB-CRC32注射程序。
請跟我一起來:
打開VB6.0 新建工程
新建類模塊,名字改為「clsCRC」,別告訴我你不會改名,當然是在「屬性窗口」改的。
將如下類模塊代碼複製到clsCRC類模塊裡去:(或者直接從我發佈的附件來條用該類模塊)
注意:類模塊後綴名是CLS,請剛接觸VB的同學注意,不要跟模塊搞混了。
我是代碼起始線————————————————————————————————
Option Explicit
Public Enum CRCAlgorithms
CRC16
CRC32
End Enum
Private m_Algorithm As Boolean
Private m_CRC16 As Long
Private m_CRC16Asm() As Byte
Private m_CRC16Init As Boolean
Private m_CRC16Table(0 To 255) As Long
Private m_CRC32 As Long
Private m_CRC32Asm() As Byte
Private m_CRC32Init As Boolean
Private m_CRC32Table(0 To 255) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'此函數作用在這裡是內聯彙編之用
Public Function AddBytes(ByteArray() As Byte) As Variant
Dim ByteSize As Long
'異常處理
On Local Error GoTo NoData
'計算大小
ByteSize = UBound(ByteArray) - LBound(ByteArray) + 1
'異常處理
On Local Error GoTo 0
'內聯彙編提高處理速度
Select Case m_Algorithm
Case CRC16
Call CallWindowProc(VarPtr(m_CRC16Asm(0)), VarPtr(m_CRC16), VarPtr(ByteArray(LBound(ByteArray))), VarPtr(m_CRC16Table(0)), ByteSize)
Case CRC32
Call CallWindowProc(VarPtr(m_CRC32Asm(0)), VarPtr(m_CRC32), VarPtr(ByteArray(LBound(ByteArray))), VarPtr(m_CRC32Table(0)), ByteSize)
End Select
NoData:
'返回新值
AddBytes = Value
End Function
Public Function AddString(Text As String) As Variant
'將字符轉為數組,以便套入函數計算CRC
AddString = AddBytes(StrConv(Text, vbFromUnicode))
End Function
Public Property Let Algorithm(New_Value As CRCAlgorithms)
'選擇新算法
m_Algorithm = New_Value
'確定已經初始化新算法
Select Case m_Algorithm
Case CRC16
If (Not m_CRC16Init) Then Call InitializeCRC16
Case CRC32
If (Not m_CRC32Init) Then Call InitializeCRC32
End Select
'標記
Call Clear
End Property
Public Property Get Algorithm() As CRCAlgorithms
Algorithm = m_Algorithm
End Property
Public Function CalculateBytes(ByteArray() As Byte) As Variant
'重置CRC計算
Call Clear
'計算
CalculateBytes = AddBytes(ByteArray)
End Function
Public Function CalculateFile(Filename As String) As Variant
Dim Filenr As Integer
Dim ByteArray() As Byte
'檢測文件是否包換數據
If (FileLen(Filename) = 0) Then Exit Function
'二進制模式讀取文件儲存到數組裡
Filenr = FreeFile
Open Filename For Binary As #Filenr
ReDim ByteArray(0 To LOF(Filenr) - 9)
Get #Filenr, , ByteArray()
Close #Filenr
'將該數組交給處理函數計算出CRC
CalculateFile = CalculateBytes(ByteArray)
End Function
Public Property Get Value() As Variant
Select Case m_Algorithm
Case CRC16
Value = (m_CRC16 And 65535)
Case CRC32
Value = (Not m_CRC32)
End Select
End Property
Public Property Let Value(New_Value As Variant)
Select Case m_Algorithm
Case CRC16
m_CRC16 = New_Value
Case CRC32
m_CRC32 = New_Value
End Select
End Property
Private Sub InitializeCRC16()
Dim i As Long
Dim j As Long
Dim k As Long
Dim CRC As Long
Dim sASM As String
'創建表格
For i = 0 To 255
k = i * 256
CRC = 0
For j = 0 To 7
If (((CRC Xor k) And 32768) = 32768) Then
CRC = (CRC * 2) Xor &H1021
Else
CRC = (CRC * 2)
End If
k = k * 2
Next
m_CRC16Table(i) = CRC '(CRC And 65535)
Next
'內聯彙編預處理
sASM = "5589E55756505351528B45088B008B750C8B7D108B4D1431DB8A1E30E3668B149F30C66689D0464975EF25FFFF00008B4D0889015A595B585E5F89EC5DC21000"
ReDim m_CRC16Asm(0 To Len(sASM) \ 2 - 1)
For i = 1 To Len(sASM) Step 2
m_CRC16Asm(i \ 2) = Val("&H" & Mid$(sASM, i, 2))
Next
'標記
m_CRC16Init = True
End Sub
Public Sub Clear()
m_CRC16 = 0
m_CRC32 = &HFFFFFFFF
End Sub
Private Sub InitializeCRC32()
Dim i As Long
Dim sASM As String
m_CRC32Table(0) = &H0
m_CRC32Table(1) = &H77073096
m_CRC32Table(2) = &HEE0E612C
m_CRC32Table(3) = &H990951BA
m_CRC32Table(4) = &H76DC419
m_CRC32Table(5) = &H706AF48F
m_CRC32Table(6) = &HE963A535
m_CRC32Table(7) = &H9E6495A3
m_CRC32Table(8) = &HEDB8832
m_CRC32Table(9) = &H79DCB8A4
m_CRC32Table(10) = &HE0D5E91E
m_CRC32Table(11) = &H97D2D988
m_CRC32Table(12) = &H9B64C2B
m_CRC32Table(13) = &H7EB17CBD
m_CRC32Table(14) = &HE7B82D07
m_CRC32Table(15) = &H90BF1D91
m_CRC32Table(16) = &H1DB71064
m_CRC32Table(17) = &H6AB020F2
m_CRC32Table(18) = &HF3B97148
m_CRC32Table(19) = &H84BE41DE
m_CRC32Table(20) = &H1ADAD47D
m_CRC32Table(21) = &H6DDDE4EB
m_CRC32Table(22) = &HF4D4B551
m_CRC32Table(23) = &H83D385C7
m_CRC32Table(24) = &H136C9856
m_CRC32Table(25) = &H646BA8C0
m_CRC32Table(26) = &HFD62F97A
m_CRC32Table(27) = &H8A65C9EC
m_CRC32Table(28) = &H14015C4F
m_CRC32Table(29) = &H63066CD9
m_CRC32Table(30) = &HFA0F3D63
m_CRC32Table(31) = &H8D080DF5
m_CRC32Table(32) = &H3B6E20C8
m_CRC32Table(33) = &H4C69105E
m_CRC32Table(34) = &HD56041E4
m_CRC32Table(35) = &HA2677172
m_CRC32Table(36) = &H3C03E4D1
m_CRC32Table(37) = &H4B04D447
m_CRC32Table(38) = &HD20D85FD
m_CRC32Table(39) = &HA50AB56B
m_CRC32Table(40) = &H35B5A8FA
m_CRC32Table(41) = &H42B2986C
m_CRC32Table(42) = &HDBBBC9D6
m_CRC32Table(43) = &HACBCF940
m_CRC32Table(44) = &H32D86CE3
m_CRC32Table(45) = &H45DF5C75
m_CRC32Table(46) = &HDCD60DCF
m_CRC32Table(47) = &HABD13D59
m_CRC32Table(48) = &H26D930AC
m_CRC32Table(49) = &H51DE003A
m_CRC32Table(50) = &HC8D75180
m_CRC32Table(51) = &HBFD06116
m_CRC32Table(52) = &H21B4F4B5
m_CRC32Table(53) = &H56B3C423
m_CRC32Table(54) = &HCFBA9599
m_CRC32Table(55) = &HB8BDA50F
m_CRC32Table(56) = &H2802B89E
m_CRC32Table(57) = &H5F058808
m_CRC32Table(58) = &HC60CD9B2
m_CRC32Table(59) = &HB10BE924
m_CRC32Table(60) = &H2F6F7C87
m_CRC32Table(61) = &H58684C11
m_CRC32Table(62) = &HC1611DAB
m_CRC32Table(63) = &HB6662D3D
m_CRC32Table(64) = &H76DC4190
m_CRC32Table(65) = &H1DB7106
m_CRC32Table(66) = &H98D220BC
m_CRC32Table(67) = &HEFD5102A
m_CRC32Table(68) = &H71B18589
m_CRC32Table(69) = &H6B6B51F
m_CRC32Table(70) = &H9FBFE4A5
m_CRC32Table(71) = &HE8B8D433
m_CRC32Table(72) = &H7807C9A2
m_CRC32Table(73) = &HF00F934
m_CRC32Table(74) = &H9609A88E
m_CRC32Table(75) = &HE10E9818
m_CRC32Table(76) = &H7F6A0DBB
m_CRC32Table(77) = &H86D3D2D
m_CRC32Table(78) = &H91646C97
m_CRC32Table(79) = &HE6635C01
m_CRC32Table(80) = &H6B6B51F4
m_CRC32Table(81) = &H1C6C6162
m_CRC32Table(82) = &H856530D8
m_CRC32Table(83) = &HF262004E
m_CRC32Table(84) = &H6C0695ED
m_CRC32Table(85) = &H1B01A57B
m_CRC32Table(86) = &H8208F4C1
m_CRC32Table(87) = &HF50FC457
m_CRC32Table(88) = &H65B0D9C6
m_CRC32Table(89) = &H12B7E950
m_CRC32Table(90) = &H8BBEB8EA
m_CRC32Table(91) = &HFCB9887C
m_CRC32Table(92) = &H62DD1DDF
m_CRC32Table(93) = &H15DA2D49
m_CRC32Table(94) = &H8CD37CF3
m_CRC32Table(95) = &HFBD44C65
m_CRC32Table(96) = &H4DB26158
m_CRC32Table(97) = &H3AB551CE
m_CRC32Table(98) = &HA3BC0074
m_CRC32Table(99) = &HD4BB30E2
m_CRC32Table(100) = &H4ADFA541
m_CRC32Table(101) = &H3DD895D7
m_CRC32Table(102) = &HA4D1C46D
m_CRC32Table(103) = &HD3D6F4FB
m_CRC32Table(104) = &H4369E96A
m_CRC32Table(105) = &H346ED9FC
m_CRC32Table(106) = &HAD678846
m_CRC32Table(107) = &HDA60B8D0
m_CRC32Table(108) = &H44042D73
m_CRC32Table(109) = &H33031DE5
m_CRC32Table(110) = &HAA0A4C5F
m_CRC32Table(111) = &HDD0D7CC9
m_CRC32Table(112) = &H5005713C
m_CRC32Table(113) = &H270241AA
m_CRC32Table(114) = &HBE0B1010
m_CRC32Table(115) = &HC90C2086
m_CRC32Table(116) = &H5768B525
m_CRC32Table(117) = &H206F85B3
m_CRC32Table(118) = &HB966D409
m_CRC32Table(119) = &HCE61E49F
m_CRC32Table(120) = &H5EDEF90E
m_CRC32Table(121) = &H29D9C998
m_CRC32Table(122) = &HB0D09822
m_CRC32Table(123) = &HC7D7A8B4
m_CRC32Table(124) = &H59B33D17
m_CRC32Table(125) = &H2EB40D81
m_CRC32Table(126) = &HB7BD5C3B
m_CRC32Table(127) = &HC0BA6CAD
m_CRC32Table(128) = &HEDB88320
m_CRC32Table(129) = &H9ABFB3B6
m_CRC32Table(130) = &H3B6E20C
m_CRC32Table(131) = &H74B1D29A
m_CRC32Table(132) = &HEAD54739
m_CRC32Table(133) = &H9DD277AF
m_CRC32Table(134) = &H4DB2615
m_CRC32Table(135) = &H73DC1683
m_CRC32Table(136) = &HE3630B12
m_CRC32Table(137) = &H94643B84
m_CRC32Table(138) = &HD6D6A3E
m_CRC32Table(139) = &H7A6A5AA8
m_CRC32Table(140) = &HE40ECF0B
m_CRC32Table(141) = &H9309FF9D
m_CRC32Table(142) = &HA00AE27
m_CRC32Table(143) = &H7D079EB1
m_CRC32Table(144) = &HF00F9344
m_CRC32Table(145) = &H8708A3D2
m_CRC32Table(146) = &H1E01F268
m_CRC32Table(147) = &H6906C2FE
m_CRC32Table(148) = &HF762575D
m_CRC32Table(149) = &H806567CB
m_CRC32Table(150) = &H196C3671
m_CRC32Table(151) = &H6E6B06E7
m_CRC32Table(152) = &HFED41B76
m_CRC32Table(153) = &H89D32BE0
m_CRC32Table(154) = &H10DA7A5A
m_CRC32Table(155) = &H67DD4ACC
m_CRC32Table(156) = &HF9B9DF6F
m_CRC32Table(157) = &H8EBEEFF9
m_CRC32Table(158) = &H17B7BE43
m_CRC32Table(159) = &H60B08ED5
m_CRC32Table(160) = &HD6D6A3E8
m_CRC32Table(161) = &HA1D1937E
m_CRC32Table(162) = &H38D8C2C4
m_CRC32Table(163) = &H4FDFF252
m_CRC32Table(164) = &HD1BB67F1
m_CRC32Table(165) = &HA6BC5767
m_CRC32Table(166) = &H3FB506DD
m_CRC32Table(167) = &H48B2364B
m_CRC32Table(168) = &HD80D2BDA
m_CRC32Table(169) = &HAF0A1B4C
m_CRC32Table(170) = &H36034AF6
m_CRC32Table(171) = &H41047A60
m_CRC32Table(172) = &HDF60EFC3
m_CRC32Table(173) = &HA867DF55
m_CRC32Table(174) = &H316E8EEF
m_CRC32Table(175) = &H4669BE79
m_CRC32Table(176) = &HCB61B38C
m_CRC32Table(177) = &HBC66831A
m_CRC32Table(178) = &H256FD2A0
m_CRC32Table(179) = &H5268E236
m_CRC32Table(180) = &HCC0C7795
m_CRC32Table(181) = &HBB0B4703
m_CRC32Table(182) = &H220216B9
m_CRC32Table(183) = &H5505262F
m_CRC32Table(184) = &HC5BA3BBE
m_CRC32Table(185) = &HB2BD0B28
m_CRC32Table(186) = &H2BB45A92
m_CRC32Table(187) = &H5CB36A04
m_CRC32Table(188) = &HC2D7FFA7
m_CRC32Table(189) = &HB5D0CF31
m_CRC32Table(190) = &H2CD99E8B
m_CRC32Table(191) = &H5BDEAE1D
m_CRC32Table(192) = &H9B64C2B0
m_CRC32Table(193) = &HEC63F226
m_CRC32Table(194) = &H756AA39C
m_CRC32Table(195) = &H26D930A
m_CRC32Table(196) = &H9C0906A9
m_CRC32Table(197) = &HEB0E363F
m_CRC32Table(198) = &H72076785
m_CRC32Table(199) = &H5005713
m_CRC32Table(200) = &H95BF4A82
m_CRC32Table(201) = &HE2B87A14
m_CRC32Table(202) = &H7BB12BAE
m_CRC32Table(203) = &HCB61B38
m_CRC32Table(204) = &H92D28E9B
m_CRC32Table(205) = &HE5D5BE0D
m_CRC32Table(206) = &H7CDCEFB7
m_CRC32Table(207) = &HBDBDF21
m_CRC32Table(208) = &H86D3D2D4
m_CRC32Table(209) = &HF1D4E242
m_CRC32Table(210) = &H68DDB3F8
m_CRC32Table(211) = &H1FDA836E
m_CRC32Table(212) = &H81BE16CD
m_CRC32Table(213) = &HF6B9265B
m_CRC32Table(214) = &H6FB077E1
m_CRC32Table(215) = &H18B74777
m_CRC32Table(216) = &H88085AE6
m_CRC32Table(217) = &HFF0F6A70
m_CRC32Table(218) = &H66063BCA
m_CRC32Table(219) = &H11010B5C
m_CRC32Table(220) = &H8F659EFF
m_CRC32Table(221) = &HF862AE69
m_CRC32Table(222) = &H616BFFD3
m_CRC32Table(223) = &H166CCF45
m_CRC32Table(224) = &HA00AE278
m_CRC32Table(225) = &HD70DD2EE
m_CRC32Table(226) = &H4E048354
m_CRC32Table(227) = &H3903B3C2
m_CRC32Table(228) = &HA7672661
m_CRC32Table(229) = &HD06016F7
m_CRC32Table(230) = &H4969474D
m_CRC32Table(231) = &H3E6E77DB
m_CRC32Table(232) = &HAED16A4A
m_CRC32Table(233) = &HD9D65ADC
m_CRC32Table(234) = &H40DF0B66
m_CRC32Table(235) = &H37D83BF0
m_CRC32Table(236) = &HA9BCAE53
m_CRC32Table(237) = &HDEBB9EC5
m_CRC32Table(238) = &H47B2CF7F
m_CRC32Table(239) = &H30B5FFE9
m_CRC32Table(240) = &HBDBDF21C
m_CRC32Table(241) = &HCABAC28A
m_CRC32Table(242) = &H53B39330
m_CRC32Table(243) = &H24B4A3A6
m_CRC32Table(244) = &HBAD03605
m_CRC32Table(245) = &HCDD70693
m_CRC32Table(246) = &H54DE5729
m_CRC32Table(247) = &H23D967BF
m_CRC32Table(248) = &HB3667A2E
m_CRC32Table(249) = &HC4614AB8
m_CRC32Table(250) = &H5D681B02
m_CRC32Table(251) = &H2A6F2B94
m_CRC32Table(252) = &HB40BBE37
m_CRC32Table(253) = &HC30C8EA1
m_CRC32Table(254) = &H5A05DF1B
m_CRC32Table(255) = &H2D02EF8D
'內聯彙編預處理
sASM = "5589E557565053518B45088B008B750C8B7D108B4D1431DB8A1E30C3C1E80833049F464975F28B4D088901595B585E5F89EC5DC21000"
ReDim m_CRC32Asm(0 To Len(sASM) \ 2 - 1)
For i = 1 To Len(sASM) Step 2
m_CRC32Asm(i \ 2) = Val("&H" & Mid$(sASM, i, 2))
Next
'標記CRC32
m_CRC32Init = True
End Sub
Private Sub Class_Initialize()
'默認為CRC32算法
Algorithm = CRC32
End Sub
我是代碼終止線————————————————————————————————
可以看到該類模塊裡應用了VB內聯彙編的技巧,其核心是利用了CallWindowProcA,將定義好的代碼串作為數值編入VB,然後通過CallWindowProcA來指定其為執行的代碼進行執行。相關內容請到網上查找。
該模塊是我修改來急速計算文件CRC32或者CRC16的,默認情況下是計算CRC32。
如圖:
然後雙擊窗體Form1,在工具欄裡選擇「工程」,指向「部件」,選擇「Microsoft Common Dialog Contrll 6.0」,在工具箱中選擇它,添加到窗體上。並改其名為「Openfile」。
注意:細節美觀什麼的,大家自己弄,我講的一般不包含如何設置和美化界面什麼的。
如圖:
在窗體通用部分添加:
Private CRC32zhi As String
'用作儲存CRC32的值的
Private Zhuangtai As Boolean
'用作標誌寫入文件是否成功
在窗體上添加按鈕Command1,命名為「打開」,然後設計代碼使通過它跟「Openfile」掛鉤(別再問我Openfile是什麼,也就是剛才我們使用的Common Dialog控件)
Openfile的Action我們採用1模式,也就是常見的打開對話框;
Openfile的Dialog Title我們命名為" 請選擇需要添加CRC32自校驗值的目標程序"
Openfire的Filter屬性我們設置為"*.exe"
Openfire的其他屬性默認即可
為了計算並自動添加CRC32值到目標程序,並且方便大家複製移植代碼,我們有必要給它寫個過程,或者函數。這裡注射寫過程就好了,等下設計主體程序時我們也要寫函數的。
我是代碼起始線————————————————————————————————
Private Sub SetCRC32(Lujing As String)
'函數化添加CRC32
'核心代碼
On Error GoTo CRCerror
Dim cCRC As New clsCRC, FileCRC$
'啟用類模塊
cCRC.Algorithm = CRC32 '選擇算法模式是CRC32
cCRC.Clear '算法初始化
FileCRC = Hex(cCRC.CalculateFile(Lujing))
'計算出目標程序的CRC32,忽略目標程序末尾8字節數值,末尾8字節是用來儲存我們示範的CRC32值的
If Len(FileCRC) < 8 Then FileCRC = Left("00000000", 8 - Len(FileCRC)) & Hex(cCRC.CalculateFile(Lujing))
'如果CRC32值不足8位,那麼要在前面添加零來補足位數
CRC32zhi = FileCRC
'CRC32值儲存
FileNum = FreeFile
'獲得個文件號(通道)
Open Lujing For Binary As #FileNum
Seek FileNum, FileLen(Lujing) - 7
Put #FileNum, , FileCRC
Close FileNum
'用二進制模式打開目標程序,通過SEEK定位需要添加CRC32數值的位置,請注意:這個位置以後大家可以自己改
'通過PUT將我們計算號的CRC32寫入指定位置
'通過CLOSE關閉通道
Zhuangtai = True
'狀態字,表示寫入文件成功了
Exit Sub
CRCerror:
MsgBox "發生意外錯誤,請檢查目標程序是否正在運行?", , "發生意外錯誤,代碼: " & Err.Number
End Sub
我是代碼終止線————————————————————————————————
SetCRC32就是特意寫的直接完成計算CRC32和寫入目標程序的功能過程
調用格式為:SetCRC32(目標程序路徑)
看,多麼簡單不是嗎?
接下去雙擊Command1按鈕,給它設計功能代碼如下:
我是代碼起始線————————————————————————————————
Private Sub Command1_Click()
'示範
'選擇一個待添加CRC32值的自校驗程序
On Error GoTo Qingjiancha
'初始化CRC32值,主要是為了清空上次的狀態
CRC32zhi = ""
'初始化寫入成功與否的標誌
Zhuangtai = False
Dim FilenameNo1 As String
Openfile.DialogTitle = " 請選擇需要添加CRC32自校驗值的目標程序"
Openfile.Filter = "*.exe"
Openfile.Action = 1
FilenameNo1 = Openfile.Filename
If FilenameNo1 = "" Then Exit Sub
'檢查是否選擇了程序
If FileLen(FilenameNo1) < 16 Then MsgBox "請檢查目標程序是否包含足夠數據", , "請檢查NO1": Exit Sub
'檢查程序是否包含足夠空間和數據,因為儲存CRC32需要8個字節的空間,本身計算余量怎麼說也要8個字節把?8+8=16
Big.Caption = "目標程序大小為: " & FileLen(FilenameNo1) & " 字節"
SetCRC32 (FilenameNo1)
CRCzhi.Caption = "目標程序CRC32值: " & CRC32zhi
If Zhuangtai = True Then
Zhuang.Caption = "CRC32添加狀況: 添加成功,你可以啟動目標程序的自校驗來核實"
Else
Zhuang.Caption = "CRC32添加狀況: 添加失敗,請你檢查下目標程序是否正在運行中?"
End If
Exit Sub
FilenameNo1 = ""
Qingjiancha:
MsgBox "發生意外錯誤,請檢查輸入等情況是否正常,目標程序是否正在運行?", , "發生意外錯誤,代碼: " & Err.Number
FilenameNo1 = ""
End Sub
我是代碼終止線————————————————————————————————
整個程序還需要:一個名為CRCzhi的Label,一個名為Zhuang的Label
分別顯示計算出來的CRC32值,和顯示寫入文件是否成功的信息
這樣子,通過編譯,生成EXE文件,執行效果如圖:
這樣我們就完成了VB-CRC32添加校驗值到目標程序的注射端。保存工程等文件。
接下去,我們就來應用該VB-CRC32注射端配合主體程序來完成整個VB-CRC32自校驗設計
下面開始寫VB-CRC32自校驗主體程序
打開VB6.0,新建工程
按照上文一樣,建立clsCRC類模塊,代碼一致,或者直接添加附件裡的該類模塊也可以。
如圖:
然後設計如下圖的程序界面,注意需要一個名為Jieguo的Label,建立一個名為「檢測「的Command1
然後雙擊窗體,進入代碼設計界面
如圖:
在這個主體自校驗部分,大家想一下,大概需要寫幾個什麼樣的函數?方便複製和移植?
我認為是兩個函數,分別計算自身的CRC32值,和獲取已經寫入到末尾8字節的CRC32校驗值。
那麼說幹就幹吧:
我是代碼起始線————————————————————————————————
Private Function GetCRC32() As String
'函數化計算本身的CRC32
'核心代碼
Dim Lujing As String
'定義本程序自己的路徑變量
On Error GoTo CRCerror
Lujing = App.Path & "\" & App.EXEName & ".exe"
'這句語句就獲得了程序自己的啟動路徑,這個技巧VB中必須掌握,用處很多
Dim cCRC As New clsCRC, FileCRC$
'啟用類模塊
cCRC.Algorithm = CRC32 '選擇算法模式是CRC32
cCRC.Clear '算法初始化
FileCRC = Hex(cCRC.CalculateFile(Lujing))
'計算出目標程序的CRC32,忽略目標程序末尾8字節數值,末尾8字節是用來儲存我們示範的CRC32值的
If Len(FileCRC) < 8 Then FileCRC = Left("00000000", 8 - Len(FileCRC)) & Hex(cCRC.CalculateFile(Lujing))
'如果CRC32值不足8位,那麼要在前面添加零來補足位數
GetCRC32 = FileCRC
Exit Function
CRCerror:
MsgBox "發生意外錯誤,程序被破壞?", , "發生意外錯誤,代碼: " & Err.Number
End Function
我是代碼終止線————————————————————————————————
該GetCRC32函數直接當作字符變量來使用即可,可獲取自身除末尾8位外其他所有數據的CRC32值,我再強調一遍,這裡是做示範,為了方便查看和記憶,特將CRC32校驗值儲存到目標程序末尾8字節位置,實際應用中,大家可以自己選擇一個合理的位置。
我是代碼起始線————————————————————————————————
Private Function GetZHI() As String
'函數化獲得末尾標記值
'這個值是我們用CRC32添加工具添加進去的
'這個位置你也可以自己修改
'核心代碼
Dim Lujing As String
Dim ArrBytes() As Byte
Dim FilelenNO1
Dim Xunhuan As Double
'定義本程序自己的路徑變量
'On Error GoTo ZHIerror
Lujing = App.Path & "\" & App.EXEName & ".exe"
'這句語句就獲得了程序自己的啟動路徑,這個技巧VB中必須掌握,用處很多
tfile = FreeFile
Open Lujing For Binary As #tfile '利用二進制打開自身
FilelenNO1 = LOF(tfile)
ReDim ArrBytes(1 To FilelenNO1) As Byte '將目標末尾8位儲存
Get tfile, , ArrBytes
Close tfile
For Xunhuan = FilelenNO1 - 7 To FilelenNO1
'開始獲取這具體的8位
GetZHI = GetZHI & Chr(ArrBytes(Xunhuan))
Next Xunhuan
Exit Function
ZHIerror:
MsgBox "懷疑程序被破壞了", , "錯誤代碼: " & Err.Number
End Function
我是代碼終止線————————————————————————————————
該GetZHI函數同樣可以當字符形式使用,很方便,從名字上看就知道是為了獲取預先儲存在本身末尾8字節的CRC32預先計算的值。幹什麼用?當然是跟 上面的GetCRC32函數返回的字符進行比較,看結果是否跟標記的一致,一致就說明程序沒有被修改,不一致就說明程序被修改了。
這個兩個關鍵函數同樣可以被大家移植過去使用
很高興能給VB共享軟件帶來點有趣的有用的東西。
接下去就是在主體中使用這兩個函數
我們的使用代碼是:
我是代碼起始線————————————————————————————————
'就簡單的一句話就交代了^_^
'我們已經寫好了GetCRC32函數和GetZHI函數
'兩個函數返回值為字符串,當然,我們只是做測試,如果真的要
'應用到軟件中去,我推薦還是用浮點計算,製造隱藏劇情
'甚至內聯彙編處理,根據CRC32值來跳轉,讓人難以琢磨
'使用時,只要使用這兩個函數就OK了
If GetCRC32 = GetZHI Then
MsgBox "程序未被修改過,恭喜你", , "通過"
Jieguo.ForeColor = &H80000012 '更改字體顏色為黑色
Jieguo.Caption = "程序未被修改"
Else
MsgBox "程序被修改,請不要非法修改本程序,共享軟件云云...", , "被修改"
Jieguo.ForeColor = &HFF& '更改字體顏色為紅色,表示警告
Jieguo.Caption = "警告:程序被修改"
End If
我是代碼終止線————————————————————————————————
這個使用代碼,能看懂的就自己改寫,看不懂的就添加到Private Sub Form_Load()事件中去,還有Private Sub Command1_Click()事件中。
好了,保存工程後,開始編譯為EXE文件吧,編譯好後,用我們寫好的VB-CRC32添加校驗值注射工具進行注射一下,這個時候如果有殺毒軟件在的話,而且比較好的話,可能會彈出提示問你允不允許修改什麼的,我用的微點就會提示和攔截,需要防行。然後運行吧。
效果如圖:
可以看到這裡顯示的目標程序的CRC32自校驗碼為:60B04682
我們用UltraEdit打開注射過了的目標主體程序,在末尾看到:
可見已經添加成功了,運行主體程序:
看來校驗通過了,那麼我們下面來模擬下破解者修改程序的情況:
在VBExplorer中,我們找到檢測按鈕事件起始地址:405F90
代開OD來裝載目標主體程序,CTRL+G 直接到405F90
00405F90 > \55 PUSH EBP
00405F91 . 8BEC MOV EBP,ESP
00405F93 . 83EC 0C SUB ESP,0C
00405F96 . 68 76124000 PUSH <JMP.&MSVBVM60.__vbaExceptHandler> ; SE 處理程序安裝
00405F9B . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00405FA1 . 50 PUSH EAX
00405FA2 . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00405FA9 . 81EC 9C000000 SUB ESP,9C
00405FAF . 53 PUSH EBX
00405FB0 . 56 PUSH ESI
0040604D . /0F84 D1000000 JE VB防破解.00406124
『我們把這句改為必跳實驗下,看看CRC32校驗的威力
0040604D /E9 D2000000 JMP VB防破解.00406124
00406052 |90 NOP
然後保存程序,運行修改後的程序如圖:
到此我們完成了VB-CRC32自校驗程序的設計全部過程,有些問題必須講以下:
也許會有人問:「小愛老師,聽說CRC32很厲害,防修改。但是我用了你的代碼之後,剛發表的共享軟件就被人修改了,怎麼回事?」
問到點子上了,確實CRC查錯能力很強,但是它本身也有脆弱性,本身防修改,但是事實恰恰相反,你可以問下身邊的解密高手,當他們遇到CRC32自校驗的時候怎麼辦?
一般都是爆破,還有些是替換,替換的話還要重新計算新的CRC32值,比較囉嗦,所以大家都喜歡爆掉CRC32的關鍵比較點來突破CRC32,而且以此為榮。
如果你設計VB-CRC32自校驗,怎樣處理這種情況?首先你要隱蔽你的比較方式,採用浮點計算,套用異常,故意設置隱藏劇情來保護CRC-32的校驗,這是個好辦法。也有高手說要加殼帶CRC32校驗。
前輩們給的辦法是把校驗值進行變換,分段,分開,分時,不定時,在各種場合和代碼角落進行驗證,儘量不給檢測到非法修改的提示,而是檢測到非法修改也不告訴破解者,悄悄變換程序流程,讓他迷路去吧
甚至是報復破解者,這個我是不推薦的,但是我可以給個快速關機的過程,直接調用可以在幾秒內關閉對方計算機,讓對方來不及保存破解筆記和資料,註:往往破解者用影子系統或者虛擬機
我是代碼起始線————————————————————————————————
『在通用部分加入如下聲明:
Private Declare Function RtlAdjustPrivilege& Lib "ntdll" (ByVal Privilege&, ByVal NewValue&, ByVal NewThread&, OldValue&)
Private Declare Function NtShutdownSystem& Lib "ntdll" (ByVal ShutdownAction&)
Private Const SE_SHUTDOWN_PRIVILEGE& = 19
Private Const ShutDown& = 0
Private Const RESTART& = 1
Private Const POWEROFF& = 2
『在窗體代碼部分增加:
Sub TurboShutdown(Index As Integer)
RtlAdjustPrivilege SE_SHUTDOWN_PRIVILEGE, 1, 0, 0
Select Case Index
Case 1 '關機
NtShutdownSystem ShutDown
Case 2 '重啟動
NtShutdownSystem RESTART
Case 3 '關機
NtShutdownSystem POWEROFF
End Select
End Sub
我是代碼終止線————————————————————————————————
調用該快速關機指令為:
Call TurboShutdown(1)
希望對你有用,但是不要拿來欺負正常使用你軟件的顧客哦,不然把顧客都嚇跑了
注意:以上VB-CRC32全部設計代碼和工程文件及程序都發佈在附件了,請自行下載
第二章 第二講
VB時間自校驗設計
上一講我們講了使用VB進行CRC32自校驗的設計,相信是能讓部分VB軟件作者受益的。下次見到你們發表VB軟件的時候,我希望不是隨便爆破修改就能破解的了。
也許你認為VB-CRC32設計有點複雜,你問「小愛老師,有沒有簡單點的防爆破自校驗?」
當然是有的
你可以先實驗下,隨便編譯個程序,單擊右鍵查看屬性,你會發現它包含了你的最後修改時間,一般的複製,黏貼等都不會修改它的「修改時間」屬性。
然而,當破解者修改了你的軟件就會被記錄下最新的修改時間,如果破解者不注意,而你的設計又夠隱蔽,倒是可以檢查這個來判斷破解者有沒有修改過你的軟件。
來,跟我一起做運動……
打開VB6.0 新建工程
添加一個按鈕,起名為「檢測」
編寫一個檢測自身修改時間並作比較的函數:
我是代碼起始線————————————————————————————————
Private Function ShiJiancheck() As Boolean
ShiJiancheck = False
Dim iFile As String
Dim FileTime As String
iFile = App.Path & "\" & App.EXEName & ".exe"
'獲取自身啟動路徑
FileTime = Format(FileDateTime(iFile), "YYYYMMDDHHMMSS")
'獲得字符串形式的文件最後修改時間
If FileTime = "20080808080808" Then
'示範設置為2008年08月08日08時08分08秒,這裡大家可以自己定,最好不要太特別
ShiJiancheck = True
Else
ShiJiancheck = False
End If
End Function
我是代碼終止線————————————————————————————————
調用該函數直接當作布爾變量用即可
如下調用:
我是代碼起始線————————————————————————————————
Private Sub Command1_Click()
'注意,文件本身的修改時間應該不是我們設定的值,所以編譯好EXE文件後,
'用文件屬性修改器來修改文件最後修改時間到指定數值,這個數值不要太特殊了
'文件屬性修改器已經放在同個文件夾下了,請使用
If ShiJiancheck = False Then
MsgBox "文件被修改", , "警告"
Else
MsgBox "文件正常", , "通過"
End If
End Sub
我是代碼終止線————————————————————————————————
效果如圖:(正常狀態)
文件被修改後:
跟CRC32比,此辦法短小精悍,但是容易被識破,請隱蔽比較和檢測,不要把結果顯示出來,知道了吧?給破解製造一次意外事故應該不是難事吧?
第二章 第三講
VB大小自校驗設計
「小愛老師,上面的方法都要修改什麼的,太麻煩了,有沒有更通用,更普遍的辦法,且不用修改程序的呢?」
「當然有了,那就是VB裡面的檢測文件大小,但是已經見得多了,已經沒什麼殺傷力了」
Vb裡常用檢測文件大小的函數為FILELEN(路徑)
跟我一起做運動……
打開VB6.0 新建工程
先編寫個檢測自身大小的函數:
我是代碼起始線————————————————————————————————
Private Function FileBig() As Long
'如果文件巨大,那麼改LONG為DOUBLE
Dim FileLujin As String
filelujing = App.Path & "\" & App.EXEName & ".exe"
FileBig = FileLen(filelujing)
End Function
我是代碼終止線————————————————————————————————
具體使用看下面代碼:
我司代碼起始線————————————————————————————————
Private Sub Form_Load()
If FileBig > 27300 Then
'第一次這個數字隨便設置,先編譯好
'用壓縮殼將它壓縮,查看壓縮後文件大小
'回到這裡,修改數值比壓縮後的大小大那兒一些就夠了
'如果被脫殼了,程序體積就會膨脹
'從而被我們檢測出來
'當然要注意了,如果是保護殼的話
'加殼後反而更大,這個時候,我們的判斷
'語句就要反過來了
MsgBox "程序被脫殼了", , "警告"
Else
MsgBox "程序正常", , "通過"
End If
End Sub
我是代碼終止線————————————————————————————————
編譯,加殼(ASPACK)程序從45056字節壓縮為27136 字節,27300略大於27136,脫殼後應該比45056可能還要大,這樣就能實現檢測大小來發現脫殼,也就發現修改了。
如圖:
脫殼後:大小71168字節,為什麼這麼大呢?呵呵,可能是垃圾代碼和垃圾段還沒清理吧,可以用LORDPE重建,應該會小一點。
重建PE後,程序大小46261字節
運行看看:如圖
實驗成功,但是我還是要提醒一下,這種方法隱蔽點,不要提示的話,也許還能存活,對於VB程序,一旦發現自校驗,初學者或者有點基礎的人都會想到去斷點FILELEN函數,直接捕獲你的對比關鍵點。
所以自校驗的設計最關鍵在於隱蔽和起到誤導作用為好,不知不覺中就到了羊腸小道,永遠沒有回頭路……
另外要介紹的是同樣是檢測文件大小以確定是否被脫殼,有些軟件作者把數值通過計算好,通過注射方法,寫入到主體程序的文件頭,這種方法可以比較準確的限定文件大小,而且不容易被發現哦,比方說「超級硬盤搜索正式版」,它就是這麼檢測的。
有點作者把VB程序的數據全部加在一起,比較最後的和,這也是種辦法,所以大家要學會思考和創新,沒有什麼是做不到的。
第二章 第四講
VB防LOADER設計金蟬脫殼
《加密解密技術內幕》一書裡提到過兩種方法防LOADER
其指的是防SMARTCHECK,WKTVB DEBUGGER等
這些技術已經為人所熟知,起不到多麼好的作用,我們就瞭解一下吧,為我們的「金蟬脫殼」做鋪墊。
1. 查找特定的窗口標題 就像第一講裡提到的:
我是引用起始線————————————————————————————————
二、反SMARTCHECK加載,SMARTCHECK是調試VB的利器,有必要對其進行防範。小樓前輩在軟件加密技術內幕中提到兩種檢測方法:
利用VB的AppActivate函數激活SMARTCHECK窗口,然後發送ALT+F4進行關閉該窗口和利用FindWindow發現SMARTCHECK窗口直接將其關閉,其代碼基本上是這樣:
winHwnd = FindWindow(vbNullString, "Numega SmartCheck")
If winHwnd <> 0 Then
AppActivate "Numega SmartCheck"
sendkey "%{f4}", True
sendkey "%y", True
其實,我覺得直接檢測進程SMARTCHK.EXE是否存在也可以,方法跟上面類似,你還可以檢測其它比如W32DASM等進程,附件中的Anti-Load就是實例,發現SMARTCHK調用,自動退出:
…..
If InStr(LCase(Process.szExeFile), "smartchk.exe") > 0 Then
smart = Process.th32ProcessID
TerminateProcess hprocess, 0
Unload Me
Exit Do
End If
…….
我是引用終止線————————————————————————————————
2. 設置步長和時值計算法
其原理是軟件正常執行的某一塊過程是很快的,基本沒多少延時;而通過調試器加載,其加載時間往往要多出十幾倍。
這種方法其實應該是反調試反跟蹤裡用到的,這裡就只提下原理,講到反調試的時候,我再把我知道的寫出來。
目前還有異常SHE處理,使得調試器無礙繼續加載。還有其他的辦法,但是我涉及較淺,以後有機會都放到反調試一塊講。
講完常見的VB反LOADER,你是不是覺得不夠好使?如查標題,我改標題你不久查不到了嗎? 如步長記時,現在的電腦配置參差不齊,這步長時值該怎麼時值好呢?
左思右想,終於被我想到了個辦法——金蟬脫殼
所謂金蟬脫殼指的是核心的東西在你眼皮底下溜走了,抓不到。留下的是一層幻滅的輪迴。
VB金蟬脫殼反LOADER技術基於程序迭代SHELL,第一次運行不會真的開始,而是為了調用本身進行第二次運行,就此結束掉第一次運行,以此類推,知道幾百幾千次,需要的時間大概在半秒到左右。
形象點講就像小孩子走路,故意跌倒,然後爬起來,又故意跌倒,讓你永遠把握不到他,知道他再起來的時候,你早就離開那裡了。
比如A實例,運行後,重新調用A,然後本次A實例自動結束,第二次A實例啟動,再次調用A實例,然後又關閉自己。這樣調試器第一跟蹤,如果不爆破的話,勢 必無法繼續跟了,到後來,調試器裡顯示的是父本程序已經結束了,但實際中,經過幾百到幾千次迭代SHELL後,程序已經打開。
就像人生一樣,調試器跟蹤的只是你的上一世,甚至是幾百幾千世以前的你,而現在的你還好好得活著。這個時候,如果不爆破的話,調試器大概還可以用附加來強行鑽入程序空間。
這樣的思路是可行的,但是你有沒有想到過如何判斷本次運行已經達到要求,可以正常開始?還是繼續輪迴?
要求程序依靠自己的標記,而不依靠外界的標記,不然容易被人發現且從外界修改是非常容易攻破的。
因為程序是同一個程序,憑什麼上一輩子要立刻輪迴,而這輩子就可以正常存活呢?判斷的標準在哪裡?同樣的程序,同樣的標準,為什麼會產生不同的輪迴結果?
答案呼之慾出了,對了,就是隨機數。
通過概率,每次輪迴的概率是一樣的,是同樣的標準,但是概率本身又可以導致不同的方向和結果。
於是我想到設置一個循環取隨機數的結構,循環7次,每次產生一個隨機數,要麼是1,要麼是零,然後把這七個數相加來判斷是否等於零,如果等於零就不必繼續 輪迴了,如果不等於零,那麼SHELL自己,然後馬上死掉。因為每次隨機數取0活著取1的概率是一樣的,都是0.5,所以,7次隨機數取值全部為零的概率 是0.5^7=0.0078125,倒數為128,即大概需要輪迴128次才可以正常運行程序,否則都是SHELL自己,然後父本死掉。
單單靠解釋可能還是有朋友看不明白,沒關係,我們先寫程序先,慢慢測試調試,你就發現其巧妙的地方了。
首先寫一個7次循環取0或取1的結構,然後把7次結果相加,與0作比較,將輪迴金蟬脫克功能嵌入進去。以後程序在運行開頭,只要調用一次我的這個SUB過程即可實現防LOADER,等會我們還要測試下效果呢。
我是代碼起始線————————————————————————————————
Private Sub JinChan()
On Error GoTo ANTI
'只有在被調試的時候才有可能出錯,恰好被我們捕獲,呵呵
Dim Lujing As String
'儲存程序自身路徑
Dim Suiji(7) As Byte
'7個元素數組,用於儲存每次隨機數
Dim n As Long
'循環計數器
Dim Panduan As Double
'累加器
Lujing = App.Path & "\" & App.EXEName & ".exe"
'獲得程序自身路徑
For n = 1 To 7
Randomize
'每次都初始化隨機數生成器
Suiji(n) = Int(Rnd * 2)
『取隨機數0或者1
Panduan = Panduan + Suiji(n)
'累加
Next n
If Panduan > 0 Then
'如果累加總結果不為零,那就SHELL自己一次,然後通過END結束自己
Shell Lujing, 1
'進入下一個輪迴哦
End
'結束這一世
End If
'如果上面的累加器等於零,則說明達到了0.5^7的概率了,其倒數為128,即我們已經輪'回128是世了。'調試器跟蹤的只是我們的第一世。
'到這裡來的話也就是不執行SHELL內容,也不執行END,直接到這裡來了
'正常運行
Exit sub
ANTI:
MsgBox "發現調試器,請關閉調試器", , "警告"
End
End Sub
我是代碼終止線————————————————————————————————
以後只要把JinChan寫入到主窗體LOAD事件中,就實現了金蟬脫殼效果。
大家跟我來做運動:
打開VB6.0 新建工程
在窗體代碼裡,拷貝上面的代碼進去
然後在Private Sub Form_Load()裡輸入JinChan,編譯生成EXE
即:
Private Sub Form_Load()
JinChan
End Sub
先運行一下EXE,看看速度如何,然後再用OD或者SMARTCHECK等測試下,看看是不是無法跟蹤到輪迴後的這一世,前提是不能爆破。
效果還是很好的,OD如果開著HIDEOD插件的話,那麼在執行SHELL的時候,會自動捕獲錯誤以發現調試器,然後程序自動結束,也相當於起到了防LOADER作用。如果OD關閉HIDEOD插件,那麼就可以直接體現出「金蟬脫殼」的效果了。
如圖:通過捕獲異常發現調試器
如圖,如果沒有異常,那麼金蟬脫克將發揮作用,輪迴百世。調試器裡已經結束,但是程序其實輪迴轉世了。
好了,沒想到隨便寫寫可以寫這麼多,看的我頭暈了。
希望你也別頭暈,我們來總結下,《VB 共享軟件防破解涉及技術初探(二)》都講了那些內容:
1、 設計思想:水桶原理
2、 完整性校驗,包括VB-CRC32注射器和主體的編寫;文件修改時間自校驗;文件大小自校驗等
3、 防LOADER設計,包括查找標題,經典時值,還有重點的「金蟬脫殼」反LOADER
這一期就到這裡了,熬夜寫教程很累,呵呵
還是老規矩,如果有時間,有精力,有空,有能力,我將接著寫《VB 共享軟件防破解設計
技術初探(三)》,感謝大家的支持。
希望大家能多頂頂,尤其是學習VB寫軟件的朋友,希望對你有用
上個篇我粗略的講了以下幾個內容:
1、 文件完整性,防止被非法修改
2、 運行時的校驗,防止被LOADER
3、 反調試,防止動態跟蹤和掛接
4、 防靜態反彙編分析
5、 註冊碼系統(算法部分,核心內容)
6、 加殼防脫殼
7、 隱蔽性設計
8、 另闢蹊徑
列表在這裡是為了提醒初學VB發佈共享軟件的朋友,在設計VB防破解的時候,不要出現「水桶效應」,也就是說,設計如水桶,任何一個角落缺失都將導致無法全部盛滿水。
而這個水桶的捆圈恐怕就是保護文件完整性,防止修改了。
週末了,今天有點時間。趕快寫好,等下吃晚飯,練練琴,然後陪陪女朋友。
接下去,我們將開始具體至微的講解第1、2兩個內容,剩下的老規矩:日後有空,有時間,有精力,有能力的話接著寫。
1、 文件完整性,可採用CRC32或者MD5或者哈希算法等,計算出文件的加密值,在適當的時候進行對比,判斷文件被修改與否。當然那也可以加猛殼來防止文件 非法修改。還有簡單點的檢查文件最後修改時間,看看是否是你自己設置好的時間,如果不是,則很有可能被修改過;也可以檢測文件大小,往往壓縮殼被脫掉後, 文件的大小會增加;保護殼被脫掉後,文件大小會變小,我們可以根據這個設置好臨界值來檢測有沒有被脫殼。常用的還有故意設計好關於算法方面的陷阱,如果是 破解者會主動掉進你的陷阱,而事實上,這個跳轉除非爆破,不然在算法上是永遠也無法到達的,這樣就檢出破解者在修改程序流程。你可以無聲無息的程序死掉, 不要直接退出,不然會被追蹤到退出函數。
還有內存鏡像校驗,是為了防止普通的修改內存和普通斷點問題。
我們就具體演示3種VB程序的完整性校驗設計。
第一種是VB的CRC32自校驗設計,包含過程,代碼和所有工程文件及演示;
第二種是VB程序的時間檢測法則,包括過程,代碼和所有工程文件及演示;
第三種是VB程序的文件大小檢測法則,包括過程,代碼和所有工程文件及演示。
其實還有些檢測的辦法,但是原理跟我們即將大曝光的三種辦法差不多,都是衍生的吧。
第二章 第一講
VB的CRC32自校驗設計
來來來…大家跟我一起做運動,抖抖手啊,抖抖腳啊,做做深呼吸,本講將會有點長,力求做到簡單明了,容易明白,學完馬上上手,學會應用的要求,我會具體點講,不會像某些高人敝帚自珍,當然如果有錯誤的地方還請大家多多幫忙糾正,謝謝
首先來簡單複習下何謂CRC32
CRC校驗實用程序庫 在數據存儲和數據通訊領域,為了保證數據的正確,就不得不採用檢錯的手段。在諸多檢錯手段中,CRC是最著名的一種。CRC的全稱是循環冗餘校驗,其特點 是:檢錯能力極強,開銷小,易於用編碼器及檢測電路實現。從其檢錯能力來看,它所不能發現的錯誤的幾率僅為0.0047%以下。
有查表和計算法,我們可以在程序中自動生成碼表來查表計算,方便和快速
為了快速帶過原理筆墨,節省點時間吃飯,我把網路上的一篇介紹《探究CRC32算法實現原理》引述過來,原文地址:
http://www.diybl.com/course/6_system...1/134331.html#
以下是引用部分——————————————————————————————
基於不重造輪子的原則,本文儘量不涉及網絡上遍地都是的資料。
What's CRC ?
簡而言之,CRC是一個數值。該數值被用於校驗數據的正確性。CRC數值簡單地說就是通過讓你需要做
處理的數據除以一個常數而得到的餘數。當你得到這個數值後你可以將這個數值附加到你的數據後,
當數據被傳送到其他地方後,取出原始數據(可能在傳送過程中被破壞)與附加的CRC數值,然後將這裡
的原始數據除以之前那個常數(約定好的)然後得到新的CRC值。比較兩個CRC值是否相等即可確認你的
數據是否在傳送過程中出現錯誤。
那麼,如何讓你的數據除以一個常數?方法是對你的數據進行必要的編碼處理,逐字節處理成數字。
那麼這個常數是什麼?你不必關注它是什麼,也不需要關注它是如何獲得的。當你真的要動手寫一個
CRC的實現算法時,我可以告訴你,CRC的理論學家會告訴你。不同長度的常數對應著不同的CRC實現算法。
當這個常數為32位時,也就是這裡所說的CRC32。
以上內容你不必全部理解,因為你需要查閱其他資料來獲取CRC完整的理論介紹。
The mathematics behind CRC ?
很多教科書會把CRC與多項式關聯起來。這裡的多項式指的是係數為0或1的式子,例如:
a0 + a1*x + a2*x^2 + ... + an*x^n。其中a0, a1, ..., an要麼為0要麼為1。我們並不關注x取什麼值。
(如果你要關注,你可以簡單地認為x為2) 這裡把a0, a1, ..., an的值取出來排列起來,就可以表示比特
流。例如1 + x + x^3所表示的比特流就為:1101。部分資料會將這個順序顛倒,這個很正常。
什麼是生成多項式?
所謂的生成多項式,就是上面我所說的常數。注意,在這裡,一個多項式就表示了一個比特流,也就是一堆
1、0,組合起來最終就是一個數值。例如CRC32算法中,這個生成多項式為:
c(x) = 1 + x + x^2 + x^4 + x^5 + x^7 + x^8 + x^10 + x^11 + x^12 + x^16 + x^22 + x^23 + x^26 + x^32。
其對應的數字就為:11101101101110001000001100100000(x^32在實際計算時隱含給出,因此這裡沒有包含它
的係數),也就是0xEDB88320(多項式對應的數字可能顛倒,顛倒後得到的是0x04C11DB7,其實也是正確的)。
由此可以看出,CRC值也可以看成我們的數據除以一個生成多項式而得到的餘數。
如何做這個除法?
套用大部分教科書給出的計算方法,因為任何數據都可以被處理成純數字,因此,在某種程度上說,我們可以
直接開始這個除法。儘管事實上這並不是標準的除法。例如,我們的數據為1101011011(方便起見我直接給二進制
表示了,從這裡也可以看出,CRC是按bit進行計算的),給定的生成多項式(對應的值)為10011。通常的教科書
會告訴我們在進行這個除法前,會把我們的數據左移幾位(生成多項式位數-1位),從而可以容納將來計算得到
的CRC值(我上面所說的將CRC值附加到原始數據後)。但是為什麼要這樣做?我也不知道。(不知道的東西不能含糊
而過)那麼,除法就為:
1100001010
_______________
10011 ) 11010110110000 附加了幾個零的新數據
10011......... 這裡的減法(希望你不至於忘掉小學算術)是一個異或操作
-----.........
10011........
10011........
-----........
00001....... 逐bit計算
00000.......
-----.......
00010......
00000......
-----......
00101.....
00000.....
-----.....
01011....
00000....
-----....
10110...
10011...
-----...
01010..
00000..
-----..
10100.
10011.
-----.
01110
00000
-----
1110 = 這個餘數也就是所謂的CRC值,通常又被稱為校驗值。
希望進行到這裡,你可以獲取更多關於CRC的感性認識。而我們所要做的,也就是實現一個CRC的計算算法。
說白了,就是提供一個程序,給定一段數據,以及一個生成多項式(對於CRC32算法而言該值固定),然後
計算得出上面的1110餘數。
The simplest algorithm.
最簡單的實現算法,是一種模擬算法。我們模擬上面的除法過程,遵從網上一份比較全面的資料,我們設定
一個變量register。我們逐bit地將我們的數據放到register中。然後判斷register最高位是否為1,如果是
則與生成多項式異或操作,否則繼續處理。這個過程簡單地模擬了上述除法過程:
引用到此結束—————————————————————————————————
看來大家選擇CRC32作為數據校驗是有原因的,速度快,代價小,檢錯能力比較大。VB軟件作者對CRC32有個認識就好了。
我們編寫VB的CRC32自校驗程序思路如下:
1、 計算出目標文件除掉末尾8字節後的所有數據的CRC32值
2、 將上面計算出來的結果儲存在目標程序的末尾8個字節裡
3、 主體程序內置計算自身除掉末尾8字節後的所有數據的CRC32值的功能代碼
4、 主體程序讀取末尾8字節內容與計算的CRC32值比較,不一致說明被修改
由1、2點我們發現,如果手動來添加CRC32值將是件麻煩的事情,所以一般我們都會寫一個具備計算要求的CRC32值,及把該值添加到目標程序指定位置的程序,幫我們節省時間和體力。
為了方便記憶和理解,在這裡我將它命名為VB-CRC32 注射器,顧名思義,即將計算出來的CRC32注射到目標程序裡。
那麼執行自校驗的程序我稱它為VB-CRC32 主體程序。大家記住了哦,下面開始先設計VB-CRC32注射程序。
請跟我一起來:
打開VB6.0 新建工程
新建類模塊,名字改為「clsCRC」,別告訴我你不會改名,當然是在「屬性窗口」改的。
將如下類模塊代碼複製到clsCRC類模塊裡去:(或者直接從我發佈的附件來條用該類模塊)
注意:類模塊後綴名是CLS,請剛接觸VB的同學注意,不要跟模塊搞混了。
我是代碼起始線————————————————————————————————
Option Explicit
Public Enum CRCAlgorithms
CRC16
CRC32
End Enum
Private m_Algorithm As Boolean
Private m_CRC16 As Long
Private m_CRC16Asm() As Byte
Private m_CRC16Init As Boolean
Private m_CRC16Table(0 To 255) As Long
Private m_CRC32 As Long
Private m_CRC32Asm() As Byte
Private m_CRC32Init As Boolean
Private m_CRC32Table(0 To 255) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'此函數作用在這裡是內聯彙編之用
Public Function AddBytes(ByteArray() As Byte) As Variant
Dim ByteSize As Long
'異常處理
On Local Error GoTo NoData
'計算大小
ByteSize = UBound(ByteArray) - LBound(ByteArray) + 1
'異常處理
On Local Error GoTo 0
'內聯彙編提高處理速度
Select Case m_Algorithm
Case CRC16
Call CallWindowProc(VarPtr(m_CRC16Asm(0)), VarPtr(m_CRC16), VarPtr(ByteArray(LBound(ByteArray))), VarPtr(m_CRC16Table(0)), ByteSize)
Case CRC32
Call CallWindowProc(VarPtr(m_CRC32Asm(0)), VarPtr(m_CRC32), VarPtr(ByteArray(LBound(ByteArray))), VarPtr(m_CRC32Table(0)), ByteSize)
End Select
NoData:
'返回新值
AddBytes = Value
End Function
Public Function AddString(Text As String) As Variant
'將字符轉為數組,以便套入函數計算CRC
AddString = AddBytes(StrConv(Text, vbFromUnicode))
End Function
Public Property Let Algorithm(New_Value As CRCAlgorithms)
'選擇新算法
m_Algorithm = New_Value
'確定已經初始化新算法
Select Case m_Algorithm
Case CRC16
If (Not m_CRC16Init) Then Call InitializeCRC16
Case CRC32
If (Not m_CRC32Init) Then Call InitializeCRC32
End Select
'標記
Call Clear
End Property
Public Property Get Algorithm() As CRCAlgorithms
Algorithm = m_Algorithm
End Property
Public Function CalculateBytes(ByteArray() As Byte) As Variant
'重置CRC計算
Call Clear
'計算
CalculateBytes = AddBytes(ByteArray)
End Function
Public Function CalculateFile(Filename As String) As Variant
Dim Filenr As Integer
Dim ByteArray() As Byte
'檢測文件是否包換數據
If (FileLen(Filename) = 0) Then Exit Function
'二進制模式讀取文件儲存到數組裡
Filenr = FreeFile
Open Filename For Binary As #Filenr
ReDim ByteArray(0 To LOF(Filenr) - 9)
Get #Filenr, , ByteArray()
Close #Filenr
'將該數組交給處理函數計算出CRC
CalculateFile = CalculateBytes(ByteArray)
End Function
Public Property Get Value() As Variant
Select Case m_Algorithm
Case CRC16
Value = (m_CRC16 And 65535)
Case CRC32
Value = (Not m_CRC32)
End Select
End Property
Public Property Let Value(New_Value As Variant)
Select Case m_Algorithm
Case CRC16
m_CRC16 = New_Value
Case CRC32
m_CRC32 = New_Value
End Select
End Property
Private Sub InitializeCRC16()
Dim i As Long
Dim j As Long
Dim k As Long
Dim CRC As Long
Dim sASM As String
'創建表格
For i = 0 To 255
k = i * 256
CRC = 0
For j = 0 To 7
If (((CRC Xor k) And 32768) = 32768) Then
CRC = (CRC * 2) Xor &H1021
Else
CRC = (CRC * 2)
End If
k = k * 2
Next
m_CRC16Table(i) = CRC '(CRC And 65535)
Next
'內聯彙編預處理
sASM = "5589E55756505351528B45088B008B750C8B7D108B4D1431DB8A1E30E3668B149F30C66689D0464975EF25FFFF00008B4D0889015A595B585E5F89EC5DC21000"
ReDim m_CRC16Asm(0 To Len(sASM) \ 2 - 1)
For i = 1 To Len(sASM) Step 2
m_CRC16Asm(i \ 2) = Val("&H" & Mid$(sASM, i, 2))
Next
'標記
m_CRC16Init = True
End Sub
Public Sub Clear()
m_CRC16 = 0
m_CRC32 = &HFFFFFFFF
End Sub
Private Sub InitializeCRC32()
Dim i As Long
Dim sASM As String
m_CRC32Table(0) = &H0
m_CRC32Table(1) = &H77073096
m_CRC32Table(2) = &HEE0E612C
m_CRC32Table(3) = &H990951BA
m_CRC32Table(4) = &H76DC419
m_CRC32Table(5) = &H706AF48F
m_CRC32Table(6) = &HE963A535
m_CRC32Table(7) = &H9E6495A3
m_CRC32Table(8) = &HEDB8832
m_CRC32Table(9) = &H79DCB8A4
m_CRC32Table(10) = &HE0D5E91E
m_CRC32Table(11) = &H97D2D988
m_CRC32Table(12) = &H9B64C2B
m_CRC32Table(13) = &H7EB17CBD
m_CRC32Table(14) = &HE7B82D07
m_CRC32Table(15) = &H90BF1D91
m_CRC32Table(16) = &H1DB71064
m_CRC32Table(17) = &H6AB020F2
m_CRC32Table(18) = &HF3B97148
m_CRC32Table(19) = &H84BE41DE
m_CRC32Table(20) = &H1ADAD47D
m_CRC32Table(21) = &H6DDDE4EB
m_CRC32Table(22) = &HF4D4B551
m_CRC32Table(23) = &H83D385C7
m_CRC32Table(24) = &H136C9856
m_CRC32Table(25) = &H646BA8C0
m_CRC32Table(26) = &HFD62F97A
m_CRC32Table(27) = &H8A65C9EC
m_CRC32Table(28) = &H14015C4F
m_CRC32Table(29) = &H63066CD9
m_CRC32Table(30) = &HFA0F3D63
m_CRC32Table(31) = &H8D080DF5
m_CRC32Table(32) = &H3B6E20C8
m_CRC32Table(33) = &H4C69105E
m_CRC32Table(34) = &HD56041E4
m_CRC32Table(35) = &HA2677172
m_CRC32Table(36) = &H3C03E4D1
m_CRC32Table(37) = &H4B04D447
m_CRC32Table(38) = &HD20D85FD
m_CRC32Table(39) = &HA50AB56B
m_CRC32Table(40) = &H35B5A8FA
m_CRC32Table(41) = &H42B2986C
m_CRC32Table(42) = &HDBBBC9D6
m_CRC32Table(43) = &HACBCF940
m_CRC32Table(44) = &H32D86CE3
m_CRC32Table(45) = &H45DF5C75
m_CRC32Table(46) = &HDCD60DCF
m_CRC32Table(47) = &HABD13D59
m_CRC32Table(48) = &H26D930AC
m_CRC32Table(49) = &H51DE003A
m_CRC32Table(50) = &HC8D75180
m_CRC32Table(51) = &HBFD06116
m_CRC32Table(52) = &H21B4F4B5
m_CRC32Table(53) = &H56B3C423
m_CRC32Table(54) = &HCFBA9599
m_CRC32Table(55) = &HB8BDA50F
m_CRC32Table(56) = &H2802B89E
m_CRC32Table(57) = &H5F058808
m_CRC32Table(58) = &HC60CD9B2
m_CRC32Table(59) = &HB10BE924
m_CRC32Table(60) = &H2F6F7C87
m_CRC32Table(61) = &H58684C11
m_CRC32Table(62) = &HC1611DAB
m_CRC32Table(63) = &HB6662D3D
m_CRC32Table(64) = &H76DC4190
m_CRC32Table(65) = &H1DB7106
m_CRC32Table(66) = &H98D220BC
m_CRC32Table(67) = &HEFD5102A
m_CRC32Table(68) = &H71B18589
m_CRC32Table(69) = &H6B6B51F
m_CRC32Table(70) = &H9FBFE4A5
m_CRC32Table(71) = &HE8B8D433
m_CRC32Table(72) = &H7807C9A2
m_CRC32Table(73) = &HF00F934
m_CRC32Table(74) = &H9609A88E
m_CRC32Table(75) = &HE10E9818
m_CRC32Table(76) = &H7F6A0DBB
m_CRC32Table(77) = &H86D3D2D
m_CRC32Table(78) = &H91646C97
m_CRC32Table(79) = &HE6635C01
m_CRC32Table(80) = &H6B6B51F4
m_CRC32Table(81) = &H1C6C6162
m_CRC32Table(82) = &H856530D8
m_CRC32Table(83) = &HF262004E
m_CRC32Table(84) = &H6C0695ED
m_CRC32Table(85) = &H1B01A57B
m_CRC32Table(86) = &H8208F4C1
m_CRC32Table(87) = &HF50FC457
m_CRC32Table(88) = &H65B0D9C6
m_CRC32Table(89) = &H12B7E950
m_CRC32Table(90) = &H8BBEB8EA
m_CRC32Table(91) = &HFCB9887C
m_CRC32Table(92) = &H62DD1DDF
m_CRC32Table(93) = &H15DA2D49
m_CRC32Table(94) = &H8CD37CF3
m_CRC32Table(95) = &HFBD44C65
m_CRC32Table(96) = &H4DB26158
m_CRC32Table(97) = &H3AB551CE
m_CRC32Table(98) = &HA3BC0074
m_CRC32Table(99) = &HD4BB30E2
m_CRC32Table(100) = &H4ADFA541
m_CRC32Table(101) = &H3DD895D7
m_CRC32Table(102) = &HA4D1C46D
m_CRC32Table(103) = &HD3D6F4FB
m_CRC32Table(104) = &H4369E96A
m_CRC32Table(105) = &H346ED9FC
m_CRC32Table(106) = &HAD678846
m_CRC32Table(107) = &HDA60B8D0
m_CRC32Table(108) = &H44042D73
m_CRC32Table(109) = &H33031DE5
m_CRC32Table(110) = &HAA0A4C5F
m_CRC32Table(111) = &HDD0D7CC9
m_CRC32Table(112) = &H5005713C
m_CRC32Table(113) = &H270241AA
m_CRC32Table(114) = &HBE0B1010
m_CRC32Table(115) = &HC90C2086
m_CRC32Table(116) = &H5768B525
m_CRC32Table(117) = &H206F85B3
m_CRC32Table(118) = &HB966D409
m_CRC32Table(119) = &HCE61E49F
m_CRC32Table(120) = &H5EDEF90E
m_CRC32Table(121) = &H29D9C998
m_CRC32Table(122) = &HB0D09822
m_CRC32Table(123) = &HC7D7A8B4
m_CRC32Table(124) = &H59B33D17
m_CRC32Table(125) = &H2EB40D81
m_CRC32Table(126) = &HB7BD5C3B
m_CRC32Table(127) = &HC0BA6CAD
m_CRC32Table(128) = &HEDB88320
m_CRC32Table(129) = &H9ABFB3B6
m_CRC32Table(130) = &H3B6E20C
m_CRC32Table(131) = &H74B1D29A
m_CRC32Table(132) = &HEAD54739
m_CRC32Table(133) = &H9DD277AF
m_CRC32Table(134) = &H4DB2615
m_CRC32Table(135) = &H73DC1683
m_CRC32Table(136) = &HE3630B12
m_CRC32Table(137) = &H94643B84
m_CRC32Table(138) = &HD6D6A3E
m_CRC32Table(139) = &H7A6A5AA8
m_CRC32Table(140) = &HE40ECF0B
m_CRC32Table(141) = &H9309FF9D
m_CRC32Table(142) = &HA00AE27
m_CRC32Table(143) = &H7D079EB1
m_CRC32Table(144) = &HF00F9344
m_CRC32Table(145) = &H8708A3D2
m_CRC32Table(146) = &H1E01F268
m_CRC32Table(147) = &H6906C2FE
m_CRC32Table(148) = &HF762575D
m_CRC32Table(149) = &H806567CB
m_CRC32Table(150) = &H196C3671
m_CRC32Table(151) = &H6E6B06E7
m_CRC32Table(152) = &HFED41B76
m_CRC32Table(153) = &H89D32BE0
m_CRC32Table(154) = &H10DA7A5A
m_CRC32Table(155) = &H67DD4ACC
m_CRC32Table(156) = &HF9B9DF6F
m_CRC32Table(157) = &H8EBEEFF9
m_CRC32Table(158) = &H17B7BE43
m_CRC32Table(159) = &H60B08ED5
m_CRC32Table(160) = &HD6D6A3E8
m_CRC32Table(161) = &HA1D1937E
m_CRC32Table(162) = &H38D8C2C4
m_CRC32Table(163) = &H4FDFF252
m_CRC32Table(164) = &HD1BB67F1
m_CRC32Table(165) = &HA6BC5767
m_CRC32Table(166) = &H3FB506DD
m_CRC32Table(167) = &H48B2364B
m_CRC32Table(168) = &HD80D2BDA
m_CRC32Table(169) = &HAF0A1B4C
m_CRC32Table(170) = &H36034AF6
m_CRC32Table(171) = &H41047A60
m_CRC32Table(172) = &HDF60EFC3
m_CRC32Table(173) = &HA867DF55
m_CRC32Table(174) = &H316E8EEF
m_CRC32Table(175) = &H4669BE79
m_CRC32Table(176) = &HCB61B38C
m_CRC32Table(177) = &HBC66831A
m_CRC32Table(178) = &H256FD2A0
m_CRC32Table(179) = &H5268E236
m_CRC32Table(180) = &HCC0C7795
m_CRC32Table(181) = &HBB0B4703
m_CRC32Table(182) = &H220216B9
m_CRC32Table(183) = &H5505262F
m_CRC32Table(184) = &HC5BA3BBE
m_CRC32Table(185) = &HB2BD0B28
m_CRC32Table(186) = &H2BB45A92
m_CRC32Table(187) = &H5CB36A04
m_CRC32Table(188) = &HC2D7FFA7
m_CRC32Table(189) = &HB5D0CF31
m_CRC32Table(190) = &H2CD99E8B
m_CRC32Table(191) = &H5BDEAE1D
m_CRC32Table(192) = &H9B64C2B0
m_CRC32Table(193) = &HEC63F226
m_CRC32Table(194) = &H756AA39C
m_CRC32Table(195) = &H26D930A
m_CRC32Table(196) = &H9C0906A9
m_CRC32Table(197) = &HEB0E363F
m_CRC32Table(198) = &H72076785
m_CRC32Table(199) = &H5005713
m_CRC32Table(200) = &H95BF4A82
m_CRC32Table(201) = &HE2B87A14
m_CRC32Table(202) = &H7BB12BAE
m_CRC32Table(203) = &HCB61B38
m_CRC32Table(204) = &H92D28E9B
m_CRC32Table(205) = &HE5D5BE0D
m_CRC32Table(206) = &H7CDCEFB7
m_CRC32Table(207) = &HBDBDF21
m_CRC32Table(208) = &H86D3D2D4
m_CRC32Table(209) = &HF1D4E242
m_CRC32Table(210) = &H68DDB3F8
m_CRC32Table(211) = &H1FDA836E
m_CRC32Table(212) = &H81BE16CD
m_CRC32Table(213) = &HF6B9265B
m_CRC32Table(214) = &H6FB077E1
m_CRC32Table(215) = &H18B74777
m_CRC32Table(216) = &H88085AE6
m_CRC32Table(217) = &HFF0F6A70
m_CRC32Table(218) = &H66063BCA
m_CRC32Table(219) = &H11010B5C
m_CRC32Table(220) = &H8F659EFF
m_CRC32Table(221) = &HF862AE69
m_CRC32Table(222) = &H616BFFD3
m_CRC32Table(223) = &H166CCF45
m_CRC32Table(224) = &HA00AE278
m_CRC32Table(225) = &HD70DD2EE
m_CRC32Table(226) = &H4E048354
m_CRC32Table(227) = &H3903B3C2
m_CRC32Table(228) = &HA7672661
m_CRC32Table(229) = &HD06016F7
m_CRC32Table(230) = &H4969474D
m_CRC32Table(231) = &H3E6E77DB
m_CRC32Table(232) = &HAED16A4A
m_CRC32Table(233) = &HD9D65ADC
m_CRC32Table(234) = &H40DF0B66
m_CRC32Table(235) = &H37D83BF0
m_CRC32Table(236) = &HA9BCAE53
m_CRC32Table(237) = &HDEBB9EC5
m_CRC32Table(238) = &H47B2CF7F
m_CRC32Table(239) = &H30B5FFE9
m_CRC32Table(240) = &HBDBDF21C
m_CRC32Table(241) = &HCABAC28A
m_CRC32Table(242) = &H53B39330
m_CRC32Table(243) = &H24B4A3A6
m_CRC32Table(244) = &HBAD03605
m_CRC32Table(245) = &HCDD70693
m_CRC32Table(246) = &H54DE5729
m_CRC32Table(247) = &H23D967BF
m_CRC32Table(248) = &HB3667A2E
m_CRC32Table(249) = &HC4614AB8
m_CRC32Table(250) = &H5D681B02
m_CRC32Table(251) = &H2A6F2B94
m_CRC32Table(252) = &HB40BBE37
m_CRC32Table(253) = &HC30C8EA1
m_CRC32Table(254) = &H5A05DF1B
m_CRC32Table(255) = &H2D02EF8D
'內聯彙編預處理
sASM = "5589E557565053518B45088B008B750C8B7D108B4D1431DB8A1E30C3C1E80833049F464975F28B4D088901595B585E5F89EC5DC21000"
ReDim m_CRC32Asm(0 To Len(sASM) \ 2 - 1)
For i = 1 To Len(sASM) Step 2
m_CRC32Asm(i \ 2) = Val("&H" & Mid$(sASM, i, 2))
Next
'標記CRC32
m_CRC32Init = True
End Sub
Private Sub Class_Initialize()
'默認為CRC32算法
Algorithm = CRC32
End Sub
我是代碼終止線————————————————————————————————
可以看到該類模塊裡應用了VB內聯彙編的技巧,其核心是利用了CallWindowProcA,將定義好的代碼串作為數值編入VB,然後通過CallWindowProcA來指定其為執行的代碼進行執行。相關內容請到網上查找。
該模塊是我修改來急速計算文件CRC32或者CRC16的,默認情況下是計算CRC32。
如圖:
然後雙擊窗體Form1,在工具欄裡選擇「工程」,指向「部件」,選擇「Microsoft Common Dialog Contrll 6.0」,在工具箱中選擇它,添加到窗體上。並改其名為「Openfile」。
注意:細節美觀什麼的,大家自己弄,我講的一般不包含如何設置和美化界面什麼的。
如圖:
在窗體通用部分添加:
Private CRC32zhi As String
'用作儲存CRC32的值的
Private Zhuangtai As Boolean
'用作標誌寫入文件是否成功
在窗體上添加按鈕Command1,命名為「打開」,然後設計代碼使通過它跟「Openfile」掛鉤(別再問我Openfile是什麼,也就是剛才我們使用的Common Dialog控件)
Openfile的Action我們採用1模式,也就是常見的打開對話框;
Openfile的Dialog Title我們命名為" 請選擇需要添加CRC32自校驗值的目標程序"
Openfire的Filter屬性我們設置為"*.exe"
Openfire的其他屬性默認即可
為了計算並自動添加CRC32值到目標程序,並且方便大家複製移植代碼,我們有必要給它寫個過程,或者函數。這裡注射寫過程就好了,等下設計主體程序時我們也要寫函數的。
我是代碼起始線————————————————————————————————
Private Sub SetCRC32(Lujing As String)
'函數化添加CRC32
'核心代碼
On Error GoTo CRCerror
Dim cCRC As New clsCRC, FileCRC$
'啟用類模塊
cCRC.Algorithm = CRC32 '選擇算法模式是CRC32
cCRC.Clear '算法初始化
FileCRC = Hex(cCRC.CalculateFile(Lujing))
'計算出目標程序的CRC32,忽略目標程序末尾8字節數值,末尾8字節是用來儲存我們示範的CRC32值的
If Len(FileCRC) < 8 Then FileCRC = Left("00000000", 8 - Len(FileCRC)) & Hex(cCRC.CalculateFile(Lujing))
'如果CRC32值不足8位,那麼要在前面添加零來補足位數
CRC32zhi = FileCRC
'CRC32值儲存
FileNum = FreeFile
'獲得個文件號(通道)
Open Lujing For Binary As #FileNum
Seek FileNum, FileLen(Lujing) - 7
Put #FileNum, , FileCRC
Close FileNum
'用二進制模式打開目標程序,通過SEEK定位需要添加CRC32數值的位置,請注意:這個位置以後大家可以自己改
'通過PUT將我們計算號的CRC32寫入指定位置
'通過CLOSE關閉通道
Zhuangtai = True
'狀態字,表示寫入文件成功了
Exit Sub
CRCerror:
MsgBox "發生意外錯誤,請檢查目標程序是否正在運行?", , "發生意外錯誤,代碼: " & Err.Number
End Sub
我是代碼終止線————————————————————————————————
SetCRC32就是特意寫的直接完成計算CRC32和寫入目標程序的功能過程
調用格式為:SetCRC32(目標程序路徑)
看,多麼簡單不是嗎?
接下去雙擊Command1按鈕,給它設計功能代碼如下:
我是代碼起始線————————————————————————————————
Private Sub Command1_Click()
'示範
'選擇一個待添加CRC32值的自校驗程序
On Error GoTo Qingjiancha
'初始化CRC32值,主要是為了清空上次的狀態
CRC32zhi = ""
'初始化寫入成功與否的標誌
Zhuangtai = False
Dim FilenameNo1 As String
Openfile.DialogTitle = " 請選擇需要添加CRC32自校驗值的目標程序"
Openfile.Filter = "*.exe"
Openfile.Action = 1
FilenameNo1 = Openfile.Filename
If FilenameNo1 = "" Then Exit Sub
'檢查是否選擇了程序
If FileLen(FilenameNo1) < 16 Then MsgBox "請檢查目標程序是否包含足夠數據", , "請檢查NO1": Exit Sub
'檢查程序是否包含足夠空間和數據,因為儲存CRC32需要8個字節的空間,本身計算余量怎麼說也要8個字節把?8+8=16
Big.Caption = "目標程序大小為: " & FileLen(FilenameNo1) & " 字節"
SetCRC32 (FilenameNo1)
CRCzhi.Caption = "目標程序CRC32值: " & CRC32zhi
If Zhuangtai = True Then
Zhuang.Caption = "CRC32添加狀況: 添加成功,你可以啟動目標程序的自校驗來核實"
Else
Zhuang.Caption = "CRC32添加狀況: 添加失敗,請你檢查下目標程序是否正在運行中?"
End If
Exit Sub
FilenameNo1 = ""
Qingjiancha:
MsgBox "發生意外錯誤,請檢查輸入等情況是否正常,目標程序是否正在運行?", , "發生意外錯誤,代碼: " & Err.Number
FilenameNo1 = ""
End Sub
我是代碼終止線————————————————————————————————
整個程序還需要:一個名為CRCzhi的Label,一個名為Zhuang的Label
分別顯示計算出來的CRC32值,和顯示寫入文件是否成功的信息
這樣子,通過編譯,生成EXE文件,執行效果如圖:
這樣我們就完成了VB-CRC32添加校驗值到目標程序的注射端。保存工程等文件。
接下去,我們就來應用該VB-CRC32注射端配合主體程序來完成整個VB-CRC32自校驗設計
下面開始寫VB-CRC32自校驗主體程序
打開VB6.0,新建工程
按照上文一樣,建立clsCRC類模塊,代碼一致,或者直接添加附件裡的該類模塊也可以。
如圖:
然後設計如下圖的程序界面,注意需要一個名為Jieguo的Label,建立一個名為「檢測「的Command1
然後雙擊窗體,進入代碼設計界面
如圖:
在這個主體自校驗部分,大家想一下,大概需要寫幾個什麼樣的函數?方便複製和移植?
我認為是兩個函數,分別計算自身的CRC32值,和獲取已經寫入到末尾8字節的CRC32校驗值。
那麼說幹就幹吧:
我是代碼起始線————————————————————————————————
Private Function GetCRC32() As String
'函數化計算本身的CRC32
'核心代碼
Dim Lujing As String
'定義本程序自己的路徑變量
On Error GoTo CRCerror
Lujing = App.Path & "\" & App.EXEName & ".exe"
'這句語句就獲得了程序自己的啟動路徑,這個技巧VB中必須掌握,用處很多
Dim cCRC As New clsCRC, FileCRC$
'啟用類模塊
cCRC.Algorithm = CRC32 '選擇算法模式是CRC32
cCRC.Clear '算法初始化
FileCRC = Hex(cCRC.CalculateFile(Lujing))
'計算出目標程序的CRC32,忽略目標程序末尾8字節數值,末尾8字節是用來儲存我們示範的CRC32值的
If Len(FileCRC) < 8 Then FileCRC = Left("00000000", 8 - Len(FileCRC)) & Hex(cCRC.CalculateFile(Lujing))
'如果CRC32值不足8位,那麼要在前面添加零來補足位數
GetCRC32 = FileCRC
Exit Function
CRCerror:
MsgBox "發生意外錯誤,程序被破壞?", , "發生意外錯誤,代碼: " & Err.Number
End Function
我是代碼終止線————————————————————————————————
該GetCRC32函數直接當作字符變量來使用即可,可獲取自身除末尾8位外其他所有數據的CRC32值,我再強調一遍,這裡是做示範,為了方便查看和記憶,特將CRC32校驗值儲存到目標程序末尾8字節位置,實際應用中,大家可以自己選擇一個合理的位置。
我是代碼起始線————————————————————————————————
Private Function GetZHI() As String
'函數化獲得末尾標記值
'這個值是我們用CRC32添加工具添加進去的
'這個位置你也可以自己修改
'核心代碼
Dim Lujing As String
Dim ArrBytes() As Byte
Dim FilelenNO1
Dim Xunhuan As Double
'定義本程序自己的路徑變量
'On Error GoTo ZHIerror
Lujing = App.Path & "\" & App.EXEName & ".exe"
'這句語句就獲得了程序自己的啟動路徑,這個技巧VB中必須掌握,用處很多
tfile = FreeFile
Open Lujing For Binary As #tfile '利用二進制打開自身
FilelenNO1 = LOF(tfile)
ReDim ArrBytes(1 To FilelenNO1) As Byte '將目標末尾8位儲存
Get tfile, , ArrBytes
Close tfile
For Xunhuan = FilelenNO1 - 7 To FilelenNO1
'開始獲取這具體的8位
GetZHI = GetZHI & Chr(ArrBytes(Xunhuan))
Next Xunhuan
Exit Function
ZHIerror:
MsgBox "懷疑程序被破壞了", , "錯誤代碼: " & Err.Number
End Function
我是代碼終止線————————————————————————————————
該GetZHI函數同樣可以當字符形式使用,很方便,從名字上看就知道是為了獲取預先儲存在本身末尾8字節的CRC32預先計算的值。幹什麼用?當然是跟 上面的GetCRC32函數返回的字符進行比較,看結果是否跟標記的一致,一致就說明程序沒有被修改,不一致就說明程序被修改了。
這個兩個關鍵函數同樣可以被大家移植過去使用
很高興能給VB共享軟件帶來點有趣的有用的東西。
接下去就是在主體中使用這兩個函數
我們的使用代碼是:
我是代碼起始線————————————————————————————————
'就簡單的一句話就交代了^_^
'我們已經寫好了GetCRC32函數和GetZHI函數
'兩個函數返回值為字符串,當然,我們只是做測試,如果真的要
'應用到軟件中去,我推薦還是用浮點計算,製造隱藏劇情
'甚至內聯彙編處理,根據CRC32值來跳轉,讓人難以琢磨
'使用時,只要使用這兩個函數就OK了
If GetCRC32 = GetZHI Then
MsgBox "程序未被修改過,恭喜你", , "通過"
Jieguo.ForeColor = &H80000012 '更改字體顏色為黑色
Jieguo.Caption = "程序未被修改"
Else
MsgBox "程序被修改,請不要非法修改本程序,共享軟件云云...", , "被修改"
Jieguo.ForeColor = &HFF& '更改字體顏色為紅色,表示警告
Jieguo.Caption = "警告:程序被修改"
End If
我是代碼終止線————————————————————————————————
這個使用代碼,能看懂的就自己改寫,看不懂的就添加到Private Sub Form_Load()事件中去,還有Private Sub Command1_Click()事件中。
好了,保存工程後,開始編譯為EXE文件吧,編譯好後,用我們寫好的VB-CRC32添加校驗值注射工具進行注射一下,這個時候如果有殺毒軟件在的話,而且比較好的話,可能會彈出提示問你允不允許修改什麼的,我用的微點就會提示和攔截,需要防行。然後運行吧。
效果如圖:
可以看到這裡顯示的目標程序的CRC32自校驗碼為:60B04682
我們用UltraEdit打開注射過了的目標主體程序,在末尾看到:
可見已經添加成功了,運行主體程序:
看來校驗通過了,那麼我們下面來模擬下破解者修改程序的情況:
在VBExplorer中,我們找到檢測按鈕事件起始地址:405F90
代開OD來裝載目標主體程序,CTRL+G 直接到405F90
00405F90 > \55 PUSH EBP
00405F91 . 8BEC MOV EBP,ESP
00405F93 . 83EC 0C SUB ESP,0C
00405F96 . 68 76124000 PUSH <JMP.&MSVBVM60.__vbaExceptHandler> ; SE 處理程序安裝
00405F9B . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00405FA1 . 50 PUSH EAX
00405FA2 . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00405FA9 . 81EC 9C000000 SUB ESP,9C
00405FAF . 53 PUSH EBX
00405FB0 . 56 PUSH ESI
0040604D . /0F84 D1000000 JE VB防破解.00406124
『我們把這句改為必跳實驗下,看看CRC32校驗的威力
0040604D /E9 D2000000 JMP VB防破解.00406124
00406052 |90 NOP
然後保存程序,運行修改後的程序如圖:
到此我們完成了VB-CRC32自校驗程序的設計全部過程,有些問題必須講以下:
也許會有人問:「小愛老師,聽說CRC32很厲害,防修改。但是我用了你的代碼之後,剛發表的共享軟件就被人修改了,怎麼回事?」
問到點子上了,確實CRC查錯能力很強,但是它本身也有脆弱性,本身防修改,但是事實恰恰相反,你可以問下身邊的解密高手,當他們遇到CRC32自校驗的時候怎麼辦?
一般都是爆破,還有些是替換,替換的話還要重新計算新的CRC32值,比較囉嗦,所以大家都喜歡爆掉CRC32的關鍵比較點來突破CRC32,而且以此為榮。
如果你設計VB-CRC32自校驗,怎樣處理這種情況?首先你要隱蔽你的比較方式,採用浮點計算,套用異常,故意設置隱藏劇情來保護CRC-32的校驗,這是個好辦法。也有高手說要加殼帶CRC32校驗。
前輩們給的辦法是把校驗值進行變換,分段,分開,分時,不定時,在各種場合和代碼角落進行驗證,儘量不給檢測到非法修改的提示,而是檢測到非法修改也不告訴破解者,悄悄變換程序流程,讓他迷路去吧
甚至是報復破解者,這個我是不推薦的,但是我可以給個快速關機的過程,直接調用可以在幾秒內關閉對方計算機,讓對方來不及保存破解筆記和資料,註:往往破解者用影子系統或者虛擬機
我是代碼起始線————————————————————————————————
『在通用部分加入如下聲明:
Private Declare Function RtlAdjustPrivilege& Lib "ntdll" (ByVal Privilege&, ByVal NewValue&, ByVal NewThread&, OldValue&)
Private Declare Function NtShutdownSystem& Lib "ntdll" (ByVal ShutdownAction&)
Private Const SE_SHUTDOWN_PRIVILEGE& = 19
Private Const ShutDown& = 0
Private Const RESTART& = 1
Private Const POWEROFF& = 2
『在窗體代碼部分增加:
Sub TurboShutdown(Index As Integer)
RtlAdjustPrivilege SE_SHUTDOWN_PRIVILEGE, 1, 0, 0
Select Case Index
Case 1 '關機
NtShutdownSystem ShutDown
Case 2 '重啟動
NtShutdownSystem RESTART
Case 3 '關機
NtShutdownSystem POWEROFF
End Select
End Sub
我是代碼終止線————————————————————————————————
調用該快速關機指令為:
Call TurboShutdown(1)
希望對你有用,但是不要拿來欺負正常使用你軟件的顧客哦,不然把顧客都嚇跑了
注意:以上VB-CRC32全部設計代碼和工程文件及程序都發佈在附件了,請自行下載
第二章 第二講
VB時間自校驗設計
上一講我們講了使用VB進行CRC32自校驗的設計,相信是能讓部分VB軟件作者受益的。下次見到你們發表VB軟件的時候,我希望不是隨便爆破修改就能破解的了。
也許你認為VB-CRC32設計有點複雜,你問「小愛老師,有沒有簡單點的防爆破自校驗?」
當然是有的
你可以先實驗下,隨便編譯個程序,單擊右鍵查看屬性,你會發現它包含了你的最後修改時間,一般的複製,黏貼等都不會修改它的「修改時間」屬性。
然而,當破解者修改了你的軟件就會被記錄下最新的修改時間,如果破解者不注意,而你的設計又夠隱蔽,倒是可以檢查這個來判斷破解者有沒有修改過你的軟件。
來,跟我一起做運動……
打開VB6.0 新建工程
添加一個按鈕,起名為「檢測」
編寫一個檢測自身修改時間並作比較的函數:
我是代碼起始線————————————————————————————————
Private Function ShiJiancheck() As Boolean
ShiJiancheck = False
Dim iFile As String
Dim FileTime As String
iFile = App.Path & "\" & App.EXEName & ".exe"
'獲取自身啟動路徑
FileTime = Format(FileDateTime(iFile), "YYYYMMDDHHMMSS")
'獲得字符串形式的文件最後修改時間
If FileTime = "20080808080808" Then
'示範設置為2008年08月08日08時08分08秒,這裡大家可以自己定,最好不要太特別
ShiJiancheck = True
Else
ShiJiancheck = False
End If
End Function
我是代碼終止線————————————————————————————————
調用該函數直接當作布爾變量用即可
如下調用:
我是代碼起始線————————————————————————————————
Private Sub Command1_Click()
'注意,文件本身的修改時間應該不是我們設定的值,所以編譯好EXE文件後,
'用文件屬性修改器來修改文件最後修改時間到指定數值,這個數值不要太特殊了
'文件屬性修改器已經放在同個文件夾下了,請使用
If ShiJiancheck = False Then
MsgBox "文件被修改", , "警告"
Else
MsgBox "文件正常", , "通過"
End If
End Sub
我是代碼終止線————————————————————————————————
效果如圖:(正常狀態)
文件被修改後:
跟CRC32比,此辦法短小精悍,但是容易被識破,請隱蔽比較和檢測,不要把結果顯示出來,知道了吧?給破解製造一次意外事故應該不是難事吧?
第二章 第三講
VB大小自校驗設計
「小愛老師,上面的方法都要修改什麼的,太麻煩了,有沒有更通用,更普遍的辦法,且不用修改程序的呢?」
「當然有了,那就是VB裡面的檢測文件大小,但是已經見得多了,已經沒什麼殺傷力了」
Vb裡常用檢測文件大小的函數為FILELEN(路徑)
跟我一起做運動……
打開VB6.0 新建工程
先編寫個檢測自身大小的函數:
我是代碼起始線————————————————————————————————
Private Function FileBig() As Long
'如果文件巨大,那麼改LONG為DOUBLE
Dim FileLujin As String
filelujing = App.Path & "\" & App.EXEName & ".exe"
FileBig = FileLen(filelujing)
End Function
我是代碼終止線————————————————————————————————
具體使用看下面代碼:
我司代碼起始線————————————————————————————————
Private Sub Form_Load()
If FileBig > 27300 Then
'第一次這個數字隨便設置,先編譯好
'用壓縮殼將它壓縮,查看壓縮後文件大小
'回到這裡,修改數值比壓縮後的大小大那兒一些就夠了
'如果被脫殼了,程序體積就會膨脹
'從而被我們檢測出來
'當然要注意了,如果是保護殼的話
'加殼後反而更大,這個時候,我們的判斷
'語句就要反過來了
MsgBox "程序被脫殼了", , "警告"
Else
MsgBox "程序正常", , "通過"
End If
End Sub
我是代碼終止線————————————————————————————————
編譯,加殼(ASPACK)程序從45056字節壓縮為27136 字節,27300略大於27136,脫殼後應該比45056可能還要大,這樣就能實現檢測大小來發現脫殼,也就發現修改了。
如圖:
脫殼後:大小71168字節,為什麼這麼大呢?呵呵,可能是垃圾代碼和垃圾段還沒清理吧,可以用LORDPE重建,應該會小一點。
重建PE後,程序大小46261字節
運行看看:如圖
實驗成功,但是我還是要提醒一下,這種方法隱蔽點,不要提示的話,也許還能存活,對於VB程序,一旦發現自校驗,初學者或者有點基礎的人都會想到去斷點FILELEN函數,直接捕獲你的對比關鍵點。
所以自校驗的設計最關鍵在於隱蔽和起到誤導作用為好,不知不覺中就到了羊腸小道,永遠沒有回頭路……
另外要介紹的是同樣是檢測文件大小以確定是否被脫殼,有些軟件作者把數值通過計算好,通過注射方法,寫入到主體程序的文件頭,這種方法可以比較準確的限定文件大小,而且不容易被發現哦,比方說「超級硬盤搜索正式版」,它就是這麼檢測的。
有點作者把VB程序的數據全部加在一起,比較最後的和,這也是種辦法,所以大家要學會思考和創新,沒有什麼是做不到的。
第二章 第四講
VB防LOADER設計金蟬脫殼
《加密解密技術內幕》一書裡提到過兩種方法防LOADER
其指的是防SMARTCHECK,WKTVB DEBUGGER等
這些技術已經為人所熟知,起不到多麼好的作用,我們就瞭解一下吧,為我們的「金蟬脫殼」做鋪墊。
1. 查找特定的窗口標題 就像第一講裡提到的:
我是引用起始線————————————————————————————————
二、反SMARTCHECK加載,SMARTCHECK是調試VB的利器,有必要對其進行防範。小樓前輩在軟件加密技術內幕中提到兩種檢測方法:
利用VB的AppActivate函數激活SMARTCHECK窗口,然後發送ALT+F4進行關閉該窗口和利用FindWindow發現SMARTCHECK窗口直接將其關閉,其代碼基本上是這樣:
winHwnd = FindWindow(vbNullString, "Numega SmartCheck")
If winHwnd <> 0 Then
AppActivate "Numega SmartCheck"
sendkey "%{f4}", True
sendkey "%y", True
其實,我覺得直接檢測進程SMARTCHK.EXE是否存在也可以,方法跟上面類似,你還可以檢測其它比如W32DASM等進程,附件中的Anti-Load就是實例,發現SMARTCHK調用,自動退出:
…..
If InStr(LCase(Process.szExeFile), "smartchk.exe") > 0 Then
smart = Process.th32ProcessID
TerminateProcess hprocess, 0
Unload Me
Exit Do
End If
…….
我是引用終止線————————————————————————————————
2. 設置步長和時值計算法
其原理是軟件正常執行的某一塊過程是很快的,基本沒多少延時;而通過調試器加載,其加載時間往往要多出十幾倍。
這種方法其實應該是反調試反跟蹤裡用到的,這裡就只提下原理,講到反調試的時候,我再把我知道的寫出來。
目前還有異常SHE處理,使得調試器無礙繼續加載。還有其他的辦法,但是我涉及較淺,以後有機會都放到反調試一塊講。
講完常見的VB反LOADER,你是不是覺得不夠好使?如查標題,我改標題你不久查不到了嗎? 如步長記時,現在的電腦配置參差不齊,這步長時值該怎麼時值好呢?
左思右想,終於被我想到了個辦法——金蟬脫殼
所謂金蟬脫殼指的是核心的東西在你眼皮底下溜走了,抓不到。留下的是一層幻滅的輪迴。
VB金蟬脫殼反LOADER技術基於程序迭代SHELL,第一次運行不會真的開始,而是為了調用本身進行第二次運行,就此結束掉第一次運行,以此類推,知道幾百幾千次,需要的時間大概在半秒到左右。
形象點講就像小孩子走路,故意跌倒,然後爬起來,又故意跌倒,讓你永遠把握不到他,知道他再起來的時候,你早就離開那裡了。
比如A實例,運行後,重新調用A,然後本次A實例自動結束,第二次A實例啟動,再次調用A實例,然後又關閉自己。這樣調試器第一跟蹤,如果不爆破的話,勢 必無法繼續跟了,到後來,調試器裡顯示的是父本程序已經結束了,但實際中,經過幾百到幾千次迭代SHELL後,程序已經打開。
就像人生一樣,調試器跟蹤的只是你的上一世,甚至是幾百幾千世以前的你,而現在的你還好好得活著。這個時候,如果不爆破的話,調試器大概還可以用附加來強行鑽入程序空間。
這樣的思路是可行的,但是你有沒有想到過如何判斷本次運行已經達到要求,可以正常開始?還是繼續輪迴?
要求程序依靠自己的標記,而不依靠外界的標記,不然容易被人發現且從外界修改是非常容易攻破的。
因為程序是同一個程序,憑什麼上一輩子要立刻輪迴,而這輩子就可以正常存活呢?判斷的標準在哪裡?同樣的程序,同樣的標準,為什麼會產生不同的輪迴結果?
答案呼之慾出了,對了,就是隨機數。
通過概率,每次輪迴的概率是一樣的,是同樣的標準,但是概率本身又可以導致不同的方向和結果。
於是我想到設置一個循環取隨機數的結構,循環7次,每次產生一個隨機數,要麼是1,要麼是零,然後把這七個數相加來判斷是否等於零,如果等於零就不必繼續 輪迴了,如果不等於零,那麼SHELL自己,然後馬上死掉。因為每次隨機數取0活著取1的概率是一樣的,都是0.5,所以,7次隨機數取值全部為零的概率 是0.5^7=0.0078125,倒數為128,即大概需要輪迴128次才可以正常運行程序,否則都是SHELL自己,然後父本死掉。
單單靠解釋可能還是有朋友看不明白,沒關係,我們先寫程序先,慢慢測試調試,你就發現其巧妙的地方了。
首先寫一個7次循環取0或取1的結構,然後把7次結果相加,與0作比較,將輪迴金蟬脫克功能嵌入進去。以後程序在運行開頭,只要調用一次我的這個SUB過程即可實現防LOADER,等會我們還要測試下效果呢。
我是代碼起始線————————————————————————————————
Private Sub JinChan()
On Error GoTo ANTI
'只有在被調試的時候才有可能出錯,恰好被我們捕獲,呵呵
Dim Lujing As String
'儲存程序自身路徑
Dim Suiji(7) As Byte
'7個元素數組,用於儲存每次隨機數
Dim n As Long
'循環計數器
Dim Panduan As Double
'累加器
Lujing = App.Path & "\" & App.EXEName & ".exe"
'獲得程序自身路徑
For n = 1 To 7
Randomize
'每次都初始化隨機數生成器
Suiji(n) = Int(Rnd * 2)
『取隨機數0或者1
Panduan = Panduan + Suiji(n)
'累加
Next n
If Panduan > 0 Then
'如果累加總結果不為零,那就SHELL自己一次,然後通過END結束自己
Shell Lujing, 1
'進入下一個輪迴哦
End
'結束這一世
End If
'如果上面的累加器等於零,則說明達到了0.5^7的概率了,其倒數為128,即我們已經輪'回128是世了。'調試器跟蹤的只是我們的第一世。
'到這裡來的話也就是不執行SHELL內容,也不執行END,直接到這裡來了
'正常運行
Exit sub
ANTI:
MsgBox "發現調試器,請關閉調試器", , "警告"
End
End Sub
我是代碼終止線————————————————————————————————
以後只要把JinChan寫入到主窗體LOAD事件中,就實現了金蟬脫殼效果。
大家跟我來做運動:
打開VB6.0 新建工程
在窗體代碼裡,拷貝上面的代碼進去
然後在Private Sub Form_Load()裡輸入JinChan,編譯生成EXE
即:
Private Sub Form_Load()
JinChan
End Sub
先運行一下EXE,看看速度如何,然後再用OD或者SMARTCHECK等測試下,看看是不是無法跟蹤到輪迴後的這一世,前提是不能爆破。
效果還是很好的,OD如果開著HIDEOD插件的話,那麼在執行SHELL的時候,會自動捕獲錯誤以發現調試器,然後程序自動結束,也相當於起到了防LOADER作用。如果OD關閉HIDEOD插件,那麼就可以直接體現出「金蟬脫殼」的效果了。
如圖:通過捕獲異常發現調試器
如圖,如果沒有異常,那麼金蟬脫克將發揮作用,輪迴百世。調試器裡已經結束,但是程序其實輪迴轉世了。
好了,沒想到隨便寫寫可以寫這麼多,看的我頭暈了。
希望你也別頭暈,我們來總結下,《VB 共享軟件防破解涉及技術初探(二)》都講了那些內容:
1、 設計思想:水桶原理
2、 完整性校驗,包括VB-CRC32注射器和主體的編寫;文件修改時間自校驗;文件大小自校驗等
3、 防LOADER設計,包括查找標題,經典時值,還有重點的「金蟬脫殼」反LOADER
這一期就到這裡了,熬夜寫教程很累,呵呵
還是老規矩,如果有時間,有精力,有空,有能力,我將接著寫《VB 共享軟件防破解設計
技術初探(三)》,感謝大家的支持。
希望大家能多頂頂,尤其是學習VB寫軟件的朋友,希望對你有用
留言
張貼留言