📄 modremoteloaddll.bas
字号:
Attribute VB_Name = "modRemoteLoadDLL"
'----------------------------------------------------------------------------------------------------------------------------
'==============* 黑客X档案官方论坛-http://bbs.hackerxfiles.net *=======================================================
'
'
'===================* 题目:VB环境下远程DLL注入的实现 *=======================================================================
'
'==========================* 作者:编程小猪 *=========================================================================
'
'基本思想:
' 1、得到一个进程的ID。
'
' 2、使用这个ID,调用API函数OpenProcess打开进程来取得一个可用的进程句柄
'
' 3、利用进程句柄,用API函数VirtualAllocEx在进程空间中分配一小段内存来存贮一个DLL文件路径
'
' 4、用API函数GetProcAddress查找API函数LoadLibraryA在kernel32.dll中的地址
'
' 5、用API函数CreateRemoteThread在远程进程中创建一个线程来执行LoadLibrarA,加载我们的DLL
'
' 其他工作就让加载的DLL去完成。
'
'
'
'问题:
' 1.为什么要在远程进程分配内存空间来存贮DLL文件路径?
'
' 答:《WINDOWS核心编程》中是这样描述的:“(要注入的DLL文件名)字符串是在调用进程的地址空间中。该字符串
' 的地址已经被赋予新创建的远程线程,该线程将它传递给 LoadLibraryA。但是,当 LoadLibraryA 取消对内存地址的引用时,
' DLL路径名字符串将不再存在,远程进程的线程就可能引发访问违规。”
'
'
' 2.为什么要用API函数 GetProcAddress 查找API函数 LoadLibraryA 的地址来加载DLL,而不直接申明一个LoadLibraryA来加载?
'
' 答:《WINDOWS核心编程》中是这样描述的:“如果在对 CreateRemoteThread 的调用中使用一个对 LoadLibraryA 的直接
' 引用,这将在你的模块的输入节中转换成LoadLibraryA的形实替换程序的地址。将形实替换程序的地址作为远程线程的起始
' 地址来传递,会导致远程线程开始执行一些令人莫名其妙的东西。其结果很可能造成访问违规。”
' 另外,用API函数 CreateRemoteThread 创建远程线程时要传递线程函数地址,而VB里的 AddressOf 是无法取得申明的API
' 函数的地址的。
'
' 3.为什么有很多资料上说要用 LoadLibraryW 函数加载DLL?
'
' 答:这个我也不知道。。。。。额。。。。。。
' 但我试过,在VC++环境下,使用 LoadLibraryW 不提示任何错误,但DLL没有注入到远程进程,然后直接将“W”换成“A”
' 却成成功注入,汗啊,(PS:偶VC++也是菜)。在VB中也是。关于这点,有达人说是杀毒软件HOOK掉了 LoadLibraryW,据不知
' 道可不可靠消息透露,瑞星能HOOK 掉 LoadLibraryW ,修改其地址,而跟踪修改后的地址,却是一个到0xEE******的高地址跳
' 转。我用的是KV2008,不知道是不是也HOOK了 LoadLibraryW。
'
'
'
' 以上参考了某编程前辈的意见,本程序也参考了他的一个BCB程序,只是忘了那个前辈的大名了^_^。
'
'
'关于API函数:
' API(Application Programming Interface 应用编程接口)是Windows系统提供的一组编程接口函数。VB中使用API函
' 要先声明,声明之后就可以像调用自己的函一样调用,只是参数一般要多些。声明格式如下:
'
' [Public|Private] Declare {Function|Sub} 函数名 Lib "DLL库名" [Alias "别名(在DLL中的名字)"] ([[ByVal|ByRef] 参数1 As 类型[,[ByVal|ByRef] 参数2 As 类型[,....]]]) As 类型
'
' API函数别名是指函数在DLL中的名字,不是你想要叫什么就叫什么的。为什么要别名呢?你可能会注意到,声明API函
' 数时,有的别名是在函数名后多了个“A”,有的是多了个“W”,这两种函数使用的字符格式是不一样的,“A”使用ANSI字
' 符,是单字节的,而“W”使用的是Unicode字符,是双字节的。
'
' 声明API函数时一般都是从API函数浏览器里直接复制,但很多API函数浏览器里的声明是不能直接用的(包括VB自带的API
' 函数浏览器,我用的Mini版的,没这高级玩意儿)。例如很多API函数都有参数是Any型的,并且没有指定传递方式(其实没指
' 定就是使用默认的ByRef方式),在实际应用中应该把Any改为实际参数类型,并且应该指定传递方式,以免出错或导致函数
' 执行失败。仔细比较本程序中的API函数声明,看看和你的API函数浏览器里的声明有什么不同。
'
' 调用API函数时,常用到一些常量表达式,这些常量的值在这API函数浏览器里都应该有,注意在使用前声明。不要直接
' 使用常量的值,虽然这样可以使程序看起来更简单,也少写很多代码,但这不是一个好习惯,尤其是不利于转向C系列语言。
'
'*重要 调用API函数时请注意大小写,因为API函数不是VB的,是系统内核提供的,而系统内核是用C/C++写的,C/C++又是区分
' 大小写的,因为这样,API函数返回的字符串都是以C语言中的“\0”结束,处理此类字符串时要注意。
'
'*重要 调用API函数时经常要使用一些常量,有时一个参数中要使用多个常时,我们就要用到 Or 运算符,这是为什么呢?其实,
' 这些常量是用“位”标志的,就是说,API函数在使用传递给它的常量时,不是简单的判断大小,而是根据这些常量的二进制
' 码的某些位上是“1”还是“0”来决定如何处理。如果你想不通这和比较大小有什么区别,那好,我解释下。比如一个API函
' 要求传递一个长整型(long 32位)数,值为4,4的二进制为 ...0100 (应该是32位,这里把左边的0省略),而你可以传给它
' 5(...0101)、6(...0110)、7(...0111)效果都是一样的,因为它只看从右边数第三位上是不是1,其他的根本不管。因此,多个
' 常量运算时应该使用位运算符“Or”。有的书上或网上的源程序中使用“+”运算,我认为是不对的。假设有一个API函数是这
' 样,功能 A 要求是 1(...0001),功能 B 要求是 4(...0100),功能 C 要求是 6(...0110),我们需要ABC三个功能都实现,
' 到底是传递“A or B or C”还是传递“A + B + C”呢?,看看有什么不同:
'
' A ...0001 A ...0001
' B ...0100 B ...0100
' C ...0110 C ...0110
' --------------------------------------------
' Or ...0111 =7 + ...1011 =11
'
' 明显,相加得11,不符合要求,不能实现相应功能。造成这种结果的原因是“Or”是不考虑进位的加法,而“+”是要考虑进
' 位的加法,即 1 Or 1 =1 而 1 + 1 = 2。当然,我不知道Microsoft在实际定义常量时是不是为了让两种算法都行得通而故意
' 把有用的位设置来相距足够远,不会出现因进位而引起的错误。
'
' 以上是我个人的看法,写给小菜看的(哎呀,谁在扔砖头啊,砖头是宝物,乱扔他污染环境,砸到小朋友……),如果有
' 什么不对的地方,希望及时告诉我。
'
'
'说明:
' 程序主要讲DLL注入方法,为简化代码,就没有添加枚举进程,查找窗口和对当前进程提权等功能。需要打开“任务管理
' 器”,找个进程ID来运行程序,这个不难吧。
'
' 运行本程序时,如果的你的杀毒软件跳出来JJYY的说“XX想要注入到OO,该过程比较危险”之类的话是正常的,请选择“
' 允许”。
'
'
' 本程序用VB6(sp6)mini版编写,在 Windows XP SP2下调式通过。
'
'=============================* 废话结束,以下是程序 *=============================================================================================================
'常量定义
Private Const PROCESS_CREATE_THREAD = (&H2) '用OpenProcess打开进程时指定创建线程权限
Private Const PROCESS_VM_OPERATION = (&H8) '用OpenProcess打开进程时指定操作权限。MSDN上说:Enables using the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.
Private Const PROCESS_VM_WRITE = (&H20) '用OpenProcess打开进程时指定写内存空间权限
Private Const MEM_COMMIT = &H1000 '用VirtualAllocEx分配内存时用0初始化内存。MSDN上说的是:The function initializes the memory to zero.If a memory page is not yet reserved, setting this value causes the function to both reserve and commit the memory page.
Private Const PAGE_READWRITE = &H4 '用VirtualAllocEx分配内存时指定内存既可读也可写。MSDN上说的是:Enables both read and write access to the committed region of pages.
Private Const TH32CS_SNAPMODULE = &H8 '用CreateToolhelp32Snapshot创建快照时指定为模块快照
Private Const INFINITE = &HFFFFFFFF '用WaitForSingleObject等待线程返回是指定一直等待,不超时
'类型,用于在查找进程模块时调用API函数Module32First和Module32Next,结构返回模块的相关信息
Private Type MODULEENTRY32
dwSize As Long
th32ModuleID As Long
th32ProcessID As Long
GlblcntUsage As Long
ProccntUsage As Long
modBaseAddr As Long
modBaseSize As Long
hModule As Long
szModule As String * 256
szExePath As String * 260
End Type
'API函数,各个API函数在程序中的作用请参考函数在程序中的使用
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal lpBuffer As String, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" (ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long
Private Declare Function Module32First Lib "kernel32" (ByVal hSnapShot As Long, ByRef lpme As MODULEENTRY32) As Long
Private Declare Function Module32Next Lib "kernel32" (ByVal hSnapShot As Long, ByRef lpme As MODULEENTRY32) As Long
'注入DLL
Public Function LoadDLL(ByVal dwProcessId As Long, ByVal lpszLibName As String) As Boolean
Dim hProcess, hThread, dwAddress, ret As Long
Dim lpszRemoteFile, nSize As Long
Dim hMod As MODULEENTRY32 '注入用不上,因为调用IsDllLoaded判断DLL是否已经加载是要传递一个MODULEENTRY32类型的参数
'Len是返回字符数,要用LenB取得字节长度,因为路径有中文时字节数大于字符数。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -