现在的位置: 首页 > 综合 > 正文

VB变态应用之“移花接木”

2013年07月01日 ⁄ 综合 ⁄ 共 15295字 ⁄ 字号 评论关闭

今天可是个好日子啊~~就在这个好日子送给我们广大的程序大朋友们和小朋友们一个节日礼物,同时我也希望这份代码能给带来一些思路和技术上的提升,但是更希望大家能用到正途上不要搞歪门邪道。此代码的功能比较强悍,所以用到好的地方自然能发光,但是用到黑暗的地方可能会辱没了这份代码,希望大家认真对待这份珍贵的代码,我是专门花了一天时间写的,而且专门用VB语言写的,其实用C的话更简单更快,就是想在节日送给我们广大的VB爱好者一个节日礼物。在这里祝大家“节日快乐”~哈哈~~

想了很久也不知道怎么为这份代码(文章)取个好听的名字想来想去好像“移花接木”最适合。为什么这么说呢?这份代码可以完成远程调用,可以在远程进程中执行任何STDCALL声明的API函数,这样做到了“远程调用本地化”当然还没达到这种级别的效果,但是确实还是值得我们继续在这份代码上发展和研究。我在测试程序中写了三个典型的实例。首先是一个在远程进程中弹出一个消息框的测试(这里要保证目标进程已经加载了USER33.DLL才行)。第二个实例是演示了利用远程进程创建新进程的功能(在这里我想说点废话,我在我博客也发表了好几种创建SYSTEM进程的代码,当然有参考别人的代码和思路,以前也有人说过用远程注入的方式实现,但是好像是需要DLL的好了现在这份代码不再需要DLL而且你可以创建指定用户的进程,比如你可以创建SYSTEM用户甚至是LOAL SYSTEM用户等)。第三个实例是演示了NT系列函数的调用也是演示了参数带返回值的API函数在我的程序中的调用方法和取返回值的方法。其实还有很多很多的功能有待大家去研究琢磨我只是提供了一个小小的“平台”,希望大家在这个“平台”给你带来更多的精细也希望能使大家更深入的了解VB内嵌汇编的方法和需要注意些什么。我在这份代码上做了详细的注释,如果你在使用还有不明白的地方或者发现存在了某些BUG请于我一起探讨,谢谢。好了废话就不多说了大家等得都是代码。

窗体代码部分

Option Explicit

Private Type CLIENT_ID
    UniqueProcess As Long
    UniqueThread  As Long
End Type

Private Type OBJECT_ATTRIBUTES
    Length As Long
    RootDirectory As Long
    ObjectName As Long
    Attributes As Long
    SecurityDescriptor As Long
    SecurityQualityOfService As Long
End Type

Private Type STARTUPINFO
    cb As Long
    lpReserved As String
    lpDesktop As String
    lpTitle As String
    dwX As Long
    dwY As Long
    dwXSize As Long
    dwYSize As Long
    dwXCountChars As Long
    dwYCountChars As Long
    dwFillAttribute As Long
    dwFlags As Long
    wShowWindow As Integer
    cbReserved2 As Integer
    lpReserved2 As Long
    hStdInput As Long
    hStdOutput As Long
    hStdError As Long
End Type

Private Type PROCESS_INFORMATION
    hProcess As Long
    hThread As Long
    dwProcessId As Long
    dwThreadId As Long
End Type

Private Function IsArrayIsEmpty(pData() As OUT_DAT) As Boolean
    Dim i As Integer
    On Error GoTo ErrLine
    i = UBound(pData)
    IsArrayIsEmpty = False
    Exit Function
ErrLine:
    IsArrayIsEmpty = True
End Function

