【逆向工程核心原理:DLL注入】

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 就是全局钩子,所有进程都要影响
);
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值