输入相应的基址即可,默认我们输入 0x14000000,只要高出 0x10000000 就行了,当然你也可以设置为0x20000000、0x30000000等等等,只要你愿意,就随你吧(注意不能超过 0x80000000)。下图为 PeiD查看的结果:

OK,所有的操作原理都明白以后,剩下的就是正式写注入和HOOK代码了。
首先HOOK API时我前面说过,默认的注入代码方法不可取,我们需要一个类型库,这样所注入的代码操作会尽可能的“远离”msvbvm60.dll,记住,要想让你的VB代码能在其它进程中撒欢,那么就得少用些运行库中的函数,最好能全部用API解决,有时VB中默认添加的一个小小的转换函数就会让整个进程崩溃,要不然为啥VB的本机代码不支持多线程?现在我们只需要把HOOK API常用的几个API做成类型库即可。下面是需要用到的几个API函数:
ReadProcessMemory、WriteProcessMemory、GetModuleHandle、GetProcAddress、GetCurrentProcess、CopyMemory
(问:不会吧?HOOK API就这几个API就可以搞定? 答:是的)OK,以下为类型库ODL代码:
[
uuid(12345678-1234-1234-1234-123456789ABC),
helpstring("my api library"),
lcid(0x0),
version(1.0)
]
library MyAPIs
{
importlib("stdole2.tlb");
typedef [public] long HWND;
typedef [public] long DWORD;
typedef [public] long UINT;
typedef [public] long WPARAM;
typedef [public] long LPARAM;
typedef [public] long HANDLE;
[dllname("kernel32")]
module kernel32
{
[entry("WriteProcessMemory")] long WriteProcessMemory ([in] HANDLE hProcess,
[in] void* lpBaseAddress, [in] void* lpBuffer, [in] DWORD nSize, [in] DWORD* lpNumberOfBytesWritten);
[entry("ReadProcessMemory")] long ReadProcessMemory ([in] HANDLE hProcess,
[in] void* lpBaseAddress, [in] void* lpBuffer, [in] DWORD nSize, [in] DWORD* lpNumberOfBytesWritten);
[entry("GetCurrentProcess")] HANDLE GetCurrentProcess();
[entry("RtlMoveMemory")] void CopyMemory([in] void* pDest, [in] void*
pSrc, [in] long ByteLen);
[entry("GetModuleHandleA")] long GetModuleHandle ([in] LPSTR lpModuleName);
[entry("GetProcAddress")] long GetProcAddress ([in] DWORD hModule, [in] LPSTR lpProcName);
};
[dllname("user32")]
module User32
{
[entry("MessageBoxA")] long MessageBox ([in] HANDLE hWnd, [in] LPSTR lpText,
[in] LPSTR lpCaption, [in] UINT uType);
[entry("MessageBoxW")] long MessageBoxW ([in] HANDLE hWnd, [in] LPWSTR lpText,
[in] LPWSTR lpCaption, [in] UINT uType);
};
};
OK现在,上面保存名为 odl 的扩展名文件,然后用MKTYPLIB.EXE生成一下就OK了。。
该文件请到 http://cxwr.ys168.com/ 中下载
剩下的就是写代码了,不说多了,直接上代码,该代码为通过演示HOOK MessageBoxA API函数,让你明白在VB中使用纯代码HOOK API是如何实现的。如果你想HOOK NtOpenProcess 等等API也是如此。
该注入与HOOK程序中只用到了两个模块,如下:
modMain.bas 中的代码:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
'上面这些是我们自己用到的,因为我们已经引用了类型库,所以默认声明为 Private 方式,
'这样做的好处是不影响 modHOOK 模块中的相同API使用
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Public Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Public Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, lpThreadAttributes As Long, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Const MEM_RELEASE = &H8000
Public Const MEM_COMMIT = &H1000
Public Const MEM_RESERVE = &H2000
Public Const MEM_DECOMMIT = &H4000
Public Const PAGE_EXECUTE_READWRITE = &H40
Public Const SYNCHRONIZE = &H100000
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF)
Public Const INFINITE = &HFFFFFFFF
'以下全部从Delphi中翻译
Public Type IMAGE_DOS_HEADER
e_magic As Integer
e_cblp As Integer
e_cp As Integer
e_crlc As Integer
e_cparhdr As Integer
e_minalloc As Integer
e_maxalloc As Integer
e_ss As Integer
e_sp As Integer
e_csum As Integer
e_ip As Integer
e_cs As Integer
e_lfarlc As Integer
e_ovno As Integer
e_res(3) As Integer
e_oemid As Integer
e_oeminfo As Integer
e_res2(9) As Integer
e_lfanew As Long
End Type
Public Type IMAGE_FILE_HEADER
Machine As Integer
NumberOfSections As Integer
TimeDateStamp As Long
PointerToSymbolTable As Long
NumberOfSymbols As Long
SizeOfOptionalHeader As Integer
Characteristics As Integer
End Type
Public Type IMAGE_DATA_DIRECTORY
VirtualAddress As Long
Size As Long
End Type
Public Type IMAGE_OPTIONAL_HEADER
Magic As Integer
MajorLinkerVersion As Byte
MinorLinkerVersion As Byte
SizeOfCode As Long
SizeOfInitializedData As Long
SizeOfUninitializedData As Long
AddressOfEntryPoint As Long
BaseOfCode As Long
BaseOfData As Long
ImageBase As Long
SectionAlignment As Long
FileAlignment As Long
MajorOperatingSystemVersion As Integer
MinorOperatingSystemVersion As Integer
MajorImageVersion As Integer
MinorImageVersion As Integer
MajorSubsystemVersion As Integer
MinorSubsystemVersion As Integer
Win32VersionValue As Long
SizeOfImage As Long
SizeOfHeaders As Long
CheckSum As Long
Subsystem As Integer
DllCharacteristics As Integer
SizeOfStackReserve As Long
SizeOfStackCommit As Long
SizeOfHeapReserve As Long
SizeOfHeapCommit As Long
LoaderFlags As Long
NumberOfRvaAndSizes As Long
DataDirectory(15) As IMAGE_DATA_DIRECTORY
End Type
Public Type IMAGE_NT_HEADERS
Signature As Long
FileHeader As IMAGE_FILE_HEADER
OptionalHeader As IMAGE_OPTIONAL_HEADER
End Type
Public Sub Main()
Dim Pid As Long
Dim sBuf As String
sBuf = InputBox("PID", , 0)
Pid = CLng(sBuf)
If InjectMsvbvm6_dll(Pid) Then
MsgBox "插入运行库OK"
End If
If InjectExe(Pid) Then
MsgBox "已插入代码"
End If
End Sub
'///////////////////////////////////////////////////////
'///
'///说明: 插入运行库代码
'///参数: Pid=进程PID
'///返回: 成功True,否则False
'///
'///////////////////////////////////////////////////////
Public Function InjectMsvbvm6_dll(ByVal Pid As Long) As Boolean
Dim hProcess As Long, hThread As Long
Dim szDllPath As String
Dim cbDllPath As Long
Dim pBaseAddr As Long
Dim pFuncAddr As Long
Dim hMod As Long
InjectMsvbvm6_dll = False
hMod = GetModuleHandle("kernel32.dll")
pFuncAddr = GetProcAddress(hMod, "LoadLibraryA")
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, Pid)
If hProcess = 0 Then GoTo Err
szDllPath = "c:"windows"system32"msvbvm60.dll"
cbDllPath = Len(szDllPath) * 2 + 1
pBaseAddr = VirtualAllocEx(hProcess, ByVal 0&, cbDllPath, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
If pBaseAddr = 0 Then GoTo Err
If WriteProcessMemory(hProcess, ByVal pBaseAddr, ByVal szDllPath, cbDllPath, 0) = 0 Then GoTo Err
hThread = CreateRemoteThread(hProcess, ByVal 0&, 0, ByVal pFuncAddr, ByVal pBaseAddr, 0, 0)
If hThread = 0 Then GoTo Err
WaitForSingleObject hThread, INFINITE
CloseHandle hThread
InjectMsvbvm6_dll = True
Err:
If pBaseAddr <> 0 Then VirtualFreeEx hProcess, ByVal pBaseAddr, 0, MEM_RELEASE
If hProcess <> 0 Then CloseHandle hProcess
End Function
'///////////////////////////////////////////////////////
'///
'///说明: 插入代码
'///参数: Pid=进程PID
'///返回: 成功True,否则False
'///
'///////////////////////////////////////////////////////
Public Function InjectExe(ByVal Pid As Long) As Boolean
Dim hMod As Long
Dim stIDH As IMAGE_DOS_HEADER
Dim stINH As IMAGE_NT_HEADERS
Dim cbImage As Long
Dim hProcess As Long, hThread As Long
Dim pBaseAddr As Long
Dim pFuncAddr As Long
InjectExe = False
hMod = GetModuleHandle(vbNullString)
'得到相应的偏移值结构
CopyMemory stIDH, ByVal hMod, Len(stIDH)
CopyMemory stINH, ByVal (hMod + stIDH.e_lfanew), Len(stINH)
cbImage = stINH.OptionalHeader.SizeOfImage
If cbImage = 0 Then GoTo Err
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, Pid)
If hProcess = 0 Then GoTo Err
VirtualFreeEx hProcess, hMod, 0, MEM_RELEASE
pBaseAddr = VirtualAllocEx(hProcess, ByVal hMod, cbImage, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
If pBaseAddr = 0 Then GoTo Err
If WriteProcessMemory(hProcess, ByVal pBaseAddr, ByVal hMod, cbImage, 0) = 0 Then GoTo Err
'现在处理该是处理我们自己的函数地址的时候了,至于为什么会先在这里把函数地址计算好,具
'体可以看 modHook 中的说明
'
Dim pFAddr As Long
Init '先初始以便获取函数地址
pFAddr = VirtualAllocEx(hProcess, ByVal 0&, 4, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
If pFAddr = 0 Then GoTo Err
'然后把咱们的地址传进去
If WriteProcessMemory(hProcess, ByVal pFAddr, NewAddr(1), 4, 0) = 0 Then GoTo Err
pFuncAddr = GetFuncAddr(AddressOf Hook)
hThread = CreateRemoteThread(hProcess, ByVal 0&, 0, ByVal pFuncAddr, ByVal pFAddr, 0, 0)
If hThread = 0 Then GoTo Err
WaitForSingleObject hThread, INFINITE
CloseHandle hThread
InjectExe = True
Err:
'If pBaseAddr <> 0 Then VirtualFreeEx hProcess, ByVal pBaseAddr, 0, MEM_RELEASE
If hProcess <> 0 Then CloseHandle hProcess
End Function
Private Function Init() As Long
Dim pFuncAddr As Long
pFuncAddr = GetFuncAddr(AddressOf NewMessageBox)
'保存该地址,一会要注入进去的
CopyMemory NewAddr(1), pFuncAddr, 4
End Function
Private Function GetFuncAddr(ByVal func As Long) As Long
GetFuncAddr = func
End Function
然后 modHook.bas 中的代码:
Option Explicit
Public NewAddr(7) As Byte
Public Function Hook(ByVal pFAddr As Long) As Long
Dim hMod As Long
Dim pBaseAddr As Long
hMod = GetModuleHandle("user32.dll")
pBaseAddr = GetProcAddress(hMod, "MessageBoxA")
'该步骤下普遍会崩溃...我实现是米得办法啊..用OD跟踪发现读取内存有误,唉..VB就是VB..没办法
'这里有点让我抓狂,曾想过用硬编码的方式...汗!~~ 我实在是米有办法啊!!~~~
'Dim pFuncAddr As Long
' pFuncAddr = GetFuncAddr(AddressOf NewMessageBox)
' CopyMemory NewAddr(1), pFuncAddr, 4
'以下部分为机器码生成
'机器码意思为:
'
'mov eax, 我们的地址
'jmp eax
'
NewAddr(0) = &HB8
NewAddr(5) = &HFF
NewAddr(6) = &HE0
NewAddr(7) = &H0
'最后我想到一个折中的办法,就是先让注入程序帮我们把地址算好,然后我们直接调用即可.
ReadProcessMemory GetCurrentProcess, ByVal pFAddr, NewAddr(1), 4, 0
MessageBox 0, "被我给HOOK了...", "已HOOK", 32
'这一步写进去以后基本上就成功OK了..
WriteProcessMemory GetCurrentProcess, ByVal pBaseAddr, NewAddr(0), 8, 0
End Function
Public Function NewMessageBox(ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
'默认HOOK的是MessageBoxA函数,所以我们用 MessageBoxW 给我们弹出消息
'这里没有写还原函数,其实这个都很好解决,我们在用 WriteProcessMemory写入HOOK代码时可以还通过
'ReadProcessMemory读取原始代码,当需要恢复时再通过 WriteProcessMemory写回去就OK了..
MessageBoxW 0, "哈哈...被我们给HOOK了", "嘿嘿~~啦啦啦..", 16
NewMessageBox = 1
End Function
OK,上面所有代码及测试和Odl 文件都可在 http://cxwr.ys168.com/ 中下载。现在来看看测试效果,我只用了VB与Delphi写了一个测试程序,如下图:
首先是Delphi 的HOOK前和HOOK后,至于进程PID的话可以直接打开进程管理器找:

HOOK后如下:

还有一个VB测试结果,如下:

HOOK 后:

至于VC++和ASM我想应该也没问题。如果大家有兴趣可以自己试试。
注:以上在Windows XP sp2 环境下测试通过。
结束语:
最近都在忙着学内核ring0,也不知什么原因,这些天突然心血来潮要用VB来搞HOOK API,其实如果用VB借助其它语言编写的DLL来完成此功能的话我想应该非常容易,如果用纯VB来实现的话如果没有一定的汇编和OD调试基础,基本上很难用VB实现。附一张图大家看看就知道了,如下:

呵。。大家表笑,事实就是如此,上图为调试VB HOOK 的崩溃信息,说真的我都不知道我是怎么坚持下来的。就我个人认为,用VB纯代码写HOOK API是很变态的事情,至少我是这么认为的。好了,不说多了,该文章也算是学VB一年多来一个好的结尾吧,我这样说并不是说我就放弃VB了,只是我觉得用VB写Win32系统程序是一件很烦的事情,光声明这些API都不知要花多少时间,除此之外当然还有其它原因(当然除写数据库外)。所以以后大部分程序我可能不会采用VB来写,而是用Delphi、VC++和ASM等来完成。不要问我为什么,你我心里都明白!
最后我想说的是,VB是我人生中的第一个语言,因为拥有它,我才有今天,所以做人不得忘本!关于VB界内的信息我会一直关注的!另外就是复制转帖问题,请一定要保留文章出处与作者信息。谢谢合作。
注:该文中的所有资料或代码都可在 http://cxwr.ys168.com/ 中下载。