'当API的参数有返回值的演示
Private Sub cmdKill_Click()
    Dim dwFunAddress As Long
    Dim objAttr As OBJECT_ATTRIBUTES
    Dim dwAccessMask As Long
    Dim objId As CLIENT_ID
    Dim bytShellcode() As Byte
    Dim pOutData() As OUT_DAT
    Dim hProcess As Integer
    Dim i As Integer
    If Val(txtPid.Text) = 0 Then
        MsgBox "请输入正确的PID"
        txtPid.SetFocus
        Exit Sub
    End If
    If Val(txtPid1.Text) = 0 Then
        MsgBox "请输入正确的PID"
        txtPid1.SetFocus
        Exit Sub
    End If
    '获取函数地址
    dwFunAddress = GetFunAddress("ntdll.dll", "NtOpenProcess")
    If dwFunAddress = 0 Then
        MsgBox "获取函数地址失败!!"
        Exit Sub
    End If
    dwAccessMask = PROCESS_ALL_ACCESS
    objId.UniqueProcess = Val(txtPid1.Text)
    objAttr.Length = LenB(objAttr)
    If GetShellCode(dwFunAddress, 4, bytShellcode) Then
        '如果API参数有返回值的我们可以从pOutData数组结构中读取如果只有一个
        '需要返回的并且返回的只是4个字节就可以直接从pOutData(0).dwDataSize
        '中读取,如果大于4个字节在这里我们需要再次从目标进程中读取数据出来
        'ReadProcessMemory hProcess, ByVal pOutData(i).dwAddress, bytBuffer(), pOutData(0).dwDataSize, ByVal 0&
        If CallAsmFun(Val(txtPid.Text), pOutData, VarPtr(bytShellcode(0)), UBound(bytShellcode) + 1, 4, 1, 0, 4, 0, dwAccessMask, 4, 1, VarPtr(objAttr), LenB(objAttr), 1, VarPtr(objId), LenB(objId)) <> 0 Then
            MsgBox "执行失败!!"
        End If
        If Not IsArrayIsEmpty(pOutData) Then
            hProcess = pOutData(0).dwDataSize
            If hProcess Then
                Erase bytShellcode
                Erase pOutData
                dwFunAddress = GetFunAddress("ntdll.dll", "NtTerminateProcess")
                If dwFunAddress > 0 And GetShellCode(dwFunAddress, 2, bytShellcode) Then
                    If CallAsmFun(Val(txtPid.Text), pOutData, VarPtr(bytShellcode(0)), UBound(bytShellcode) + 1, 2, 0, hProcess, 4, 0, 0, 4) <> 0 Then
                        MsgBox "执行失败!!"
                    End If
                End If
            End If
            On Error Resume Next
            hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, Val(txtPid.Text))
            If hProcess Then
                VirtualFreeEx hProcess, ByVal pOutData(0).dwAddress, 0, MEM_RELEASE
            End If
            CloseHandle hProcess
        End If
    End If
End Sub

'多个参数演示,演示在远程进程中创建进程的功能
Private Sub cmdRun_Click()
    Dim dwFunAddress As Long
    Dim bytAgs() As Byte
    Dim dwAgs As Long
    Dim bytShellcode() As Byte
    Dim pOutData() As OUT_DAT
    Dim pStartInfo As STARTUPINFO
    Dim pProcInfo As PROCESS_INFORMATION
    If Val(txtPid.Text) = 0 Then
        MsgBox "请输入正确的PID"
        txtPid.SetFocus
        Exit Sub
    End If
    If Dir(txtPath.Text, 1 Or 2 Or 4) = "" Then
        MsgBox "请输入正确的文件路径"
        txtPath.SetFocus
        Exit Sub
    End If
    '获取函数地址
    dwFunAddress = GetFunAddress("kernel32.dll", "CreateProcessA")
    If dwFunAddress = 0 Then
        MsgBox "获取函数地址失败!!"
        Exit Sub
    End If
    pStartInfo.cb = LenB(pStartInfo)
    '构造ShellCode
    If GetShellCode(dwFunAddress, 10, bytShellcode) Then
        '构造执行进程路径的Buffer
        bytAgs = StrConv(txtPath.Text, vbFromUnicode)
        '获取进程路径Buffer所在本进程空间的地址因为我们需要传给CallAsmFun
        dwAgs = VarPtr(bytAgs(0))
        '远程执行我们的函数
        '其实下面函数功能相当于C里面的下面的代码,和我们直接调用API稍微有点区别,因为编译器会给我们优化
        '比如 push 0我们为了处理方便都是4个字节对齐是用&H68 0x00000000是占用4个字节的,但是编译器可能就
        '是&H6a 0x只占用2个字节
        '__asm
        '{
        '   push pStartInfo
        '   push pProcInfo
        '   push 0
        '   push 0
        '   push 0
        '   push 0
        '   push 0
        '   push 0
        '   push dwAgs
        '   push 0
        '   call CreateProcessA
        '}
        '调用方法是:
        '第一个参数是进程PID(可以是自己),第二个参数是本进程SHELLCODE的地址,第三个参数是API函数的参数个数
        '从第4个参数起就是API函数的参数结构了输入顺序和我们平时调用API的参数顺序一样,但是需要增加两个额外的
        '参数方便我在CallAsmFun中解析,这样API的一个参数就变成3个了,其中第一个是这个API传进去的参数是否是一
        '个定值(不需要寻址的),如果是就传0,否则传1表示需要在目标进程空间申请一段内存把我们需要的传进去的
        '数据(一般是字符串或者是结构)拷贝进去,第二个参数是需要传的值(这里需要注意一下,这个值跟前一个参数
        '息息相关,如果前一个参数是1的话这个参数就是我们本进程中数据的地址),第三个参数是我们需要写入值的长度
        '(以字节计算,这个值也跟第一个参数息息相关,如果第一个参数为0这个参数永远是4因为我们是4个字节对齐的
        '如果第一个参数为1那么就是表明我们需要传进去的数据(字符串和结构)的长度)
        If CallAsmFun(Val(txtPid.Text), pOutData, VarPtr(bytShellcode(0)), UBound(bytShellcode) + 1, 10, 0, 0, 4, 1, dwAgs, UBound(bytAgs) + 2, 0, 0, 4, 0, 0, 4, 0, 0, 4, 0, 0, 4, 0, 0, 4, 0, 0, 4, 1, VarPtr(pStartInfo), LenB(pStartInfo), 1, VarPtr(pProcInfo), LenB(pProcInfo)) = 0 Then
            MsgBox "执行失败!!"
        End If
    End If
