今天可是个好日子啊~~就在这个好日子送给我们广大的程序大朋友们和小朋友们一个节日礼物,同时我也希望这份代码能给带来一些思路和技术上的提升,但是更希望大家能用到正途上不要搞歪门邪道。此代码的功能比较强悍,所以用到好的地方自然能发光,但是用到黑暗的地方可能会辱没了这份代码,希望大家认真对待这份珍贵的代码,我是专门花了一天时间写的,而且专门用VB语言写的,其实用C的话更简单更快,就是想在节日送给我们广大的VB爱好者一个节日礼物。在这里祝大家“节日快乐”~哈哈~~想了很久也不知道怎么为这份代码(文章)取个好听的名字想来想去好像“移花接木”最适合。为什么这么说呢?这份代码可以完成远程调用,可以在远程进程中执行任何STDCALL声明的API函数,这样做到了“远程调用本地化”当然还没达到这种级别的效果,但是确实还是值得我们继续在这份代码上发展和研究。我在测试程序中写了三个典型的实例。首先是一个在远程进程中弹出一个消息框的测试(这里要保证目标进程已经加载了USER33.DLL才行)。第二个实例是演示了利用远程进程创建新进程的功能(在这里我想说点废话,我在我博客也发表了好几种创建SYSTEM进程的代码,当然有参考别人的代码和思路,以前也有人说过用远程注入的方式实现,但是好像是需要DLL的好了现在这份代码不再需要DLL而且你可以创建指定用户的进程,比如你可以创建SYSTEM用户甚至是LOAL SYSTEM用户等)。第三个实例是演示了NT系列函数的调用也是演示了参数带返回值的API函数在我的程序中的调用方法和取返回值的方法。其实还有很多很多的功能有待大家去研究琢磨我只是提供了一个小小的“平台”,希望大家在这个“平台”给你带来更多的精细也希望能使大家更深入的了解VB内嵌汇编的方法和需要注意些什么。我在这份代码上做了详细的注释,如果你在使用还有不明白的地方或者发现存在了某些BUG请于我一起探讨,谢谢。好了废话就不多说了大家等得都是代码。由于篇幅所限我只把关键部分代码贴在这如果想察看完整代码的请到我的博客去浏览。地址是:http://blog.csdn.net/chenhui530/archive/2008/06/01/2500112.aspx''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'参数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

解决方案 »

  1.   

    来迟一步,居然已经被人抢了这么多楼层!!顺便加入“收藏夹”,不再像某人说的Mark了之后找不到!
      

  2.   

    前幾天正在想學習怎麼建立SYSTEM進程
    這下可以好好吸取
    謝謝,LZ
      

  3.   

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
    '参数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