前言:到網(wǎng)上查PCODE的資料,到了一個講Fight Against Crack的網(wǎng)站上,那個作者講了許多陰毒的招數(shù)后,還特別說明,如果是VB程序,最好把它做成P-CODE,這會大大增加破解的難度。事實真的如此嗎?WKT的一個大蝦卻說:We are going to show that protecting a VB application is a very difficult task.The last Microsoft's invention on VB, the 'p-code', it's a delicious bite for reverse engineers. I'll show that a 'p-compiled' application may be easier to crack that a conventional compiled one. <BR> 不知是不是我孤陋寡聞,總覺得現(xiàn)在關于VB P-CODE的資料少之又少,不管國內國外只能找到各位老大們?yōu)閿?shù)不多的幾篇教程(很多也是說“我猜想”之類拿不準的話),《加密與解密》上關于這個也是一筆帶過(大概是為續(xù)集著想^_^),可能是大蝦覺得這個太簡單不屑于講,或是哪里已經有非常系統(tǒng)全面的介紹??傊郧拔沂且灰娛荲B就害怕,再見是PCODE就投降,這大概就是人家用P-CODE對付破解的原因。這幾天終于下決心自己寫了幾個程序試驗,再結合各位老大的文章,總結出一點東西,非常不全面,希望大家多多指教,多多補充。 <BR><BR>“工欲善其事,必先利其器。”那句古話好像是這么說的。我們找的工具有:WKTVBDebug(動態(tài)破解用,相當于PCODE里的SOFTICE)EXDEC(靜態(tài)分析,相當于W32DASM)SmartCheck(可以作輔助用) <BR><BR>要想破解PCODE程序,關鍵要理解里面的“助記符”(它又不同于匯編語言的“mnemonics”,我不知道該怎么表示了)的作用,PCODE的助記符乍看上去很亂,好像比匯編還難,其實它們都是由幾部分組成的。比如CVarStr就是由三部分組成(詳見下文)。VB PCODE中常見的“助記符”如下面所示:(只總結出了一點,懇請各位補充) <BR><BR>表示數(shù)據(jù)類型的: <BR><BR>I2 ---- Integer,占一個字節(jié)的整數(shù)(匯編里的BYTE) <BR>I4 ---- Integer,占兩個字節(jié)的整數(shù)(匯編里的WORD) <BR>I8 ---- Integer,占四個字節(jié)的整數(shù)(匯編里的DWORD) <BR>UI4---- Unsigned Integer,無符號整數(shù) <BR>UI8---- Unsigned Integer,無符號整數(shù) <BR>R4 ---- Real,單精度實數(shù)(Single) <BR>R8 ---- Real,雙精度實數(shù)(Double) <BR>Str---- String,字符串類型 <BR>Var---- Variant,變量類型。這就是BASIC特殊的地方,它允許用戶在使用變量前不進行聲明,這種不聲明的變量就用這種類型存儲,它可以包括數(shù)字、字串等各種類型。我看M$的這個玩意兒沒給用戶帶來方便,只能讓一些初學編程的菜鳥思維混亂,讓咱們破解時也非常郁悶:(。它的存儲方式非常奇怪,比方說你看到一個VARIANT類型的數(shù)據(jù)被放到內存里了,你跟過去找,結果什么也找不到??囱险f應該D *(EAX+8),原來它真正的數(shù)據(jù)往后挪了8個字節(jié),真不知在搞什么.....BTW:如果是一個數(shù)值類型的數(shù)據(jù),它的地址向后移8個字節(jié)即為真正的數(shù)值,如果是一個字符串型的數(shù)據(jù),它的地址向后移8個字節(jié)即為指向一個UNICODE字串的指針。 <BR><BR>表示堆棧操作的:(PCODE沒有寄存器,全部通過堆棧傳送數(shù)據(jù),因此非常重要) <BR><BR>St ---- Store,把當前棧頂?shù)臄?shù)據(jù)放在內存里 <BR>Ld ---- Load,把內存某處的數(shù)據(jù)壓入堆棧 <BR>Lit---- Literal,把一個“立即數(shù)”壓入堆棧 <BR><BR>其它重要的: <BR><BR>C ---- Convert,數(shù)據(jù)轉換。如CI4I2即把BYTE擴充為WORD(I2->I4) <BR>Eq ---- Equal,判斷是否相等,并把結果(0或1)入棧 <BR>Lt ---- 判斷是否小于 <BR>Gt ---- 判斷是否大于 <BR>Len---- 得到字串長度 <BR><BR>跳轉指令: <BR><BR>Branch ---- 無條件跳轉 <BR>BranchT ---- 棧頂數(shù)據(jù)為真則跳 <BR>BranchF ---- 棧頂數(shù)據(jù)為假則跳 <BR><BR>一些算術運算: <BR><BR>Add , Sub 等等應該都比較好認吧。 <BR><BR>從一篇介紹PCODE的文章里抄來一些,不知有沒有用: <BR><BR>Prefix Control <BR>------------------------------------------------------------------------------------ <BR>cbo Combo box <BR>chk Check box <BR>cmd Command Button <BR>dir Directory box <BR>drv Drive list box <BR>fil File list box <BR>fra Frame <BR>frm Form <BR>grd Grid <BR>hsb Horizontal scrollbar <BR>img Image <BR>lbl Label <BR>lin Line <BR>lst List box <BR>mnu Menu <BR>ole OLE client <BR>opt Option button <BR>pic Picture Box <BR>shp Shape <BR>tmr Timer <BR>txt Text box <BR>vsb Vertical scrollbar <BR>----------------------------------------------------------------------------------------- <BR><BR>還有一些不太清楚的,都是我的猜想,希望大蝦解釋: <BR><BR>Call ---- 調用過程 <BR>Free ---- 釋放內存空間 <BR>Rf ---- 局部變量???? <BR>Pr ---- ???? <BR>Ad ---- 是不是Address?? <BR>HardType--是干什么的? <BR><BR>這些組合在一起就成了多種多樣的指令,很有趣吧。 <BR><BR>還有一個要特別強調的是PCODE的堆棧,PCODE幾乎所有的指令都要對堆棧進行操作,有許多指令都是針對棧頂?shù)囊粋€或兩個數(shù)據(jù)進行操作,因此在動態(tài)調試PCODE時要十分注意右邊顯示的堆棧區(qū),并經常查看內存,這樣才能理解指令的意義。 <BR><BR>下面來實踐一下,運行起塵封已久的VB,在FORM上放一個TEXT1,一個BUTTON1,雙擊Button1,在下面輸入: <BR><BR>Private Sub Command1_Click() <BR> st1 = Text1.Text <BR> st2 = "" <BR> m = Len(Text1.Text) <BR> For i = 1 To m <BR> st2 = st2 + Mid$(Text1.Text, m - i + 1, 1) <BR> Next i <BR> MsgBox st2, vbOKOnly, "CRACK" <BR>End Sub <BR><BR>呵呵,很簡單是不是。按一下按鈕就把TEXT里的文本反過來顯示在消息框里。 <BR>下面來“生成工程”,注意一定要在“選項”里選擇生成P-CODE文件。然后用Exdec分析一下: <BR><BR>Proc: 401a90 <BR>4019B0: 04 FLdRfVar local_008C ;好像是一個指向TEXT的指針 <BR>4019B3: 21 FLdPrThis ;先給一個下馬威,前幾句全不太明白! <BR>4019B4: 0f VCallAd text ;用WKTVBDebug過這一句時能看到Form1.text1 <BR>4019B7: 19 FStAdFunc local_0088 ;猜想應該是取得句柄之類的事情 <BR>4019BA: 08 FLdPr local_0088 ; <BR>4019BD: 0d VCallHresult get__ipropTEXTEDIT ;調用,從字面上可以看出是GetText <BR>4019C2: 3e FLdZeroAd local_008C ;好像壓入一個指向上面文本的指針,不太清楚,反正上面這個過程很經典啦,幾乎從文本框讀數(shù)都是這樣 <BR>4019C5: 46 CVarStr local_00AC ;把上面得到的字串轉為Var格式 <BR>4019C8: Lead1/f6 FStVar ;再把這個VAR數(shù)據(jù)入棧 st1 <BR>4019CC: 1a FFree1Ad local_0088 ;釋放前面的空間 <BR>4019CF: 3a LitVarStr: ( local_00CC ) ;壓入一個立即數(shù):空字串st2="" <BR>4019D4: Lead2/00 FStVarCopy <BR>4019D8: 04 FLdRfVar local_008C <BR>4019DB: 21 FLdPrThis <BR>4019DC: 0f VCallAd text <BR>4019DF: 19 FStAdFunc local_0088 <BR>4019E2: 08 FLdPr local_0088 <BR>4019E5: 0d VCallHresult get__ipropTEXTEDIT ;和上面相同,得到字串 <BR>4019EA: 6c ILdRf local_008C ;壓入字串 <BR>4019ED: 4a FnLenStr ;得到字串的長度m <BR>4019EE: Lead2/69 CVarI4 local_00CC ;轉為VAR類型 <BR>4019F2: Lead1/f6 FStVar ;VAR類型的長度入棧 <BR>4019F6: 2f FFree1Str local_008C ;釋放內存空間 <BR>4019F9: 1a FFree1Ad local_0088 <BR>4019FC: 28 LitVarI2: ( local_00FC ) 0x1 (1) ;壓入一個立即數(shù)0x1 <BR>401A01: 04 FLdRfVar local_00EC ;local_00EC是循環(huán)變量i <BR>401A04: 04 FLdRfVar local_00DC ;這個是上面得到的長度m <BR>401A07: Lead3/68 ForVar: (when done) 401A67 ;FOR i=1 to m 開始循環(huán) <BR>401A0D: 04 FLdRfVar local_008C <BR>401A10: 21 FLdPrThis <BR>401A11: 0f VCallAd text <BR>401A14: 19 FStAdFunc local_0088 <BR>401A17: 08 FLdPr local_0088 <BR>401A1A: 0d VCallHresult get__ipropTEXTEDIT ;和上面相同的過程,得到字串 <BR>401A1F: 04 FLdRfVar local_00BC ;把local_BC壓入,這實際上是st2 <BR>401A22: 28 LitVarI2: ( local_013C ) 0x1 (1) ;壓一個0x1,CALL的參數(shù) <BR>401A27: 04 FLdRfVar local_00DC ;字串長度m <BR>401A2A: 04 FLdRfVar local_00EC ;循環(huán)變量i <BR>401A2D: Lead0/9c SubVar ;相減 m-i <BR>401A31: 28 LitVarI2: ( local_00CC ) 0x1 (1) ;再壓入一個0x1 <BR>401A36: Lead0/94 AddVar local_012C ;再加1, m-i+1,CALL的參數(shù) <BR>401A3A: Lead1/22 CI4Var ;轉成整數(shù)型 <BR>401A3C: 6c ILdRf local_008C ;壓入,作為下面CALL的參數(shù) <BR>401A3F: 0b ImpAdCallI2 ;這是rtcMidCharBStr,源碼中的Mid$() <BR>401A44: 46 CVarStr local_014C ;把取得的字符轉成Var型 <BR>401A47: Lead0/94 AddVar local_015C ;把新取得的字符和上面的401A1F處的st2連起來 <BR>401A4B: Lead1/f6 FStVar <BR>401A4F: 2f FFree1Str local_008C <BR>401A52: 1a FFree1Ad local_0088 ;釋放 <BR>401A55: 36 FFreeVar <BR>401A5E: 04 FLdRfVar local_00EC ;設好循環(huán)變量 <BR>401A61: Lead3/7e NextStepVar: (continue) 401A0D ;NEXT i,循環(huán)變量+1,直到結束 <BR>401A67: 27 LitVar_Missing ;VB里面那些帶[]的可選參數(shù),如果不加設定 <BR>401A6A: 27 LitVar_Missing ;就會變成這種Missing或NULL的形式 <BR>401A6D: 3a LitVarStr: ( local_00CC ) CRACK ;壓入字串,MsgBox的標題 <BR>401A72: 4e FStVarCopyObj local_00AC ;把剛壓入的字串復制到local_AC <BR>401A75: 04 FLdRfVar local_00AC ;再壓進去一次(???) <BR>401A78: f5 LitI4: 0x0 0 (....) ;消息框的樣式 vbOKOnly <BR>401A7D: 04 FLdRfVar local_00BC ;這是上面計算得到的反轉字串 <BR>401A80: 0a ImpAdCallFPR4: ;這個是rtcMsgBox,共有五個參數(shù) <BR>401A85: 36 FFreeVar <BR>401A8E: 13 ExitProcHresult ;結束過程 <BR><BR>我盡量想把分析寫得明白一些,但還是有幾句解釋不清,希望精通PCODE的大俠解釋一下,小弟代表廣大菜鳥同胞感激不盡。 |