End Sub

'显示消息框的演示
Private Sub cmdShow_Click()
    Dim dwFunAddress As Long
    Dim bytAgs1() As Byte
    Dim bytAgs2() As Byte
    Dim dwAgs1 As Long, dwAgs2 As Long
    Dim bytShellcode() As Byte
    Dim pOutData() As OUT_DAT
    If Val(txtPid.Text) = 0 Then
        MsgBox "请输入正确的PID"
        txtPid.SetFocus
        Exit Sub
    End If
    dwFunAddress = GetFunAddress("user32.dll", "MessageBoxA")
    If GetShellCode(dwFunAddress, 4, bytShellcode) Then
        bytAgs1 = StrConv(txtNote.Text, vbFromUnicode)
        dwAgs1 = VarPtr(bytAgs1(0))
        bytAgs2 = StrConv(txtCaption.Text, vbFromUnicode)
        dwAgs2 = VarPtr(bytAgs2(0))
        If CallAsmFun(Val(txtPid.Text), pOutData, VarPtr(bytShellcode(0)), UBound(bytShellcode) + 1, 4, 0, 0, 4, 1, dwAgs1, UBound(bytAgs1) + 2, 1, dwAgs2, UBound(bytAgs2) + 2, 0, 0, 4) <= 0 Then
            MsgBox "执行失败!!"
        End If
    End If
End Sub


Private Sub Form_Load()
    '提升进程权限
    If Not EnablePrivilege(SE_DEBUG_PRIVILEGE, True) Then
        MsgBox "提升进程权限失败"
        EnablePrivilege SE_DEBUG_PRIVILEGE, False
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    EnablePrivilege SE_DEBUG_PRIVILEGE, False
End Sub

Private Sub txtPid1_GotFocus()
    If txtPid1.Text = "请输入需要结束的进程PID" Then
        txtPid1.Text = ""
    End If
End Sub

Private Sub txtPid_GotFocus()
    If txtPid.Text = "请输入目标进程PID" Then
        txtPid.Text = ""
    End If
End Sub

Private Sub txtNote_GotFocus()
    If txtNote.Text = "请输入需要显示的信息" Then
        txtNote.Text = ""
    End If
End Sub

Private Sub txtCaption_GotFocus()
    If txtCaption.Text = "请输入标题" Then
        txtCaption.Text = ""
    End If
End Sub

Private Sub txtPath_GotFocus()
    If txtPath.Text = "请输入需要创建进程的路径" Then
        txtPath.Text = ""
    End If
End Sub
提权模块代码部分

Option Explicit
'提权相关常数
Public Const SE_MIN_WELL_KNOWN_PRIVILEGE = 2
Public Const SE_CREATE_TOKEN_PRIVILEGE = 2
Public Const SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = 3
Public Const SE_LOCK_MEMORY_PRIVILEGE = 4
Public Const SE_INCREASE_QUOTA_PRIVILEGE = 5

