關於VB中資料的儲存格式和定址方式 菜鳥獻醜了~~~
看雪資料發表於2004-07-01
關於VB中資料的儲存格式和定址方式
前言:
大家最喜歡破什麼語言寫的軟體?相信沒人會回答VB,好像一種語言越是“高階”,越是“傻瓜”,編譯系統自動加入的程式碼就越多,會把源程式的意圖隱藏起來,破解的難度反而越大(我指的是完全破解出演算法,寫出序號產生器)。用ASM直接寫的程式,反彙編的結果和源程式相似得可怕,用VC寫的也比較容易讀懂,用DELPHI寫的就有一定難度了,不過畢竟還有一個好用的DEDE,VB寫的呢?冗長的程式碼,複雜的儲存方式,鋪天蓋地的DLL,足以讓人崩潰。以前大概用VB的還都是些菜鳥級的程式設計師,加的保護也非常簡單,破解VB程式還不算太困難,到了現在,好像VB已經成了一種把程式碼複雜化的加殼軟體,紛紛被各路程式設計好手採用,把高難度的演算法用超複雜的程式碼保護起來,嗚呼哀哉!最近連遇幾個軟體,全是AsProtect+VB(好像還是P-CODE),令人鬱悶的組合,幾天破解未果,想從頭把關於VB的一些東東仔細研究一下,於是就有了這篇文章。我想高手們大概早就研究過了,也許是不屑寫出來而己,還請各位多多指點。
先看看VB常用的資料型別有哪些:
程式碼:
Byte 1個位元組 0到255 Boolean 2個位元組 True或False Integer 2個位元組 -32,768到32,767 Long(長整型) 4個位元組 -2,147,483,648到2,147,483,647 Single(單精度浮點型) 4個位元組 負數時從-3.402823E38到-1.401298E-45 正數時從1.401298E-45到3.402823E38 Double(雙精度浮點型) 8個位元組 負數時從-1.79769313486232E308到-4.94065645841247E-324 正數時從4.94065645841247E-324到1.79769313486232E308 Currency(變比整型) 8個位元組 從-922,337,203,685,477.5808到922,337,203,685,477.5807 Decimal 14個位元組 沒有小數點時為79,228,162,514,264,337,593,543,950,335 而小數點右邊有28位數時為7.9228162514264337593543950335 最小的非零值為0.0000000000000000000000000001 Date 8個位元組 100年1月1日到9999年12月31日 Object 4個位元組 任何Object引用 String(變長) 10位元組+串長度 0到大約20億 String(定長) 字串長度1到大約65,400 Variant(數字) 16個位元組 任何數字值,最大可達Double的範圍 Variant(字元) 22個位元組+串長度 與變長String有相同的範圍
像Integer,Long,Single,Double等“直接”的型別比較容易,和其他的語言一樣直接看記憶體就可以了。
比較特殊的是Currency,他的值要除10000才是真正的值,不過這個用的不多。
最麻煩的是Variant型別,因為VB是設計成一種傻瓜式的語言,對資料型別沒有嚴格的規定,甚至可以不用宣告變數而直接使用,所以在反彙編後的VB程式中,關於型別轉換的語句佔了很大一部分,只要一涉及資料計算,總會看到一堆數來回轉換,其中許多函式的引數,還有未經宣告直接使用的變數等,都是Variant型別。這種型別在VB中到處要用到,十分重要,但又常常使人困惑。它在記憶體中的定址方式很特殊,為此VB還專門為其提供了一組函式(多帶有Var字樣),這些函式其實大多放在Oleaut32.dll中,但往往再由msvbvm60.dll來呼叫,比如__vbaVarTstEq,__vbaVarTstNe,__vbaVarMove,__vbaVarAdd,__vbaVarSub,VarBstrCmp等等。Variant變數的定址方式在看雪的書中略有提及但不詳細,我在這裡補充一些:
首先我們必須明白,那些未宣告型別的Variant變數並不是真的沒有資料型別,只不過是VB編譯系統將這些變數的“型別資訊”也包含在變數的資料中了,等到程式執行時根據對該變數所進行的操作來靈活地決定變數屬於什麼型別,比如有這麼幾句
程式碼:
Dim roba As Variant roba=4321 Text1.Text=roba
程式宣告瞭一個Variant變數roba(或者乾脆什麼也沒宣告)又給它賦了一個值4321,那麼編譯器就知道這時候roba是一個Integer型變數,可是下面呢又把它賦值給了Text1.Text(也就是在一個文字框裡把4321顯示出來)這時候編譯器馬上又插入語句使roba變為字串型變數。(真是難為M$那幫人了)
那麼這種變數究竟是怎樣儲存的呢?看下面的例子:
程式碼:
Private Sub Command1_Click() Dim a, b As Variant a = "RoBa" b = Text1.Text If a = b Then MsgBox "Well done!", vbOKOnly, "Crack" End If End Sub
用W32DASM反彙編,查詢字串,很容易找到下面:
程式碼:
:00401D49 8D45DC lea eax, dword ptr [ebp-24] :00401D4C 8D4DCC lea ecx, dword ptr [ebp-34] :00401D4F 50 push eax ;變數a :00401D50 51 push ecx ;變數b * Reference To: MSVBVM60.__vbaVarTstEq, Ord:0000h | :00401D51 FF1540104000 Call dword ptr [00401040] ;比較 :00401D57 6685C0 test ax, ax :00401D5A 0F8484000000 je 00401DE4 ;不同就跳走了 * Reference To: MSVBVM60.__vbaVarDup, Ord:0000h | :00401D60 8B3D7C104000 mov edi, dword ptr [0040107C] :00401D66 B904000280 mov ecx, 80020004 :00401D6B 894D8C mov dword ptr [ebp-74], ecx :00401D6E B80A000000 mov eax, 0000000A :00401D73 894D9C mov dword ptr [ebp-64], ecx :00401D76 8D9564FFFFFF lea edx, dword ptr [ebp+FFFFFF64] :00401D7C 8D4DA4 lea ecx, dword ptr [ebp-5C] :00401D7F 894584 mov dword ptr [ebp-7C], eax :00401D82 894594 mov dword ptr [ebp-6C], eax * Possible StringData Ref from Code Obj ->"CCrack" | :00401D85 C7856CFFFFFFFC174000 mov dword ptr [ebp+FFFFFF6C], 004017FC :00401D8F 899D64FFFFFF mov dword ptr [ebp+FFFFFF64], ebx :00401D95 FFD7 call edi :00401D97 8D9574FFFFFF lea edx, dword ptr [ebp+FFFFFF74] :00401D9D 8D4DB4 lea ecx, dword ptr [ebp-4C] * Possible StringData Ref from Code Obj ->"WWell done!" | :00401DA0 C7857CFFFFFFE0174000 mov dword ptr [ebp+FFFFFF7C], 004017E0 :00401DAA 899D74FFFFFF mov dword ptr [ebp+FFFFFF74], ebx :00401DB0 FFD7 call edi :00401DB2 8D5584 lea edx, dword ptr [ebp-7C] :00401DB5 8D4594 lea eax, dword ptr [ebp-6C] :00401DB8 52 push edx :00401DB9 8D4DA4 lea ecx, dword ptr [ebp-5C] :00401DBC 50 push eax :00401DBD 51 push ecx :00401DBE 8D55B4 lea edx, dword ptr [ebp-4C] :00401DC1 56 push esi :00401DC2 52 push edx * Reference To: MSVBVM60.rtcMsgBox, Ord:0253h | :00401DC3 FF1528104000 Call dword ptr [00401028] ;出現成功對話方塊
很明顯的比較方式,用SoftICE跟一下,胡亂輸入1111,中斷在401D51處,可是當D eax,D ecx時只能看到08
:d eax
016F:0063F3EC 08 00 00 00 00 00 4A 21-CC 0F 51 00 86 72 6F 17 ......J!..Q..ro.
016F:0063F3FC F4 F8 63 00 B6 10 40 00-34 F3 63 00 A0 10 40 00 ..c...@.4.c...@.
016F:0063F40C 01 00 00 00 1C F4 63 00-73 AD 02 66 CC 05 51 00 ......c.s..f..Q.
:d ecx
016F:0063F3DC 08 00 00 00 36 18 76 8B-E0 0F 51 00 0C 00 0D 00 ....6.v...Q.....
016F:0063F3EC 08 00 00 00 00 00 4A 21-CC 0F 51 00 86 72 6F 17 ......J!..Q..ro.
016F:0063F3FC F4 F8 63 00 B6 10 40 00-34 F3 63 00 A0 10 40 00 ..c...@.4.c...@.
當然不可能是把兩個08比較,實際的UNICODE字串地址是在8個位元組後的地方。即510FCC和510FE0
:d 510fcc
016F:00510FCC 52 00 6F 00 42 00 61 00-00 00 00 00 14 00 00 A0 R.o.B.a.........
016F:00510FDC 08 00 00 00 31 00 31 00-31 00 31 00 00 00 00 00 ....1.1.1.1.....
016F:00510FEC 11 00 00 A0 1C 00 41 00-0C 00 41 00 EC 0F 51 00 ......A...A...Q.
:d 510fe0
016F:00510FE0 31 00 31 00 31 00 31 00-00 00 00 00 11 00 00 A0 1.1.1.1.........
016F:00510FF0 1C 00 41 00 0C 00 41 00-EC 0F 51 00 02 00 00 A0 ..A...A...Q.....
016F:00511000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ................
那麼08是什麼意思呢?為什麼EAX,ECX要指向這麼一個莫名其妙的值呢?我猜想那個08就是表示Varient的實際型別,換一個型別試試:
程式碼:
Private Sub Command1_Click() Dim b As Variant b = Text1.Text If b = 5678 Then MsgBox "Well done!", vbOKOnly, "Crack" End If End Sub
程式碼:
:00401D13 50 push eax :00401D14 51 push ecx :00401D15 C7857CFFFFFF2E160000 mov dword ptr [ebp+FFFFFF7C], 0000162E ;162Eh=5678 :00401D1F C78574FFFFFF02800000 mov dword ptr [ebp+FFFFFF74], 00008002 ;型別值 * Reference To: MSVBVM60.__vbaVarTstEq, Ord:0000h | :00401D29 FF1540104000 Call dword ptr [00401040] :00401D2F 6685C0 test ax, ax :00401D32 0F8484000000 je 00401DBC
在401D29時,d eax仍然看到08,d *(eax+8)可以看到我們隨意輸入的字串,而d ecx時看到
:d ecx
016F:0063F384 02 80 00 00 66 24 27 06-2E 16 00 00 B0 00 DD 00 ....f$'.........
016F:0063F394 00 00 00 00 00 00 00 00-00 00 00 00 00 00 08 00 ................
016F:0063F3A4 00 00 00 00 10 DB 01 00-0E 84 D7 3A 00 00 00 00 ...........:....
可以看到02,那麼按上面方面類推,ecx+8處是什麼呢?162E,呵~~~~,不就是5678的十六進位制嗎,那麼02當然就表示Integer了.(高位的80不知道什麼作用,改成00似乎也沒有影響)
問題清楚一些了,Variant變數的第一個位元組表示資料的實際型別,後面七個位元組不知有什麼用,在第九個位元組處才是資料的值或資料的地址。
我整理出的Variant變數的各種實際型別的程式碼:
程式碼:
02 Integer 用d eax+8可以看到,佔兩位元組 03 Long 用d eax+8可以看到,佔四位元組 04 Single 用ds eax+8可以看到 05 Double 用dl eax+8可以看到 08 String 用d *(eax+8)可以看到 0B Boolean 用d eax+8可以看到,True為FFFFFFFF 11 Byte 用d eax+8可以看到,佔一位元組
以後當你D出一個05,08這樣的數字時不會再感到莫名其妙了吧。
還是有許多不明白的地方,比如中間的七位到底有什麼用,在那些有Var字樣的函式內部實現的過程究竟是怎樣(我跟進了一個vbaVarAdd發現極其複雜)等等,還請各位大大指出來,幫助我們這些在黑暗中摸索的菜鳥們。
相關文章
- Android中資料儲存的方式有哪些2018-02-26Android
- 計算機儲存器容量和定址能力的關係2024-10-09計算機
- Docker容器中資料兩種持久化儲存方式:卷和掛載宿主目錄2020-11-17Docker持久化
- 菜鳥求助關於資料比對程式的OO問題!!!2005-01-26
- 關於InnoDB表資料和索引資料的儲存2022-07-18索引
- [轉貼於菜鳥之Oracle & Java]在sqlplus中呼叫函式和儲存過程2004-12-31OracleJavaSQL函式儲存過程
- 表中資料的更改量儲存檢視2005-10-28
- [獻醜了!] Android AOP註解GoodAt2019-09-02AndroidGo
- 暫存器定址和暫存器間接定址的區別2023-05-18
- I/0埠有關的定址方式2015-11-28
- oracle資料塊中資料儲存(摘錄)2011-03-03Oracle
- Android中資料儲存之SharedPreferences2014-11-22Android
- 第十五篇:關於TCP通訊程式中資料的傳遞格式2017-05-19TCP
- Bond——大資料時代的資料交換和儲存格式2024-07-08大資料
- 關於資料儲存的一個故事2012-12-06
- 關於hibernate 和 儲存過程2009-10-15儲存過程
- Python中資料格式化的pprint和pformat2013-08-20PythonORM
- 弱弱的問一個菜鳥問題(關於單態和連線池)2009-02-03
- java 資料儲存方式2017-09-22Java
- 分散式系統中資料儲存方案實踐2022-07-20分散式
- 基於內容定址的分散式儲存系統IPFS,你怎麼看?2019-02-25分散式
- 資料儲存的三種方式2016-06-17
- vb呼叫儲存過程的方法2012-06-28儲存過程
- 關於MYSQL中FLOAT和DOUBLE型別的儲存2016-04-12MySql型別
- MyISAM表的儲存格式---行格式2017-04-13
- 資料儲存的方式(只說三種方式)2016-06-07
- 和菜鳥一起學linux之initramfs方式啟動2013-08-18Linux
- Hbase儲存格式2013-12-18
- redis-5.資料儲存格式2021-01-13Redis
- Mysql 行的儲存格式2021-12-09MySql
- iOS儲存資料的4種方式2014-12-07iOS
- Redis儲存結構以及儲存格式2011-12-07Redis
- Linux“菜鳥”到“菜鳥的一些建議2020-10-15Linux
- 關於Mysql資料儲存,你瞭解多少?2023-02-09MySql
- 終於弄明白了 RocketMQ 的儲存模型2022-12-30MQ模型
- 關於事務的儲存過程2009-07-29儲存過程
- 變數的儲存方式和生存期2024-11-14變數
- iOS開發資料儲存篇—iOS中的幾種資料儲存方式2018-11-29iOS