#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;
}