吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 1331|回复: 8
收起左侧

[VC] 使用 LdrLoadDll 注入DLL, 支持注入任务管理器

[复制链接]
福仔 发表于 2022-1-1 11:39
本帖最后由 福仔 于 2022-1-1 11:39 编辑
#include <iostream>
#include "../Inject_Include.h"
#pragma warning(disable:4996)

typedef struct UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
}*PUNICODE_STRING;
typedef struct ANSI_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PSTR   Buffer;
}*PANSI_STRING;

typedef LONG(NTAPI* PFN_RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);
typedef LONG(NTAPI* PFN_RtlInitAnsiString)(PANSI_STRING, PCSTR);
typedef LONG(NTAPI* PFN_LdrLoadDll)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
typedef LONG(NTAPI* PFN_LdrGetProcedureAddress)(PVOID BaseAddress, PANSI_STRING Name, ULONG Ordinal, PVOID* ProcedureAddress);
typedef int(WINAPI* PFN_MessageBox)(HWND, LPCWSTR, LPCWSTR, int);
typedef LPVOID(WINAPI* PFN_CallFun)(LPVOID);

typedef struct CALL_ARGUMENT_DATA
{
    PFN_RtlInitUnicodeString    fnRtlInitUnicodeString;     // 加载unicode字符串
    PFN_LdrLoadDll              fnLdrLoadDll;               // 加载dll的函数

    // 下面5个是 LdrLoadDll 需要使用的数据, DllName通过RtlInitUnicodeString来提供被 LdrLoadDll 使用
    WCHAR                       DllName[260];               // dll完整路径
    PWCHAR                      DllPath;                    // LdrLoadDll第一个参数, Dll路径, 可以为0
    ULONG                       Flags;                      // LdrLoadDll第二个参数, 标识
    UNICODE_STRING              UnicodeString;              // LdrLoadDll第三个参数, dll路径 UNICODE_STRING 结构
    HANDLE                      hModule;                    // LdrLoadDll第四个参数, 模块地址, 注入后模块地址保存到这里

    // 下面这些成员是获取函数地址使用的数据
    PFN_LdrGetProcedureAddress  fnLdrGetProcedureAddress;   // 获取函数地址
    PFN_RtlInitAnsiString       fnRtlInitAnsiString;        // 加载ansi字符串
    ANSI_STRING                 AnsiString;                 // 获取函数名的ansi字符串结构
    ULONG                       Ordinal;                    // LdrGetProcedureAddress 第三个参数
    PFN_CallFun                 fun;                        // LdrGetProcedureAddress第四个参数, 被调用的函数名 函数原型, GetProcAddress() 得到的函数

    PFN_MessageBox              pfn_MessageBox;             // 信息框函数地址
    BOOL                        isDebug;                    // 是否调试, 调试的话就弹出信息框
    char                        funName[260];               // 被调用的函数名
    DWORD                       funArg;                     // 传递到被调用的函数参数
    LPVOID                      funRet;                     // 被调用函数的返回值
    char                        argData[2000];              // 传递到函数里的数据, 参数数据最大支持2000个字节
}*LPCALL_ARGUMENT_DATA;

// 加载dll并调用指定函数
LPVOID WINAPI test_load_call___(LPCALL_ARGUMENT_DATA data)
{
    if (data->isDebug)
        data->pfn_MessageBox(0, data->DllName, 0, 0);
    if (!data->hModule)
    {
        data->fnRtlInitUnicodeString(&data->UnicodeString, data->DllName);
        data->fnLdrLoadDll(data->DllPath, data->Flags, &data->UnicodeString, &data->hModule);
    }
    if (!data->hModule)
        return 0;

    // 加载函数名 ANSI_STRING 结构
    // 然后调用 LdrGetProcedureAddress 获取函数名
    data->fnRtlInitAnsiString(&data->AnsiString, data->funName);
    if (data->fnLdrGetProcedureAddress(data->hModule, &data->AnsiString, data->Ordinal, (LPVOID*)&data->fun))
        return 0;
    data->funRet = data->fun(((LPBYTE)(data)) + data->funArg);
    return data->funRet;
}

