dll 注入器 32 位和 x64 dll 文件在 notepad.exe x64 中不起作用

dll injector 32 bits and x64 dll file don't work in notepad.exe x64

我有一个用 Visual Basic 6 编译的 DLL 注入器,我正在尝试在 x64 notepad.exe 上注入我的 DLL (x64),但没有任何效果。

我在网上搜索过这个并且看到了这个:

[IMPORTANT: 32-BIT / 64-BIT]

This is a portability table:

  • 32bit program inject 32bit dll in a 32bit target
  • 32bit program inject 64bit dll in a 64bit target
  • 64bit program inject 32bit dll in a 32bit target
  • 64bit program inject 64bit dll in a 64bit target

如果这是真的,那么我的喷油器应该可以正常工作。

有人可以帮我吗?

使用的代码:

Module1.bas

Option Explicit

Private Const INFINITE                  As Long = &HFFFF

Private Const TOKEN_ADJUST_PRIVILEGES   As Long = &H20
Private Const TOKEN_QUERY               As Long = &H8
Private Const SE_PRIVILEGE_ENABLED      As Long = &H2
Private Const ANYSIZE_ARRAY             As Long = 1

Private Const SE_DEBUG_NAME             As String = "SeDebugPrivilege"

Private Const PAGE_READWRITE            As Long = &H4
Private Const MEM_RELEASE               As Long = &H8000
Private Const MEM_COMMIT                As Long = &H1000

Private Const STANDARD_RIGHTS_REQUIRED  As Long = &HF0000
Private Const SYNCHRONIZE               As Long = &H100000
Private Const PROCESS_VM_OPERATION As Long = (&H8)
Private Const PROCESS_VM_WRITE As Long = (&H20)

Private Const TH32CS_SNAPPROCESS As Long = 2&


Private Const PROCESS_ALL_ACCESS        As Long = _
                                        (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or PROCESS_VM_WRITE Or PROCESS_VM_OPERATION Or &HFFF)

Private Type PROCESSENTRY32
    dwSize As Long
    cntUsage As Long
    th32ProcessID As Long
    th32DefaultHeapID As Long
    th32ModuleID As Long
    cntThreads As Long
    th32ParentProcessID As Long
    pcPriClassBase As Long
    dwFlags As Long
    szexeFile As String * 260
End Type

Private Type Luid
    lowpart                     As Long
    highpart                    As Long
End Type

Private Type LUID_AND_ATTRIBUTES
    pLuid                       As Luid
    Attributes                  As Long
End Type

Private Type TOKEN_PRIVILEGES
    PrivilegeCount              As Long
    Privileges(ANYSIZE_ARRAY)   As LUID_AND_ATTRIBUTES
End Type

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) 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, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private 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
Private Declare Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function LookupPrivilegeValue Lib "advapi32" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As String, ByVal lpName As String, lpLuid As Luid) As Long
Private Declare Function AdjustTokenPrivileges Lib "advapi32" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As Any, ReturnLength As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function CreateToolhelp32Snapshot Lib "kernel32.dll" (ByVal lFlags As Long, lProcessID As Long) As Long
Private Declare Function ProcessFirst Lib "kernel32.dll" Alias "Process32First" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long
Private Declare Function ProcessNext Lib "kernel32.dll" Alias "Process32Next" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long


Public Function InjectByPID(ByVal sDllPath As String, ByVal lProcessID As Long) As Boolean
    Dim lProc As Long
    Dim lLibAdd As Long
    Dim lMem As Long
    Dim lRet As Long
    Dim lThread As Long

    On Local Error GoTo InjectByPID_Error

    '//Adjust token privileges to open system processes
    Call AdjustPrivileges(GetCurrentProcess)

    '// Open the process with all access
    lProc = OpenProcess(PROCESS_ALL_ACCESS, False, lProcessID)
    If lProc = 0 Then GoTo InjectByPID_Error

    '// Get the address of LoadLibrary
    lLibAdd = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA")
    If lLibAdd = 0 Then GoTo InjectByPID_Error

    '// Allocate memory to hold the path to the Dll File in the process's memory
    lMem = VirtualAllocEx(lProc, 0, Len(sDllPath), MEM_COMMIT, PAGE_READWRITE)
    If lMem = 0 Then GoTo InjectByPID_Error

    '// Write the path to the Dll File in the location just created
    Call WriteProcessMemory(lProc, ByVal lMem, ByVal sDllPath, Len(sDllPath), lRet)
    If lRet = 0 Then GoTo InjectByPID_Error

    '// Create a remote thread that starts begins at the LoadLibrary function and _
     is passed are memory pointer
    lThread = CreateRemoteThread(lProc, ByVal 0, 0, ByVal lLibAdd, ByVal lMem, 0, 0&)
    If lThread = 0 Then GoTo InjectByPID_Error

    '// Wait for the thread to finish
    Call WaitForSingleObject(lThread, INFINITE)

    '// Free the memory created on the other process
    Call VirtualFreeEx(lProc, lMem, Len(sDllPath), MEM_RELEASE)

    '//Release the handle to the other process
    Call CloseHandle(lProc)

    InjectByPID = True

    On Error GoTo 0
    Exit Function