' end_wdm
'
' Unsolicited Input is obsolete and unused.
'

Public Const SE_UNSOLICITED_INPUT_PRIVILEGE = 6

' begin_wdm
Public Const SE_MACHINE_ACCOUNT_PRIVILEGE = 6
Public Const SE_TCB_PRIVILEGE = 7
Public Const SE_SECURITY_PRIVILEGE = 8
Public Const SE_TAKE_OWNERSHIP_PRIVILEGE = 9
Public Const SE_LOAD_DRIVER_PRIVILEGE = 10
Public Const SE_SYSTEM_PROFILE_PRIVILEGE = 11
Public Const SE_SYSTEMTIME_PRIVILEGE = 12
Public Const SE_PROF_SINGLE_PROCESS_PRIVILEGE = 13
Public Const SE_INC_BASE_PRIORITY_PRIVILEGE = 14
Public Const SE_CREATE_PAGEFILE_PRIVILEGE = 15
Public Const SE_CREATE_PERMANENT_PRIVILEGE = 16
Public Const SE_BACKUP_PRIVILEGE = 17
Public Const SE_RESTORE_PRIVILEGE = 18
Public Const SE_SHUTDOWN_PRIVILEGE = 19
Public Const SE_DEBUG_PRIVILEGE = 20
Public Const SE_AUDIT_PRIVILEGE = 21
Public Const SE_SYSTEM_ENVIRONMENT_PRIVILEGE = 22
Public Const SE_CHANGE_NOTIFY_PRIVILEGE = 23
Public Const SE_REMOTE_SHUTDOWN_PRIVILEGE = 24
Public Const SE_UNDOCK_PRIVILEGE = 25
Public Const SE_SYNC_AGENT_PRIVILEGE = 26
Public Const SE_ENABLE_DELEGATION_PRIVILEGE = 27
Public Const SE_MANAGE_VOLUME_PRIVILEGE = 28
Public Const SE_IMPERSONATE_PRIVILEGE = 29
Public Const SE_CREATE_GLOBAL_PRIVILEGE = 30
Public Const SE_MAX_WELL_KNOWN_PRIVILEGE = SE_CREATE_GLOBAL_PRIVILEGE
Public Const STATUS_NO_TOKEN = &HC000007C
Private Declare Function RtlAdjustPrivilege Lib "ntdll.dll" (ByVal Privilege As Long, ByVal Enable As Boolean, ByVal Client As Boolean, WasEnabled As Long) As Long

Public Function EnablePrivilege(ByVal Privilege As Long, Enable As Boolean) As Boolean
    Dim ntStatus As Long
    Dim WasEnabled As Long
    ntStatus = RtlAdjustPrivilege(Privilege, Enable, True, WasEnabled)
    If ntStatus = STATUS_NO_TOKEN Then
        ntStatus = RtlAdjustPrivilege(Privilege, Enable, False, WasEnabled)
    End If
    If ntStatus = 0 Then
        EnablePrivilege = True
    Else
        EnablePrivilege = False
    End If
End Function
核心内嵌汇编部分(主要是完成API调用的汇编码)

Option Explicit
Private 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 VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, lpThreadAttributes As Any, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length 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
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
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function GetExitCodeThread Lib "kernel32" (ByVal hThread As Long, lpExitCode As Long) As Long
Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long

Private Const INFINITE = &HFFFFFFFF
Private Const MEM_COMMIT = &H1000
Public Const MEM_RELEASE = &H8000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Const PAGE_READWRITE = &H4
Private Const SYNCHRONIZE As Long = &H100000
Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000
Public Const PROCESS_ALL_ACCESS As Long = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF)

Public Type OUT_DAT
    dwAddress As Long
    dwDataSize As Long
