返回列表 回复 发帖

[分享] BSTR Hack 技术与应用

[分享] BSTR Hack 技术与应用

Part 1. BSTR 结构

在 VB6 里, 我们使用 String 类型来处理字符串. String (不考虑定长字符串的情况) 实际上是一个指向 BSTR 的指针, 让我们来看一下它的结构.
  1. Sub Main()
  2.     Dim x As String
  3.     Dim a As Long
  4.     a = &H70514
  5.     x = "Hello World!"
  6.     MsgBox "a = " & Hex(a) & vbCrLf & _
  7.         "VarPtr(a) = " & Hex(VarPtr(a)) & vbCrLf & _
  8.         "VarPtr(x) = " & Hex(VarPtr(x)) & vbCrLf & _
  9.         "StrPtr(x) = " & Hex(StrPtr(x)) & vbCrLf
  10. End Sub
复制代码
将这段程序编译成 EXE, 并用 Windbg 载入. go~ 出现如下对话框:
---------------------------
工程1
---------------------------
a = 70514
VarPtr(a) = 12FD80
VarPtr(x) = 12FD7C
StrPtr(x) = 14FB7C
---------------------------
确定   
---------------------------
Ctrl+Break~ 我们来看一下 VarPtr(x) 对应的内存.
0:001> dd 12fd7c l 8
0012fd7c  0014fb7c 00070514 0012fea8 004010a6
0012fd8c  0012fb2c 00401088 0012fed4 7339a030
由此我们可以知道, String 在栈上的部分只有四字节. 并且这四字节存放的内容等于 StrPtr(x).

继续看 StrPtr(x), 下面直接给出结果.
0:001> db 14fb7c - 4 l 40
0014fb78  18 00 00 00 48 00 65 00-6c 00 6c 00 6f 00 20 00  ....H.e.l.l.o. .
0014fb88  57 00 6f 00 72 00 6c 00-64 00 21 00 00 00 ad ba  W.o.r.l.d.!.....
0014fb98  ab ab ab ab ab ab ab ab-00 00 00 00 00 00 00 00  ................
0014fba8  05 00 07 00 43 07 18 00-0a 00 00 00 37 00 30 00  ....C.......7.0.
这个指针指向一个以 0000 结尾的 Unicode 字符串, 在这个字符串的前面有 4 个字节, 记录这个字符串的长度.

-

Part 2. 字符串处理相关函数

VB 使用 SysAllocString 和 SysFreeString 来给分配和销毁字符串内存, 这和 HeapAlloc 略有不同. 由于一些程序编写者经常滥用诸如字符串连接之类的操作, OLEAUT32 用内存池特别优化了有关内存分配的函数.

具体的算法可以参考这篇文章 (Heap Feng Shui in JavaScript):

http://bbs.pediy.com/showthread.php?t=55879

我们不用研究这么高深的东西, 只需要知道, 在 VB 中, 下面这种操作是相当低效的 (假设 a, b 都是字符串):
  1. a = b
  2. b = vbNullString
复制代码
上面这两句是想把 b 转移给 a, 但是编译器并不知道这一点, 它先给 a 分配一块和 b 字符串一样大小的内存, 再把 b 里的内容复制过去, 最后将 b 指向的内存释放. 如果从时间复杂度角度考虑, 就是本来 O(1) 的操作变成了 O(n) (n 为字符串长度).

从效率上考虑, 这显然是不可接受的. 能不能找出一种更好的方法呢?

-

Part 3. VB 的指针相关函数

在 VB 中, 我们有 VarPtr, StrPtr, ObjPtr 等函数, 分别用于获得不同类型变量的地址. 在 kernel32 或 ntdll 导出的 RtlMoveMemory 函数的帮助下, 几乎无所不能.

用 RtlMoveMemory 来复制 4 字节的内存, 似乎显得太慢. 不过 msvbvm60 里导出了一组函数, 能够快速地复制小内存.

这组函数包括 GetMem1, GetMem2, GetMem4, GetMem8, PutMem1, PutMem2, PutMem4 和 PutMem8. 我们只讨论 GetMem4 和 PutMem4, 因为我们这里要复制的所有东西都是 4 字节的.

从函数名字上来理解, GetMem4 是用来“读内存”, PutMem4 是用来“写内存”, 不过你大可不必这么理解. 这样理解会更为恰当: GetMem4 是从指针到指针的复制, 而 PutMem4 是从值到指针的复制. 我们可以给这两个函数起一个别名, 以避免在编程时受到函数名称的误导.

我们这样声明:
  1. Declare Sub RefToRef Lib "msvbvm60.dll" Alias "GetMem4" (ByRef SrcRef As Long, ByRef DstRef As Long)
  2. Declare Sub RefFromValue Lib "msvbvm60.dll" Alias "PutMem4" (ByRef DstRef As Long, ByVal SrcValue As Long)