InjectByPID_Error:
    '// Free the memory created on the other process
    Call VirtualFreeEx(lProc, lMem, Len(sDllPath), MEM_RELEASE)
    '//Release the handle to the other process
    Call CloseHandle(lProc)
End Function

Public Function AdjustPrivileges(ByVal lProcessID As Long) As Boolean
    Dim lToken              As Long
    Dim tTOKEN_PRIVILEGES   As TOKEN_PRIVILEGES

    On Local Error GoTo AdjustPrivileges_Error

    If Not OpenProcessToken(lProcessID, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, lToken) = 0 Then
        With tTOKEN_PRIVILEGES
            If LookupPrivilegeValue(vbNullString, SE_DEBUG_NAME, .Privileges(0).pLuid) = 0 Then
                Exit Function
            End If
            .PrivilegeCount = 1
            .Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
        End With
        If Not AdjustTokenPrivileges(lToken, 0, tTOKEN_PRIVILEGES, Len(tTOKEN_PRIVILEGES), 0&, 0&) = 0 Then
            AdjustPrivileges = True
        End If
    End If

    On Error GoTo 0
    Exit Function

AdjustPrivileges_Error:

End Function

'Get PID
Public Function whereISmyFUFUprocess(ByVal ProcessName As String) As Long
    Dim procSnapshot As Long
    Dim uProcess As PROCESSENTRY32
    Dim success As Long
    Dim ProcessId As Long
    Dim ProcessId_found As Boolean

    ProcessId_found = False
     
    procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0&)

    If procSnapshot = -1 Then Exit Function

    uProcess.dwSize = Len(uProcess)
    success = ProcessFirst(procSnapshot, uProcess)

    If success = 1 Then
        Do
            If LCase(VBA.Left$(uProcess.szexeFile, InStr(1, uProcess.szexeFile, Chr(0)) - 1)) = LCase(ProcessName) Then
                ProcessId = uProcess.th32ProcessID
                Debug.Print "First process found with PID: " & ProcessId
                    If ProcessId_found = True Then
                        Debug.Print "Second process found with PID: " & ProcessId
                        whereISmyFUFUprocess = ProcessId
                        Exit Do
                    End If
                  ProcessId_found = True
            End If
        Loop While ProcessNext(procSnapshot, uProcess)

    End If
     
    If whereISmyFUFUprocess = 0 Then
        whereISmyFUFUprocess = ProcessId
    End If
     
    Call CloseHandle(procSnapshot)
     
End Function

表格 1

Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)


Private Sub Command1_Click()

Dim PID As Long


' // Run Notepad
    Shell "notepad.exe", vbNormalFocus
    
    Sleep 1000
    
   PID = whereISmyFUFUprocess("notepad.exe")
   
   Sleep 1000
   
   InjectByPID "Project1.dll", PID

End Sub

检查您是否获得进程 ID。

如果我没记错的话(我以前试过),你无法仅使用 API 从 32 位进程获取 64 位进程的列表;因此您的 VB6 应用程序将只能看到 32 位进程。您需要(另一个)64 位助手来为您提供 64 位和 32 位进程 ID 的列表,然后您就可以使用它了。

编辑 #1: CreateToolhelp32Snapshot() 的文档提到:

If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).

更正: 不相关,因为您调用 CreateToolhelp32Snapshot() 时没有指定进程包含在快照中(即第二个参数为空)

您仍然可以在调试时通过获取 64 位记事本进程的 PID 并将其手动输入并直接输入 InjectByPID() 来检查程序的注入部分是否正常工作。

编辑 #2: 您可能会通过 WMI 获得包含 64 位进程的进程列表。见 this Super User question.

更正: CreateToolhelp32Snapshot() 列出 64 位和 32 位进程就好了。我可能混淆了 EnumProcesses().

好的。这可能不是 complete/direct 答案,因为它只提供了解决问题的方向;另外,我不精通 amd64 汇编代码,所以我无法帮助你。

