首页 > 技术文章 > dll注入及卸载实践

elpsycongroo 2018-01-19 20:02 原文

三种方法:具体详见《逆向工程核心原理》。

1、创建远程线程CreateRemoteThread()

2、使用注册表AppInit_DLLs

3、消息钩取SetWindowsHookEx()

一、远程线程(注意将szPATH数组建在函数中会出现栈溢出,需要建立全局变量)

#include "windows.h"
#include "tchar.h"

#pragma comment(lib, "urlmon.lib")

HMODULE g_hMod = NULL;
TCHAR szPath[MAX_PATH] = { 0, };
DWORD WINAPI ThreadProc(LPVOID lParam) {

    if (!GetModuleFileName(g_hMod, szPath, MAX_PATH))
        return FALSE;

    TCHAR *p = _tcsrchr(szPath, '\\');
    if (!p)
        return FALSE;

    _tcscpy_s(p + 1, MAX_PATH, L"index.html");

    URLDownloadToFile(NULL, L"http://www.xidian.edu.cn", 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:
        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
        CloseHandle(hThread);
        break;
    }

    return TRUE;
}
myhack.cpp
#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)(lstrlen(szDllPath) + 1) * sizeof(TCHAR);
    LPTHREAD_START_ROUTINE pThreadProc;

    // 获得dwPID进程ID对应的目标进程句柄
    if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
        return FALSE;

    // 在目标进程地址空间中为DLL路径名szDllPath开辟一块存储空间,将szDllPath路径字符串写入该空间
    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);

    // 获取当前进程地址空间中LoadLibraryW()函数的地址,该函数由kernel32.dll导入
    hMod = GetModuleHandle(L"kernel32.dll");
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");

    // 在目标进程中运行线程,该线程执行LoadLibraryW()函数并传入被注入DLL路径作为参数
    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;
    }
    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;
}
inject.cpp

卸载:

// EjectDll.exe

#include "windows.h"
#include "tlhelp32.h"
#include "tchar.h"

//由进程名找到进程id号
DWORD FindProcessID(LPCTSTR szProcessName) {
    DWORD dwPID = 0xFFFFFFFF;
    HANDLE hSnapShot = INVALID_HANDLE_VALUE;
    PROCESSENTRY32 pe;

    // 获得系统进程的快照
    pe.dwSize = sizeof(PROCESSENTRY32);
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);

    Process32First(hSnapShot, &pe);
    do {
        if (!_tcsicmp(szProcessName, (LPCTSTR)pe.szExeFile)) {
            dwPID = pe.th32ProcessID;
            break;
        }
    } while (Process32Next(hSnapShot, &pe));

    CloseHandle(hSnapShot);
    return dwPID;
}

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) {
    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return FALSE;

    if (!LookupPrivilegeValue(NULL,           // lookup privilege on local system
        lpszPrivilege,  // privilege to lookup 
        &luid))        // receives LUID of privilege
        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))
        return FALSE;

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
        return FALSE;

    return TRUE;
}

BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName) {
    BOOL bMore = FALSE, bFound = FALSE;
    HANDLE hSnapshot, hProcess, hThread;
    HMODULE hModule = NULL;
    MODULEENTRY32 me = { sizeof(me) };
    LPTHREAD_START_ROUTINE pThreadProc;

    // dwPID = notepad进程的id号
    // 使用TH32CS_SNAPMODULE参数,获得加载到notepad进程地址空间的DLL信息
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);

    bMore = Module32First(hSnapshot, &me);
    for (; bMore; bMore = Module32Next(hSnapshot, &me)) {
        if (!_tcsicmp((LPCTSTR)me.szModule, szDllName) ||
            !_tcsicmp((LPCTSTR)me.szExePath, szDllName)) {
            bFound = TRUE;
            break;
        }
    }

    if (!bFound) {
        CloseHandle(hSnapshot);
        return FALSE;
    }

    if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
        return FALSE;

    hModule = GetModuleHandle(L"kernel32.dll");
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
    hThread = CreateRemoteThread(hProcess, NULL, 0,
        pThreadProc, me.modBaseAddr,
        0, NULL);
    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hThread);
    CloseHandle(hProcess);
    CloseHandle(hSnapshot);

    return TRUE;
}

int _tmain(int argc, TCHAR* argv[]) {
    DWORD dwPID = 0xFFFFFFFF;

    dwPID = FindProcessID(L"notepad.exe");
    if (dwPID == 0xFFFFFFFF) //没有找到notepad进程
        return 1;

    // 更改特权
    if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
        return 1;

    // 卸载DLL
    if (EjectDll(dwPID, L"myhack.dll"))
        _tprintf(L"EjectDll(%d, \"%s\") success!!!\n", dwPID, L"myhack.dll");
    else
        _tprintf(L"EjectDll(%d, \"%s\") failed!!!\n", dwPID, L"myhack.dll");

    return 0;
}
eject.cpp

二、使用注册表(调用进程执行程序)

修改AppInit_DLLs和LoadAppInit_DLLs,路径名使用单右斜杠

#include "windows.h"
#include "tchar.h"

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:
        //获得当前DLL被装载到的进程的可执行文件的路径到szPath中
        if (!GetModuleFileName(NULL, szPath, MAX_PATH))
            break;
        if (!(p = _tcsrchr(szPath, '\\')))
            break;
        if (lstrcmpi(p + 1, _T("notepad.exe")))
            break;
        //当前DLL被加载到的进程的可执行文件为notepad.exe,调用IE访问www.xidian.edu.cn
        wsprintf(szCmd, _T("%s %s"), _T("C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe"), _T("http://www.xidian.edu.cn"));
        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;
}
myhack2.cpp

三、消息钩取

详见12.24逆向工程上机作业

推荐阅读