复制代码
你可以将这三个 Ref 排列组合地换成 Ptr, 产生 6 个不同的函数, 你也可以在需要用指针的时候使用 ByVal. 我们举一个例子说明这个问题:
  1. Dim a As Long, b As Long

  2. b = 70514

  3. RefToRef b, a
  4. RefToRef ByVal VarPtr(b), a
  5. RefToRef b, ByVal VarPtr(a)
  6. RefToRef ByVal VarPtr(b), ByVal VarPtr(a)
  7. RefFromValue a, b
  8. RefFromValue ByVal VarPtr(a), b

  9. MsgBox a
复制代码
这六句话是等价的.

-

Part 4. 将这些东西应用到字符串上

我们可以先用一个最简单的例子来说明这项技术的可行性. 新建一个工程, 移除 Form1, 添加一个模块, 输入如下代码:
  1. Declare Sub RefToRef Lib "msvbvm60.dll" Alias "GetMem4" (ByRef SrcRef As Long, ByRef DstRef As Long)
  2. Declare Sub RefFromValue Lib "msvbvm60.dll" Alias "PutMem4" (ByRef DstRef As Long, ByVal SrcValue As Long)

  3. Sub Main()
  4.     Dim a As String, b As String
  5.     a = "This is a string"
  6.     RefFromValue ByVal VarPtr(b), StrPtr(a) ' BSTR Attach
  7.     MsgBox a & vbCrLf & b
  8.     RefFromValue ByVal VarPtr(b), 0         ' BSTR Detach
  9. End Sub
复制代码
不想写字了, 下面的代码请大家自行理解. 如果有疑问我改天补充说明一下.
  1. Function StringDetach(ByRef x As String) As Long
  2.     StringDetach = StrPtr(x)
  3.     RefFromValue ByVal VarPtr(x), 0
  4. End Function

  5. Function StringAttach(ByRef x As String, ByVal p As Long) As Long
  6.     StringAttach = StrPtr(x)
  7.     RefFromValue ByVal VarPtr(x), p
  8. End Function
复制代码
Example: 交换字符串
  1. Sub StringSwap(ByRef a As String, ByRef b As String)
  2.     Dim p As Long
  3.     p = StringDetach(a)
  4.     p = StringAttach(b, p)
  5.     StringAttach a, p
  6. End Sub

  7. Sub Main()
  8.     Dim a As String, b As String
  9.     a = "World"
  10.     b = "Hello"
  11.     StringSwap a, b
  12.     MsgBox a & " " & b
  13. End Sub
复制代码
此技术在 PsNull、IcyListView 等程序中广泛使用...

[ 本帖最后由 iceboy 于 2009-3-10 22:29 编辑 ]
7

评分次数

  • blk661

  • youhm

  • reker

  • yimins

  • sgz888

  • dolphins

  • VBProFan

沙发支持。
  沙发的靠背 来了
每个人都是一座山 世上最难攀越的山 其实是自己
My Blog:
http://blog.csdn.net/tanaya
研究得很深入啊,PFPF!
不错,支持个!关注
MS没人给我加分,唉!
不流行加分了。。,如果再流行请问我不灌水是否会加多点???
这种水平了,基本上VB的EXE都可以破解了吧。
你不能也不能还是不能对他们如何如何,并且只能也只能还是只能这样了!☆☆☆☆☆
。。。。。
饿。。。icy你太强了。。。一个指针和一个bstr居然能写那么多。。
囧。。我绝对没那么多空打那么多字。。我很懒的

不过给新手看的话会理解的比较透。。。
1

评分次数

  • iceboy

200字节。。。额。。
发帖只发精品,回帖只回废话。
MyBlog
IMTab.cn

回复 #7 reker 的帖子

这个东西看着简单, 不过如果像这样理解, 会变得很优美.
写这篇文章的时候想到了很多东西, 表达不出来.
比如 StringDetach 和 StringAttach 像一个字符串栈.

ps: 释放内存忘写了, 补上:
  1. Sub StringFree(ByVal p As Long)
  2.     Dim x As String
  3.     StringAttach x, p
  4.     ' x = vbNullString
  5. End Sub
复制代码
-

应用举例: 假设一个 UNICODE_STRING 结构指向一个紧跟在后面的 Unicode 字符串 (很常见, 比如 ObQueryNameString 的返回数据). 把这个结构 +4 偏移处的指针改成长度, 再对 +8 偏移处 StringAttach, 就可以在 VB 中直接使用了, 用完了以后 StringDetach, 再改回去.

[ 本帖最后由 iceboy 于 2009-3-11 19:09 编辑 ]
优美。。。
看来我的水平、悟性和你的已经不是一个层次上的了
200字节。。。额。。
发帖只发精品,回帖只回废话。
MyBlog
IMTab.cn
返回列表