根据 this articleCreateRemoteThread() 要在 64 位进程上工作 需要从另一个 64 位进程调用它 (注意: 这个答案是基于我没有测试的那个假设)。

知道这一点后,您有三 (3) 个选项:

  1. 使用 x64 代理代表您的 x86/VB6 注入器调用 CreateRemoteThread()。其他一切都在 VB6 中完成,包括引导代码的注入。

    • 要求: 使用您选择的语言和工具构建的 x64 可执行文件(代理) 一些手写的 amd64 机器代理调用的代码(引导代码)。
    • 难度:具有挑战性(除非编写和调试手写的 amd64 汇编代码是您最喜欢的消遣之一)
    • 优点:相对来说,none.
    • 缺点:两部分注入器加上你需要写一些amd64机器代码来注入你的DLL。不必要的复杂。
    • 伪code/program流: (1) x86注入器获取进程ID,然后处理目标(x64)进程; (2) x86 注入器将一块内存分配到目标 (x64) 进程中,该内存块足够大以保存被注入的 DLL 的路径 以及 负责将该 DLL 加载到远程进程中的 amd64 引导代码; (3) x86 注入器将 DLL 路径和引导代码写入分配的内存; (4) x86 注入器执行 x64 代理并将复制的进程句柄和指向已分配内存的指针传递给它(如果它没有启动,则偏移到引导代码的入口点在分配的内存块的开头); (5) x64 代理使用引导代码的进程句柄和入口点地址调用 CreateRemoteThread()(6) 引导代码获取 "kernel32.dll" 的模块地址,proc。 LoadLibraryW() 的地址并从提供的路径加载 DLL;远程线程从那里继续; (7) 同时,x64 代理 returns 到 CreateRemoteThread() 调用的 x86 注入器结果。
  2. 好吧,如果我们要为我们的注入添加对 x64 代理的依赖,为什么不让它做整个 DLL 加载事情而不是一些自举代码。然后 x64 代理 负责(至少)解析地址并调用 LoadLibraryW() 以将我们的 DLL 加载到目标进程中。

    最简单的方法是让 x86 注入器找到目标的进程 ID,当目标进程是 64 位进程时,将注入的 DLL 的进程 ID 和路径传递给 x64 代理,这样它就可以了注射代替。

    • 要求: 使用您选择的语言和工具(代理)构建的 x64 可执行文件。
    • 难度:容易;只需要了解为 x64 平台构建的另一种语言
    • 优点: 不再需要乱搞 amd64 机器码。
    • 缺点:仍然是两部分式喷油器。
    • 伪code/program流: (1) x86注入器获取目标(x64)进程ID; (2) x86注入器执行x64代理,传递目标进程ID和要注入的DLL路径; (3) x64代理在目标进程内分配内存,写入DLL路径,然后解析&调用LoadLibraryW()CreateRemoteThread()连同地址指向到我们注入远程进程的 DLL 路径;远程线程从那里继续; (4)CreateRemoteThread() 调用之后(或者在失败之前),x64 代理 returns 到 x86 注入器调用的结果或它的任何错误遇到了。
  3. 利用 Heaven's Gate(概念 here; example of use here)从您的 x86、VB6 内置注入器中 运行 amd64 代码。

    • 要求: 一些(机器编译的)amd64 代码将调用 GetModuleHandle()LoadLibraryW()CreateRemoteThread()easy 部分...);

      ...以及我们需要在进程中分配的所有 x86 代码 space 到放入 amd64 机器代码字节,修复堆栈以加载 64 位二进制文​​件,使用 ntdll.dll LdrLoadDll() [[[=104] 加载 kernel32.dll 的 amd64 版本=] 通过挂钩和修补 ntdll.dll 的 RtlEqualUnicodeString(),这样我们可以第二次加载 "kernel32.dll" 但在另一个地址,*或* 通过释放加载的 32 位 kernel32.dll 并在我们 运行 处理 amd64 代码 ]] 时将其替换为 64 位模式,切换到 64 位模式,然后清理并撤消所有内容安全地回到 x86 模式。
    • 难度:难。不确定一切 都可以在 VB6 中完成(特别是与堆栈相关的部分)。
    • 优点:一体式喷油器
    • 缺点:如果执行得好,none。
    • 伪code/program流程:你应该阅读http://rce.co/knockin-on-heavens-gate-dynamic-processor-mode-switching/ and look at the code (HeavenInjector) that has been written exactly for doing what you're trying to do, i.e. injecting libraries into 64-bit processes from a 32-bit one. Another example of implementation for this technique would be the WOW64Ext Library上的文章。

希望您在阅读本文后对接下来要尝试的内容有所了解。