// 获取ntdll.dll的模块句柄
inline static HMODULE GetNtdllHandle()
{
    static HMODULE hNtdll = 0;
    if (!hNtdll)
        hNtdll = GetModuleHandleW(L"ntdll.dll");
    return hNtdll;
}

// nArgSize 最大支持2000个字节
void _make_fun(CALL_ARGUMENT_DATA& data, LPCWSTR dllFileName, LPCSTR funName, LPCVOID pArgData = 0, int nArgSize = 0)
{
    HMODULE hNtdll = GetNtdllHandle();
    data.fnRtlInitUnicodeString         = (PFN_RtlInitUnicodeString)    GetProcAddress(hNtdll, "RtlInitUnicodeString");
    data.fnRtlInitAnsiString            = (PFN_RtlInitAnsiString)       GetProcAddress(hNtdll, "RtlInitAnsiString");
    data.fnLdrLoadDll                   = (PFN_LdrLoadDll)              GetProcAddress(hNtdll, "LdrLoadDll");
    data.fnLdrGetProcedureAddress       = (PFN_LdrGetProcedureAddress)  GetProcAddress(hNtdll, "LdrGetProcedureAddress");

    HANDLE hModule;
    while (true)
    {
        // 获取MessageBoxW函数地址
        typedef LONG(NTAPI* PFN_LdrGetDllHandle)(
            IN PWSTR            DllPath             OPTIONAL,
            IN PULONG           DllCharacteristics  OPTIONAL,
            IN PUNICODE_STRING         DllName,
            OUT PVOID*          DllHandle
            );

        PFN_LdrGetDllHandle LdrGetDllHandle = (PFN_LdrGetDllHandle)GetProcAddress(hNtdll, "LdrGetDllHandle");
        if (!LdrGetDllHandle) break;

        UNICODE_STRING msgBoxW;
        data.fnRtlInitUnicodeString(&msgBoxW, L"user32.dll");
        LONG err = LdrGetDllHandle(0, 0, &msgBoxW, &hModule);
        if (err || !hModule) break;

        ANSI_STRING msgBoxA;
        data.fnRtlInitAnsiString(&msgBoxA, "MessageBoxW");
        err = data.fnLdrGetProcedureAddress(hModule, &msgBoxA, 0, (LPVOID*)&data.pfn_MessageBox);
        break;
    }

    if (!data.pfn_MessageBox)
        __debugbreak(); // 获取信息框失败, 

    wcscpy_s(data.DllName, 260, dllFileName);
    strcpy_s(data.funName, 260, funName);

    data.DllPath = NULL;
    data.Flags = 0;
    data.hModule = 0;
    data.funArg = offsetof(CALL_ARGUMENT_DATA, argData);

    if (nArgSize && pArgData)
    {
        if (nArgSize > 2000)
        {
            MessageBoxW(0, L"注入dll, 尺寸超限了", 0, 0);
            __debugbreak();
        }
        memcpy(data.argData, pArgData, nArgSize);
    }
}

//操作系统版本判断
inline static BOOL IsVistaOrLater()
{
    OSVERSIONINFO osvi;
    memset(&osvi, 0, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionExW(&osvi);
    if (osvi.dwMajorVersion >= 6)
        return TRUE;
    return FALSE;
}

// 创建远程线程, 返回线程句柄
// hProcess = 进程句柄, 需要在这个进程上创建一条线程
// lpStartAddress = 线程执行的函数
// lpParameter = 线程参数
inline static HANDLE NtCreateThreadEx(HANDLE hProcess, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, int* err = 0)
{
    if (err)*err = 0;
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES;
    typedef OBJECT_ATTRIBUTES* POBJECT_ATTRIBUTES;

    typedef DWORD64(WINAPI* PFN_NtCreateThreadEx)(
        __out PHANDLE ThreadHandle,
        __in ACCESS_MASK DesiredAccess,
        __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
        __in HANDLE ProcessHandle,
        __in LPTHREAD_START_ROUTINE lpStartAddress,
        __in_opt PVOID lpParameter,
        __in ULONG dwCreationFlags,
        __in_opt ULONG_PTR StackZeroBits,
        __in_opt SIZE_T StackCommit,
        __in_opt SIZE_T StackReserve,
        __in_opt PVOID  AttributeList
        );

    HANDLE hThread = NULL;

    int ret = 0;
    if (IsVistaOrLater())// Vista, 7, Server2008
    {
        static PFN_NtCreateThreadEx pFunc = (PFN_NtCreateThreadEx)GetProcAddress(GetNtdllHandle(), "NtCreateThreadEx");
        if (pFunc)
            ret = (int)pFunc(&hThread, 0x1FFFFF, NULL, hProcess, lpStartAddress, lpParameter, FALSE, NULL, NULL, NULL, NULL);
        if (err)*err = ret;
    }
    else
    {
        // 2000, XP, Server2003
        hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, lpParameter, 0, NULL);
        if (!hThread)
        {
            if (err)*err = GetLastError();
        }    }
    return hThread;
}

