Windows Practice_Dll&Hook_DetourHook库
来源:互联网 发布:生产线显示屏 网络 编辑:程序博客网 时间:2024/06/05 10:15
Detours
Detours是经过微软认证的一个开源软件,下载地址,虽然是开源软件,但是它又分成了两个版本,分别是:
- Detours Professional 3.0 is available for commercial use.
- Detours Express 3.0 is available for immediate download under a no-fee license for research, non-commercial, and non-production use. Detours Express may be used to prototype (but not deploy) commercial projects.
这两个版本的代码是一模一样的,所以如果你的公司稍微大一些的话,就不要使用Detours Professional 3.0版本,以免引来不必要的官司。
Detours编译生成对应的库
这个库实际上就做一件事情,那就是注入的事情。
下面我们来看一下如何使用这个开源库。下载回来的文件目录结构如下:
因为3.0版本支持32位和64位同时挂钩,所以我们可以进行32位的编译和64位的编译。首先我们来看如何编译32位库。
首先找到编译工具,如下所示:
打开后界面如下:
编译界面如下:
对于64位编译,找到64位的编译工具,编译完成界面如下所示:
最后就会生成对应的32位库和64位的库,它们的头文件都一样,如下图所示:
Detours库的使用
首先将lib库和include头文件拷贝到工程里面,然后就可以直接使用了。
// EasyHook.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h"#include <Windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")static int (WINAPI *OldMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT) = MessageBoxW;int WINAPI NewMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType){ return OldMessageBoxW(hWnd, L"经过修改的MessageBox", lpCaption, uType);}void Hook(){ int error = DetourTransactionBegin(); if (error != NO_ERROR) { printf("DetourTransactionBegin Error\r\n"); } error = DetourUpdateThread(GetCurrentThread()); if (error != NO_ERROR) { printf("DetourUpdateThread Error\r\n"); } error = DetourAttach(&(PVOID&)OldMessageBoxW, NewMessageBoxW); if (error != NO_ERROR) { printf("DetourAttach Error\r\n"); } error = DetourTransactionCommit(); if (error != NO_ERROR) { printf("DetourTransactionCommit Error\r\n"); }}int main(){ MessageBoxW(nullptr, L"Test", L"Tips", MB_OK); Hook(); MessageBoxW(nullptr, L"Test", L"Tips", MB_OK); system("pause"); return 0;}
VS2015下简单的反汇编过程查看
我们说这个库与我们前面实现的挂钩方式不同,那么不同点在哪儿呢?我们使用反汇编调试一下:
从图上可以看出,我们可以看出在调用Hook函数的前后,我们的MessageBoxW函数的地址是没有发生变化的,那么它是怎么实现挂钩呢?
先别急我们再继续往下走,猜想可能的区别就是在于MessageBoxW函数里面的代码不一样了。首先我们来看一下调用Hook函数之前的MessageBoxW的汇编代码是什么样子的!!!如下图所示:
我们再看一下调用Hook函数之后的MessageBoxW函数的汇编代码
细心的朋友会马上发现,这不是第一行代码就直接跳转到我们自己的函数了吗?
下面是我们自己函数的汇编代码:
我们用vs2015就先调试到这儿,先让大家对这个库的原理有一个初步的了解。
x64dbg反汇编软件的反汇编过程查看
下面我们将使用x64dbg反汇编软件进行一步一步的跟踪我们的代码。(对于这个工具使用就不再说明了,感兴趣的朋友可以去了解一下。)
首先,我们找到main函数的反汇编代码,为了简单起见,我们直接在第二个MessageBoxW函数上下一个断点,如下图所示:
其次,我们运行到断点处
进入第二个MessageBoxW函数,如下:
从上图中我们看到第一行代码是一个跳转指令,正好跳转到我们自己的函数,我们就再进入我们自己的函数,如下图所示:
里面有一个call指令,调用OldMessageBoxW函数,我们再进入
上图就是这个Hook库的关键代码了,我们用方框圈起来。我们可以看出,总共有5个字节,这5个字节正好是1个字节的jmp加上4个字节的地址。这就是著名的5字节inline Hook!。
剩下的就不详细说明了。
为了能够更好的查看调用Hook的挂钩过程,我们使用源代码的方式进行跟踪一边。
Hook库源代码的挂钩过程跟踪
使用源码的好处就是我们能够跟踪到源码中,看看源码是怎么实现的。工程结构和代码如下图所示:
实际上我们在了解一个新的库的时候,如果有文档的话,看文档和demo是最好的学习方式,恰好Detours给了我们详细的文档和示例代码。这里我们就不多做说明了。
简单的反调试
很多时候,我们不希望别人对我们的程序进行调试,尤其是修改里面的一些功能,这里我们就以Win32程序为例。
// CheckMe.cpp : 定义应用程序的入口点。//#include "stdafx.h"#include "CheckMe.h"#include <process.h>#define MAX_LOADSTRING 100// 全局变量: HINSTANCE hInst; // 当前实例WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名// 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance);BOOL InitInstance(HINSTANCE, int);LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);unsigned int __stdcall CheckMeThread(void *param){ while (true) { DWORD dwPrevTime = GetTickCount(); Sleep(1000); if (GetTickCount() - dwPrevTime > 2000) { ExitProcess(-1); } } return 0;}int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow){ UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。 CloseHandle((HANDLE)_beginthreadex(nullptr, 0, CheckMeThread, nullptr, 0, nullptr)); // 初始化全局字符串 LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_CHECKME, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CHECKME)); MSG msg; // 主消息循环: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam;}//// 函数: MyRegisterClass()//// 目的: 注册窗口类。//ATOM MyRegisterClass(HINSTANCE hInstance){ WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHECKME)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CHECKME); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex);}//// 函数: InitInstance(HINSTANCE, int)//// 目的: 保存实例句柄并创建主窗口//// 注释: //// 在此函数中,我们在全局变量中保存实例句柄并// 创建和显示主程序窗口。//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){ hInst = hInstance; // 将实例句柄存储在全局变量中 HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE;}//// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)//// 目的: 处理主窗口的消息。//// WM_COMMAND - 处理应用程序菜单// WM_PAINT - 绘制主窗口// WM_DESTROY - 发送退出消息并返回////LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_COMMAND: { int wmId = LOWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: 在此处添加使用 hdc 的任何绘图代码... EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0;}// “关于”框的消息处理程序。INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){ UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE;}
这样对于一个新手来说,他使用OD来调试这个程序就很难达到目的了。
那么难道我们没有其它办法来对这样的程序进行调试吗?答案是有的。
因为我们知道这个程序使用的是GetTickCount函数进行的检查,那么我们就可以将这个函数Hook住,来达到反反调试的目的。
反反调试
利用Hook库进行反反调试的演示。
上图显示了我们要用到的三个工程:
其中CheckMe使我们要反反调试的一个对象,也就是上面的代码,它增加了一个线程来检测是否被调试,如果发现被调试,那么就直接结束进程。
HookTickCount是一个Dll程序,用来挂钩的
HookGetTickCountLoad是用来将HookTickCount的Dll程序注入到CheckMe程序中。下面我们来看HookTickCount的源代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "stdafx.h"#include <Windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")static DWORD (WINAPI *Old_GetTickCount)(VOID) = GetTickCount;DWORD WINAPI New_GetTickCount(VOID){ return 0;}extern "C" _declspec(dllexport) void Hook(){ // 使用Hook库,必须至少有一个导出函数来帮助做一些事情,否则就会注入失败。}BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ if (DetourIsHelperProcess()) { return TRUE; } if (ul_reason_for_call == DLL_PROCESS_ATTACH) { DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)Old_GetTickCount, New_GetTickCount); DetourTransactionCommit(); } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)Old_GetTickCount, New_GetTickCount); DetourTransactionCommit(); } return TRUE;}
HookGetTickCountLoad程序实现:
////////////////////////////////////////////////////////////////////////////////// Test DetourCreateProcessWithDll function (withdll.cpp).//// Microsoft Research Detours Package, Version 3.0.//// Copyright (c) Microsoft Corporation. All rights reserved.//#include <stdio.h>#include <windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")#pragma warning(push)#if _MSC_VER > 1400#pragma warning(disable:6102 6103) // /analyze warnings#endif#include <strsafe.h>#pragma warning(pop)////////////////////////////////////////////////////////////////////////////////void PrintUsage(void){ printf("Usage:\n" " withdll.exe [options] [command line]\n" "Options:\n" " /d:file.dll : Start the process with file.dll.\n" " /v : Verbose, display memory at start.\n" " /? : This help screen.\n");}////////////////////////////////////////////////////////////////////////////////// This code verifies that the named DLL has been configured correctly// to be imported into the target process. DLLs must export a function with// ordinal #1 so that the import table touch-up magic works.//struct ExportContext{ BOOL fHasOrdinal1; ULONG nExports;};static BOOL CALLBACK ExportCallback(_In_opt_ PVOID pContext, _In_ ULONG nOrdinal, _In_opt_ LPCSTR pszSymbol, _In_opt_ PVOID pbTarget){ (void)pContext; (void)pbTarget; (void)pszSymbol; ExportContext *pec = (ExportContext *)pContext; if (nOrdinal == 1) { pec->fHasOrdinal1 = TRUE; } pec->nExports++; return TRUE;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void TypeToString(DWORD Type, char *pszBuffer, size_t cBuffer){ if (Type == MEM_IMAGE) { StringCchPrintfA(pszBuffer, cBuffer, "img"); } else if (Type == MEM_MAPPED) { StringCchPrintfA(pszBuffer, cBuffer, "map"); } else if (Type == MEM_PRIVATE) { StringCchPrintfA(pszBuffer, cBuffer, "pri"); } else { StringCchPrintfA(pszBuffer, cBuffer, "%x", Type); }}void StateToString(DWORD State, char *pszBuffer, size_t cBuffer){ if (State == MEM_COMMIT) { StringCchPrintfA(pszBuffer, cBuffer, "com"); } else if (State == MEM_FREE) { StringCchPrintfA(pszBuffer, cBuffer, "fre"); } else if (State == MEM_RESERVE) { StringCchPrintfA(pszBuffer, cBuffer, "res"); } else { StringCchPrintfA(pszBuffer, cBuffer, "%x", State); }}void ProtectToString(DWORD Protect, char *pszBuffer, size_t cBuffer){ if (Protect == 0) { StringCchPrintfA(pszBuffer, cBuffer, ""); } else if (Protect == PAGE_EXECUTE) { StringCchPrintfA(pszBuffer, cBuffer, "--x"); } else if (Protect == PAGE_EXECUTE_READ) { StringCchPrintfA(pszBuffer, cBuffer, "r-x"); } else if (Protect == PAGE_EXECUTE_READWRITE) { StringCchPrintfA(pszBuffer, cBuffer, "rwx"); } else if (Protect == PAGE_EXECUTE_WRITECOPY) { StringCchPrintfA(pszBuffer, cBuffer, "rcx"); } else if (Protect == PAGE_NOACCESS) { StringCchPrintfA(pszBuffer, cBuffer, "---"); } else if (Protect == PAGE_READONLY) { StringCchPrintfA(pszBuffer, cBuffer, "r--"); } else if (Protect == PAGE_READWRITE) { StringCchPrintfA(pszBuffer, cBuffer, "rw-"); } else if (Protect == PAGE_WRITECOPY) { StringCchPrintfA(pszBuffer, cBuffer, "rc-"); } else if (Protect == (PAGE_GUARD | PAGE_EXECUTE)) { StringCchPrintfA(pszBuffer, cBuffer, "g--x"); } else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READ)) { StringCchPrintfA(pszBuffer, cBuffer, "gr-x"); } else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READWRITE)) { StringCchPrintfA(pszBuffer, cBuffer, "grwx"); } else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_WRITECOPY)) { StringCchPrintfA(pszBuffer, cBuffer, "grcx"); } else if (Protect == (PAGE_GUARD | PAGE_NOACCESS)) { StringCchPrintfA(pszBuffer, cBuffer, "g---"); } else if (Protect == (PAGE_GUARD | PAGE_READONLY)) { StringCchPrintfA(pszBuffer, cBuffer, "gr--"); } else if (Protect == (PAGE_GUARD | PAGE_READWRITE)) { StringCchPrintfA(pszBuffer, cBuffer, "grw-"); } else if (Protect == (PAGE_GUARD | PAGE_WRITECOPY)) { StringCchPrintfA(pszBuffer, cBuffer, "grc-"); } else { StringCchPrintfA(pszBuffer, cBuffer, "%x", Protect); }}static BYTE buffer[65536];typedef union{ struct { DWORD Signature; IMAGE_FILE_HEADER FileHeader; } ih; IMAGE_NT_HEADERS32 ih32; IMAGE_NT_HEADERS64 ih64;} IMAGE_NT_HEADER;struct SECTIONS{ PBYTE pbBeg; PBYTE pbEnd; CHAR szName[16];} Sections[256];DWORD SectionCount = 0;DWORD Bitness = 0;PCHAR FindSectionName(PBYTE pbBase, PBYTE& pbEnd){ for (DWORD n = 0; n < SectionCount; n++) { if (Sections[n].pbBeg == pbBase) { pbEnd = Sections[n].pbEnd; return Sections[n].szName; } } pbEnd = NULL; return NULL;}ULONG PadToPage(ULONG Size){ return (Size & 0xfff) ? Size + 0x1000 - (Size & 0xfff) : Size;}BOOL GetSections(HANDLE hp, PBYTE pbBase){ DWORD beg = 0; DWORD cnt = 0; SIZE_T done; IMAGE_DOS_HEADER idh; if (!ReadProcessMemory(hp, pbBase, &idh, sizeof(idh), &done) || done != sizeof(idh)) { return FALSE; } if (idh.e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; } IMAGE_NT_HEADER inh; if (!ReadProcessMemory(hp, pbBase + idh.e_lfanew, &inh, sizeof(inh), &done) || done != sizeof(inh)) { printf("No Read\n"); return FALSE; } if (inh.ih.Signature != IMAGE_NT_SIGNATURE) { printf("No NT\n"); return FALSE; } beg = idh.e_lfanew + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + inh.ih.FileHeader.SizeOfOptionalHeader; cnt = inh.ih.FileHeader.NumberOfSections; Bitness = (inh.ih32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? 32 : 64;#if 0 printf("%d %d count=%d\n", beg, Bitness, cnt);#endif IMAGE_SECTION_HEADER ish; for (DWORD n = 0; n < cnt; n++) { if (!ReadProcessMemory(hp, pbBase + beg + n * sizeof(ish), &ish, sizeof(ish), &done) || done != sizeof(ish)) { printf("No Read\n"); return FALSE; } Sections[n].pbBeg = pbBase + ish.VirtualAddress; Sections[n].pbEnd = pbBase + ish.VirtualAddress + PadToPage(ish.Misc.VirtualSize); memcpy(Sections[n].szName, ish.Name, sizeof(ish.Name)); Sections[n].szName[sizeof(ish.Name)] = '\0';#if 0 printf("--- %p %s\n", Sections[n].pbBeg, Sections[n].szName);#endif } SectionCount = cnt; return TRUE;}BOOL DumpProcess(HANDLE hp){ ULONG64 base; ULONG64 next; MEMORY_BASIC_INFORMATION mbi; printf(" %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "Address", "Offset", "Size", "Typ", "Sta", "Prot", "Ini", "Contents"); printf(" %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "------------", "--------", "--------", "---", "---", "----", "---", "-----------------"); for (next = 0;;) { base = next; ZeroMemory(&mbi, sizeof(mbi)); if (VirtualQueryEx(hp, (PVOID)base, &mbi, sizeof(mbi)) == 0) { break; } if ((mbi.RegionSize & 0xfff) == 0xfff) { break; } next = (ULONG64)mbi.BaseAddress + mbi.RegionSize; if (mbi.State == MEM_FREE) { continue; } CHAR szType[16]; TypeToString(mbi.Type, szType, ARRAYSIZE(szType)); CHAR szState[16]; StateToString(mbi.State, szState, ARRAYSIZE(szState)); CHAR szProtect[16]; ProtectToString(mbi.Protect, szProtect, ARRAYSIZE(szProtect)); CHAR szAllocProtect[16]; ProtectToString(mbi.AllocationProtect, szAllocProtect, ARRAYSIZE(szAllocProtect)); CHAR szFile[MAX_PATH]; szFile[0] = '\0'; DWORD cb = 0; PCHAR pszFile = szFile; if (base == (ULONG64)mbi.AllocationBase) {#if 0 cb = pfGetMappedFileName(hp, (PVOID)mbi.AllocationBase, szFile, ARRAYSIZE(szFile));#endif if (GetSections(hp, (PBYTE)mbi.AllocationBase)) { next = base + 0x1000; StringCchPrintfA(szFile, ARRAYSIZE(szFile), "%d-bit PE", Bitness); } } if (cb > 0) { for (DWORD c = 0; c < cb; c++) { szFile[c] = (szFile[c] >= 'a' && szFile[c] <= 'z') ? szFile[c] - 'a' + 'A' : szFile[c]; } szFile[cb] = '\0'; } if ((pszFile = strrchr(szFile, '\\')) == NULL) { pszFile = szFile; } else { pszFile++; } PBYTE pbEnd; PCHAR pszSect = FindSectionName((PBYTE)base, pbEnd); if (pszSect != NULL) { pszFile = pszSect; if (next > (ULONG64)pbEnd) { next = (ULONG64)pbEnd; } } CHAR szDesc[128]; ZeroMemory(&szDesc, ARRAYSIZE(szDesc)); if (base == (ULONG64)mbi.AllocationBase) { StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), " %12I64x %8I64x %8I64x: %3s %3s %4s %3s : %s", (ULONG64)base, (ULONG64)base - (ULONG64)mbi.AllocationBase, (ULONG64)next - (ULONG64)base, szType, szState, szProtect, szAllocProtect, pszFile); } else { StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), " %12s %8I64x %8I64x: %3s %3s %4s %3s : %s", "-", (ULONG64)base - (ULONG64)mbi.AllocationBase, (ULONG64)next - (ULONG64)base, szType, szState, szProtect, szAllocProtect, pszFile); } printf("%s\n", szDesc); } return TRUE;}//////////////////////////////////////////////////////////////////////// main.//int CDECL main(int argc, char **argv){ BOOLEAN fNeedHelp = FALSE; BOOLEAN fVerbose = FALSE; LPCSTR rpszDllsRaw[256]; LPCSTR rpszDllsOut[256]; DWORD nDlls = 0; for (DWORD n = 0; n < ARRAYSIZE(rpszDllsRaw); n++) { rpszDllsRaw[n] = NULL; rpszDllsOut[n] = NULL; } int arg = 1; for (; arg < argc && (argv[arg][0] == '-' || argv[arg][0] == '/'); arg++) { CHAR *argn = argv[arg] + 1; CHAR *argp = argn; while (*argp && *argp != ':' && *argp != '=') argp++; if (*argp == ':' || *argp == '=') *argp++ = '\0'; switch (argn[0]) { case 'd': // Set DLL Name case 'D': if (nDlls < ARRAYSIZE(rpszDllsRaw)) { rpszDllsRaw[nDlls++] = argp; } else { printf("withdll.exe: Too many DLLs.\n"); fNeedHelp = TRUE; break; } break; case 'v': // Verbose case 'V': fVerbose = TRUE; break; case '?': // Help fNeedHelp = TRUE; break; default: fNeedHelp = TRUE; printf("withdll.exe: Bad argument: %s\n", argv[arg]); break; } } if (arg >= argc) { fNeedHelp = TRUE; } if (nDlls == 0) { fNeedHelp = TRUE; } if (fNeedHelp) { PrintUsage(); return 9001; } /////////////////////////////////////////////////////////// Validate DLLs. // for (DWORD n = 0; n < nDlls; n++) { CHAR szDllPath[1024]; PCHAR pszFilePart = NULL; if (!GetFullPathNameA(rpszDllsRaw[n], ARRAYSIZE(szDllPath), szDllPath, &pszFilePart)) { printf("withdll.exe: Error: %s is not a valid path name..\n", rpszDllsRaw[n]); return 9002; } DWORD c = (DWORD)strlen(szDllPath) + 1; PCHAR psz = new CHAR [c]; StringCchCopyA(psz, c, szDllPath); rpszDllsOut[n] = psz; HMODULE hDll = LoadLibraryExA(rpszDllsOut[n], NULL, DONT_RESOLVE_DLL_REFERENCES); if (hDll == NULL) { printf("withdll.exe: Error: %s failed to load (error %d).\n", rpszDllsOut[n], GetLastError()); return 9003; } ExportContext ec; ec.fHasOrdinal1 = FALSE; ec.nExports = 0; DetourEnumerateExports(hDll, &ec, ExportCallback); FreeLibrary(hDll); if (!ec.fHasOrdinal1) { printf("withdll.exe: Error: %s does not export ordinal #1.\n", rpszDllsOut[n]); printf(" See help entry DetourCreateProcessWithDllEx in Detours.chm.\n"); return 9004; } } ////////////////////////////////////////////////////////////////////////// STARTUPINFOA si; PROCESS_INFORMATION pi; CHAR szCommand[2048]; CHAR szExe[1024]; CHAR szFullExe[1024] = "\0"; PCHAR pszFileExe = NULL; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); szCommand[0] = L'\0'; StringCchCopyA(szExe, sizeof(szExe), argv[arg]); for (; arg < argc; arg++) { if (strchr(argv[arg], ' ') != NULL || strchr(argv[arg], '\t') != NULL) { StringCchCatA(szCommand, sizeof(szCommand), "\""); StringCchCatA(szCommand, sizeof(szCommand), argv[arg]); StringCchCatA(szCommand, sizeof(szCommand), "\""); } else { StringCchCatA(szCommand, sizeof(szCommand), argv[arg]); } if (arg + 1 < argc) { StringCchCatA(szCommand, sizeof(szCommand), " "); } } printf("withdll.exe: Starting: `%s'\n", szCommand); for (DWORD n = 0; n < nDlls; n++) { printf("withdll.exe: with `%s'\n", rpszDllsOut[n]); } fflush(stdout); DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED; SetLastError(0); SearchPathA(NULL, szExe, ".exe", ARRAYSIZE(szFullExe), szFullExe, &pszFileExe); if (!DetourCreateProcessWithDllsA(szFullExe[0] ? szFullExe : NULL, szCommand, NULL, NULL, TRUE, dwFlags, NULL, NULL, &si, &pi, nDlls, rpszDllsOut, NULL)) { DWORD dwError = GetLastError(); printf("withdll.exe: DetourCreateProcessWithDllEx failed: %d\n", dwError); if (dwError == ERROR_INVALID_HANDLE) {#if DETOURS_64BIT printf("withdll.exe: Can't detour a 32-bit target process from a 64-bit parent process.\n");#else printf("withdll.exe: Can't detour a 64-bit target process from a 32-bit parent process.\n");#endif } ExitProcess(9009); } if (fVerbose) { DumpProcess(pi.hProcess); } ResumeThread(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); DWORD dwResult = 0; if (!GetExitCodeProcess(pi.hProcess, &dwResult)) { printf("withdll.exe: GetExitCodeProcess failed: %d\n", GetLastError()); return 9010; } for (DWORD n = 0; n < nDlls; n++) { if (rpszDllsOut[n] != NULL) { delete[] rpszDllsOut[n]; rpszDllsOut[n] = NULL; } } return dwResult;}/////////////////////////////////////////////////////////////////// End of File.
最后使用x32od 调试的时候,将已经运行起来的CheckMe程序附加上就可以进行调试了!!!是不是很酷呢???
除了上面的5字节注入外还有一些其他的注入方式
- APC注入
- 输入法注入,在切换输入法的时候进行注入,并且不会被查杀
- 劫持注入,平时的程序都要加载系统Dll,但是有一个加载顺序,先加载自身Dll,那么我就可以写一个同名的Dll让你加载,达到劫持注入的目的。
- WriteProcessMemory注入,在启动进程后会暂停主,然后写入一个LoadLibrary函数,然后再启动一个远线程,然后执行LoadLibrary里面的代码,从而达到注入的目的。
- 还有无Dll注入,也就是注入代码
mhook库
官网下载地址
这里就不多做介绍了,它的代码比较简洁,能够用于商业和非商业。
- Windows Practice_Dll&Hook_DetourHook库
- Windows Practice_Dll&Hook_Hook是什么?
- Windows Practice_Dll&Hook_IAT Hook
- Windows Practice_Dll&Hook_消息钩子
- Windows Practice_Dll&Hook_封装IAT Hook
- Windows 进程库
- ruby windows 库
- linux/windows库准备工作
- windows版ncurses库
- windows动态链接库
- windows 动态链接库
- windows 常用库功能
- windows静态库回顾
- windows动态库回顾
- Windows线程库
- Windows库(笔记备忘)
- windows动态链接库
- LIBXML2库windows使用指南
- 那些“不务正业”的软件.......
- 队列与栈的一些基本问题
- poj 2308 Dearboy’s Puzzle
- Codeforces 101484 H Eating Pie
- 树状数组(模板)
- Windows Practice_Dll&Hook_DetourHook库
- 基于Excel的QR二维码生成工具——原理及算法详解(之六)
- windows 环境下在python中安装tensorflow报错问题
- 集成学习
- C++多态
- 1
- 17.10.3日报
- 深入理解ES6 -- 函数
- mysql列值相加为空