End Type

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'参数Params是可变参数其中第一个参数为你写的SHELLCODE Buffer的地址,第二个参数是这个
'SHELLCODE Buffer的长度,第三个参数是API参数个数,从第四个参数起每3个参数形成API函
'数中的一个参数,其中第一个参数表明是否需要申请内存,第二个参数是值(这里如果需要申
'请内存的话这个值将是你需要)写入目标进程的Buffer所在你的进程空间的地址,第三个参数
'是Buffer长度(如果不需要申请内存的这个值可以填0因为默认是以&H68来Push参数的都是4个
'字节对齐,以后的API参数都是一样依次类推下去。直到API参数都完了后就是CALL的机器码E8
'接着是CallValue这个需要计算(我的程序会自动计算),后面紧接着是return 10h,然后再
'填个0好让CPU不要识别错了,因为可能你写到的地方最后一个字节不为0这样return值就会出错
'造成栈不平,参数pOutData为后加上去的主要是用来返回有些API的参数需要返回值的情况下,用
'发很简单传个数组进来即可然后返回的只是一个4个字节数据就保存在它的dwDataSize中,如果
'大于4个字节那么dwAddress是目标进程的数据所在地址dwDataSize是数据的长度,如果我们需要
'把这部分数据读出来只需要再次用ReadProcessMemory读取一次,如果有多个参数就遍历下数组
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function CallAsmFun(ByVal dwProcessId As Long, pOutData() As OUT_DAT, ParamArray Params()) As Long
    'lplpRemoteAddress 是在目标进程为ShellCode申请的内存块地址,lpRemoteAddresses()是一些参数申请的内存快地址
    '一般只有传结构或者是字符串的时候才需要
    Dim lpRemoteAddress As Long, lpRemoteAddresses() As Long, intCount As Integer '在目标进程申请的内存计数
    Dim hProcess As Long '进程句柄
    Dim lngRet As Long '返回的结果
    Dim hThread As Long, dwThreadId As Long '创建的选择线程句柄和TID
    Dim i As Integer, j As Integer
    Dim dwValue As Long, dwAddress As Long '值和地址
    Dim intAgsCount As Integer '参数个数
    Dim intOutCount As Integer
    Dim blnIsFind As Boolean
    '打开目标进程
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwProcessId)
    If hProcess Then
        '在目标进程申请一块内存,长度是SHELLCODE的长度,好把SHELLCODE写进去
        lpRemoteAddress = VirtualAllocEx(hProcess, ByVal 0&, CLng(Params(1)), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
        If lpRemoteAddress Then
            dwAddress = CLng(Params(0)) '我们进程中SHELLCODE的地址
            '把我们生成的SHELLCODE写入目标进程中
            If WriteProcessMemory(hProcess, ByVal lpRemoteAddress, ByVal dwAddress, CLng(Params(i + 1)), ByVal 0) Then
                '获取需要申请内存的参数计数
                For i = Val(Params(2)) * 3 To 3 Step -3
                    If Val(Params(i)) = 1 Then
                        intCount = intCount + 1
                    End If
                Next
                If intCount > 0 Then
                    ReDim lpRemoteAddresses(intCount - 1) '申请保存参数申请内存的地址方便后面释放
                End If
                intCount = 0
                intAgsCount = CLng(Params(2)) '我们传进来的第二个参数是API函数的参数个数
                For i = intAgsCount * 3 To 3 Step -3 '从最后一个API参数开始取
                    If Val(Params(i)) = 1 Then
                        '如果是需要申请内存的参数(比如字符串或者结构等)我们就再申请一块内存
                        lpRemoteAddresses(intCount) = VirtualAllocEx(hProcess, ByVal 0&, CLng(Params(i + 2)), MEM_COMMIT, PAGE_READWRITE)
                        '把我们进程空间的才参数内存写入目标进程我们申请的内存块中
                        If CLng(Params(i + 1)) <> 0 Then
                            lngRet = WriteProcessMemory(hProcess, ByVal lpRemoteAddresses(intCount), ByVal CLng(Params(i + 1)), CLng(Params(i + 2)), ByVal 0)
                            If lngRet = 0 Then GoTo RET
                        Else
                            ReDim Preserve pOutData(0 To intOutCount)
                            pOutData(intOutCount).dwAddress = lpRemoteAddresses(intCount)
                            pOutData(intOutCount).dwDataSize = CLng(Params(i + 2))
                            intOutCount = intOutCount + 1
                        End If
                        '因为是__stdcall所以最前面的参数应该是在最后面相反最前面的在最后面
                        dwAddress = lpRemoteAddress + 4 + 5 * (intAgsCount - (i / 3)) + 1
                        '更改SHELLCODE里的push值,因为开始我们传进来的是我们的进程空间的地址,现在我们要替换成目标进程空间的地址
                        lngRet = WriteProcessMemory(hProcess, ByVal dwAddress, lpRemoteAddresses(intCount), 4, ByVal 0)
                        If lngRet = 0 Then GoTo RET
                        intCount = intCount + 1
                    Else
                        '如果参数不需要申请内存就直接写入值即可
                        dwAddress = lpRemoteAddress + 4 + 5 * (intAgsCount - (i / 3)) + 1
                        dwValue = Params(i + 1)
                        lngRet = WriteProcessMemory(hProcess, ByVal dwAddress, dwValue, 4, ByVal 0)
                        If lngRet = 0 Then GoTo RET
                    End If
                Next
            End If
            '计算E8 XXXXXXXX中的XXXXXXXX所在目标进程空间中的地址
            dwAddress = lpRemoteAddress + intAgsCount * 5 + 4 + 1
            '获取函数的真正地址
            CopyMemory dwValue, ByVal CLng(Params(0)), 4
            '计算 XXXXXXXX的地址
            dwValue = dwValue - (lpRemoteAddress + intAgsCount * 5 + 4) - 5
            '更新E8后的XXXXXXXX值这样才能正确执行函数
            lngRet = WriteProcessMemory(hProcess, ByVal dwAddress, dwValue, 4, ByVal 0)
            If lngRet = 0 Then GoTo RET
            '创建远程线程执行我们的SHELLCODE,这里我们可以换成Debug的Api比如SetThreadContext和QueueAPC之类的函数也行
            hThread = CreateRemoteThread(hProcess, ByVal 0, 0, ByVal lpRemoteAddress + 4, ByVal 0, 0, dwThreadId)
            If hThread Then
                '等待线程执行结束
                WaitForSingleObject hThread, INFINITE
                For i = 0 To intOutCount - 1
                    If pOutData(i).dwDataSize = 4 Then
                        ReadProcessMemory hProcess, ByVal pOutData(i).dwAddress, pOutData(i).dwDataSize, 4, ByVal 0&
                    End If
                Next
                '获取返回值
                GetExitCodeThread hThread, lngRet
            End If
        End If
    End If
RET:
    '清理我们申请的内存和关闭相关句柄
    If hProcess Then
        For i = 0 To intCount - 1
            If intOutCount = 0 Then
                VirtualFreeEx hProcess, ByVal lpRemoteAddresses(i), 0, MEM_RELEASE
            Else
                For j = 0 To intOutCount - 1
                    If lpRemoteAddresses(i) = pOutData(j).dwAddress Then
                        blnIsFind = True
                        Exit For
                    End If
                Next
                If Not blnIsFind Then VirtualFreeEx hProcess, ByVal lpRemoteAddresses(i), 0, MEM_RELEASE
            End If
        Next
        If lpRemoteAddress Then VirtualFreeEx hProcess, ByVal lpRemoteAddress, 0, MEM_RELEASE
    End If
    If hProcess Then CloseHandle hProcess
    If hThread Then CloseHandle hThread
    CallAsmFun = lngRet
End Function

'获取API函数的地址
Public Function GetFunAddress(ByVal strLibName As String, ByVal strFunName As String) As Long
    Dim hMod As Long, dwFunAddress As Long
    hMod = LoadLibrary(strLibName)
    If hMod Then
        dwFunAddress = GetProcAddress(hMod, strFunName)
    End If
    FreeLibrary hMod
    GetFunAddress = dwFunAddress
End Function

'Public Function SetAgsValue(ByVal dwRemoteShellCodeAddress As Long, ByVal intAgsIndex As Integer, ByVal dwValue As Long) As Long
'
'End Function

'构造SHELLCODE,以&H68 4个字节对齐方式构造
Public Function GetShellCode(ByVal dwFunAddress As Long, ByVal intAgsCount As Integer, bytShellcode() As Byte) As Boolean
    Dim i As Integer
On Error GoTo ErrLine
    ReDim bytShellcode(intAgsCount * 5 + 4 + 8 - 1)
    CopyMemory bytShellcode(0), dwFunAddress, 4
    For i = 4 To intAgsCount * 5 Step 5
        bytShellcode(i) = &H68
        CopyMemory bytShellcode(i + 1), 0, 4
    Next
    bytShellcode(i) = &HE8
    CopyMemory bytShellcode(i + 1), 0, 4
    bytShellcode(i + 5) = &HC2
    bytShellcode(i + 6) = &H10
    bytShellcode(i + 7) = 0
    GetShellCode = True
    Exit Function
ErrLine:
    GetShellCode = False
End Function
【上篇】
【下篇】

抱歉!评论已关闭.