// 注入dll, 返回被执行的函数的返回值
// pid = 被注入的进程ID
// lpszDllFileName = 注入的dll完整路径, 32位进程只能注入32位dll, 64位进程只能注入64位dll
// lpszFunName = 注入进去加载dll后需要执行的函数名
//               被执行的函数必须是 __stdcall, 必须只有一个参数, 必须有返回值
//               否则调用后导致堆栈不平衡从而造成被注入进程的崩溃
// pArgData = 传递到被执行函数里的参数数据
// nArgSize = 参数数据的尺寸, 单位为字节
// pModuleHandle = 接收dll被注入后的模块地址, 为0则不接收
LPVOID InjectDll(DWORD pid, LPCWSTR lpszDllFileName, LPCSTR lpszFunName, LPCVOID pArgData, DWORD nArgSize, HANDLE* pModuleHandle = 0)
{
    if (pModuleHandle)
        *pModuleHandle = 0;
    if (nArgSize > 2000)
    {
        MessageBoxW(0, L"传递到dll里的参数数据最大支持2000个字节", L"参数尺寸过大", 0);
        return 0;
    }
    wchar_t dbg[260];

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
    if (!hProcess)
    {
        swprintf(dbg, 260, L"打开进程%d失败, 错误码 = %d\nline = %d\nfun = %s\nfile = %s",
            pid, GetLastError(), __LINE__, __FUNCTIONW__, __FILEW__);
        MessageBoxW(0, dbg, L"打开进程失败", 0);
        return 0;
    }

    // 这一段代码是 加载dll, 并调用指定函数
    // 这些机器码是 test_load_call___ 这个函数的编译后的指令
    const BYTE opCode[] =
    {
    #ifdef _WIN64
        0x48, 0x89, 0x4c, 0x24, 0x08, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x83, 0xb8, 0x78, 0x02, 0x00, 0x00,
        0x00, 0x74, 0x1f, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x83, 0xc0, 0x10, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0x48, 0x8b,
        0xd0, 0x33, 0xc9, 0x48, 0x8b, 0x44, 0x24, 0x30, 0xff, 0x90, 0x70, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48,
        0x83, 0xb8, 0x38, 0x02, 0x00, 0x00, 0x00, 0x75, 0x5b, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x83, 0xc0, 0x10, 0x48, 0x8b,
        0x4c, 0x24, 0x30, 0x48, 0x81, 0xc1, 0x28, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xd0, 0x48, 0x8b, 0x44, 0x24, 0x30, 0xff, 0x10,
        0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x05, 0x38, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x30, 0x48, 0x81, 0xc1, 0x28,
        0x02, 0x00, 0x00, 0x4c, 0x8b, 0xc8, 0x4c, 0x8b, 0xc1, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x8b, 0x90, 0x20, 0x02, 0x00, 0x00,
        0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x88, 0x18, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x44, 0x24, 0x30, 0xff, 0x50, 0x08,
        0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x83, 0xb8, 0x38, 0x02, 0x00, 0x00, 0x00, 0x75, 0x07, 0x33, 0xc0, 0xe9, 0xa9, 0x00,
        0x00, 0x00, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x05, 0x7c, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x30, 0x48, 0x81,
        0xc1, 0x50, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xd0, 0x48, 0x8b, 0x44, 0x24, 0x30, 0xff, 0x90, 0x48, 0x02, 0x00, 0x00, 0x48,
        0x8b, 0x44, 0x24, 0x30, 0x48, 0x05, 0x68, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x30, 0x48, 0x81, 0xc1, 0x50, 0x02,
        0x00, 0x00, 0x4c, 0x8b, 0xc8, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x44, 0x8b, 0x80, 0x60, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xd1,
        0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x88, 0x38, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x44, 0x24, 0x30, 0xff, 0x90, 0x40,
        0x02, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x04, 0x33, 0xc0, 0xeb, 0x3c, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x8b, 0x80, 0x80, 0x03,
        0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x30, 0x48, 0x03, 0xc8, 0x48, 0x8b, 0xc1, 0x48, 0x8b, 0xc8, 0x48, 0x8b, 0x44, 0x24,
        0x30, 0xff, 0x90, 0x68, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24, 0x30, 0x48, 0x89, 0x81, 0x88, 0x03, 0x00, 0x00, 0x48,
        0x8b, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x80, 0x88, 0x03, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x28, 0xc3

    #else
        0x55, 0x8b, 0xec, 0x8b, 0x45, 0x08, 0x83, 0xb8, 0x40, 0x02, 0x00, 0x00, 0x00, 0x74, 0x18, 0x6a, 0x00, 0x6a, 0x00, 0x8b,
        0x4d, 0x08, 0x83, 0xc1, 0x08, 0x51, 0x6a, 0x00, 0x8b, 0x55, 0x08, 0x8b, 0x82, 0x3c, 0x02, 0x00, 0x00, 0xff, 0xd0, 0x8b,
        0x4d, 0x08, 0x83, 0xb9, 0x20, 0x02, 0x00, 0x00, 0x00, 0x75, 0x46, 0x8b, 0x55, 0x08, 0x83, 0xc2, 0x08, 0x52, 0x8b, 0x45,
        0x08, 0x05, 0x18, 0x02, 0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x8b, 0x11, 0xff, 0xd2, 0x8b, 0x45, 0x08, 0x05, 0x20, 0x02,
        0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x81, 0xc1, 0x18, 0x02, 0x00, 0x00, 0x51, 0x8b, 0x55, 0x08, 0x8b, 0x82, 0x14, 0x02,
        0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x8b, 0x91, 0x10, 0x02, 0x00, 0x00, 0x52, 0x8b, 0x45, 0x08, 0x8b, 0x48, 0x04, 0xff,
        0xd1, 0x8b, 0x55, 0x08, 0x83, 0xba, 0x20, 0x02, 0x00, 0x00, 0x00, 0x75, 0x07, 0x33, 0xc0, 0xe9, 0x83, 0x00, 0x00, 0x00,
        0x8b, 0x45, 0x08, 0x05, 0x44, 0x02, 0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x81, 0xc1, 0x2c, 0x02, 0x00, 0x00, 0x51, 0x8b,
        0x55, 0x08, 0x8b, 0x82, 0x28, 0x02, 0x00, 0x00, 0xff, 0xd0, 0x8b, 0x4d, 0x08, 0x81, 0xc1, 0x38, 0x02, 0x00, 0x00, 0x51,
        0x8b, 0x55, 0x08, 0x8b, 0x82, 0x34, 0x02, 0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x81, 0xc1, 0x2c, 0x02, 0x00, 0x00, 0x51,
        0x8b, 0x55, 0x08, 0x8b, 0x82, 0x20, 0x02, 0x00, 0x00, 0x50, 0x8b, 0x4d, 0x08, 0x8b, 0x91, 0x24, 0x02, 0x00, 0x00, 0xff,
        0xd2, 0x85, 0xc0, 0x74, 0x04, 0x33, 0xc0, 0xeb, 0x2a, 0x8b, 0x45, 0x08, 0x8b, 0x4d, 0x08, 0x03, 0x88, 0x48, 0x03, 0x00,
        0x00, 0x51, 0x8b, 0x55, 0x08, 0x8b, 0x82, 0x38, 0x02, 0x00, 0x00, 0xff, 0xd0, 0x8b, 0x4d, 0x08, 0x89, 0x81, 0x4c, 0x03,
        0x00, 0x00, 0x8b, 0x55, 0x08, 0x8b, 0x82, 0x4c, 0x03, 0x00, 0x00, 0x5d, 0xc2, 0x04, 0x00

    #endif
    };
    const int opCodeSize = sizeof(opCode) / sizeof(opCode[0]);
    // 申请的缓冲区尺寸, 这里存放被执行的子程序代码, 存放参数, 4k对齐
    const int AllocSize = 0x1000 * 1;

    LPBYTE pAddress = 0;
    bool isOk = false;
    HANDLE hModule = 0;
    LPVOID funRet = 0;
    __try
    {
        pAddress = (LPBYTE)VirtualAllocEx(hProcess, NULL, AllocSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (pAddress == NULL)
        {
            swprintf(dbg, 260, L"VirtualAllocEx申请内存失败, 目标进程 = %d, 申请尺寸 = %d, 最后错误 = %d\nline = %d\nfun = %s\nfile = %s",
                pid, AllocSize, GetLastError(), __LINE__, __FUNCTIONW__, __FILEW__);
            MessageBoxW(0, dbg, L"申请内存失败", 0);
            __leave;
        }

        // 如果申请更大的内存的话, 就使用最后的0x1000个字节存放参数和函数
        // 参数地址是字节码的后面
        LPBYTE pCode = (LPBYTE)(pAddress + AllocSize - 0x1000);
        LPBYTE pArg  = (LPBYTE)(pCode    + opCodeSize);

        // 0x1000 个字节用来存放 被执行的函数字节码
        // 传递到dll函数里的参数数据
        // 第一步先写入被执行的函数字节码
        BOOL bWriteOK = WriteProcessMemory(hProcess, pCode, opCode, opCodeSize, NULL);    // 写入函数, 被注入的程序执行这段代码
        if (!bWriteOK)
        {
            swprintf(dbg, 260, L"写入函数体到进程%d失败, 写入地址 = 0x%016llX, 写入尺寸 = %d\nline = %d\nfun = %s\nfile = %s",
                pid, (ULONG64)pCode, (int)opCodeSize, __LINE__, __FUNCTIONW__, __FILEW__);
            MessageBoxW(0, dbg, L"写入函数体失败", 0);
            __leave;
        }

        CALL_ARGUMENT_DATA data = { 0 };

        // data 这个结构是注入进去的函数需要的数据
        // data.argData 这个是2000个字节, 存放传入到dll函数里的数据
        // ntdll里的函数一般在进程A 和 进程B 里的地址都是一样的
        // 我们这个进程就是进程A, 被注入的进程就是进程B
        // 我们在进程A先取到这些函数的地址, 在进程B里直接调用
        // 把函数地址处理好, 目标进行会调用这些函数
        _make_fun(data, lpszDllFileName, lpszFunName, pArgData, nArgSize);

        // 把注入的函数 使用的参数写入进程, 参数数据也在data这个结构里
        bWriteOK = WriteProcessMemory(hProcess, pArg, &data, sizeof(data), NULL);
        if (!bWriteOK)
        {
            swprintf(dbg, 260, L"写入参数数据到进程%d失败, 写入地址 = 0x%016llX, 写入尺寸 = %d\nline = %d\nfun = %s\nfile = %s",
                pid, (ULONG64)pArg, (int)sizeof(data), __LINE__, __FUNCTIONW__, __FILEW__);
            MessageBoxW(0, dbg, L"写入参数数据体失败", 0);
            __leave;
        }

        int err = 0;
        // 创建一条远程线程, 线程执行的函数是 pCode, pCode就是 test_load_call___ 这个函数
        // 参数是 pArg
        HANDLE hThread = NtCreateThreadEx(hProcess, (LPTHREAD_START_ROUTINE)pCode, pArg, &err);
        if (hThread == NULL)
        {
            swprintf(dbg, 260, L"创建远程线程失败, 错误码 = %d\nline = %d\nfun = %s\nfile = %s",
                err, __LINE__, __FUNCTIONW__, __FILEW__);
            MessageBoxW(0, dbg, L"创建远程线程失败", 0);
            __leave;
        }

        // 等待完成
        WaitForSingleObject(hThread, INFINITE);
        if (hThread != NULL)
            CloseHandle(hThread);
        isOk = true;

        // 注入完成, 读取一些数据
        if (pModuleHandle)
        {
            // 读取模块地址
            const int offsetModule = offsetof(CALL_ARGUMENT_DATA, hModule);
            ReadProcessMemory(hProcess, pArg + offsetModule, &hModule, sizeof(hModule), 0);
            *pModuleHandle = hModule;
        }
        // 读取函数返回值
        const int offsetFunRet = offsetof(CALL_ARGUMENT_DATA, funRet);
        ReadProcessMemory(hProcess, pArg + offsetFunRet, &funRet, sizeof(funRet), 0);
    }
    __finally
    {
        // 如果这个地址是作为两个进程交互使用的缓冲区, 那这里就不需要释放, 自己把地址保存起来
        if (pAddress)   // 释放内存
            VirtualFreeEx(hProcess, pAddress, 0, MEM_RELEASE);
        CloseHandle(hProcess);  // 关闭进程
    }

    return funRet;
}

int main()
{
    std::cout << "请输入被注入的进程ID: ";
    DWORD pid;
    std::cin >> pid;
    if (pid == 0)
        return 0;

    // argData 是作为参数数据传递到被调用的函数里, 2000个字节, 大小根据自己需要调整
    // 一般不建议超过2000, 如果有超过2000, 建议多申请一块内存, 把数据写入到那里, 然后把地址传递过去
    DLL_ARGUMENT_STRUCT arg = { 0 };

    // 传递到dll里就是下面这些数据
    arg.isDebug = 0;    //dll里处理, 在被调用的函数里是否弹出信息框
    arg.pid     = GetCurrentProcessId();
    arg.tid     = GetCurrentThreadId();
    arg.xxxx    = 123456;

    wchar_t dllFileName[260];
    const int fileBuffer = sizeof(dllFileName) / sizeof(dllFileName[0]);
    GetModuleFileNameW(GetModuleHandleW(0), dllFileName, fileBuffer); // 先获取到程序运行路径
    wchar_t* pos = wcsrchr(dllFileName, '\\');
    if (pos) pos[1] = 0;
    wcscat_s(dllFileName, fileBuffer, L"Inject_DLL.dll");

    HANDLE hModule = 0;
    LPVOID ret = InjectDll(pid, dllFileName, "spy_function_name", &arg, sizeof(arg), &hModule);
    printf("注入结束, 函数返回 = %lld, 模块句柄 = 0x%016llX", (LONG64)ret, (LONG64)hModule);

    return 0;
}

DLL 的代码

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
#include <stdio.h>
#include "../Inject_Include.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

EXTERN_C _declspec(dllexport) LPVOID WINAPI spy_function_name(LPDLL_ARGUMENT_STRUCT arg)
{
    wchar_t text[260];
    swprintf_s(text, 260,
        L"dll被调用, 当前附加的进程 = %d\n"
        L"接收到的参数地址 = 0x%p\n"
        L"arg->isDebug = %d\n"
        L"arg->pid = %d\n"
        L"arg->tid = %d\n"
        L"arg->xxxx = %d\n",
        GetCurrentThreadId(), arg, arg->isDebug, arg->pid, arg->tid, arg->xxxx);
    MessageBoxW(0, text, L"DLL注入成功", 0);
    return (LPVOID)654321;
}


Inject.zip (12.63 KB, 下载次数: 123)


免费评分

参与人数 8威望 +1 吾爱币 +26 热心值 +8 收起 理由
xrryz + 1 + 1 谢谢@Thanks!
又红又专 + 2 + 1 热心回复!
czenmyth + 1 + 1 谢谢@Thanks!
朱朱你堕落了 + 3 + 1 我很赞同!
kaixianxian + 1 + 1 我很赞同!
我是来日狗的 + 1 + 1 我很赞同!
565266718 + 2 + 1 我很赞同!
苏紫方璇 + 1 + 15 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

n92738 发表于 2022-1-1 13:52
先保存 感谢楼主
null2008 发表于 2022-1-1 13:56
chensh 发表于 2022-1-1 13:57
雨之幽 发表于 2022-1-1 15:27
可以呦!!
fangchang819 发表于 2022-1-1 18:40
先收藏,谢谢提供!
lhglhg 发表于 2022-1-1 20:20
可以呦!!
空处 发表于 2022-1-2 06:42
多谢分享,已收藏
tiramisu17 发表于 2022-1-2 10:53
学习 下大佬作品
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-5-22 03:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表