zoukankan      html  css  js  c++  java
  • 32位进程注入64位进程

    在之前写注入都是32位exe文件注入32位dll到32位exe文件中,或者都是64位。但是之前看到关于32位进程注入64位进程的方法,将学习笔记记录下来。

    之前的文章:注入小结

    我们需要借助GitHub上的开源库rewolf-wow64ext 这个库的目的就是让运行在Wow64环境中的x86应用程序可以直接调用x64下ntdll.dll中的Native API。通过这个开源项目我们大致可以知道:

        ①在x64下的进程,不管是32位或者是64位,实际上都映射了两个地址空间,一个是32位,一个是64位。相当于一个进程的两种工作模式,而且这两种工作模式是可以进行切换的;

        ②Wow64进程中的r12寄存器指向64位的TEB结构(TEB64);

        ③每个32位进程都会加重ntdll32.dll和ntdll.dll模块。其中ntdll.dll是64位模块,我们可以将进程的32位模式改为64位模式,然后再去操作64位进程。

    具体的操作:

        ① 进程的32位模式改成64位模式

    #define X64_Start() X64_Start_with_CS(0x33)
    #define X64_End() X64_End_with_CS(0x23)

     在wow64ext中对x64 api进程调用时,使用X64_Start_with_CS(0x33)设置进程的'运行模式"为64位。

    #define EMIT(a) __asm __emit (a)
    
    #define X64_Start_with_CS(_cs) 
        { 
        EMIT(0x6A) EMIT(_cs)                         /*  push   _cs             */ 
        EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0)   /*  call   $+5             */ 
        EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5)        /*  add    dword [esp], 5  */ 
        EMIT(0xCB)                                   /*  retf                   */ 
        }
    
    #define X64_End_with_CS(_cs) 
        { 
        EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0)                                 /*  call   $+5                   */ 
        EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /*  mov    dword [rsp + 4], _cs  */ 
        EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD)                                    /*  add    dword [rsp], 0xD      */ 
        EMIT(0xCB)                                                                 /*  retf                         */ 
        }

    可以看到主要是借助retf将CS寄存器的值设置为0x33。这里提一下题外话,可以百度一下ret,iret和retf三者之间的区别。

    ②获得目标函数所在模块(ntdll.dll)在x64模式下的加载基地址:

    #define X64_Push(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x50 | ((r) & 7))
    
    DWORD64 getTEB64()
    {
        reg64 reg;
        reg.v = 0;   
        X64_Start();
        // R12 register should always contain pointer to TEB64 in WoW64 processes
        X64_Push(_R12);
        // below pop will pop QWORD from stack, as we're in x64 mode now
        __asm pop reg.dw[0]
        X64_End();
        return reg.v;
    }

    关于TEB的获得是通过r12-->TEB64--->PEB--->LDR匹配到ntdll.dll来找到ntdll.dll的加载基地址。

    ③解析PE结构找到目标函数在"x64模式"下的真实地址(GetProcAddr())。

    ④通过函数地址调用"x64模式"下的目标函数。这里要注意x64函数调用约定的改变,前4个参数通过rcx,rdx,r8,r9来传递,之后通过堆栈传递。X64Call()已经封装好了。

    接下来我们可以开始实际的工作了。

    NTSTATUS
    NTAPI
    RtlCreateUserThread(
        _In_ HANDLE processHandle,
        _In_ SECURITY_DESCRIPTOR* securityDescriptor,
        _In_ BOOLEAN createSuspended,
        _In_ ULONG stackZeroBits,
        _Inout_opt_ size_t* stackReserved,
        _Inout_opt_ size_t* stackCommit,
        _In_ const void* startAddress,
        _In_ void* startParameter,
        _Inout_ HANDLE* threadHandle,
        _Inout_opt_ CLIENT_ID* clientID
        );
    NTSTATUS
    NTAPI
    LdrLoadDll(
        _In_opt_ PWSTR SearchPath,
        _In_opt_ PULONG LoadFlags,
        _In_ PUNICODE_STRING Name,
        _Out_opt_ PVOID *BaseAddress
        );
    VOID
    NTAPI
    RtlExitUserThread(
        _In_ NTSTATUS Status
        );

    不同于之前利用CreateRemoteThread()来创建线程。因为CreateRemoteThread()是由Kernel32.dll导出的,wow64ext这个库只针对ntdll.dll(同理LoadLibrary也不能调用)。所以采用ntdll中未文档化的RtlCreateUserThread()来创建远程线程,LdrLoadDll()加载dll,在远程线程中调用RtlExitUserThread()终止远程线程。

    // Wow64Injectx64.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include "Wow64Injectx64.h"
    #include <memory>
    #include <string>
    #include <Windows.h>
    #include "wow64ext.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    #pragma comment(lib,"wow64ext.lib")
    
    // 唯一的应用程序对象
    CWinApp theApp;
    
    using namespace std;
    
    typedef struct _UNICODE_STRING {
        USHORT    Length;     //UNICODE占用的内存字节数,个数*2;
        USHORT      MaximumLength; 
        DWORD64   Buffer;     //注意这里指针的问题
    } UNICODE_STRING ,*PUNICODE_STRING;
    
    
    
    unsigned char shell_code[] = {
        0x48, 0x89, 0x4c, 0x24, 0x08,                               // mov       qword ptr [rsp+8],rcx 
        0x57,                                                       // push      rdi
        0x48, 0x83, 0xec, 0x20,                                     // sub       rsp,20h
        0x48, 0x8b, 0xfc,                                           // mov       rdi,rsp
        0xb9, 0x08, 0x00, 0x00, 0x00,                               // mov       ecx,8
        0xb8, 0xcc, 0xcc, 0xcc, 0xcc,                               // mov       eac,0CCCCCCCCh
        0xf3, 0xab,                                                 // rep stos  dword ptr [rdi]
        0x48, 0x8b, 0x4c, 0x24, 0x30,                               // mov       rcx,qword ptr [__formal]
        0x49, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       r9,0  //PVOID*  BaseAddr opt
        0x49, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       r8,0  //PUNICODE_STRING Name
        0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       rdx,0
        0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       rcx,0
        0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       rax,0 
        0xff, 0xd0,                                                 // call      rax   LdrLoadDll
        0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       rcx,0
        0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov       rax,0
        0xff, 0xd0                                                  // call      rax
    };
    
    
    enum  InjectResult{
        OK,
        Error_NoSuchFile,
        Error_OpenProcess,
        Error_VirtualAllocEx,
        Error_GetProcAddress,
        Error_WriteProcessMemory,
        Error_CreateRemoteThread
    };
    
    
    InjectResult Wow64Injectx64(DWORD processid,const TCHAR* file_path);
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
        cout<<"查看要注入进程的ID"<<endl;   
        ULONG_PTR ProcessID = 0;
        
        printf("Input ProcessID
    ");
        cin>>ProcessID;
        WCHAR file_path[] = L"E:\Messagebox.dll";
    
        
        if (OK==Wow64Injectx64(ProcessID,file_path))
        {
            printf("Inject Success!
    ");
        }
        return 0;
    }
    
    
    InjectResult Wow64Injectx64(DWORD processid,const TCHAR* file_path)
    {
        
        if (!PathFileExists(file_path))
        {
            return Error_NoSuchFile;
        }
    
        HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processid);
        if (INVALID_HANDLE_VALUE == handle)
        {
            return Error_OpenProcess;
        }
    
        size_t file_path_mem_length = (size_t)::_tcslen(file_path);
        size_t paramemter_size = (file_path_mem_length+1)*sizeof(TCHAR) + sizeof(UNICODE_STRING) + sizeof(DWORD64);
        DWORD64 paramemter_mem_addr = (DWORD64)VirtualAllocEx64(handle,NULL,paramemter_size,MEM_COMMIT,PAGE_READWRITE);
        DWORD64  shell_code_addr = (DWORD64)VirtualAllocEx64(handle,NULL,sizeof(shell_code),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        if ((!paramemter_mem_addr) || (!shell_code_addr))
        {
            return Error_VirtualAllocEx;
        }
        
        char * paramemter_mem_local = new char[paramemter_size];
        memset(paramemter_mem_local,0,paramemter_size);
    
        PUNICODE_STRING ptr_unicode_string = (PUNICODE_STRING)(paramemter_mem_local + sizeof(DWORD64));
        ptr_unicode_string->Length = file_path_mem_length;
        ptr_unicode_string->MaximumLength = file_path_mem_length*2;
        wcscpy((WCHAR*)(ptr_unicode_string+1),file_path);
        ptr_unicode_string->Buffer = (DWORD64)((char*)paramemter_mem_addr+sizeof(DWORD64)+sizeof(UNICODE_STRING));
    
        DWORD64 ntdll64 = GetModuleHandle64(L"ntdll.dll");
        DWORD64 ntdll_LdrLoadDll = GetProcAddress64(ntdll64,"LdrLoadDll");
        DWORD64 ntdll_RtlCreateUserThread = GetProcAddress64(ntdll64,"RtlCreateUserThread");
        DWORD64 ntdll_RtlExitThread = GetProcAddress64(ntdll64,"RtlExitUserThread");
        if (NULL == ntdll_LdrLoadDll || NULL==ntdll_RtlCreateUserThread || NULL==ntdll_RtlExitThread)
        {
            return Error_GetProcAddress;
        }
    
        //r9
        memcpy(shell_code+32,&paramemter_mem_addr,sizeof(DWORD64));
    
        //r8
        DWORD64 ptr = paramemter_mem_addr+sizeof(DWORD64);
        memcpy(shell_code+42,&ptr,sizeof(PUNICODE_STRING));
    
        //LdrLoaddll
        memcpy(shell_code+72,&ntdll_LdrLoadDll,sizeof(DWORD64));
    
        //RtlExitUserThread
        memcpy(shell_code+94,&ntdll_RtlExitThread,sizeof(DWORD64));
        size_t write_size = 0;
        if (!WriteProcessMemory64(handle,paramemter_mem_addr,paramemter_mem_local,paramemter_size,NULL) ||
            !WriteProcessMemory64(handle,shell_code_addr,shell_code,sizeof(shell_code),NULL))
        {
            return Error_WriteProcessMemory;
        }
        DWORD64 hRemoteThread = 0;
        struct {
            DWORD64 UniqueProcess;
            DWORD64 UniqueThread;
        } client_id;
        int a = X64Call(ntdll_RtlCreateUserThread,10,
            (DWORD64)handle,                    // ProcessHandle
            (DWORD64)NULL,                      // SecurityDescriptor
            (DWORD64)FALSE,                     // CreateSuspended
            (DWORD64)0,                         // StackZeroBits
            (DWORD64)NULL,                      // StackReserved
            (DWORD64)NULL,                      // StackCommit
            shell_code_addr,                    // StartAddress
            (DWORD64)NULL,                      // StartParameter
            (DWORD64)&hRemoteThread,            // ThreadHandle
            (DWORD64)&client_id);               // ClientID)
        if (INVALID_HANDLE_VALUE == (HANDLE)hRemoteThread)
        {
            return Error_CreateRemoteThread;
        }
        return OK;
    }

    完整Demo地址:https://github.com/ChengChengCC/Ark-tools/tree/master/Wow64Injectx64

    关于Windows x64的学习,《Windows Internals》(中文译版《深入解析Windows操作系统》,潘老师译的)不错。顺便吐槽下学校把那么多的好书都放在阅览室,只能看,不能借,好多全新的书上都是灰!

  • 相关阅读:
    中国石油昆仑加油卡
    157 01 Android 零基础入门 03 Java常用工具类01 Java异常 01 异常介绍 02 异常内容简介
    156 01 Android 零基础入门 03 Java常用工具类01 Java异常 01 异常介绍 01 Java常用工具类简介
    155 01 Android 零基础入门 02 Java面向对象 07 Java多态 07 多态知识总结 01 多态总结
    154 01 Android 零基础入门 02 Java面向对象 07 Java多态 06 内部类 05 匿名内部类
    153 01 Android 零基础入门 02 Java面向对象 07 Java多态 06 内部类 04 方法内部类
    152 01 Android 零基础入门 02 Java面向对象 07 Java多态 06 内部类 03 静态内部类
    151 01 Android 零基础入门 02 Java面向对象 07 Java多态 06 内部类 02 成员内部类
    150 01 Android 零基础入门 02 Java面向对象 07 Java多态 06 内部类概述 01 内部类概述
    149 01 Android 零基础入门 02 Java面向对象 07 Java多态 05 接口(重点)07 接口的继承
  • 原文地址:https://www.cnblogs.com/lanrenxinxin/p/4821152.html
Copyright © 2011-2022 走看看